convert.cpp

Go to the documentation of this file.
00001 // $Id: convert.cpp 1282 2006-06-09 09:46:49Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 // These functions provide conversion between Millipoints and Strings.
00099 
00100 /*  Author:     Rik
00101     Created:    11/5/93
00102     Purpose:    These functions will provide a means of converting from Doc Coords (millipoints)
00103                 to Strings and visa versa. For example, convert 72000 millipoints to the string
00104                 1in or 72pt as well as converting from the string '1in72pt' to 144000
00105                 millipoints. The units to convert to can be chosen, as can the number of 
00106                 decimal points. When converting from string back to millipoints, all the valid
00107                 units are added together. If an error is detected (ie '4cm72zx' ), then
00108                 everything up to the error will be used (4cm).  */
00109 
00110 
00111 
00112 // Better find out about the string class and all the other types and stuff
00113 
00114 #include "camtypes.h"                           // Good ol' Camtypes
00115 //#include "ccmaths.h"                          // 64 bit muldiv - in camtypes.h [AUTOMATICALLY REMOVED]
00116 //#include "convert.h"                          // function prototypes - in camtypes.h [AUTOMATICALLY REMOVED]
00117 //#include "markn.h"                                // For unit constants
00118 //#include "node.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00119 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00120 //#include "units.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00121 //#include "app.h"                              // Camelot object - in camtypes.h [AUTOMATICALLY REMOVED]
00122 //#include "peter.h"                                // _R(IDS_MEMORYFORMAT_BYTE) ...
00123 #include "localenv.h"                           // for locale string settings
00124 //#include "richard3.h"                         // more naughty inline strings...
00125 
00126 
00127 // Put my version number into the About box
00128 DECLARE_SOURCE( "$Revision: 1282 $" );
00129 
00130 // Declare smart memory handling in Debug builds
00131 #define new CAM_DEBUG_NEW
00132 
00133 CC_IMPLEMENT_DYNAMIC(DimScale, CCObject)
00134 
00135 // Set up the defaults for the Convert class
00136 
00137 // The default DimScale object is an inactive one that is used as a fall-back in the 
00138 // frightening event of one not being found by DimScale::GetPtrDimScale(Node*)
00139 DimScale*   pDefaultDimScale = NULL;
00140 
00141 char        Convert::DecimalPoint       = '.';  // Character to separate whole part of number from fractional part
00142 char        Convert::ThousandSep        = ',';  // Char to separate thousands, e.g. 10,000
00143 char        Convert::MinusSign          = '-';  // What to show if go less than zero
00144 UINT32      Convert::NumDecimalPlaces   = 2;    // Number of decimal places to display to by default
00145 
00146 /******************************************************************************************
00147 
00148 >   static BOOL Convert::Init()
00149 
00150     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00151     Created:    25/1/95
00152     Inputs:     -
00153     Outputs:    -
00154     Returns:    -
00155     Purpose:    AppPrefsDlg Init method. Called when the kernel initialises.
00156                 It reads from the Windows ini file the settings for things like the
00157                 current decimal point character, thousands separator and number of
00158                 decimal places and stores these for later use.
00159     SeeAlso:    GetCurrentNumberFormat();
00160 
00161 ******************************************************************************************/
00162 
00163 BOOL Convert::Init()
00164 {
00165 
00166 //  // Declare any preferences that we require.
00167 //  if ( Camelot.DeclareSection(TEXT("Preferences"), 3) )
00168 //  {
00169 //      // section declared ok so now define the preference option  
00170 //      Camelot.DeclarePref(TEXT("Preferences"), TEXT("DecimalPointChar"), &DecimalPoint, 0, 255);
00171 //      Camelot.DeclarePref(TEXT("Preferences"), TEXT("ThousandSepChar"), &ThousandSep, 0, 255);
00172 //  }
00173 
00174     // Get the current details from the OS about the number format specified by the user
00175     // If fails then return this to the caller.
00176     return GetCurrentNumberFormat();
00177 }
00178 
00179 /********************************************************************************************
00180 
00181 >   static  BOOL Convert::GetCurrentNumberFormat()
00182 
00183     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00184     Created:    12/9/95
00185     Inputs:     -
00186     Outputs:    - 
00187     Returns:    -
00188     Purpose:    Read from the operating system what the user has defined to be their decimal
00189                 point character and thousands separator character and store these in the
00190                 class variables.
00191                 It is now also called from the mainframe message handler, when it 
00192                 receives a WM_WININICHANGE message.
00193     Errors:     -
00194     SeeAlso:    CMainFrame::OnWinIniChange()
00195 
00196 ********************************************************************************************/
00197 
00198 BOOL Convert::GetCurrentNumberFormat()
00199 {
00200     String_8    ThousandsSepStr( _T(",") ); 
00201     String_8    DecimalPointStr( _T(".") ); 
00202     NumDecimalPlaces = 2;
00203 
00204     // Read from the operating system what the user has defined to be their decimal point
00205     // character and thousands separator character.
00206     LocalEnvironment::GetThousandsSeparator(&ThousandsSepStr);
00207     LocalEnvironment::GetDecimalPointChar(&DecimalPointStr);
00208     LocalEnvironment::GetNumberOfDecimalPlaces(&NumDecimalPlaces);
00209     
00210     // Set up the static char variables to reflect these
00211     ThousandSep = ((TCHAR *) ThousandsSepStr)[0];
00212     DecimalPoint = ((TCHAR *) DecimalPointStr)[0];
00213 
00214     // Check for "testing" of internationalisation.
00215     ERROR3IF(ThousandSep == DecimalPoint,
00216                 "Convert::GetCurrentNumberFormat: decimal point and "
00217                 "thousands separator are the same");
00218 
00219 //char to TCHAR for DBCS
00220 TRACEUSER( "Neville", wxT("InitConvert() ThousandsSepStr=%s\n"), (TCHAR *)ThousandsSepStr );
00221 TRACEUSER( "Neville", wxT("InitConvert() DecimalPointStr=%s\n"), (TCHAR *)DecimalPointStr );
00222 TRACEUSER( "Neville", wxT("InitConvert() NumDecimalPlaces=%d\n"), NumDecimalPlaces );
00223 
00224     return TRUE;
00225 }
00226 
00227 
00228 /********************************************************************************************
00229 
00230 >   static  char Convert::GetDecimalPointChar()
00231 
00232     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00233     Created:    12/9/95
00234     Inputs:     -
00235     Outputs:    - 
00236     Returns:    The current decimal point character being used.
00237     Purpose:    To find out what the current decimal point character is.
00238     SeeAlso:    SetDecimalPointChar(); GetCurrentNumberFormat();
00239 
00240 ********************************************************************************************/
00241 
00242 char Convert::GetDecimalPointChar()
00243 {
00244     return DecimalPoint;
00245 }
00246 
00247 /********************************************************************************************
00248 
00249 >   static  char Convert::GetThousandsSepChar()
00250 
00251     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00252     Created:    12/9/95
00253     Inputs:     -
00254     Outputs:    - 
00255     Returns:    The current thousands separator character being used.
00256     Purpose:    To find out what the current thousands separator character is.
00257     SeeAlso:    SetThousandsSepChar(); GetCurrentNumberFormat();
00258 
00259 ********************************************************************************************/
00260 
00261 char Convert::GetThousandsSepChar()
00262 {
00263     return ThousandSep;
00264 }
00265 
00266 
00267 /********************************************************************************************
00268 
00269 >   static  UINT32 Convert::GetNumberDecimalPlaces()
00270 
00271     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00272     Created:    12/9/95
00273     Inputs:     -
00274     Outputs:    - 
00275     Returns:    The current number of decimal places being used.
00276     Purpose:    To find out what the current number of decimal places is.
00277     SeeAlso:    SetNumberDecimalPlaces();
00278 
00279 ********************************************************************************************/
00280 
00281 UINT32 Convert::GetNumberDecimalPlaces()
00282 {
00283     return NumDecimalPlaces;
00284 }
00285 
00286 /********************************************************************************************
00287 
00288 >   static  BOOL Convert::SetDecimalPointChar(char NewDecimalPoint)
00289 
00290     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00291     Created:    12/9/95
00292     Inputs:     -
00293     Outputs:    - 
00294     Returns:    True if set correctly, False otherwise.
00295     Purpose:    Allows the setting up of the character to separate whole part of number from
00296                 the fractional part in displayed numbers e.g. 56.79
00297                 This is read from the OS at present. This function just provided just in case
00298                 we wish to overide this in the future.
00299     SeeAlso:    GetDecimalPointChar(); GetCurrentNumberFormat();
00300 
00301 ********************************************************************************************/
00302 
00303 BOOL Convert::SetDecimalPointChar(char NewDecimalPoint)
00304 {
00305     // Don't allow a blank to be set.
00306     //if (NewDecimalPoint = '') return FALSE;
00307 
00308     DecimalPoint = NewDecimalPoint;
00309 
00310     return TRUE;
00311 }
00312 
00313 /********************************************************************************************
00314 
00315 >   static  BOOL Convert::SetThousandsSepChar(char NewThousandsSep)
00316 
00317     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00318     Created:    12/9/95
00319     Inputs:     -
00320     Outputs:    - 
00321     Returns:    True if set correctly, False otherwise.
00322     Purpose:    Allows the setting up of the character to be used to separate thousands in
00323                 displayed numbers e.g. 10,000.
00324                 This is read from the OS at present. This function just provided just in case
00325                 we wish to overide this in the future.
00326 
00327     SeeAlso:    GetThousandsSepChar(); GetCurrentNumberFormat();
00328 
00329 ********************************************************************************************/
00330 
00331 BOOL Convert::SetThousandsSepChar(char NewThousandsSep)
00332 {
00333     // Don't allow a blank to be set.
00334     //if (NewThousandsSep = '') return FALSE;
00335 
00336     ThousandSep = NewThousandsSep;
00337 
00338     return TRUE;
00339 }
00340 
00341 /********************************************************************************************
00342 
00343 >   static  BOOL Convert::SetNumberDecimalPlaces(UINT32 NewDPs)
00344 
00345     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00346     Created:    12/9/95
00347     Inputs:     NewDPs  new number of decimal places to use
00348     Outputs:    - 
00349     Returns:    True if set correctly, False otherwise.
00350     Purpose:    Allows the setting up of the number of decimal places to display to by default
00351                 This is read from the OS at present. This function just provided just in case
00352                 we wish to overide this in the future.
00353     SeeAlso:    GetNumberDecimalPlaces(); GetCurrentNumberFormat();
00354 
00355 ********************************************************************************************/
00356 
00357 BOOL Convert::SetNumberDecimalPlaces(UINT32 NewDPs)
00358 {
00359     // Set some limit to the number allowed
00360     if (NewDPs > 9) return FALSE;
00361 
00362     NumDecimalPlaces = NewDPs; 
00363 
00364     return TRUE;
00365 }
00366 
00367 
00368 /******************************************************************************************
00369 
00370 >   static BOOL Convert::ReplaceDecimalPoint(StringBase* pString)
00371 
00372     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00373     Created:    27/1/95
00374     Inputs:     pString - Pointer to the string to be parsed.
00375     Outputs:    pString - Pointer to the string that should now have the proper decimal point 
00376     Returns:    TRUE if the conversion worked, false otherwise
00377     Purpose:    Searches the specified string for a decimal point and replaces this with the
00378                 specified DecimalPoint character. It assumes that a check has been made
00379                 already to see if we are using a non-decimal point character and so this
00380                 routine is only called when the replacement is actually required.
00381                 This MUST ALWAYS be after the StripTrailingZeros code. Otherwise, the 
00382                 StripTrailingZeros code would have to search for two items, a decimal point
00383                 and the international form of the decimal point.
00384 
00385     SeeAlso:    MillipointsToString; DimScale::ConvertToUnits; DoubleToString;
00386                 Convert::StripTrailingZeros;
00387 
00388 ********************************************************************************************/
00389 
00390 BOOL Convert::ReplaceDecimalPoint(StringBase* pString)
00391 {
00392     // Could probably be optimised to be quicker
00393 
00394     // Make up a string of the new decimal point character 
00395     String_8 InsertStr;
00396     ((TCHAR *) InsertStr)[0] = DecimalPoint;
00397     ((TCHAR *) InsertStr)[1] = 0;
00398 
00399     // Work out the position of the current decimal point character, - 1 if none
00400     INT32   Position;
00401     String_8            InsertMark(_R(IDS_CONVERT_DP_CHAR));
00402 
00403     Position = pString->Sub(InsertMark);
00404     
00405     // If decimal point was found then put the new decimal point character in place 
00406     if (Position > 0)
00407     {
00408         pString->Remove(Position, 1);
00409         pString->Insert(InsertStr, Position);          
00410     }
00411     
00412     return TRUE;
00413 }
00414 
00415 /********************************************************************************************
00416 
00417 >   static BOOL Convert::StripTrailingZeros(StringBase* pString)
00418 
00419     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00420     Created:    12/7/95
00421     Inputs:     pString - string to have trailing zeros removed
00422     Outputs:    pString - string with trailing zeros removed
00423     Returns:    FALSE if fails
00424     Purpose:    Strip trailing zeros (& decimal point) from a string containing a decimal number
00425                 This MUST ALWAYS be called before the replace decimal point character code.
00426                 Otherwise, we would have to search for two items, a decimal point and the 
00427                 international form of the decimal point.
00428     SeeAlso:    MillipointsToString; DimScale::ConvertToUnits; DoubleToString;
00429                 Convert::ReplaceDecimalPoint;
00430 
00431 ********************************************************************************************/
00432 
00433 BOOL Convert::StripTrailingZeros(StringBase* pString)
00434 {
00435     // Get the decimal point character that we are going to search for into one of our
00436     // strings. This MUST be the decimal point character as this is ALWAYS called before
00437     // the replace decimal point character. Otherwise, we would have to search for two
00438     // items.
00439     String_8 DPChar(_R(IDS_CONVERT_DP_CHAR));
00440     const String_8 ZeroChar(_R(IDS_CONVERT_ZERO_CHAR));
00441 
00442     // if there is a decimal point in the string ...
00443     if (pString->Sub(DPChar)!=-1)
00444     {
00445         // skip backwards over trailing zeros
00446         String_8        TmpStr;
00447         INT32               NewStrLen = pString->Length();
00448         do
00449         {
00450             NewStrLen-=1;
00451             pString->Mid(&TmpStr,NewStrLen,1);
00452         } while (TmpStr==ZeroChar);
00453 
00454         // if this previous char is NOT a decimal point DO NOT strip it
00455         if (TmpStr!=DPChar)
00456             NewStrLen+=1;
00457 
00458         // remove the trailing zeros from the original string
00459         pString->Left(pString,NewStrLen);
00460     }
00461 
00462     return TRUE;
00463 }
00464 
00465 
00466 /********************************************************************************************
00467 
00468 >   static BOOL Convert::IsCharUnitType(TCHAR Char)
00469 
00470     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 
00471     Created:    27/6/94
00472     Inputs:     Char - the character to check
00473     Outputs:    -
00474     Returns:    TRUE  - This could be part of a unit type specifier
00475                 FALSE - Sorry, but it's either a white space or a number
00476     Purpose:    Checks to see if this char could be part of a string that specifies a unit
00477                 We have to allow most chars so that arbitrary units can be defined like such
00478                 as pounds, dollars or percentages
00479                 Illegal unit specifier chars are :-
00480                     ASCII value <= ' '
00481                     Numericals          - '1', '2', etc
00482                     Minus sign          - '-'
00483                     Decimal point       - '.'
00484                     Thousand separator  - ',' as in "10,000" 
00485     Errors:     -
00486 
00487 ********************************************************************************************/
00488 
00489 BOOL Convert::IsCharUnitType(TCHAR Char)
00490 {
00491     return (    (unsigned(Char) > unsigned(TEXT(' '))) &&
00492                 (!StringBase::IsNumeric(Char)) &&
00493                 (Char != MinusSign) &&
00494                 (Char != DecimalPoint) &&
00495                 (Char != ThousandSep)
00496             );
00497 } 
00498 
00499 /********************************************************************************************
00500 
00501 >   static BOOL Convert::IsCharStartOfNumber(TCHAR Char)
00502 
00503     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 
00504     Created:    27/6/94
00505     Inputs:     Char - the character to check
00506     Outputs:    -
00507     Returns:    TRUE  - This could be the first char of a number
00508                 FALSE - Sorry, but it's definitely not a number
00509     Purpose:    Checks to see if this char could be the first char in a string that specifies
00510                 a number
00511                 Legal number-starting chars are :-
00512                     Numericals          - '1', '2', etc
00513                     Minus sign          - '-'
00514                     Decimal point       - '.'
00515     Errors:     -
00516 
00517 ********************************************************************************************/
00518 
00519 BOOL Convert::IsCharStartOfNumber(TCHAR Char)
00520 {
00521     return (    (StringBase::IsNumeric(Char)) ||
00522                 (Char == MinusSign) ||
00523                 (Char == DecimalPoint)
00524             );
00525 }
00526 
00527 /********************************************************************************************
00528 
00529 >   static BOOL Convert::ReadUnitType(StringBase* pStr,INT32* pPos,UnitType* pUnitType)
00530 
00531     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 
00532     Created:    27/6/94
00533     Inputs:     pStr - Ptr to the string to get unit type
00534                 pPos - *pPos = the pos to start scannning the string from (0 is first char)
00535                 pUnitType - Ptr to a UnitType
00536     Outputs:    *pPos is the pos the scanning stopped
00537                 *pUnitType is the units represented by the string
00538     Returns:    TRUE  - units have been recognised and value stored in *pUnitType is valid
00539                         OR
00540                         no units have been specified and *pUnitType == NOTYPE
00541                 FALSE - What are these units eh?
00542     Purpose:    General purpose routine for extracting the unit type from a string
00543                 E.g. "42cm45mm" with *pPos = 2 returns TRUE with *pUnitType == CENTIMETRES & *pPos == 4
00544                      "42cm45mm" with *pPos = 6 returns TRUE with *pUnitType == MILLIMETRES & *pPos == 8
00545     Errors:     -
00546 
00547 ********************************************************************************************/
00548 
00549 BOOL Convert::ReadUnitType(const StringBase &Str,INT32* pPos,UnitType* pUnitType)
00550 {
00551     INT32                   len = Str.Length();
00552     const TCHAR        *pChar = (const TCHAR *)Str;
00553     TCHAR               UnitCharArray[256]; 
00554     INT32 i;
00555     BOOL ok = TRUE;
00556     //Added for DBCS; Strip leading crap
00557     while (*pPos < len && iswspace(pChar[*pPos])) //while (*pPos < len && pChar[*pPos] <= ' ')
00558           (*pPos)++ ;           
00559 
00560     i = 0;
00561     if (IsCharUnitType(pChar[*pPos]))
00562     {
00563         // Copy unit-specifying chars into UnitCharArray
00564         // NO LONGER copes with wierd unit specifiers that contain numbers too. e.g. "nu2", "b54c"
00565         // as of 18/5/95 (MarkN)
00566         while ( *pPos < len && (IsCharUnitType(pChar[*pPos])) && i<256) // || StringBase::IsNumeric(pChar[*pPos])) && 
00567             UnitCharArray[i++] = pChar[(*pPos)++];
00568     }
00569 
00570     UnitCharArray[i] = 0;   // Visit the string Terminator (I'm a null char; that's what I do)
00571 
00572     String_256 UnitString = UnitCharArray;
00573     
00574     //char changed to TCHAR for DBCS 
00575 //  TCHAR* p = UnitString;  // for debugging purposes
00576     DocUnitList* pDocUnitList = DocUnitList::GetCurrentDocUnitList();
00577 
00578     if (!UnitString.IsEmpty())
00579     {
00580         // if the string isn't empty, then we must recognise the unit
00581         // otherwise we'll have to fail
00582         *pUnitType = pDocUnitList->FindUnitType(UnitString);
00583         ok = (*pUnitType != NOTYPE);
00584     }
00585     else
00586         *pUnitType = NOTYPE;    // Empty string means NOTYPE means use a default type from somewhere
00587     
00588 
00589     return (ok);
00590 }
00591 
00592 
00593 /********************************************************************************************
00594 
00595 >   static BOOL Convert::ReadNumber(StringBase* pStr,INT32* pPos,double* pResult)
00596 
00597     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 
00598     Created:    27/6/94
00599     Inputs:     pStr - Ptr to the string to get value from
00600                 pPos - *pPos = the pos to start scannning the string from (0 is first char)
00601                 pResult  - Ptr to a double
00602     Outputs:    *pPos is the pos the scanning stopped
00603                 *pResult = The number represented at the specified portion of the string
00604     Returns:    TRUE  - a valid number was read
00605                 FALSE - something's a bit dodgey about that number mate
00606     Purpose:    General purpose routine for extracting the number from a string
00607                 E.g. "42cm45.7mm"  with *pPos == 0 returns TRUE with *pResult and  42.0 & *pPos == 2
00608                      "42cm-45.7mm" with *pPos == 4 returns TRUE with *pResult and -45.7 & *pPos == 9
00609     Errors:     -
00610 
00611 ********************************************************************************************/
00612 
00613 BOOL Convert::ReadNumber( const StringBase &Str,INT32* pPos,double* pResult)
00614 {
00615     INT32           len         = Str.Length();
00616     const TCHAR    *pChar       = Str;
00617     BOOL            IsNegative  = FALSE;
00618     double          Number      = 0.0;
00619 
00620     //Added for DBCS Strip leading crap
00621     while (*pPos < len && iswspace(pChar[*pPos]))  //while (*pPos < len && pChar[*pPos] <= ' ')
00622         (*pPos)++;
00623     
00624     // Check for a minus sign; Added for DBCS
00625     if( pChar[*pPos] == MinusSign ) //if ( pChar[*pPos] == MinusSign )
00626     {
00627         IsNegative = TRUE;
00628         (*pPos)++;
00629         if (*pPos >= len)   return FALSE;
00630     }
00631     
00632     // Get the actual number                                        Added for DBCS                                  
00633     while( *pPos < len && 
00634         ( StringBase::IsNumeric(pChar[*pPos]) || 
00635            pChar[*pPos] == ThousandSep ) )//|| pChar[*pPos] == ThousandSep) )
00636     {
00637         //Added for DBCS
00638         if (pChar[*pPos] != ThousandSep ) //if (pChar[*pPos] != ThousandSep)
00639         {
00640             Number = (Number * 10.0) + ( pChar[*pPos] - TEXT('0') );
00641         }
00642         (*pPos)++;
00643     }
00644 
00645     // Check for a decimal place; Added for DBCS 
00646     if ( pChar[*pPos] == DecimalPoint) //if ( pChar[*pPos] == DecimalPoint )
00647     {
00648         (*pPos)++;
00649         if (*pPos < len)    // If the string ends in a DP, then we return the number now
00650         {   
00651             // Otherwise, we continue reading the fractional part of the string...
00652             INT32 DecimalFactor = 10;
00653             while ( *pPos < len  &&  StringBase::IsNumeric(pChar[*pPos]) )
00654             {
00655                 Number += (double)( pChar[*pPos] - TEXT('0') ) / DecimalFactor;
00656                 DecimalFactor *= 10;
00657                 (*pPos)++;
00658             }
00659         }
00660     }
00661 
00662     // If the number started with a minus sign, then make sure it is negative
00663     if (IsNegative)
00664         Number = -Number;
00665 
00666     *pResult = Number;
00667     return TRUE;
00668 }
00669 
00670 /********************************************************************************************
00671 
00672 >   static double Convert::ConvertToNewUnits(double Value,UnitType Units,UnitType NewUnits)
00673 
00674     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00675     Created:    27/6/94
00676     Inputs:     Value   - value to convert
00677                 OldUnits- units Value is defined in
00678                 NewUnits- the units you want Value to be converted toTYPE
00679     Outputs:    -
00680     Returns:    The new value
00681     Purpose:    Used convert one value into an equivalent value in another unit base
00682                 E.g. ConvertToNewUnits(3,CENTIMETRES,MILLIMETRES) would return 30.0
00683                 because 3cm == 30mm             
00684 
00685 ********************************************************************************************/
00686 
00687 double Convert::ConvertToNewUnits(double Value,UnitType OldUnits,UnitType NewUnits)
00688 {
00689     ENSURE(NewUnits != NOTYPE,"Can't convert to NOTYPE units");
00690 
00691     DocUnitList* pDocUnitList = DocUnitList::GetCurrentDocUnitList();
00692     Unit* pNewUnit = pDocUnitList->FindUnit(NewUnits);
00693     double NumMillipoints = 1.0;
00694 
00695     if (OldUnits != NOTYPE)
00696     {
00697         Unit* pOldUnit = pDocUnitList->FindUnit(OldUnits);
00698         NumMillipoints = Value * pOldUnit->GetMillipoints();
00699     }
00700     else
00701         NumMillipoints = Value;
00702 
00703     return (NumMillipoints / pNewUnit->GetMillipoints());
00704 }
00705 
00706 /********************************************************************************************
00707 
00708 >   Static BOOL Convert::StringToComponents(StringBase* InputString,
00709                                             double* pValue, UnitType* pUnits)
00710 
00711     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 
00712     Created:    14/6/94 (changed considerably on 27/6/94 by Markn)
00713     Inputs:     InputString - The string to get values from
00714                 pValue      - The value of the numerical part of the string
00715                 pUnits      - The unit value of the unit part of the string
00716                               if no units are specified, *pUnits = NOTYPE
00717     Outputs:    -
00718     Returns:    TRUE    - Valid string
00719                 FALSE   - Something wrong with the string
00720     Purpose:    General purpose routine for extracting the value and unit components of a string.
00721                 E.g.1 the string "42.6in" would extract the value 42.6 and the unit type INCHES
00722                 E.g.2 The string "42.6" would give *pValue=42.6,*pUnits=NOTYPE, and TRUE is returned.
00723                 E.g.3 "4in5in" gives *pValue=9,*pUnits=INCHES, and returns TRUE
00724                 E.g.4 "1in2cm" gives *pValue = 1.79,*pUnits=INCHES, and returns TRUE
00725                     In this case it takes the first unit specified as the dominant unit (INCHES in this
00726                     case), so the result is 1in plus 2cm converted to INCHES which is about 0.79in
00727     Errors:     This function can fail if the string was not a valid one. ie the
00728                 string '12zx'. zx is not a unit that Camelot understands
00729                 and so fails.
00730 
00731 ********************************************************************************************/
00732 
00733 BOOL Convert::StringToComponents( const StringBase &str,double* pValue,UnitType* pUnits)
00734 {
00735     TCHAR*      MyString;
00736     TCHAR       Char;
00737     INT32       Pos         = 0;
00738     INT32       len         = str.Length();
00739     String_256  InputString( str );
00740 //  BOOL        IsNegative  = FALSE;
00741     double      Result      = 0.0;
00742     UnitType    MainUnits   = NOTYPE;
00743     
00744     *pValue = 1.0;
00745     *pUnits = INCHES;
00746     
00747     // Make sure that the string is in lower case as per SI units
00748     InputString.toLower();
00749     MyString = (TCHAR *)InputString;
00750 
00751     // I might consider adding this to the base class StringBase, BUT at the moment
00752     // its not really necessary ....
00753     //
00754     // JCF: fixed this to be internationally portable ie. what is alphanumeric in
00755     // your language?   
00756     //
00757     while (Pos < len)
00758     {
00759         if (!StringBase::IsAlphaNumeric(MyString[Pos]) &&
00760             MyString[Pos] != TEXT('-') &&
00761             MyString[Pos] != TEXT('.') &&
00762             MyString[Pos] != TEXT(','))
00763         {
00764             return FALSE;
00765         }
00766 
00767         Pos++;
00768     }
00769 
00770     Pos = 0;
00771 
00772     while (Pos < len)
00773     {
00774         double Number = 0.0;        
00775         UnitType Units;
00776 
00777         // Strip leading crap   Added for DBCS
00778         while (Pos < len && iswspace( MyString[Pos] ))   //while (Pos < len && MyString[Pos] <= ' ')
00779                Pos++;
00780     
00781         Char = MyString[Pos];
00782         
00783         if (IsCharStartOfNumber(Char))
00784         {
00785             if (!ReadNumber(InputString,&Pos,&Number))
00786                 return FALSE;
00787             if (!ReadUnitType(InputString,&Pos,&Units))
00788                 return FALSE;
00789         }
00790         else
00791         {
00792             if (!ReadUnitType(InputString,&Pos,&Units))
00793                 return FALSE;
00794             if (!ReadNumber(InputString,&Pos,&Number))
00795                 return FALSE;
00796         }
00797         
00798         if (MainUnits == NOTYPE) MainUnits = Units;
00799 
00800         if (MainUnits != Units && MainUnits != NOTYPE)
00801             Number = ConvertToNewUnits(Number,Units,MainUnits);
00802 
00803         Result += Number;
00804     }
00805 
00806     *pUnits = MainUnits;
00807     *pValue = Result;
00808 
00809     return TRUE;
00810 }
00811 
00812 /********************************************************************************************
00813 
00814 >   static double Convert::StringToDouble( StringBase* pInputString, UnitType Default, 
00815                                            BOOL* ValidString )
00816 
00817     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00818     Created:    8/3/94 - modified 14/6/94
00819     Inputs:     pInputString - The string to convert to its millipoint value
00820                 Default - the Unit type to be used if no other units have been
00821                 specified in the string
00822     Outputs:    ValidString - The Address of a bool. This will be set to TRUE if
00823                 the function converted the string without error, FALSE otherwise.
00824     Returns:    double - the number of Millipoints represented by the string 
00825     Purpose:    Convert the string into a floating point representation of the number of 
00826                 millipoints. eg '1in' would be converted to 72000.0 millipoints.
00827                 Does NOT cope with '0.25in0.75in' - this would return 18000.0 millipoints
00828                 instead of 72000.0 millipoints.
00829                 If you want a MILLIPOINT value, use StringToMillipoint to ensure correct
00830                 rounding.
00831     Errors:     This function can fail if the string was not a valid one. ie the
00832                 string '12zx'. zx is not a unit that StringToDouble understands
00833                 and so fails.
00834     SeeAlso:    StringToMillipoint
00835 
00836 ********************************************************************************************/
00837 
00838 double Convert::StringToDouble( const StringBase &InputString, UnitType Default, BOOL* ValidString )
00839 {
00840     double      Number = 1.0;
00841     UnitType    Units;
00842 
00843     *ValidString = StringToComponents( InputString,&Number,&Units);
00844 
00845     if (Units == NOTYPE)
00846         Units = Default;
00847 
00848     if (*ValidString)
00849     {
00850         DocUnitList* pDocUnitList = DocUnitList::GetCurrentDocUnitList();
00851         Unit* pUnit = pDocUnitList->FindUnit(Units);
00852         return (Number * pUnit->GetMillipoints());      // Get the number to millipoints and multiply
00853     }
00854     else
00855         return 72000.0;
00856 }
00857 
00858 
00859 /********************************************************************************************
00860 
00861 >   static MILLIPOINT Convert::StringToMillipoints( StringBase* pInputString, UnitType Default, 
00862                                                     BOOL* ValidString )
00863 
00864     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00865     Created:    8/3/94 - modified 14/6/94
00866     Inputs:     pInputString - The string to convert to its millipoint value
00867                 Default - the Unit type to be used if no other units have been
00868                 specified in the string
00869     Outputs:    ValidString - The Address of a bool. This will be set to TRUE if
00870                 the function converted the string without error, FALSE otherwise.
00871     Returns:    MILLIPOINT - An integer version of the number of Millipoints represented by 
00872                 the string 
00873     Purpose:    Convert the string into a MILLIPOINT representation of the number of 
00874                 millipoints. eg '1in' would be converted to 72000 millipoints.
00875                 Does NOT cope with '0.25in0.75in' - this would return 18000 millipoints
00876                 instead of 72000 millipoints.
00877     Errors:     This function can fail if the string was not a valid one. ie the
00878                 string '12zx'. zx is not a unit that StringToDouble understands
00879                 and so fails.
00880 
00881 ********************************************************************************************/
00882 
00883 MILLIPOINT Convert::StringToMillipoints( const StringBase &InputString, UnitType Default, BOOL* ValidString )
00884 {
00885     double result = StringToDouble( InputString,Default,ValidString);
00886 
00887     return (MILLIPOINT)(result+0.5);
00888 }
00889 
00890 
00891 /********************************************************************************************
00892 
00893 >   static void Convert::NumberToString( MILLIPOINT Number, StringBase* MyString )
00894 
00895     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
00896     Created:    1/9/93
00897     Inputs:     Number - The number to be turned into a string
00898     Outputs:    MyString - the string is appended to this string
00899     Purpose:    Appends the string representation of the given number to the end
00900                 of MyString
00901 
00902 ********************************************************************************************/
00903 
00904 void Convert::NumberToString( MILLIPOINT Number, StringBase* MyString )
00905 {
00906     INT32  Factor = 1;
00907     TCHAR ch[2]; 
00908     ch[1] = TEXT('\0');
00909     
00910     // Get a factor that 
00911     while (Factor*10 <= Number)
00912         Factor *= 10;
00913 
00914     while (Factor > 1)
00915     {
00916         // calculate the most significant digit and remove it from the number
00917         INT32 Digit = INT32(Number / Factor);
00918         ch[0] = TEXT('0') + Digit;
00919         *MyString += String_8(ch);
00920         
00921         // Add the digit into the string
00922         Number = Number - (Digit*Factor);
00923         Factor /= 10;
00924     }
00925 
00926     // add in the last character
00927     ch[0] = TEXT('0') + (INT32)Number;
00928     *MyString += String_8(ch);
00929     
00930 }
00931 
00932 
00933 
00934 
00935 /********************************************************************************************
00936 
00937 >   static BOOL Convert::MillipointsToString( double MpValue, UnitType TheUnit,
00938                                               StringBase* OutputString, INT32 DecimalPlaces =  -1)
00939 
00940     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> (rewritten by MarkN to use new units system - 6/7/94)
00941     Created:    1/9/93
00942     Inputs:     MpValue - The number of millipoints to be converted
00943                 TheUnit - The units that you need the result in
00944                 OutputString - Stirng to put value into (See outputs)
00945                 DecimalPlaces - The number of Decimal places required (0-3). This defaults to
00946                 -1 which means use the default preference value. 
00947     Outputs:    OutputString - pointer to a string that is big enough to hold
00948                 the resulting number plus its type (ie 12.45cm)
00949     Returns:    TRUE if all went well and the string is valid, FALSE otherwise
00950     Purpose:    Convert a number in MpValue to a string representation of that
00951                 number in the given units. ie converting 72000 millipoints to inches
00952                 would give the string '1in'.
00953                 If DecimalPlaces = -1 then use the default preference value which the user
00954                 has specified.
00955     See Also:   DocUnitList
00956 
00957 ********************************************************************************************/
00958 
00959 BOOL Convert::MillipointsToString( double MpValue, UnitType TheUnit, StringBase* OutputString,
00960                                    INT32 DecimalPlaces)
00961 {
00962     ERROR2IF(OutputString == NULL,FALSE,"MillipointsToString NULL output string supplied");
00963     // Decimal places will be -1 if the default number is to be used.
00964     
00965     double Value = 1.0;
00966     String_32 Specifier;
00967     TCHAR p[256], format[256], dpformat[256];
00968     
00969     DocUnitList* pDocUnitList = DocUnitList::GetCurrentDocUnitList();
00970     DocUnitList FactoryDefUnits;
00971     if(pDocUnitList==NULL)
00972     {
00973         // certain classes (eg OpDescriptors) may want to call this function to set
00974         // values in controls after they have been read in by the bars/dialogs etc...
00975         // However at that point (Document::GetCurrent() == NULL) so you can't get
00976         // a DocUnitList from the current doc. Hence create our own default units
00977         FactoryDefUnits.Init();
00978         FactoryDefUnits.MakeDefaultUnits();
00979         pDocUnitList = &FactoryDefUnits;
00980     }
00981 
00982     Unit* pUnit = pDocUnitList->FindUnit(TheUnit);
00983 
00984     // Find out how many Units MpValue represents
00985     Value = MpValue / pUnit->GetMillipoints();
00986 
00987     // Get the specifier of the units we're in
00988     Specifier = pUnit->GetSpecifier();
00989 
00990     // check if we want the default number of decimal places
00991     if (DecimalPlaces == -1) DecimalPlaces = NumDecimalPlaces;
00992 
00993     //_stprintf(dpformat,"%%.%df",DecimalPlaces);   // Makes "%.xf" where x is num dp
00994     // Makes the output form "%.xf" where x is num dp.
00995     // %g instead of %f gives leading zero supression but then requires number significant
00996     // figures rather than number of decimal places.
00997     camSnprintf( dpformat, 256, TEXT("%%.%df"), DecimalPlaces) ;
00998 
00999     // Create the string to stick in an editable field (or wherever you like)
01000     if (pUnit->IsPrefix())
01001     {
01002         // Prefix units so show units followed by value
01003         camSnprintf( format, 256, _T("%%s%s"), (LPCTSTR) dpformat );                // ie. %s %.3f
01004         camSnprintf( p, 256, format, (LPCTSTR)Specifier, (double)Value );           // uses FP
01005         *OutputString = p;
01006         // Look for all zeros after decimal point and if so then remove
01007         //StripTrailingZeros(OutputString);
01008     }
01009     else
01010     {
01011         // Suffix units so show value followed by units
01012         camSnprintf( p, 256, dpformat, (double)Value );                     // uses FP
01013         *OutputString = p;
01014 
01015         // Look for all zeros after decimal point and if so then remove
01016         StripTrailingZeros(OutputString);
01017 
01018         // Finally, add in the unit specifier
01019         *OutputString += Specifier;
01020     }
01021 
01022     
01023     // Extra bodge required so that if the user has specified display values using
01024     // a non full stop to show decimal points then we must replace the point that
01025     // is present by the specified character.
01026     if (DecimalPoint != '.')
01027     {
01028         ReplaceDecimalPoint(OutputString);
01029     }
01030     
01031     return TRUE;
01032 }
01033 
01034 
01035 /********************************************************************************************
01036 
01037 >   static BOOL Convert::LongToString( INT32 Number, StringBase* OutputString )
01038 
01039     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
01040     Created:    17/9/93
01041     Inputs:     Number - The number you want turning into a string
01042     Outputs:    OutputString - The string that gets created
01043     Returns:    TRUE if the conversion worked, false otherwise
01044     Purpose:    Converts a INT32 to a its string equivalent.
01045     SeeAlso:    StringToLong
01046 
01047 ********************************************************************************************/
01048 
01049 BOOL Convert::LongToString( INT32 Number, StringBase* OutputString )
01050 {
01051     OutputString -> Empty();
01052 
01053     if (Number < 0)
01054     {
01055         TCHAR   buff[2] ;
01056         buff[0] = TEXT('-');
01057         buff[1] = TEXT('\0');
01058 
01059         *OutputString += String_8(buff);
01060         Number = -Number;
01061         
01062     }
01063     
01064     NumberToString( Number, OutputString );
01065     
01066     return TRUE;
01067 }
01068 
01069 /********************************************************************************************
01070 
01071 >   static BOOL Convert::DoubleToString( double Number, StringBase* OutputString, INT32 DecimalPlaces )
01072 
01073     Author:     Alex_Bligh (Xara Group Ltd) <camelotdev@xara.com>
01074     Created:    16/12/94
01075     Inputs:     Number - The number you want turning into a string
01076                 DecimalPlaces - The number of Decimal places required (0-3). This defaults to
01077                 -1 which means use the default preference value. Don't override it unless
01078                 absolutely necessary.
01079 
01080     Outputs:    OutputString - The string that gets created
01081     Returns:    TRUE if the conversion worked, false otherwise
01082     Purpose:    Converts a double to a its string equivalent.
01083     SeeAlso:    StringToDouble
01084 
01085 This routine is a bit of a bodge
01086 
01087 ********************************************************************************************/
01088 
01089 BOOL Convert::DoubleToString( double Number, StringBase* OutputString, INT32 DecimalPlaces /* =-1 */ )
01090 {
01091     // Generate the output string in a simple char array
01092     TCHAR dpformat[32]; 
01093     TCHAR TempString[32];
01094 
01095     // Use the default/preference or desired number of decimal places
01096     if (DecimalPlaces < 0)
01097         DecimalPlaces = (INT32) NumDecimalPlaces;       // Use the preference value
01098 
01099     camSnprintf( dpformat, 32, _T("%%.%df"), (INT32) DecimalPlaces);        // make %.xf formatting string
01100     camSnprintf( TempString, 32, dpformat, (double)Number );                    // uses FP
01101 
01102     *OutputString = TempString;     // Copy the resulting string into the String
01103     
01104     // Look for all zeros after decimal point and if so then remove
01105     StripTrailingZeros(OutputString);
01106 
01107     // Extra bodge required so that if the user has specified display values using
01108     // a non full stop to show decimal points then we must replace the point that
01109     // is present by the specified character.
01110     if (DecimalPoint != '.')
01111     {
01112         ReplaceDecimalPoint(OutputString);
01113     }
01114     return TRUE;
01115 }
01116 
01117 
01118 /********************************************************************************************
01119 
01120 >   static BOOL Convert::StringToLong( StringBase* InputString, INT32* Number )
01121 
01122     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
01123     Created:    17/9/93
01124     Inputs:     InputString - The string that you want turning into a number
01125     Outputs:    Number - The number you want turning into a string
01126     Returns:    TRUE if the conversion worked, false otherwise
01127     Purpose:    Converts a string into its INT32 equivalent
01128     SeeAlso:    LongToString
01129 
01130 ********************************************************************************************/
01131 
01132 BOOL Convert::StringToLong( const StringBase &InputString, INT32* pNumber)
01133 {
01134     // Get a pointer version of the string
01135     const TCHAR* pMyString = (const TCHAR*)InputString;
01136     INT32 nLength = InputString.Length();
01137     INT32 nPos = 0;
01138     
01139     // Check for a minus sign - added for DBCS
01140     BOOL fIsNegative = FALSE;
01141     if (pMyString[nPos] == TEXT('-') )   // if (pMyString[Pos] == TEXT('-'))
01142     {
01143         fIsNegative = TRUE;
01144         nPos++;
01145         if (nPos >= nLength) return 0;
01146     }
01147             
01148     // Get the actual number
01149     INT32 nTotal     = 0;
01150     while (nPos < nLength && StringBase::IsNumeric(pMyString[nPos]))
01151     {
01152         nTotal = (nTotal * 10) + pMyString[nPos] - TEXT('0');
01153         nPos++;
01154     }
01155     
01156     // If we have not read in the whole string, then it was not valid
01157     if (nPos < nLength && !StringBase::IsSpace(pMyString[nPos])) return FALSE;  
01158 
01159     // If the number started with a minus sign, then make sure it is negative
01160     if (fIsNegative) nTotal = -nTotal;
01161 
01162     *pNumber = nTotal;
01163     return TRUE;
01164 }
01165 
01166 /********************************************************************************************
01167 
01168 >   static BOOL Convert::StringToDouble( StringBase* InputString, double * Number )
01169 
01170     Author:     Alex_Bligh (Xara Group Ltd) <camelotdev@xara.com>
01171     Created:    16/12/94
01172     Inputs:     InputString - The string that you want turning into a double
01173     Outputs:    Number - The number you want turning into a string
01174     Returns:    TRUE if the conversion worked, false otherwise
01175     Purpose:    Converts a string into its double equivalent
01176     SeeAlso:    DoubleToString
01177 
01178                 Used to be a bodge as atof() doesn't work in unicode but converted to use
01179                 the other functions which should do it properly.
01180 
01181 ********************************************************************************************/
01182 
01183 BOOL Convert::StringToDouble( const StringBase &InputString, double * Number )
01184 {
01185 //#if UNICODE
01186 //#error "I'm screwed! atof() doesn't work for UNICODE"
01187 //#else
01188 //  *Number = atof((char *)*InputString);
01189 //  return(TRUE);
01190 //#endif
01191 
01192     // Cannot use atof as does not cope with a non-decimal point character which
01193     // the user may be specifying so use our form of atof.
01194     // atof will also allow say 26.98mm where we should really be erroring.
01195     // ReadNumber ignores everything after a dodgy decimal point which is not correct. 
01196     // StringToComponents will include units as well. We do not want this part so ignore it.
01197     UnitType Units;
01198     BOOL ok = StringToComponents(InputString,Number,&Units);
01199 
01200     // Check if units are NOTYPE and if not then return failure.
01201     if (Units != NOTYPE)
01202         return FALSE;
01203 
01204     return ok;
01205 }
01206 
01207 
01208 #define MIN_MILLIPOINT_VAL (-2147483648.0)  // Min signed 32 bit val - 0x80000000
01209 #define MAX_MILLIPOINT_VAL ( 2147483647.0)  // Max signed 32 bit val - 0x7fffffff
01210 
01211 /********************************************************************************************
01212 
01213 >   static BOOL Convert::ConvertDoubleToMillipoint(double Value,MILLIPOINT* pResult)
01214 
01215     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01216     Created:    6/7/94
01217     Inputs:     Value = the fp value to convert
01218     Outputs:    pResult = the MILLIPOINT var to place the result in
01219     Returns:    TRUE if the conversion was OK
01220                 FALSE if the conversion caused an overflow error
01221     Purpose:    Converts a double to a MILLIPOINT, checking first whether such a conversion
01222                 is possible.
01223                 It returns FALSE if Value is beyond the limits of a signed 32 bit integer.
01224     SeeAlso:    ConvertMillipointToDouble
01225 
01226 ********************************************************************************************/
01227 
01228 BOOL Convert::ConvertDoubleToMillipoint(double Value,MILLIPOINT* pResult)
01229 {
01230     Value += 0.5;   // Round up the value
01231 
01232     if ((Value < MIN_MILLIPOINT_VAL) || (Value > MAX_MILLIPOINT_VAL))
01233         return FALSE;
01234 
01235     *pResult = (MILLIPOINT)Value;
01236     return TRUE;
01237 }
01238 
01239 /********************************************************************************************
01240 
01241 >   static void Convert::ConvertMillipointToDouble(MILLIPOINT Value,double* pResult)
01242 
01243     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01244     Created:    6/7/94
01245     Inputs:     Value = the MILLIPOINT value to convert
01246     Outputs:    pResult = the double var to place the result in
01247     Returns:    -
01248     Purpose:    Converts a MILLIPOINT to a double.
01249                 At the moment, this function just does a simple cast.
01250                 I've only put it in because I did the sister function ConvertDoubleToMillipoint
01251     SeeAlso:    ConvertDoubleToMillipoint
01252 
01253 ********************************************************************************************/
01254 
01255 void Convert::ConvertMillipointToDouble(MILLIPOINT Value,double* pResult)
01256 {
01257     *pResult = (double)Value;
01258 }
01259 
01260 
01261 /******************************************************************************************
01262 
01263 >   static UINT32 Convert::StringToBytes(String_256 *pStr, BOOL *Valid)
01264 
01265     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
01266     Created:    20/1/95
01267     Inputs:     pStr -  pointer to all manner of memory am