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