kerneldc.cpp

Go to the documentation of this file.
00001 // $Id: kerneldc.cpp 1432 2006-07-11 15:46:55Z 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 
00099 // Device Contexts that are kernel-safe.
00100 
00101 /*
00102 */
00103 
00104 #include "camtypes.h"
00105 
00106 #include "kerneldc.h"
00107 #include "colourix.h"
00108 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00109 //#include "epsfiltr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00110 
00111 DECLARE_SOURCE("$Revision: 1432 $");
00112 
00113 #define new CAM_DEBUG_NEW
00114 
00115 CC_IMPLEMENT_DYNAMIC(KernelDC, CCDummyDC);
00116 
00117 /********************************************************************************************
00118 
00119 >   KernelDC::KernelDC(RenderType rType)
00120 
00121     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00122     Created:    23/04/95
00123     Inputs:     The type of DC being made.
00124     Purpose:    Initialise a kernel DC.
00125                 This initialises the user space origin to (0,0) by default (only relevant
00126                 for DCs that use the PostScript stream functions).
00127     SeeAlso:    KernelDC::SetOrigin; KernelDC::OutputUserSpaceValue; 
00128                 KernelDC::OutputCoord
00129 
00130 ********************************************************************************************/
00131 
00132 KernelDC::KernelDC(RenderType rType) : CCDummyDC(rType)
00133 {
00134     // Initialise other fields.
00135     LineWidth = 0;
00136     Origin.x = 0;
00137     Origin.y = 0;
00138 
00139     // Default to 2dp accuracy for user space values.
00140     FullAccuracy = FALSE;
00141 
00142     // No ASCII85 conversion by default.
00143     RawBuf = NULL;
00144     A85Buf = NULL;
00145     RawBufSize = 0;
00146     RLEtheASCII85Data = FALSE;
00147 }
00148 
00149 /********************************************************************************************
00150 
00151 >   KernelDC::KernelDC(CDC *pDC, RenderType rType)
00152 
00153     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00154     Created:    23/04/95
00155     Inputs:     The OIL DC pointer, and the type of DC being made.
00156     Purpose:    Initialise a kernel DC.
00157                 This initialises the user space origin to (0,0) by default (only relevant
00158                 for DCs that use the PostScript stream functions).
00159     SeeAlso:    KernelDC::SetOrigin; KernelDC::OutputUserSpaceValue; 
00160                 KernelDC::OutputCoord
00161 
00162 ********************************************************************************************/
00163 
00164 KernelDC::KernelDC(CNativeDC *pDC, RenderType rType) : CCDummyDC(pDC, rType)
00165 {
00166     // Initialise other fields.
00167     LineWidth = 0;
00168     Origin.x = 0;
00169     Origin.y = 0;
00170 
00171     // Default to 2dp accuracy for user space values.
00172     FullAccuracy = FALSE;
00173 
00174     // No ASCII85 conversion by default.
00175     RawBuf = NULL;
00176     A85Buf = NULL;
00177     RawBufSize = 0;
00178     RLEtheASCII85Data = FALSE;
00179 }
00180 
00181 /********************************************************************************************
00182 
00183 >   void KernelDC::SetOrigin(DocCoord &NewOrigin)
00184 
00185     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00186     Created:    28/03/94
00187     Inputs:     NewOrigin - the desired origin (in spread coords)
00188     Purpose:    Set the user space origin to the specified position in spread coordinates.
00189     SeeAlso:    KernelDC::OutputUserSpaceValue; KernelDC::OutputCoord
00190 
00191 ********************************************************************************************/
00192 
00193 void KernelDC::SetOrigin(DocCoord &NewOrigin)
00194 {
00195     Origin = NewOrigin;
00196 }
00197 
00198 /********************************************************************************************
00199 
00200 >   BOOL KernelDC::OutputCoord(DocCoord& Coord, EPSAccuracy Accuracy = ACCURACY_NORMAL)
00201 
00202     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00203     Created:    28/03/94
00204     Inputs:     Coord - the coordinate to write out to the file.
00205                 Accuracy - optional parameter - specifies how numbers should be output:
00206                     ACCURACY_NORMAL:        2dp
00207                     ACCURACY_ROUNDUP:       0dp, rounded up
00208                     ACCURACY_ROUNDDOWN:     0dp, rounded down.
00209     Returns:    TRUE if the data was written ok;
00210                 FALSE if not => ERROR1
00211     Purpose:    Write out a coordinate x,y pair to the export file, automatically 
00212                 converting from spread coordinates to the EPS user space coordinate system,
00213                 including adjusting the origin.
00214     SeeAlso:    KernelDC::OutputUserSpaceValue
00215     Errors:     File/disk error => ERROR1
00216 
00217 ********************************************************************************************/
00218 
00219 BOOL KernelDC::OutputCoord(DocCoord& Coord, EPSAccuracy Accuracy)
00220 {
00221     BOOL Ok = (OutputUserSpaceValue(Coord.x - Origin.x, Accuracy) &&
00222                OutputUserSpaceValue(Coord.y - Origin.y, Accuracy));
00223 
00224     return Ok;
00225 }
00226 
00227 
00228 /********************************************************************************************
00229 
00230 >   BOOL KernelDC::OutputUserSpaceValue(MILLIPOINT n, 
00231                                         EPSAccuracy Accuracy = ACCURACY_NORMAL)
00232 
00233     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00234     Created:    28/03/94
00235     Inputs:     n - the value (in millipoints) to output.
00236                 Accuracy - optional parameter - specifies how numbers should be output:
00237                     ACCURACY_NORMAL:        2dp, or 3dp (see KernelDC::SetFullAccuracy)
00238                     ACCURACY_ROUNDUP:       0dp, rounded up
00239                     ACCURACY_ROUNDDOWN:     0dp, rounded down.
00240     Returns:    TRUE if the data was written ok;
00241                 FALSE if not => ERROR1
00242 
00243     Purpose:    Output a 'user space' value to the export file.
00244                 User space is the coordinate system used for EPS files (and more generally,
00245                 PostScript programs).   For Illustrator-based EPS, the user space is
00246                 expressed in units of points, and usually has the origin at (0.0).
00247                 By default, we follow the Illustrator convention of truncating values to
00248                 2dp (so we can generate files compatible with Illustrator etc), but
00249                 Camelot EPS uses the full 3dp accuracy (we don't store more any accuracy 
00250                 than this internally).  The accuracy can be changed by calling
00251                 KernelDC::SetFullAccuracy
00252                 Note that this routine does not do origin translation, because
00253                 it may be used for dimensions such as line widths, which have no earthly use
00254                 for origins (and anyway, it's a bit tricky to do origin translation with 
00255                 only one dimension!).
00256 
00257                 e.g. OutputUserSpaceValue(31465) will output "3.147" to the export file.
00258 
00259     SeeAlso:    KernelDC::OutputCoord; KernelDC::OutputToken;
00260                 KernelDC::SetFullAccuracy
00261     Errors:     Disk/file error => ERROR1
00262 
00263 ********************************************************************************************/
00264 
00265 BOOL KernelDC::OutputUserSpaceValue(MILLIPOINT n, EPSAccuracy Accuracy)
00266 {
00267     TCHAR Buf[20];
00268     INT32 Integer;
00269     INT32 Fraction;
00270 
00271     const TCHAR * negative=_T("-");
00272     const TCHAR * positive=_T("");
00273     const TCHAR * sign = positive;
00274 
00275     // Convert millipoint to EPS user space value in desired format.
00276     switch (Accuracy)
00277     {
00278         case ACCURACY_NORMAL:
00279             // Convert to points, getting integer and fractional parts
00280             // invert the sign if necessary
00281             if (n<0)
00282             {
00283                 sign=negative;
00284                 n=-n;
00285             }
00286 
00287             // as n is positive (or zero), this works in the way expected. Both
00288             // Integer and fraction are >=0 too.    
00289             Integer  = n / 1000;
00290             Fraction = n % 1000;
00291 
00292             // Output to string (accurate to 2/3dp)
00293 
00294             // If fraction is 0, just output integer value.
00295             if (Fraction == 0)
00296             {
00297                 camSprintf(Buf, _T("%d"), Integer);
00298             }
00299             else if (FullAccuracy)
00300             {
00301                 camSprintf(Buf, _T("%s%d.%.3d"), sign, Integer, Fraction);
00302             }
00303             else
00304             {
00305                 // Normal 2dp accuracy
00306                 Fraction=(Fraction+5)/10;
00307                 camSprintf(Buf, _T("%s%d.%.2d"), sign, Integer, Fraction);
00308             }
00309             break;
00310 
00311         case ACCURACY_ROUNDDOWN:
00312             // Convert to points, getting integer part.
00313             if (n < 0)
00314                 Integer = (n - 999)/ 1000;
00315             else
00316                 Integer = (n) / 1000;
00317 
00318             // Output to string (accurate to 0dp)
00319             camSprintf(Buf, _T("%d"), Integer);
00320             break;
00321 
00322         case ACCURACY_ROUNDUP:
00323             // Convert to points, getting integer part.
00324             if (n < 0)
00325                 Integer = (n) / 1000;
00326             else
00327                 Integer = (n + 999) / 1000;
00328 
00329             // Output to string (accurate to 0dp)
00330             camSprintf(Buf, _T("%d"), Integer);
00331             break;
00332     }
00333 
00334     return OutputToken(Buf);
00335 }
00336 
00337 /********************************************************************************************
00338 
00339 >   BOOL KernelDC::OutputColourValue(UINT32 n)
00340 
00341     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00342     Created:    28/03/94
00343     Inputs:     n - the colour value (range 0-255) to write to the EPS file.
00344     Returns:    TRUE if the data was written ok;
00345                 FALSE if not => ERROR1
00346     Purpose:    Output a colour value to the export file.  A 'colour value' is a value
00347                 as used in the Camelot 'Colour' class, i.e. in the range 0 to 255.
00348                 This range is converted to the range 0.0 to 1.0, and output to the file.
00349     SeeAlso:    KernelDC::OutputColour
00350     Errors:     Disk/file error => ERROR1
00351 
00352 ********************************************************************************************/
00353 
00354 BOOL KernelDC::OutputColourValue(UINT32 n)
00355 {
00356     // Convert to points, getting integer and fractional parts
00357     INT32 Integer  = n / 255;
00358     INT32 Fraction = ((n % 255) * 100) / 255;
00359 
00360     // Output to string
00361     TCHAR Buf[20];
00362     // Ensure we always get at least 2 decimal figures with %.2d
00363     camSprintf(Buf, _T("%d.%.2d"), Integer, Abs(Fraction));
00364     return OutputToken(Buf);
00365 }
00366 
00367 /********************************************************************************************
00368 
00369 >   BOOL KernelDC::OutputColour(PColourCMYK *pCol)
00370 
00371     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00372     Created:    28/03/94
00373     Inputs:     Col - the CMYK colour values to be output.
00374     Returns:    TRUE if the data was written ok;
00375                 FALSE if not => ERROR1
00376     Purpose:    Output a colour, as expressed by the Camelot 'Colour' class.  This function
00377                 takes the CMYK variation, is this is most appropriate to EPS files.
00378                 Camelot colour values are converted from the 0-255 range to the 0.0-1.0
00379                 range before being output.
00380 
00381                 e.g.
00382                 MonoOn
00383                     PColourCMYK Col = { 255, 255, 128, 0 };
00384                     pDC->OutputColour(&Col);
00385                 MonoOff
00386                 will give the following output:
00387                 MonoOn
00388                     1.0 1.0 0.5 0.0
00389                 MonoOff
00390     SeeAlso:    KernelDC::OutputColourValue
00391     Errors:     Disk/file error => ERROR1
00392 
00393 ********************************************************************************************/
00394 
00395 BOOL KernelDC::OutputColour(PColourCMYK *pCol)
00396 {
00397     // Output each of the colour values.
00398     BOOL Ok = (OutputColourValue(pCol->Cyan)    &&
00399                OutputColourValue(pCol->Magenta) &&
00400                OutputColourValue(pCol->Yellow)  &&
00401                OutputColourValue(pCol->Key));
00402 
00403     // Return success or failure.
00404     return Ok;
00405 }
00406 
00407 /********************************************************************************************
00408 
00409 >   BOOL KernelDC::OutputNamedColour(DocColour *pCol, ColourContext* pContext = NULL)
00410 
00411     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00412     Created:    09/08/94
00413     Inputs:     pCol - the colour to output.
00414                 pContext - the context to use to convert the colour before output.
00415                            if this is NULL the default CMYK context will be used.
00416     Returns:    TRUE if the data was written ok;
00417                 FALSE if not => ERROR1
00418     Purpose:    Similar to OutputColour(), except it outputs the colour name and tint
00419                 of the colour as well.  If pCol does not reference an indexed colour,
00420                 then the name "NoName" is used.
00421     SeeAlso:    KernelDC::OutputColour
00422     Errors:     Disk/file error => ERROR1
00423 
00424 ********************************************************************************************/
00425 
00426 BOOL KernelDC::OutputNamedColour(DocColour *pCol, ColourContext* pContext)
00427 {
00428     // Get CMYK version of this colour.
00429     PColourCMYK CMYK;
00430     pCol->GetCMYKValue(pContext, &CMYK);
00431 
00432     // Output CMYK version
00433     if (!OutputColour(&CMYK))
00434         return FALSE;
00435         
00436     // Get the indexed colour from the DocColour.
00437     IndexedColour *pIndCol = pCol->FindParentIndexedColour();
00438 
00439     // Cope with the unexpected!
00440 //  ENSURE(pIndCol != NULL, "Named colour has no index colour!");
00441 
00442     if (pIndCol == NULL)
00443     {
00444         if (pCol->IsTransparent())
00445         {
00446             // This is a 'no colour' type colour, so output a zero-length colour name,
00447             // as this is the only way we can handle this at the moment.
00448             if (!OutputString(_T("")))
00449                 return FALSE;
00450         }
00451         else
00452         {
00453             // Otherwise make up a colour name (see epsfiltr.h).
00454             if (!OutputString(ImmediateColourFudgeyBodgeName))
00455                 return FALSE;
00456         }
00457     }
00458     else
00459     {
00460         // Got an indexed colour - output its name
00461         // (Pass in TRUE to get a unique-identifier for local colours rather than "Local colour")
00462         String_64 *ColName = pIndCol->GetName(TRUE);
00463         if (!OutputString((TCHAR *) (*ColName)))
00464             return FALSE;
00465     }
00466 
00467     // Always tint 0
00468     return OutputToken(_T("0"));
00469 }
00470 
00471 
00472 /********************************************************************************************
00473 
00474 >   BOOL KernelDC::OutputColourName(DocColour *pCol)
00475 
00476     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
00477     Created:    29/11/00
00478     Inputs:     pCol - the colour to output.
00479     Returns:    TRUE if the data was written ok;
00480                 FALSE if not => ERROR1
00481     Purpose:    Outputs a named colour's name as a string. If pCol does not reference an 
00482                 indexed colour, then the name "NoName" is used. This was seperated from 
00483                 OutputNamedColour so that the DeviceContext will not need to worry about
00484                 which ColourModel to use (CMYK, RGB, etc...), as this will be determined 
00485                 by the RenderRegion.
00486     SeeAlso:    KernelDC::OutputNamedColour
00487     Errors:     Disk/file error => ERROR1
00488 
00489 ********************************************************************************************/
00490 
00491 BOOL KernelDC::OutputColourName(DocColour *pCol)
00492 {
00493     // Success / Failure flag for the export of this colour's name.
00494     BOOL ok = TRUE;
00495         
00496     // Get the indexed colour from the DocColour.
00497     IndexedColour *pIndCol = pCol->FindParentIndexedColour();
00498 
00499     if (pIndCol == NULL)
00500     {
00501         if (pCol->IsTransparent())
00502         {
00503             // This is a 'no colour' type colour, so output a zero-length colour name,
00504             // as this is the only way we can handle this at the moment.
00505             ok = OutputString(_T(""));
00506         }
00507         else
00508         {
00509             // Otherwise make up a colour name (see epsfiltr.h).
00510             ok = OutputString(ImmediateColourFudgeyBodgeName);
00511         }
00512     }
00513     else
00514     {
00515         // Got an indexed colour - output its name
00516         // (Pass in TRUE to get a unique-identifier for local colours rather than "Local colour")
00517         String_64 *ColName = pIndCol->GetName(TRUE);
00518         ok = OutputString((TCHAR *) (*ColName));
00519     }
00520 
00521     return ok;
00522 }
00523 
00524 
00525 /********************************************************************************************
00526 
00527 >   BOOL KernelDC::OutputString(TCHAR *pString)
00528 
00529     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00530     Created:    10/08/94
00531     Inputs:     pString - the string token to output.
00532     Returns:    TRUE if the data was written ok;
00533                 FALSE if not => ERROR1
00534     Purpose:    Output a string in PostScript format, i.e. delimited by '(' and ')', 
00535                 and escaping any parentheses so the string is syntactically correct.
00536                 e.g.  "String" is output as "(String)",
00537                 and   "Hello (there)" is output as "(Hello \(there\))"
00538                 and so on.
00539     SeeAlso:    KernelDC
00540     Errors:     Disk/file error => ERROR1
00541 
00542 ********************************************************************************************/
00543 
00544 BOOL KernelDC::OutputString(TCHAR *pString)
00545 {
00546     TCHAR Buf[128];
00547 
00548     // Open string delimiter
00549     Buf[0] = '(';
00550 
00551     // Copy the string, looking for embedded delimiters.
00552     INT32 src = 0,
00553         dst = 1;
00554     while ( (pString[src]) && (dst < 120 ) )    //while ((pString[src] != 0) && (dst < 120))-adapted for DBCS
00555     {
00556         if( (pString[src]== _T('(')) || (pString[src]==_T(')')) || (pString[src]== _T('\\')) )
00557       //if( (pString[src] == '(')    || (pString[src] == ')')      || (pString[src] == '\\') )-adapted for DBCS
00558         {
00559             // escape this delimiter
00560             Buf[dst++] = '\\';
00561         }
00562 
00563         // Copy this character
00564         Buf[dst++] = pString[src++];
00565     }
00566 
00567     ERROR3IF(dst > 120, "String too long in KernelDC::OutputString");
00568 
00569     // Terminate the string token
00570     Buf[dst++] = ')';
00571     Buf[dst] = 0;
00572 
00573     // Output it
00574     return OutputToken(Buf);
00575 }
00576 
00577 /********************************************************************************************
00578 
00579 >   BOOL KernelDC::OutputMatrix(Matrix * Mat)
00580                      
00581     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
00582     Created:    22/08/94
00583     Inputs:     M- pointer to the matrix to output to the EPS stream.
00584     Returns:    TRUE if the data was written ok;
00585                 FALSE if not => ERROR1
00586     Purpose:    Output a Matrix to the EPS stream.
00587     Errors:     Disk/file error => ERROR1
00588 
00589 ********************************************************************************************/
00590 
00591 BOOL KernelDC::OutputMatrix(Matrix * M)
00592 {
00593     FIXED16 abcd[4];
00594     INT32 ef[2];
00595     M->GetComponents(abcd, ef);
00596 
00597     if(!OutputReal(abcd[0].MakeDouble()))
00598         return FALSE;
00599     if(!OutputReal(abcd[1].MakeDouble()))
00600         return FALSE;
00601     if(!OutputReal(abcd[2].MakeDouble()))
00602         return FALSE;
00603     if(!OutputReal(abcd[3].MakeDouble()))
00604         return FALSE;
00605     if(!OutputUserSpaceValue(ef[0]))
00606         return FALSE;
00607     if(!OutputUserSpaceValue(ef[1]))
00608         return FALSE;
00609     return TRUE;
00610 
00611 
00612 }
00613 
00614 
00615 /********************************************************************************************
00616 
00617 >   BOOL KernelDC::OutputValue(INT32 Value)
00618                      
00619     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00620     Created:    22/08/94
00621     Inputs:     Value - the number to write to the EPS stream.
00622     Returns:    TRUE if the data was written ok;
00623                 FALSE if not => ERROR1
00624     Purpose:    Output a signed integer to the EPS stream.
00625     Errors:     Disk/file error => ERROR1
00626 
00627 ********************************************************************************************/
00628 
00629 BOOL KernelDC::OutputValue(INT32 Value)
00630 {
00631     TCHAR buf[30];
00632     camSprintf(buf, _T("%d"), Value);
00633     return OutputToken(buf);
00634 }
00635 
00636 /********************************************************************************************
00637 
00638 >   BOOL KernelDC::OutputValue(UINT32 Value)
00639 
00640     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00641     Created:    22/08/94
00642     Inputs:     Value - the number to write to the EPS stream.
00643     Returns:    TRUE if the data was written ok;
00644                 FALSE if not => ERROR1
00645     Purpose:    Output an unsigned integer to the EPS stream.
00646     Errors:     Disk/file error => ERROR1
00647 
00648 ********************************************************************************************/
00649 
00650 BOOL KernelDC::OutputValue(UINT32 Value)
00651 {
00652     TCHAR buf[30];
00653     camSprintf(buf, _T("%u"), Value);
00654     return OutputToken(buf);
00655 }
00656 
00657 
00658 /********************************************************************************************
00659 
00660 >   BOOL KernelDC::OutputReal(double Value)
00661 
00662     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00663     Created:    07/11/94
00664     Inputs:     Value - the number to write to the EPS stream.
00665     Returns:    TRUE if the data was written ok;
00666                 FALSE if not => ERROR1
00667     Purpose:    Output a real (floating point) number to the EPS stream.
00668     Errors:     Disk/file error => ERROR1
00669 
00670 ********************************************************************************************/
00671 
00672 BOOL KernelDC::OutputReal(double Value)
00673 {
00674     TCHAR buf[100]; // 100 should be enough for a floating point number!
00675     // Save floating point in scientific notation (because otherwise the number output
00676     // could be very long, e.g. 6.2e66 or similar would be very long if we didn't use
00677     // the exponent syntax).
00678     camSprintf(buf, _T("%g"), Value);
00679     return OutputToken(buf);
00680 }
00681 
00682 
00683 
00684 /********************************************************************************************
00685 
00686 >   BOOL KernelDC::OutputFloat(const double Value, const UINT32 DecPl)
00687 
00688     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00689     Created:    20/04/95
00690     Inputs:     Value - the number to write to the EPS stream.
00691                 DecPl - the number of decimal places to output. (1..8)
00692     Returns:    TRUE if the data was written ok;
00693                 FALSE if not => ERROR1
00694     Purpose:    Output a real (floating point) number to the EPS stream.
00695                 
00696     Errors:     Disk/file error => ERROR1
00697 
00698 ********************************************************************************************/
00699 
00700 BOOL KernelDC::OutputFloat(const double Value, const UINT32 DecPl)
00701 {
00702     TCHAR buf[100];
00703     TCHAR *pch=buf;
00704     INT32 len=0, dp=-1;
00705 
00706     switch (DecPl)
00707     {
00708         case 1: camSprintf(buf,_T("%.1f"),Value); break;
00709         case 2: camSprintf(buf,_T("%.2f"),Value); break;
00710         case 4: camSprintf(buf,_T("%.4f"),Value); break;
00711         case 5: camSprintf(buf,_T("%.5f"),Value); break;
00712         case 6: camSprintf(buf,_T("%.6f"),Value); break;
00713         case 7: camSprintf(buf,_T("%.7f"),Value); break;
00714         case 8: camSprintf(buf,_T("%.8f"),Value); break;
00715         default:camSprintf(buf,_T("%.3f"),Value); break;
00716     }
00717 
00718     // supress a few trailing zero's
00719     while (*pch != '\0')
00720     {
00721         if (*pch=='.')
00722             dp=len;
00723         len++;
00724         pch++;
00725     }
00726 
00727     // check no decimal place
00728     if (dp==-1)
00729         return OutputToken(buf);
00730 
00731     pch--;
00732     while ((len>0) && (*pch=='0'))
00733     {
00734         pch--;
00735         len--;
00736     }
00737 
00738     if ((len==0) || (*pch=='.'))
00739         pch++;
00740 
00741     pch++;
00742     *pch='\0';
00743 
00744     return OutputToken(buf);
00745 }
00746 
00747 /********************************************************************************************
00748 
00749 >   BOOL KernelDC::OutputArray(INT32* Array, INT32 ArraySize)
00750                  
00751     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
00752     Created:    15/04/95
00753     Inputs:     Array, pointer to the array data.
00754                 ArraySize, the number of elements in the array.
00755     Returns:    TRUE if the data was written ok;
00756                 FALSE if not => ERROR1
00757     Purpose:    Output an Array to the EPS stream.
00758     Errors:     Disk/file error => ERROR1
00759 
00760 ********************************************************************************************/
00761 
00762 BOOL KernelDC::OutputArray(INT32* Array, INT32 ArraySize)
00763 {
00764     // Output the 'ArrayStart'
00765     if (!OutputToken(_T("[")))
00766         return FALSE;
00767 
00768     // Output the actual array elements
00769     for (INT32 el = 0; el < ArraySize; el++)
00770     {
00771         if(!OutputUserSpaceValue(Array[el]))
00772             return FALSE;
00773     }
00774 
00775     // Output the 'ArrayEnd'
00776     if (!OutputToken(_T("]")))
00777         return FALSE;
00778 
00779     return TRUE;
00780 }
00781 
00782 /********************************************************************************************
00783 
00784 >   INT32 KernelDC::OutputRawBinary(BYTE *Data, UINT32 Length, UINT32 Alignment = 1)
00785 
00786     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00787     Created:    22/08/94
00788     Inputs:     Data - pointer to the data to output.
00789                 Length - the number of bytes to output.
00790                 Alignment - the byte alignment to use - it will pad the end of
00791                             the data with 0 bytes if Length is not divisible by
00792                             this parameter.  Hence use 1 for no padding.
00793     Returns:    The number of bytes output to the file, in terms of the source data, not
00794                 in terms of the number of ASCII characters used to represent them.
00795                 -1 => error occured while writing => ERROR1
00796     Purpose:    Outputs a sequence of bytes as raw hex data, as used by PostScript
00797                 operators such as readhexstring.
00798     Errors:     Disk/file error => ERROR1
00799 
00800 ********************************************************************************************/
00801 
00802 INT32 KernelDC::OutputRawBinary(BYTE *Data, UINT32 Length, UINT32 Alignment)
00803 {
00804     INT32 nBytes = 0;
00805 
00806     // Do 30 bytes at a time so we get lines with 60 characters on each.
00807     if (LineWidth > 0)
00808     {
00809         if (!OutputNewLine())
00810             // Error encountered
00811             return -1;
00812     }
00813 
00814     // Work out the padding needed
00815     ENSURE(Alignment != 0, "Bad alignment in OutputRawBinary!");
00816     UINT32 Padding = Alignment - (Length % Alignment);
00817     if (Padding == Alignment)
00818         Padding = 0;
00819 
00820     while (Length > 0)
00821     {
00822         // Work out how much data to output
00823         UINT32 ChunkLength = 32;
00824         if (Length < ChunkLength)
00825             ChunkLength = Length;
00826 
00827         // Convert the next chunk to hex and write it out
00828         TCHAR HexBuf[80];
00829         ConvertToHex(Data, ChunkLength, HexBuf);
00830         if (!OutputTCHARAsChar(HexBuf, ChunkLength * 2))
00831         {
00832             // Error
00833             return -1;
00834         }
00835         
00836         nBytes += ChunkLength;
00837 
00838         // Adjust length and check for padding requirements
00839         Length -= ChunkLength;
00840         Data += ChunkLength;
00841 
00842         if ((Length == 0) && (Padding > 0))
00843         {
00844             // Put the string "00" into HexBuf
00845             HexBuf[0] = '0';
00846             HexBuf[1] = '0';
00847             HexBuf[2] = 0;
00848 
00849             // Output it however many times we need to
00850             while (Padding > 0)
00851             {
00852                 if (!OutputTCHARAsChar(HexBuf, 2))
00853                     // Error
00854                     return -1;
00855 
00856                 nBytes++;
00857                 Padding--;
00858             }
00859         }
00860 
00861         if (!OutputNewLine())
00862             // Error encountered
00863             return -1;
00864     }
00865     
00866     // All done
00867     return nBytes;
00868 }
00869 
00870 
00871 /********************************************************************************************
00872 
00873 >   void KernelDC::ConvertToHex(BYTE *Data, UINT32 Length, TCHAR *Buf)
00874 
00875     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00876     Created:    22/08/94
00877     Inputs:     Data - pointer to the data to convert
00878                 Length - the number of bytes to convert.
00879     Outputs:    Buf - the buffer to place the hex string into.
00880                       NB. must be big enough to hold the 0-terminator!
00881     Purpose:    Convert a block of bytes to a hexadecimal ASCII stroing representation of
00882                 the data.
00883     SeeAlso:    KernelDC::OutputRawBinary
00884 
00885 ********************************************************************************************/
00886 
00887 void KernelDC::ConvertToHex(BYTE *Data, UINT32 Length, TCHAR *Buf)
00888 {   
00889     UINT32 DataOfs = 0, 
00890           DestOfs = 0;
00891 
00892     while (DataOfs < Length)
00893     {
00894         // Extract each 4-bit set and encode as hex
00895         INT32 Nybble = (Data[DataOfs] & 0xF0) >> 4;
00896         ENSURE(Nybble < 16, "Bad hex digit in KernelDC::ConvertToHex");
00897 
00898         TCHAR Ch;
00899         if (Nybble < 10)
00900             Ch = '0' + (TCHAR) Nybble;
00901         else
00902             Ch = 'A' + (TCHAR) (Nybble - 10);
00903 
00904         Buf[DestOfs++] = Ch;
00905 
00906         Nybble = Data[DataOfs] & 0xF;
00907         ENSURE(Nybble < 16, "Bad hex digit in KernelDC::ConvertToHex");
00908 
00909         if (Nybble < 10)
00910             Ch = '0' + (TCHAR) Nybble;
00911         else
00912             Ch = 'A' + (TCHAR) (Nybble - 10);
00913 
00914         Buf[DestOfs++] = Ch;
00915 
00916         // Do the next byte...
00917         DataOfs++;
00918     }
00919 
00920     // Terminate the string
00921     Buf[DestOfs] = 0;
00922 }
00923 
00924 
00925 // By default, enough room to convert 100 quadruples at once.
00926 const static INT32 A85DataSize = 100;
00927 
00928 BOOL KernelDC::StartASCII85Output(BOOL RunLengthEncode)
00929 {
00930     // Sanity check
00931     ERROR2IF(A85Buf != NULL, FALSE, "Unfinished ASCII85 output!");
00932 
00933     // Remember whether or not we need to RLE the data.
00934     RLEtheASCII85Data = RunLengthEncode;
00935 
00936     // Allocate buffers
00937     // (Jason here - NOTE that I add a 4 byte padding to the end of both buffers in case
00938     // of small overflow. Otherwise, the ConvertToASCII85 routine fills the buffer to the
00939     // brim and then slaps a 0 terminator on the end, corrupting the heap)
00940     RawBuf = (LPBYTE) CCMalloc((A85DataSize * 4) + 4);
00941     if (RawBuf == NULL)
00942         return(FALSE);
00943     
00944     A85Buf = (LPBYTE) CCMalloc((A85DataSize * 5) + 4);
00945     if (A85Buf == NULL)
00946     { 
00947         CCFree(RawBuf);
00948         return(FALSE);
00949     }
00950 
00951     // No characters in buffer yet.
00952     RawBufSize = 0;
00953 
00954     // Ok
00955     return TRUE;
00956 }
00957 
00958 INT32 KernelDC::EndASCII85Output()
00959 {
00960     // Are we useing RLE compression?
00961     if (RLEtheASCII85Data)
00962     {
00963         // Ok - end of data, so we add the RLE EOD marker to the buffer (byte value 128)
00964         BYTE EOD[2];
00965         EOD[0] = (BYTE) 128;
00966         if (!QueueASCII85Data(EOD, 1))
00967             // An error occured
00968             return -1;
00969     }
00970 
00971     // Flush out the buffer, padding with zeroes if necessary.
00972     INT32 nBytes = FlushASCII85Buffer();
00973 
00974     // End of ASCII85 data, so output the ASCII85 EOD marker.
00975     TCHAR EOD[] = _T("~>");
00976     OutputTCHARAsChar(EOD, 2);
00977     OutputNewLine();
00978 
00979     // Free up the buffers
00980     CCFree(RawBuf);
00981     CCFree(A85Buf);
00982     RawBuf = NULL;
00983     A85Buf = NULL;
00984     RawBufSize = 0;
00985     RLEtheASCII85Data = FALSE;
00986 
00987     // Tell caller how many byts we saved
00988     return nBytes;
00989 }
00990 
00991 /********************************************************************************************
00992 
00993 >   INT32 KernelDC::OutputASCII85(BYTE *Data, UINT32 Length)
00994 
00995     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00996     Created:    3/7/95
00997     Inputs:     Data - pointer to the data to output.
00998                 Length - the number of bytes to output.
00999                 RunLengthEncode - if TRUE then run length encode the data before encoding it
01000                                   to ASCII85 format (see Red Book for RLE spec).
01001     Returns:    The number of bytes output to the file, in terms of the source data, not
01002                 in terms of the number of ASCII characters used to represent them.
01003                 -1 => error occured while writing => ERROR1
01004     Purpose:    Outputs a sequence of bytes as ASCII85 hex data, as used by PostScript
01005                 Level 2.  (This encoding should not be used when generating PostScript that
01006                 must be compatible with Level 1 interpreters).
01007     Errors:     Disk/file error => ERROR1
01008 
01009 ********************************************************************************************/
01010 
01011 INT32 KernelDC::OutputASCII85(BYTE *Data, UINT32 Length)
01012 {
01013     // Sanity check
01014     ERROR2IF(RawBuf == NULL, FALSE, "ASCII85 output not initialised correctly!");
01015 
01016     // Run length encode the data first if required by the caller.
01017     BYTE *pRLLBuf = NULL;
01018 
01019     if (RLEtheASCII85Data)
01020     {
01021         // Encode this data using run length encoding.
01022         INT32 NewLength = Length;
01023         pRLLBuf = KernelDC::RunLengthEncode(Data, &NewLength);
01024         if (pRLLBuf == NULL)
01025             // Error encoding data
01026             return -1;
01027 
01028         #ifdef _DEBUG
01029 
01030             // Debug check - let's just decompress that data to make sure it was encoded ok!
01031             INT32 DecodedLength = NewLength;
01032             BYTE *Decoded = RunLengthDecode(pRLLBuf, &DecodedLength);
01033 
01034             // Check for data equality
01035             BOOL ValidEncoding = (DecodedLength == (INT32) Length);
01036 
01037             if (ValidEncoding)
01038                 // Perform byte-wise comparison of data
01039                 ValidEncoding = (memcmp(Data, Decoded, Length) == 0);
01040 
01041             // De-allocate the decoding buffer
01042             CCFree(Decoded);
01043 
01044             ERROR2IF(!ValidEncoding, -1, "Error in RunLengthEncoding integrity check!");
01045 
01046         #endif
01047 
01048         // Point ASCII85 routine to the RLL encoded data
01049         Data = pRLLBuf;
01050         Length = NewLength;
01051     }
01052 
01053 
01054     INT32 nBytes = -1;
01055 
01056     // Start this chunk on a new line.
01057     if (LineWidth > 0)
01058     {
01059         if (!OutputNewLine())
01060         {
01061             // Error encountered
01062             if (RLEtheASCII85Data)
01063                 CCFree(pRLLBuf);
01064             return -1;
01065         }
01066     }
01067 
01068     // Queue up the data (which may or may not be RLL encoded).
01069     if (QueueASCII85Data(Data, Length))
01070         // Data queued successfully.
01071         nBytes = Length;
01072 
01073     // Free up the buffer used for run length encoding.
01074     if (RLEtheASCII85Data)
01075         CCFree(pRLLBuf);
01076 
01077     // All done
01078     return nBytes;
01079 }
01080 
01081 
01082 BOOL KernelDC::QueueASCII85Data(BYTE *Data, UINT32 Length)
01083 {
01084     INT32 MaxData = A85DataSize * 4;
01085 
01086     // Keep filling and flushing the buffer until we are out of data to send.
01087     INT32 nBytes = Length;
01088     while (nBytes > 0)
01089     {
01090         ERROR2IF((INT32) RawBufSize > MaxData, FALSE, "ASCII85 buffer overflow!");
01091 
01092         if ((INT32) RawBufSize == MaxData)
01093         {
01094             // Buffer is full - encode it and write it to disk.
01095             if (FlushASCII85Buffer() == -1)
01096                 return FALSE;
01097         }
01098 
01099         // Put as much data into the buffer as possible
01100         INT32 SpaceLeft = MaxData - RawBufSize;
01101         if (nBytes > SpaceLeft)
01102         {
01103             // Not enough room to put it all in, so fill up the buffer
01104             memcpy(RawBuf + RawBufSize, Data, SpaceLeft);
01105             RawBufSize += SpaceLeft;
01106             Data += SpaceLeft;
01107             nBytes -= SpaceLeft;
01108         }
01109         else
01110         {
01111             // Enough room in buffer to put all the data in, so do it.
01112             memcpy(RawBuf + RawBufSize, Data, nBytes);
01113             RawBufSize += nBytes;
01114             nBytes = 0;
01115         }
01116     }
01117 
01118     // All ok
01119     return TRUE;
01120 }
01121 
01122 INT32 KernelDC::ConvertToASCII85(BYTE *Src, UINT32 Length, BYTE *Dest)
01123 {
01124     // Precompute the powers of 85 to use when encoding.
01125 /*
01126     static const INT32 Power85[5] = { 1, 
01127                                      85, 
01128                                      85 * 85, 
01129                                      85 * 85 * 85, 
01130                                      85 * 85 * 85 * 85 };
01131 */
01132 
01133     // Start at the beginning of the buffer
01134 //  INT32 SrcOfs = 0;
01135     INT32 DstOfs = 0;
01136 
01137     while (Length > 0)
01138     {
01139         // Encode four bytes as five characters.
01140         UINT32 n=0;
01141         
01142         if (Length >= 4)
01143         {
01144             // Normal 4 bytes of data
01145             n = Src[0];
01146             n = (n << 8) | Src[1];
01147             n = (n << 8) | Src[2];
01148             n = (n << 8) | Src[3];
01149         }
01150         else
01151         {
01152             // Pad with zeros...
01153             switch (Length)
01154             {
01155                 case 3:
01156                     n = Src[0];
01157                     n = (n << 8) | Src[1];
01158                     n = (n << 8) | Src[2];
01159                     n <<= 8;
01160                     break;
01161 
01162                 case 2:
01163                     n = Src[0];
01164                     n = (n << 8) | Src[1];
01165                     n <<= 16;
01166                     break;
01167 
01168                 case 1:
01169                     n = Src[0];
01170                     n <<= 24;
01171                     break;
01172 
01173             }
01174         }
01175 
01176         if ((n == 0) && (Length >= 4))
01177         {
01178             // Special case - use "z" instead of "!!!!!"
01179             Dest[DstOfs++] = 'z';
01180         }
01181         else
01182         {
01183         #if 1
01184             register UINT32 q = n/7225;
01185             register unsigned r = (unsigned)n-7225*(unsigned)q;
01186             register unsigned t;
01187             Dest[DstOfs+3] = (t = r/85) + '!';
01188             Dest[DstOfs+4] = r - 85*t + '!';
01189             Dest[DstOfs+0] = (t = q/7225) + '!';
01190             r = (unsigned)q - 7225*t;
01191             Dest[DstOfs+1] = (t = r/85) + '!';
01192             Dest[DstOfs+2] = r - 85*t + '!';
01193 
01194             if (Length >= 4)
01195                 DstOfs += 5;
01196             else
01197                 // Special case for last 5-tuple - see Red Book, bottom of p129 
01198                 DstOfs += (Length + 1);
01199         #else
01200 /*
01201             for (INT32 i = 4; i >= 0; i--)
01202             {
01203                 // Reduce the number to a 5 digit base-85 number.
01204                 UINT32 m = n / Power85[i];
01205                 n -= m * Power85[i];
01206                 Dest[DstOfs++] = (TCHAR) (m + 33);
01207             }
01208 */
01209         #endif
01210         }
01211 
01212         // Move on to the next four bytes
01213         Src += 4;
01214         if (Length < 4)
01215             Length = 0;
01216         else
01217             Length -= 4;
01218     }
01219 
01220     // Finished encoding - terminate the string (not strictly necessary but what the hell).
01221     // (Jason here... What do you mean "What the hell?" - you've just written one byte off the
01222     // end of the buffer, and corrupted the heap! I've now added 4 bytes padding
01223     // on our buffers (in StartASCII85Output) to make sure this is safe)
01224     Dest[DstOfs] = 0;
01225 
01226     // Return how many bytes this ASCII85 data takes up
01227     return DstOfs;
01228 }
01229 
01230 INT32 KernelDC::ConvertFromASCII85(BYTE *Src, UINT32 Length, BYTE *Dest)
01231 {
01232     // Precompute the powers of 85 to use when encoding.
01233     static const INT32 Power85[5] = { 1, 
01234                                      85, 
01235                                      85 * 85, 
01236                                      85 * 85 * 85, 
01237                                      85 * 85 * 85 * 85 };
01238 
01239     // Start at the beginning of the buffer
01240 //  INT32 SrcOfs = 0;
01241     INT32 DstOfs = 0;
01242     BOOL FoundEOD = FALSE;
01243 
01244     while ((Length > 0) && (!FoundEOD))
01245     {
01246         // Decode five characters into four bytes.
01247         UINT32 n = 0;
01248         UINT32 TupleLength = (Length >= 5) ? 5 : Length;
01249 
01250         // Look for the EOD marker
01251         for (UINT32 i = 0; i < 5; i++)
01252         {
01253             if ((Src[i] == '~') && ((i + 1) < Length) && (Src[i + 1] == '>'))
01254             {
01255                 // Found the EOD marker in the data
01256                 FoundEOD = TRUE;
01257 
01258                 // Shorten the tuple
01259                 TupleLength = i;
01260             }
01261         }
01262 
01263         if (Src[0] == 'z')
01264         {
01265             // Skip the 'z' character
01266             TupleLength = 1;
01267         }
01268         else
01269         {           
01270             // Decode base-85 numbers.
01271             for (UINT32 i = 0; i < 5; i++)
01272             {
01273                 if (i < TupleLength)
01274                     n += ((Src[i] - '!') * Power85[4 - i]);
01275                 else if (i == TupleLength)
01276                     // Round up fractional part
01277                     n += 0x80 << ((4 - i) * 8);
01278 
01279                 // 'z' is not allowed within a tuple
01280                 ERROR2IF(Src[i] == 'z', -1, "Illegal 'z' in ASCII85 stream");
01281             }
01282         }
01283 
01284         // Find out how many bytes we just decoded.
01285         UINT32 nBytesDecoded = TupleLength - 1;
01286 
01287         // Copy the decoded data into the buffer.
01288         UINT32 Shift = 24;
01289         while (nBytesDecoded > 0)
01290         {
01291             Dest[DstOfs++] = (BYTE) ((n >> Shift) & 0xFF);
01292             nBytesDecoded--;
01293             Shift -= 8;
01294         }
01295 
01296         // Move on to the next tuple.
01297         Src += TupleLength;
01298         Length -= TupleLength;
01299     }
01300 
01301     // Check the lengths match
01302     ERROR2IF(Length != 0, -1, "Incorrect length while decoding ASCII85 data");
01303     //ERROR2IF(!FoundEOD,   -1, "No EOD found while decoding ASCII85 data");
01304 
01305     // Finished encoding - terminate the string (not strictly necessary but what the hell).
01306     Dest[DstOfs] = 0;
01307 
01308     // Return how many bytes this decoded ASCII85 data takes up
01309     return DstOfs;
01310 }
01311 
01312 INT32 KernelDC::FlushASCII85Buffer()
01313 {
01314     INT32 ConvertedLength = ConvertToASCII85(RawBuf, RawBufSize, A85Buf);
01315 
01316     #ifdef _DEBUG
01317 
01318         // Let's just check that it was encoded corrrectly.
01319         // (NOTE: I allocate 4 bytes more than necessary because ConvertFromASCII85 may
01320         // write an extra terminator byte past the end of the buffer memory)
01321         BYTE *Dest = (BYTE *) CCMalloc(RawBufSize + 4);
01322         if (Dest == NULL)
01323             // Error - no more memory
01324             return -1;
01325 
01326         INT32 nBytes = KernelDC::ConvertFromASCII85(A85Buf, ConvertedLength, Dest);
01327         ERROR2IF(nBytes < 0, -1, "Error in decoding ASCII85 data");
01328 
01329         // Length check
01330         if (nBytes != (INT32) RawBufSize)
01331             ERROR3("Length of decoded ASCII85 data does not match original! Output may be corrupt");
01332 
01333         // Binary comparison
01334         if (memcmp(RawBuf, Dest, RawBufSize) != 0)
01335             ERROR3("Decoded ASCII85 data does not match original! Output may be corrupt");
01336 
01337         // Clean up.
01338         CCFree(Dest);
01339 
01340     #endif
01341 
01342     RawBufSize = 0;
01343     if (!OutputDirect(A85Buf, ConvertedLength))
01344     {
01345         // Error
01346         return -1;
01347     }
01348 
01349     // All ok
01350     return ConvertedLength;
01351 }
01352 
01353 
01354 BYTE *KernelDC::RunLengthEncode(BYTE *Data, INT32 *pLength)
01355 {
01356     // Run length encode the data first if required by the caller.
01357     BYTE *pRLLBuf = NULL;
01358 
01359     // Work out how much space we will need (i.e. work out the worst case overhead for
01360     // run length encoding).
01361     // This is based on no repetition at all, i.e. no opportunity for compression.
01362     // This results in a one byte overhead per 128 bytes.
01363 
01364     INT32 Length = *pLength;
01365     INT32 Overhead = (Length / 128) + 10;  // Add 10 for good measure!  No GPFs here...
01366 
01367     // Get a buffer to convert the data in. Allocate 4 byes extra just to be safe
01368     INT32 RLLSize = Length + Overhead;
01369     pRLLBuf = (LPBYTE) CCMalloc(RLLSize + 4);
01370     if (pRLLBuf == NULL)
01371         // Error;
01372         return NULL;
01373 
01374     // Ok - we've got the buffer, so encode the data.
01375     // We don't bother to RLL unless we get a gain, i.e. 3 or more repeating characters.
01376     // (2 repeating bytes gives the same space usage, and can interrupt the stream so
01377     // actually uses more space).
01378     INT32 SeqLength = 0;
01379     INT32 DestOfs = 0;
01380     INT32 SrcOfs = 0;
01381     INT32 Ofs = 0;
01382     INT32 Len = Length;
01383 
01384     while (Len > 0)
01385     {
01386         // Check for limit on sequence length.
01387         ERROR2IF(SeqLength > 128, NULL, "Sequence too long in RLE encoding!");
01388 
01389         if (SeqLength == 128)
01390         {
01391             // Got a full sequence - copy it to the destination buffer.
01392             ERROR2IF(DestOfs + SeqLength >= RLLSize, NULL, "RLE buffer over-run!");
01393             pRLLBuf[DestOfs++] = SeqLength - 1;
01394             memcpy(pRLLBuf + DestOfs, Data + SrcOfs, SeqLength);
01395             DestOfs += SeqLength;
01396             SrcOfs += SeqLength;
01397             SeqLength = 0;
01398         }
01399 
01400         // Look for repeating characters
01401         if ((Len > 2) && (Data[Ofs] == Data[Ofs + 1]) && (Data[Ofs] == Data[Ofs + 2]))
01402         {
01403             // Ooh - found 3 repeating characters - see if there are any more.
01404 
01405             // First flush out any previous bytes.
01406             if (SeqLength > 0)
01407             {
01408                 ERROR2IF(DestOfs + SeqLength >= RLLSize, NULL, "RLE buffer over-run!");
01409                 pRLLBuf[DestOfs++] = SeqLength - 1;
01410                 memcpy(pRLLBuf + DestOfs, Data + SrcOfs, SeqLength);
01411                 DestOfs += SeqLength;
01412             }
01413 
01414             // Sequence starts at this character.
01415             SrcOfs = Ofs;
01416             SeqLength = 0;
01417 
01418             while ((Len > 0) && (SeqLength < 128) && (Data[Ofs] == Data[SrcOfs]))
01419             {
01420                 // Try next character
01421                 Len--;
01422                 Ofs++;
01423                 SeqLength++;
01424             }
01425 
01426             // End of sequence of repeating characters - place it into buffer.
01427             ERROR2IF(DestOfs + 2 > RLLSize, NULL, "RLE buffer over-run!");
01428             pRLLBuf[DestOfs++] = 257 - SeqLength;
01429             pRLLBuf[DestOfs++] = Data[SrcOfs];
01430 
01431             // Move to next character
01432             //Ofs++;
01433             SeqLength = 0;
01434             SrcOfs = Ofs;
01435         }
01436         else
01437         {
01438             // Add this character to the current sequence.
01439             Len--;
01440             Ofs++;
01441             SeqLength++;
01442         }
01443     }
01444 
01445     // Flush remaining sequence, if there is one.
01446     if (SeqLength > 0)
01447     {
01448         ERROR2IF(DestOfs + SeqLength >= RLLSize, NULL, "RLE buffer over-run!");
01449         pRLLBuf[DestOfs++] = SeqLength - 1;
01450         memcpy(pRLLBuf + DestOfs, Data + SrcOfs, SeqLength);
01451         DestOfs += SeqLength;
01452     }
01453 
01454     // Return the pointer to the RLL encoded data, and tell caller how long the data is.
01455     *pLength = DestOfs;
01456     return pRLLBuf;
01457 }
01458 
01459 BYTE *KernelDC::RunLengthDecode(BYTE *Data, INT32 *pLength)
01460 {
01461     // Ok, scan the data to see how large it will expand to.
01462     INT32 i = 0;
01463     INT32 Length = *pLength;
01464     INT32 Size = 0;
01465     BOOL FoundEOD = FALSE;
01466 
01467     while (i < Length)
01468     {
01469         if (Data[i] <= 127)
01470         {
01471             // Straight copying of data
01472             Size += (Data[i] + 1);
01473 
01474             // Skip past the data
01475             i += (Data[i] + 2);
01476         }
01477         else if (Data[i] > 128)
01478         {
01479             // Repeated data
01480             Size += (257 - Data[i]);
01481 
01482             // Skip past repeat count and byte to repeat.
01483             i += 2;
01484         }
01485         else
01486         {
01487             // 128 == End of stream
01488             FoundEOD = TRUE;
01489             break;
01490         }
01491     }
01492 
01493     // Got the size of data stream - allocate a buffer.
01494     if (Size == 0)
01495     {
01496         // Something not right here - cope with it gracefully
01497         *pLength = 0;
01498         return NULL;
01499     }
01500 
01501     // Allocate a buffer. Allocate 4 bytes extra just in case of slight buffer overruns
01502     BYTE *pRLLBuf = (BYTE *) CCMalloc(Size + 1 + 4);
01503     if (pRLLBuf == NULL)
01504     {
01505         // Error - no memory
01506         *pLength = 0;
01507         return NULL;
01508     }
01509 
01510     // Ok, actually decode it now.
01511     INT32 j = 0;
01512     i = 0;
01513     FoundEOD = FALSE;
01514 
01515     while (i < Length)
01516     {
01517         if (Data[i] <= 127)
01518         {
01519             // Straight copying of data
01520             memcpy(pRLLBuf + j, Data + i + 1, Data[i] + 1);
01521 
01522             // Skip past the data
01523             j += (Data[i] + 1);
01524             i += (Data[i] + 2);
01525         }
01526         else if (Data[i] > 128)
01527         {
01528             // Repeated data
01529             memset(pRLLBuf + j, Data[i + 1], 257 - Data[i]);
01530 
01531             // Skip past repeat count and byte to repeat.
01532             j += (257 - Data[i]);
01533             i += 2;
01534         }
01535         else
01536         {
01537             // 128 == End of stream
01538             FoundEOD = TRUE;
01539             break;
01540         }
01541     }
01542 
01543     // Sanity checks
01544     if (j!=Size)
01545     {
01546         *pLength=0;
01547         ERROR2(NULL, "Incorrect decoding of Run length data");
01548     }
01549 
01550     // Ok, we've decoded it.
01551     *pLength = j;
01552     return pRLLBuf;
01553 }
01554 
01555 
01556 /********************************************************************************************
01557 
01558 >   void KernelDC::SetFullAccuracy(BOOL Full)
01559 
01560     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01561     Created:    21/11/94
01562     Inputs:     Full:  TRUE => Use 3dp when saving user space values
01563                       FALSE => Use 2dp when saving user space values
01564     Purpose:    Change the accuracy used when saving out user space values to the EPS file.
01565                 This defaults to 2dp, but can be enabled to full accuracy (3dp) by 
01566                 passing in TRUE.
01567                 We still do 2dp because that is what Illustrator and most of the other
01568                 mediocre programs use and we don't want to generate files that might
01569                 upset them.  Camelot EPS uses the full 3dp accuracy though.
01570 
01571 ********************************************************************************************/
01572 
01573 void KernelDC::SetFullAccuracy(BOOL Full)
01574 {
01575     FullAccuracy = Full;
01576 }
01577 
01578 
01579 /********************************************************************************************
01580 
01581 >   BOOL KernelDC::OutputNewLine()
01582 
01583     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01584     Created:    28/03/94
01585     Returns:    FALSE (see Purpose)
01586     Purpose:    Causes a new line to be started in the EPS/PS output.   This is used
01587                 to give a pleasant appearance to the file - most EPS/PS commands (as
01588                 opposed to operands) are followed by a new line.
01589 
01590                 NB. This base class version will always raise an ERROR2 and return FALSE
01591                     because this function must be over-ridden in order to use the output
01592                     functions.
01593 
01594     SeeAlso:    KernelDC; KernelDC::OutputToken
01595     Errors:     Always => ERROR2
01596 
01597 ********************************************************************************************/
01598 
01599 BOOL KernelDC::OutputNewLine()
01600 {
01601     ERROR2(FALSE, "OutputNewLine() called for base class KernelDC");
01602 }
01603 
01604 /********************************************************************************************
01605 
01606 >   BOOL KernelDC::OutputToken(TCHAR *Str)
01607 
01608     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01609     Created:    28/03/94
01610     Inputs:     Str - the character string to write to the stream.
01611     Returns:    FALSE (see Purpose)
01612     Purpose:    Outputs a string token to the EPS/PS stream.
01613                 This is the central routine through which the other high-level routines
01614                 eventually come. The other routines convert their output to a string,
01615                 which they then pass on to this routine.
01616                 A record is kept of the current line width - if it is over 70 characters
01617                 wide before the token is output, then a new line is output to keep
01618                 the lines in the EPS file reasonably short.
01619                 For this reason, it is important not to output strings that contain
01620                 newline characters, because this routine will not notice, and hence
01621                 the LineWidth count will be wrong.
01622                 This routine also ensures that tokens are separated by either a space
01623                 or a newline, so it is not necessary to output spaces directly to keep the 
01624                 tokens separate - it happens automatically.
01625 
01626                 NB. This base class version will always raise an ERROR2 and return FALSE
01627                     because this function must be over-ridden in order to use the output
01628                     functions.
01629 
01630     SeeAlso:    KernelDC; KernelDC::OutputNewLine; KernelDC::OutputDirect
01631     Errors:     Always => ERROR2
01632 
01633 ********************************************************************************************/
01634 
01635 BOOL KernelDC::OutputToken(TCHAR *Str)
01636 {
01637     ERROR2(FALSE, "OutputToken() called for base class KernelDC");
01638 }
01639 
01640 
01641 /********************************************************************************************
01642 
01643 >   BOOL KernelDC::OutputDirect(BYTE *Buf, INT32 nBytes)
01644 
01645     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01646     Created:    04/23/95
01647     Inputs:     Buf - the bytes to send to the stream.
01648                 nBytes - the number of bytes to send to the stream.
01649     Returns:    FALSE (see Purpose)
01650     Purpose:    Send bytes directly to the PostScript stream with no alteration or padding.
01651                 Used for sending binary/hex data to stream.
01652 
01653                 NB. This base class version will always raise an ERROR2 and return FALSE
01654                     because this function must be over-ridden in order to use the output
01655                     functions.
01656 
01657     SeeAlso:    KernelDC::OutputNewLine; KernelDC::OutputToken
01658     Errors:     Always => ERROR2
01659 
01660 ********************************************************************************************/
01661 
01662 BOOL KernelDC::OutputDirect(BYTE *, INT32)
01663 {
01664     ERROR2(FALSE, "OutputDirect() called for base class KernelDC");
01665 }
01666 
01667 
01668 
01669 /********************************************************************************************
01670 
01671 >   BOOL KernelDC::OutputTCHARAsChar(TCHAR *Buf, INT32 nBytes)
01672 
01673     Author:     Alex Bligh
01674     Created:    13/06/2006
01675     Inputs:     Buf - the bytes to send to the stream.
01676                 nBytes - the number of bytes to send to the stream (i.e the number of
01677                 TCHARs to read)
01678     Returns:    TRUE if all the bytes were sent ok;
01679                 FALSE if not.
01680     Purpose:    Send bytes directly to the PostScript stream with no alteration or padding.
01681                 Used for sending binary/hex data to stream. We send the BYTE equal to
01682                 the TCHAR with no conversion
01683     SeeAlso:    KernelDC::OutputNewLine; KernelDC::OutputToken
01684 
01685 ********************************************************************************************/
01686 
01687 BOOL KernelDC::OutputTCHARAsChar(TCHAR *Buf, INT32 nBytes)
01688 {
01689     if (sizeof(TCHAR) == sizeof(char))
01690         return OutputDirect((BYTE *)Buf, nBytes);
01691 
01692     BYTE * pByte=new BYTE[nBytes];
01693     if (!pByte)
01694         return FALSE;
01695 
01696     INT32 i;
01697     for (i=0; i<nBytes; i++)
01698         pByte[i]=Buf[i]; // 1:1 copy
01699 
01700     BOOL ok=OutputDirect(pByte, nBytes);
01701 
01702     delete (pByte);
01703     return ok;
01704 }
01705 
01706 //
01707 // ExportDC class
01708 //
01709 
01710 
01711 /********************************************************************************************
01712 
01713 >   ExportDC::ExportDC(Filter *Parent)
01714 
01715     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01716     Created:    28/03/94
01717     Purpose:    Creates a DC of the correct type (RENDERTYPE_FILE).
01718     SeeAlso:    EPSExportDC::EPSExportDC
01719 
01720 ********************************************************************************************/
01721 
01722 ExportDC::ExportDC(Filter *Parent) : KernelDC(RENDERTYPE_FILE)
01723 {
01724     // Sanity check
01725     ENSURE(Parent != NULL, "NULL parent filter in ExportDC creation!");
01726 
01727     // Install parent
01728     ParentFilter = Parent;
01729     ExportFile = NULL;
01730 }
01731 
01732 /********************************************************************************************
01733 
01734 >   BOOL ExportDC::Init(CCLexFile* pFile)
01735 
01736     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01737     Created:    28/03/94
01738     Inputs:     pFile - the file to connect this DC to.
01739     Returns:    TRUE if DC connected to file successfully, FALSE if an error occured.
01740     Purpose:    Initialise an export DC by connecting it to a named file.
01741     Errors:     Unable to open the file.
01742     SeeAlso:    ExportDC
01743 
01744 ********************************************************************************************/
01745 
01746 BOOL ExportDC::Init(CCLexFile* pFile)
01747 {
01748     // This file is already open when we get it
01749     ExportFile = pFile;
01750 
01751     // Make sure that the file is open
01752     ERROR2IF(!ExportFile->isOpen(), FALSE, "File was not open in ExportDC::Init()");
01753 
01754     // File opened ok.
01755     return TRUE;
01756 }
01757 
01758 /********************************************************************************************
01759 
01760 >   ExportDC::~ExportDC()
01761 
01762     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01763     Created:    28/03/94
01764     Purpose:    Deinitialise an Export device context.  If the file connected to this DC
01765                 is still open, the file is closed.
01766     SeeAlso:    ExportDC
01767 
01768 ********************************************************************************************/
01769 
01770 ExportDC::~ExportDC()
01771 {
01772     // This is no longer needed as the file is closed by the caller
01773     /*
01774     if (ExportFile.isOpen())
01775     {
01776         if (IsUserName("Tim"))
01777             TRACE( _T("File still open in CCExportDC dtor"));
01778 
01779         ExportFile.close();
01780     }
01781     */
01782 }
01783 
01784 
01785 /********************************************************************************************
01786 
01787 >   Filter *ExportDC::GetParentFilter()
01788 
01789     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01790     Created:    05/08/94
01791     Returns:    Pointer to the parent filter object.
01792     Purpose:    Get a pointer to the filter object associated with this export device
01793                 context.
01794     SeeAlso:    Filter
01795 
01796 ********************************************************************************************/
01797 
01798 Filter *ExportDC::GetParentFilter()
01799 {
01800     return ParentFilter;
01801 }
01802 

Generated on Sat Nov 10 03:45:34 2007 for Camelot by  doxygen 1.4.4