00001 // $Id: drawfltr.cpp 1282 2006-06-09 09:46:49Z alex $ 00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE 00003 ================================XARAHEADERSTART=========================== 00004 00005 Xara LX, a vector drawing and manipulation program. 00006 Copyright (C) 1993-2006 Xara Group Ltd. 00007 Copyright on certain contributions may be held in joint with their 00008 respective authors. See AUTHORS file for details. 00009 00010 LICENSE TO USE AND MODIFY SOFTWARE 00011 ---------------------------------- 00012 00013 This file is part of Xara LX. 00014 00015 Xara LX is free software; you can redistribute it and/or modify it 00016 under the terms of the GNU General Public License version 2 as published 00017 by the Free Software Foundation. 00018 00019 Xara LX and its component source files are distributed in the hope 00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the 00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00022 See the GNU General Public License for more details. 00023 00024 You should have received a copy of the GNU General Public License along 00025 with Xara LX (see the file GPL in the root directory of the 00026 distribution); if not, write to the Free Software Foundation, Inc., 51 00027 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00028 00029 00030 ADDITIONAL RIGHTS 00031 ----------------- 00032 00033 Conditional upon your continuing compliance with the GNU General Public 00034 License described above, Xara Group Ltd grants to you certain additional 00035 rights. 00036 00037 The additional rights are to use, modify, and distribute the software 00038 together with the wxWidgets library, the wxXtra library, and the "CDraw" 00039 library and any other such library that any version of Xara LX relased 00040 by Xara Group Ltd requires in order to compile and execute, including 00041 the static linking of that library to XaraLX. In the case of the 00042 "CDraw" library, you may satisfy obligation under the GNU General Public 00043 License to provide source code by providing a binary copy of the library 00044 concerned and a copy of the license accompanying it. 00045 00046 Nothing in this section restricts any of the rights you have under 00047 the GNU General Public License. 00048 00049 00050 SCOPE OF LICENSE 00051 ---------------- 00052 00053 This license applies to this program (XaraLX) and its constituent source 00054 files only, and does not necessarily apply to other Xara products which may 00055 in part share the same code base, and are subject to their own licensing 00056 terms. 00057 00058 This license does not apply to files in the wxXtra directory, which 00059 are built into a separate library, and are subject to the wxWindows 00060 license contained within that directory in the file "WXXTRA-LICENSE". 00061 00062 This license does not apply to the binary libraries (if any) within 00063 the "libs" directory, which are subject to a separate license contained 00064 within that directory in the file "LIBS-LICENSE". 00065 00066 00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS 00068 ---------------------------------------------- 00069 00070 Subject to the terms of the GNU Public License (see above), you are 00071 free to do whatever you like with your modifications. However, you may 00072 (at your option) wish contribute them to Xara's source tree. You can 00073 find details of how to do this at: 00074 http://www.xaraxtreme.org/developers/ 00075 00076 Prior to contributing your modifications, you will need to complete our 00077 contributor agreement. This can be found at: 00078 http://www.xaraxtreme.org/developers/contribute/ 00079 00080 Please note that Xara will not accept modifications which modify any of 00081 the text between the start and end of this header (marked 00082 XARAHEADERSTART and XARAHEADEREND). 00083 00084 00085 MARKS 00086 ----- 00087 00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara 00089 designs are registered or unregistered trademarks, design-marks, and/or 00090 service marks of Xara Group Ltd. All rights in these marks are reserved. 00091 00092 00093 Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. 00094 http://www.xara.com/ 00095 00096 =================================XARAHEADEREND============================ 00097 */ 00098 00099 // An input filter for importing RISC OS Draw format files. 00100 00101 00102 #include "camtypes.h" 00103 #include "drawfltr.h" 00104 00105 #include <ctype.h> 00106 00107 #include <afxdlgs.h> 00108 00109 //#include "pathname.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00110 //#include "document.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00111 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00112 //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00113 //#include "ensure.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00114 #include "paper.h" 00115 #include "nodepath.h" 00116 //#include "paths.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00117 //#include "tim.h" 00118 #include "lineattr.h" 00119 #include "progress.h" // for the progress indicator 00120 //#include "tim.h" 00121 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00122 //#include "oilfltrs.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00123 //#include "group.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00124 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00125 #include "page.h" 00126 //#include "trans2d.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00127 //#include "attrmgr.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00128 00129 00130 DECLARE_SOURCE("$Revision: 1282 $"); 00131 00132 00133 CC_IMPLEMENT_DYNAMIC(AcornDrawFilter, VectorFilter) 00134 00135 00136 00137 #define DRAWOBJECT_FONTTABLE (0) 00138 #define DRAWOBJECT_TEXT (1) 00139 #define DRAWOBJECT_PATH (2) 00140 #define DRAWOBJECT_SPRITE (5) 00141 #define DRAWOBJECT_GROUP (6) 00142 #define DRAWOBJECT_TAGGED (7) 00143 #define DRAWOBJECT_TEXTAREA (9) 00144 #define DRAWOBJECT_TEXTCOLUMN (10) 00145 #define DRAWOBJECT_OPTIONS (11) 00146 #define DRAWOBJECT_TRANSFORMEDTEXT (12) 00147 #define DRAWOBJECT_TRANSFORMEDSPRITE (13) 00148 00149 #define DRAWOBJECT_ERROR (-1) // => Error reading object header 00150 00151 00152 00153 00154 #define DRAWTAG_ENDOFPATH (0) 00155 #define DRAWTAG_MOVETO (2) 00156 #define DRAWTAG_CLOSESUBPATH (5) 00157 #define DRAWTAG_LINETO (8) 00158 #define DRAWTAG_CURVETO (6) 00159 00160 00161 00162 #define SIZEOF_MOVETO (12) 00163 #define SIZEOF_CLOSESUBPATH (4) 00164 #define SIZEOF_LINETO (12) 00165 #define SIZEOF_CURVETO (28) 00166 00167 00168 00169 00170 00171 #define DRAW_TRANSPARENT (0xFFFFFFFF) 00172 00173 00174 00175 /******************************************************************************************** 00176 00177 > class DrawColour 00178 00179 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00180 Created: 08/12/93 00181 Purpose: Mirrors the representation of a colour as used in Acorn Draw files. 00182 SeeAlso: DrawPathStyle; DashPatternHeader 00183 00184 ********************************************************************************************/ 00185 00186 class DrawColour 00187 { 00188 public: 00189 union 00190 { 00191 struct 00192 { 00193 BYTE Reserved : 8; 00194 BYTE Red : 8; 00195 BYTE Green : 8; 00196 BYTE Blue : 8; 00197 } Component; 00198 UINT32 ColourValue; 00199 } Data; 00200 }; 00201 00202 00203 /******************************************************************************************** 00204 00205 typedef DrawPathStyle 00206 00207 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00208 Created: 08/12/93 00209 Purpose: Holds the style information for a path as used in Acorn Draw files. 00210 SeeAlso: DrawColour; DashPatternHeader 00211 00212 ********************************************************************************************/ 00213 00214 typedef union 00215 { 00216 UINT32 Value; 00217 struct 00218 { 00219 UINT32 Join : 2; 00220 UINT32 EndCap : 2; 00221 UINT32 StartCap : 2; 00222 UINT32 WindingRule : 1; 00223 UINT32 DashPresent : 1; 00224 UINT32 Reserved : 8; 00225 UINT32 CapWidth : 8; 00226 UINT32 CapLength : 8; 00227 } Data; 00228 } DrawPathStyle; 00229 00230 00231 /******************************************************************************************** 00232 00233 > class DashPatternHeader 00234 00235 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00236 Created: 08/12/93 00237 Purpose: The header for the dash pattern structure contained in Acorn Draw files. 00238 It is usually followed by a series of dash and gap lengths in the file. 00239 SeeAlso: DrawColourl; DrawPathStyle 00240 00241 ********************************************************************************************/ 00242 00243 class DashPatternHeader 00244 { 00245 public: 00246 UINT32 Offset; 00247 UINT32 NumElements; 00248 }; 00249 00250 00251 /******************************************************************************************** 00252 00253 > class DrawPathElement 00254 00255 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00256 Created: 08/12/93 00257 Purpose: Used to load in a path element from a Draw file. Not all of the 'Coords' 00258 array is always used - it depends on the path element. 00259 SeeAlso: DrawPathHeader 00260 00261 ********************************************************************************************/ 00262 00263 class DrawPathElement 00264 { 00265 public: 00266 UINT32 Tag; 00267 DocCoord Coords[3]; 00268 }; 00269 00270 00271 /******************************************************************************************** 00272 00273 > class DrawPathHeader 00274 00275 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00276 Created: 08/12/93 00277 Purpose: Used to load in the header information for a path object in a Draw file. 00278 It holds details on the fill and line colours, the line width, and the 00279 style of the path. 00280 SeeAlso: DrawPathElement; DrawColour; DrawPathStyle 00281 00282 ********************************************************************************************/ 00283 00284 class DrawPathHeader 00285 { 00286 public: 00287 DrawColour FillColour; 00288 DrawColour LineColour; 00289 UINT32 LineWidth; 00290 DrawPathStyle Style; 00291 }; 00292 00293 00294 /******************************************************************************************** 00295 00296 > AcornDrawFilter::AcornDrawFilter() 00297 00298 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00299 Created: 18/11/93 00300 Purpose: Filter constructor - this initialises the default attributes and the 00301 input buffer. 00302 00303 ********************************************************************************************/ 00304 00305 AcornDrawFilter::AcornDrawFilter() 00306 { 00307 // Set up filter descriptions. 00308 FilterName.Load(_R(IDT_DRAW_FILTERNAME)); 00309 FilterInfo.Load(_R(IDT_DRAW_FILTERINFO)); 00310 FilterID = FILTERID_ACORN_DRAW; 00311 00312 #ifndef STANDALONE 00313 Flags.CanImport = TRUE; 00314 Flags.CanExport = FALSE; 00315 #else 00316 Flags.CanImport = FALSE; 00317 Flags.CanExport = FALSE; 00318 #endif 00319 00320 #if 0 00321 // No attributes yet 00322 DefLineWidthAttr = NULL; 00323 DefLineColAttr = NULL; 00324 DefFillColAttr = NULL; 00325 #endif 00326 00327 // No buffer yet 00328 DataBuf = NULL; 00329 DataBufSize = 0; 00330 }; 00331 00332 00333 /******************************************************************************************** 00334 00335 > AcornDrawFilter::~AcornDrawFilter() 00336 00337 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00338 Created: 18/11/93 00339 Purpose: Destructor for the filter - this deallocates the input buffer. 00340 00341 ********************************************************************************************/ 00342 00343 AcornDrawFilter::~AcornDrawFilter() 00344 { 00345 // Clean up our input buffer 00346 CCFree(DataBuf); 00347 } 00348 00349 00350 /******************************************************************************************** 00351 00352 > BOOL AcornDrawFilter::Init() 00353 00354 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00355 Created: 18/11/93 00356 Returns: Always TRUE at the moment. 00357 Purpose: Initialise the filter (attaches a DrawOILFilter object). 00358 SeeAlso: DrawOILFilter 00359 00360 ********************************************************************************************/ 00361 00362 BOOL AcornDrawFilter::Init() 00363 { 00364 // Get the OILFilter object 00365 pOILFilter = new DrawOILFilter(this); 00366 if (pOILFilter == NULL) 00367 return FALSE; 00368 00369 // All ok 00370 return TRUE; 00371 } 00372 00373 /******************************************************************************************** 00374 00375 > virtual BOOL AcornDrawFilter::IsDefaultDocRequired(const TCHAR* pcszPathName) 00376 00377 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 00378 Created: 16/10/95 00379 Inputs: pcszPathName pointer to the pathname to check 00380 Returns: TRUE if the filter requires a default document, FALSE if not. 00381 Purpose: Works out if opening a file of this type requires a default document to be 00382 loaded. If the file format supplies the document then return FALSE otherwise 00383 return TRUE. An example would be opening a bitmap file. This has no document 00384 defined in the file format and so we need to laod the default document before 00385 importing the bitmap into this file. 00386 In this version we return TRUE as either this format has no page size or 00387 nobody has implemented it yet. 00388 SeeAlso: Filter; Filter::IsDefaultDocRequired; CCamDoc::OnOpenDocument; 00389 SeeAlso: FilterFamily::DoImport; Filter::DoImport; 00390 00391 ********************************************************************************************/ 00392 00393 BOOL AcornDrawFilter::IsDefaultDocRequired(const TCHAR* pcszPathName) 00394 { 00395 // No need to check the pathname, just return TRUE as all currently known bitmap filters 00396 // will require the default document. 00397 return TRUE; 00398 } 00399 00400 00401 /******************************************************************************************** 00402 00403 > INT32 AcornDrawFilter::HowCompatible(PathName& Filename, ADDR HeaderStart, 00404 UINT32 HeaderSize, UINT32 FileSize) 00405 00406 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00407 Created: 21/03/94 00408 Inputs: Filename - name of the file. 00409 HeaderStart - Address of the first few bytes of the file. 00410 HeaderSize - the number of bytes in the header pointed to by FileStart. 00411 FileSize - the size of the whole file, in bytes. 00412 Returns: Compatibility: 0 => Not a Draw file; 10 => It is a Draw file 00413 Purpose: Analyse a file to see if it is an Acorn Draw file - at present this 00414 is done by checking to see if the first four bytes are "Draw". 00415 SeeAlso: AcornDrawFilter 00416 00417 ********************************************************************************************/ 00418 00419 INT32 AcornDrawFilter::HowCompatible(PathName& Filename, ADDR HeaderStart, 00420 UINT32 HeaderSize, UINT32 FileSize) 00421 00422 { 00423 PORTNOTE("byteorder", "TODO: Check byte ordering") 00424 if (camStrncmp((char *) HeaderStart, "Draw", 4) == 0) 00425 { 00426 // It's a Draw file. 00427 return 10; 00428 } 00429 00430 // It's not a Draw file. 00431 return 0; 00432 } 00433 00434 00435 /******************************************************************************************** 00436 00437 > BOOL AcornDrawFilter::PrepareToImport() 00438 00439 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00440 Created: 22/02/94 00441 Returns: TRUE if it succeeds, FALSE if not. 00442 Purpose: Sets up the Draw filter so it can read in a Draw file. 00443 00444 ********************************************************************************************/ 00445 00446 BOOL AcornDrawFilter::PrepareToImport() 00447 { 00448 // Get a default set of attributes for ink objects. 00449 if (!SetUpCurrentAttrs()) 00450 return FALSE; 00451 00452 // Shouldn't have a data buffer at this point 00453 ENSURE(DataBuf == NULL, "DataBuf is non-NULL in PrepareToImport()"); 00454 00455 // No objects read yet 00456 HeaderSize = 0; 00457 DataSize = 0; 00458 00459 // Get a Diskfile object 00460 DrawFile = NULL; 00461 00462 // Ok so far 00463 return TRUE; 00464 } 00465 00466 00467 /******************************************************************************************** 00468 00469 > void AcornDrawFilter::CleanUpAfterImport() 00470 00471 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00472 Created: 24/02/94 00473 Purpose: Delete dynamic objects used in the import process. 00474 SeeAlso: AcornDrawFilter::PrepareToImport; AcornDrawFilter::DoImport 00475 00476 ********************************************************************************************/ 00477 00478 void AcornDrawFilter::CleanUpAfterImport() 00479 { 00480 DeleteCurrentAttrs(); 00481 DrawFile = NULL; 00482 CCFree(DataBuf); 00483 DataBuf = NULL; 00484 DataBufSize = 0; 00485 } 00486 00487 00488 /******************************************************************************************** 00489 00490 > BOOL AcornDrawFilter::DoImport(SelOperation *Op, CCLexFile* pFile, 00491 Document *DestDoc, BOOL AutoChosen, ImportPosition* Pos, 00492 KernelBitmap** ppImportedBitmap, DocCoord* pPosTranslate, String_256* URL) 00493 00494 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00495 Created: 18/11/93 00496 Inputs: Op - pointer to the operation that this read process is associated with. 00497 pFile - The file that we are trying to import 00498 DestDoc - pointer to the document to insert the Draw file data into. 00499 AutoChosen - 00500 Pos - 00501 ppImportedBitmap - this is used mainly in the bitfltr.cpp for the HTML 00502 import filter. HTMLFilter::DoImport() needs a pointer to a kernel bitmap 00503 to set the background bitmap up into Camelot. 00504 pPosTranslate - This is used too by the HTMLFilter in order to do a formatting. 00505 URL - original URL of the imported file 00506 Returns: TRUE if the read was successful, FALSE if not. 00507 Purpose: Import the named Acorn draw file into the specified document. 00508 As yet, only path and group objects are handled. Tagged objects are 00509 handled correctly, so, e.g. TableMate files can be loaded by Camelot 00510 (although the results are not very interesting). 00511 Currently, the data is always positioned on the first page of the first 00512 spread in the first chapter. 00513 If the read is successful, the End() function of the 'Op' operation is 00514 called, otherwise it is not called. 00515 Errors: Unable to open file, corrupted document tree found. 00516 00517 ********************************************************************************************/ 00518 00519 BOOL AcornDrawFilter::DoImport(SelOperation *Op, CCLexFile* pFile, 00520 Document *DestDoc, BOOL AutoChosen, ImportPosition* Pos, 00521 KernelBitmap** ppImportedBitmap, DocCoord* pPosTranslate, String_256* URL) 00522 { 00523 // Let's get ready 00524 if (!PrepareToImport()) 00525 return FALSE; 00526 00527 // Make sure that there is a layer to put the bitmap onto 00528 if (!MakeSureLayerExists(DestDoc)) 00529 // There is no layer and one could not be made, so we will have to fail 00530 return FALSE; 00531 00532 // Find the layer on the first page of this document... 00533 pLayer = GetActiveLayer(DestDoc); 00534 ENSURE(pLayer != NULL, "Spread has no active layer"); 00535 00536 // pNode is where new objects will go - they all go into a group so the user 00537 // can easily drag the imported Draw file around. They can then ungroup it afterwards 00538 // if they want. 00539 NodeGroup *pDrawGroup = new NodeGroup; 00540 ERRORIF(pDrawGroup == NULL, _R(IDT_DRAW_NOMEMORY), FALSE); 00541 pNode = pDrawGroup; 00542 00543 Spread *pSpread; 00544 00545 if (Pos == NULL) 00546 { 00547 // For now, position Draw objects on 1st page of spread 1 00548 PORTNOTE("spread", "Multi-spread warning!") 00549 pSpread = GetFirstSpread(DestDoc); 00550 pPage = (Page *) pSpread->FindFirstPageInSpread(); 00551 ENSURE(pPage->IsKindOf(CC_RUNTIME_CLASS(Page)), 00552 "AcornDrawFilter::Read(): Could not find first Page"); 00553 00554 // Use bottom left of page as origin 00555 DocRect PageRect = pPage->GetPageRect(); 00556 Origin = PageRect.lo; 00557 } 00558 else 00559 { 00560 pSpread = Pos->pSpread; 00561 Origin = Pos->Position; 00562 } 00563 00564 // No complex path initially 00565 ComplexPath = FALSE; 00566 00567 // Make a note of the disk file 00568 DrawFile = pFile; 00569 00570 // Disable exceptions and error reporting for this file - we'll do it ourselves 00571 DrawFile->SetReportErrors(FALSE); 00572 DrawFile->SetThrowExceptions(FALSE); 00573 00574 // Find out the size of the file, in bytes. 00575 INT32 filesize = DrawFile->Size(); 00576 00577 // Initialise 00578 eof = FALSE; 00579 00580 // Set the progress indicator, this next bit might take a while. 00581 String_64 ImportMessage(_R(IDT_IMPORTMSG_ACORNDRAW)); 00582 ImportMessage = GetImportProgressString(pFile, _R(IDT_IMPORTMSG_ACORNDRAW)); 00583 BeginSlowJob(filesize, TRUE, &ImportMessage); 00584 00585 BytesRead = 0; 00586 LastProgressUpdate = 0; 00587 00588 // Find out details on the file 00589 ReadFileHeader(); 00590 00591 // Check that this is an Acorn Draw file...the first four characters in the file 00592 // should be "Draw". If we've been chosen automatically, then don't bother as we've 00593 // already checked this. 00594 if (DrawFile->eof() || (!AutoChosen && (camStrncmp(FileHeader.Ident, "Draw", 4) != 0))) 00595 { 00596 // Could not find the ident header - close the file, and return error. 00597 EndSlowJob(); 00598 CleanUpAfterImport(); 00599 ERROR(_R(IDT_DRAW_NOTADRAWFILE), FALSE); 00600 } 00601 00602 // Remember file errors 00603 BOOL Error = FALSE; 00604 00605 // Process each object in the file 00606 do 00607 { 00608 // Read and process each object 00609 if (ReadObjectHeader()) 00610 { 00611 // Header read ok so there is another object to process 00612 if (!ProcessObject()) 00613 // Unable to process object - set error flag 00614 Error = TRUE; 00615 } 00616 } 00617 while ((BytesRead < filesize) && !Error); 00618 00619 // All work has been completed . . . 00620 EndSlowJob(); 00621 00622 // All done 00623 BOOL Failed = Error && (BytesRead < filesize); 00624 00625 // Free up dynamic objects used for import 00626 CleanUpAfterImport(); 00627 00628 // If the load failed for any reason, delete the subtree we have created; otherwise 00629 // graft it into the tree. 00630 if (Failed) 00631 { 00632 // Failed - delete the sub-tree we just created, free the buffer, and return error. 00633 pDrawGroup->CascadeDelete(); 00634 delete pDrawGroup; 00635 return FALSE; 00636 } 00637 else 00638 { 00639 // It worked - add the node into the tree 00640 00641 // Remember current bounding rectangle of the group 00642 DocRect BoundsRect = pDrawGroup->GetBoundingRect(TRUE); 00643 00644 if (Pos != NULL) 00645 { 00646 // It should be centred on the given position... 00647 DocCoord Centre; 00648 Centre.x = (BoundsRect.lo.x + BoundsRect.hi.x) / 2; 00649 Centre.y = (BoundsRect.lo.y + BoundsRect.hi.y) / 2; 00650 00651 Trans2DMatrix Xlate(Pos->Position.x - Centre.x, Pos->Position.y - Centre.y); 00652 pDrawGroup->Transform(Xlate); 00653 } 00654 00655 // Insert the node and invalidate its region 00656 if (!Op->DoInsertNewNode(pDrawGroup, pSpread, TRUE)) 00657 { 00658 // It didn't work - delete the sub-tree we just created 00659 pDrawGroup->CascadeDelete(); 00660 delete pDrawGroup; 00661 pDrawGroup = NULL; 00662 } 00663 00664 } 00665 00666 // All ok 00667 return TRUE; 00668 } 00669 00670 /******************************************************************************************** 00671 00672 > BOOL AcornDrawFilter::ReadFileHeader() 00673 00674 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00675 Created: 18/11/93 00676 Returns: TRUE if the read is successful, FALSE if an error was encountered. 00677 Purpose: Read the header block of an Acorn Draw file. 00678 SeeAlso: AcornDrawFilter::ReadObjectHeader 00679 Scope: Private 00680 00681 ********************************************************************************************/ 00682 00683 BOOL AcornDrawFilter::ReadFileHeader() 00684 { 00685 DrawFile->read(&FileHeader, sizeof(FileHeader)); 00686 BytesRead += sizeof(FileHeader); 00687 return TRUE; 00688 } 00689 00690 /******************************************************************************************** 00691 00692 > BOOL AcornDrawFilter::ReadObjectHeader() 00693 00694 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00695 Created: 18/11/93 00696 Returns: TRUE if the header was read ok, FALSE if not. 00697 Purpose: This function reads in the header of a Draw object from the input file, 00698 and stores the result in the ObjectHeader member variable. 00699 Using the data in the header it then sets up the HeaderSize and DataSize 00700 member variables correctly. It is not ok just to use sizeof(ObjectHeader) 00701 as this is not always accurate because some objects in Draw files has 00702 stupid headers which are smaller than the standard size, so we have to 00703 compensate for this. In such cases we also have to rewind the file so we 00704 are in the correct position to read in the data following the header. 00705 Errors: If the EOF is found. 00706 SeeAlso: AcornDrawFilter::ReadObjectData; AcornDrawFilter::ReadFileHeader 00707 Scope: Private 00708 00709 ********************************************************************************************/ 00710 00711 BOOL AcornDrawFilter::ReadObjectHeader() 00712 { 00713 // Set default header size 00714 FilePos BeforePos = DrawFile->tell(); 00715 00716 HeaderSize = sizeof(ObjectHeader); 00717 00718 DrawFile->read(&ObjectHeader, sizeof(ObjectHeader)); 00719 00720 BytesRead += sizeof(ObjectHeader); 00721 00722 FilePos AfterPos = DrawFile->tell(); 00723 00724 if ((UINT32) (AfterPos-BeforePos) != sizeof(ObjectHeader)) 00725 { 00726 ERROR3_PF(("Header bytes read - actual: %d, planned: %d", (AfterPos-BeforePos), sizeof(ObjectHeader))); 00727 // If EOF found, then an error has occured 00728 ERROR1(FALSE, _R(IDT_DRAW_BADSYNTAX)); 00729 } 00730 00731 // Check for silly objects that don't have a bounding box, and move the input pointer 00732 // back to cope with this. 00733 switch (ObjectHeader.Type) 00734 { 00735 case DRAWOBJECT_FONTTABLE: 00736 // Move back over the bounding box fields (which don't really exist) 00737 FilePos Pos = DrawFile->tellIn(); 00738 00739 // Bounding box fields take up 16 bytes in Acorn Draw files. 00740 DrawFile->seekIn(Pos - 16); 00741 BytesRead -= 16; 00742 00743 // Adjust header size 00744 HeaderSize -= 16; 00745 break; 00746 } 00747 00748 DataSize = ObjectHeader.Size - HeaderSize; 00749 00750 // If eof not found, then no error 00751 return TRUE; 00752 } 00753 00754 /******************************************************************************************** 00755 00756 > BOOL AcornDrawFilter::ProcessObject() 00757 00758 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00759 Created: 19/11/93 00760 Returns: TRUE if the object was processed with no errors, FALSE if not. 00761 Purpose: Routes the object data to the appropriate function to be processed, 00762 according to the tag in the object's header data. 00763 If the object is not understood, then the data is simply discarded. 00764 Errors: - 00765 SeeAlso: AcornDrawFilter::ProcessPath; AcornDrawFilter::ProcessGroup; 00766 AcornDrawFilter::ProcessTaggedObject; AcornDrawFilter::SkipObject 00767 Scope: Private 00768 00769 ********************************************************************************************/ 00770 00771 BOOL AcornDrawFilter::ProcessObject() 00772 { 00773 if (BytesRead > (LastProgressUpdate + 2048)) 00774 { 00775 LastProgressUpdate = BytesRead; 00776 if (!ContinueSlowJob(BytesRead)) 00777 return FALSE; 00778 } 00779 00780 switch (ObjectHeader.Type) 00781 { 00782 case DRAWOBJECT_PATH: return ProcessPath(); 00783 case DRAWOBJECT_GROUP: return ProcessGroup(); 00784 case DRAWOBJECT_TAGGED: return ProcessTaggedObject(); 00785 default: return SkipObject(); 00786 } 00787 } 00788 00789 /******************************************************************************************** 00790 00791 > BOOL AcornDrawFilter::ProcessPath() 00792 00793 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00794 Created: 18/11/93 00795 Returns: TRUE if the path object is read and converted ok, FALSE if not. 00796 Purpose: Read in the data for a Draw path object, and convert it to an equivalent 00797 Camelot NodePath object, and add it to the node pointed to by the pNode 00798 member variable. 00799 Errors: File reading error, out of memory. 00800 SeeAlso: AcornDrawFilter::ProcessObject 00801 Scope: Private 00802 00803 ********************************************************************************************/ 00804 00805 BOOL AcornDrawFilter::ProcessPath() 00806 { 00807 // Attempt to read the data for this object 00808 if (!ReadObjectData()) 00809 return FALSE; 00810 00811 // Construct the path and add it to our group node... 00812 00813 // Create a new NodePath pbject 00814 NodePath *pPath = new NodePath(pNode, LASTCHILD); 00815 if ((pPath == NULL) || (!pPath->SetUpPath())) 00816 { 00817 // Couldn't initialise path - delete path (if created) and return error. 00818 delete pPath; 00819 ERROR(_R(IDT_DRAW_NOMEMORY), FALSE); 00820 } 00821 00822 // Position tag at start of path. 00823 pPath->InkPath.FindStartOfPath(); 00824 00825 // Examine path header info 00826 DrawPathHeader *pHeader = (DrawPathHeader *) DataBuf; 00827 00828 // Find first path element 00829 DrawPathElement *pElement = (DrawPathElement *) (pHeader + 1); 00830 00831 // Skip dash pattern if present 00832 if (pHeader->Style.Data.DashPresent) 00833 { 00834 DashPatternHeader *pDashPattern = (DashPatternHeader *) pElement; 00835 pElement = (DrawPathElement *) 00836 ( ((ADDR) pElement) + sizeof(DashPatternHeader) + (4 * pDashPattern->NumElements) ); 00837 } 00838 00839 // Process path elements until no more data is left. 00840 UINT32 BytesUsed = 0; 00841 00842 INT32 Tag = (pElement->Tag) & 0xFF; 00843 00844 while (Tag != DRAWTAG_ENDOFPATH) 00845 { 00846 switch (Tag) 00847 { 00848 case DRAWTAG_MOVETO: 00849 BytesUsed = SIZEOF_MOVETO; 00850 00851 TransformCoord(pElement->Coords[0]); 00852 00853 // Insert a moveto into the path 00854 if (!pPath->InkPath.InsertMoveTo(pElement->Coords[0])) 00855 // Not enough dynamic heap to insert the moveto command 00856 goto NoMemory; 00857 break; 00858 00859 case DRAWTAG_LINETO: 00860 BytesUsed = SIZEOF_LINETO; 00861 00862 TransformCoord(pElement->Coords[0]); 00863 00864 // Insert a lineto into the path 00865 if (!pPath->InkPath.InsertLineTo(pElement->Coords[0])) 00866 // Not enough dynamic heap to insert the lineto command 00867 goto NoMemory; 00868 break; 00869 00870 case DRAWTAG_CURVETO: 00871 BytesUsed = SIZEOF_CURVETO; 00872 00873 TransformCoord(pElement->Coords[0]); 00874 TransformCoord(pElement->Coords[1]); 00875 TransformCoord(pElement->Coords[2]); 00876 00877 // Insert a curveto into the path 00878 if (!pPath->InkPath.InsertCurveTo(pElement->Coords[0], 00879 pElement->Coords[1], pElement->Coords[2])) 00880 // Not enough dynamic heap to insert the curveto command 00881 goto NoMemory; 00882 break; 00883 00884 case DRAWTAG_CLOSESUBPATH: 00885 BytesUsed = SIZEOF_CLOSESUBPATH; 00886 00887 // Terminate sub-path 00888 if (!pPath->InkPath.CloseSubPath()) 00889 // Not enough dynamic heap to insert the final element of the path 00890 goto NoMemory; 00891 00892 break; 00893 00894 default: 00895 // Don't understand this element! 00896 ERROR1(FALSE, _R(IDT_DRAW_BADSYNTAX)); 00897 } 00898 00899 // Move pointer onto next path element 00900 pElement = (DrawPathElement *) (((ADDR) pElement) + BytesUsed); 00901 00902 Tag = (pElement->Tag) & 0xFF; 00903 } 00904 00905 // check that the path is OK 00906 if(!pPath->InkPath.EnsureValid()) 00907 { 00908 // no, it's completely knackered 00909 pPath->UnlinkNodeFromTree(); 00910 delete pPath; 00911 // don't error about it. 00912 return TRUE; 00913 } 00914 00915 // Use the path header to set the attributes on this path 00916 AddAttributes(pPath, pHeader); 00917 00918 // Terminate path properly. 00919 pPath->InvalidateBoundingRect(); 00920 00921 // All ok 00922 return TRUE; 00923 00924 NoMemory: 00925 // Error - Out of memory while reading Draw file 00926 00927 // Destroy any half-created paths 00928 if (pPath != NULL) 00929 { 00930 pPath->CascadeDelete(); 00931 delete pPath; 00932 } 00933 // Set the error for the caller to report 00934 ERROR(_R(IDT_DRAW_NOMEMORY), FALSE); 00935 } 00936 00937 /******************************************************************************************** 00938 00939 > BOOL AcornDrawFilter::ProcessGroup() 00940 00941 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00942 Created: 18/11/93 00943 Returns: - 00944 Purpose: Read in a Draw group object, which can be an arbitrary group of Draw objects, 00945 possibly including other groups. A NodeGroup object is constructed from 00946 the group's data and added to the node pointed to by the member variable 00947 pNode. 00948 Errors: Out of memory, error processing objects in the group, unexpected EOF. 00949 SeeAlso: AcornDrawFilter::ProcessObject 00950 Scope: Private 00951 00952 ********************************************************************************************/ 00953 00954 #define DRAW_GROUPNAMESIZE (12) 00955 00956 BOOL AcornDrawFilter::ProcessGroup() 00957 { 00958 // Remembers file read errors 00959 BOOL Error = FALSE; 00960 00961 // Skip past the group name 00962 DrawFile->seekIn(DRAW_GROUPNAMESIZE, ios::cur); 00963 BytesRead += DRAW_GROUPNAMESIZE; 00964 00965 // Create a group node, and make pNode point to it, so that all objects in the group 00966 // are attached to it. 00967 NodeGroup *pGroup = new NodeGroup(pNode, LASTCHILD); 00968 if (pGroup == NULL) 00969 { 00970 // Not enough heap to create group 00971 ERROR(_R(IDT_DRAW_NOMEMORY), FALSE); 00972 } 00973 00974 Node *pOldNode = pNode; 00975 pNode = pGroup; 00976 00977 // Work out where the end of the group is 00978 FilePos EndPos = DrawFile->tellIn(); 00979 DataSize -= DRAW_GROUPNAMESIZE; 00980 EndPos += DataSize; 00981 00982 // Read (and process) each object in the group, until the end of group or end of file 00983 // is found. 00984 do 00985 { 00986 // Read in and process the next object 00987 if (!(ReadObjectHeader() && ProcessObject())) 00988 Error = TRUE; 00989 00990 } while (!DrawFile->eof() && (DrawFile->tellIn() < EndPos)); 00991 00992 00993 // Restore the node pointer to the parent of this group 00994 pNode = pOldNode; 00995 00996 // If EOF found, then the group was truncated, so return error. 00997 // Also return error if object reading failed in any way. 00998 if (Error) 00999 // Error has already been set 01000 return FALSE; 01001 01002 if (DrawFile->eof()) 01003 ERROR1(FALSE, _R(IDT_DRAW_BADSYNTAX)); 01004 01005 // Must have worked 01006 return TRUE; 01007 } 01008 01009 #define DRAW_TAGSIZE (4) 01010 01011 /******************************************************************************************** 01012 01013 > BOOL AcornDrawFilter::ProcessTaggedObject() 01014 01015 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 01016 Created: 19/11/93 01017 Returns: TRUE if the tagged object is read and process ok, FALSE if not. 01018 Purpose: Read in and process a tagged object from a Draw file. 01019 A tagged object is a normal object with some arbitrary data following it. 01020 This function can handle the tagged object being a group which itself 01021 contains tagged objects, and so on. 01022 Errors: Out of memory, error processing the tagged object. 01023 SeeAlso: AcornDrawFilter::ProcessObject; AcornDrawFilter::ReadObjectHeader 01024 Scope: Private 01025 01026 ********************************************************************************************/ 01027 01028 BOOL AcornDrawFilter::ProcessTaggedObject() 01029 { 01030 // Remembers file read errors 01031 BOOL Error = FALSE; 01032 01033 // Skip past the object tag 01034 DrawFile->seekIn(DRAW_TAGSIZE, ios::cur); 01035 BytesRead += DRAW_TAGSIZE; 01036 01037 // Work out where the end of the tagged object is 01038 FilePos EndPos = DrawFile->tellIn(); 01039 DataSize -= DRAW_TAGSIZE; 01040 EndPos += DataSize; 01041 01042 // Read (and process) the object 01043 if (!(ReadObjectHeader() && ProcessObject())) 01044 // Something went wrong so return error 01045 return FALSE; 01046 01047 // Skip the word-aligned data following the object 01048 DrawFile->seekIn(EndPos); 01049 BytesRead = EndPos; 01050 01051 // All ok 01052 return TRUE; 01053 } 01054 01055 /******************************************************************************************** 01056 01057 > BOOL AcornDrawFilter::SkipObject() 01058 01059 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 01060 Created: 18/11/93 01061 Returns: TRUE always at present. 01062 Purpose: Skips past the data for this object, usually because the object is not 01063 supported by this filter and/or Camelot. 01064 SeeAlso: AcornDrawFilter::ProcessObject 01065 Scope: Private 01066 01067 ********************************************************************************************/ 01068 01069 BOOL AcornDrawFilter::SkipObject() 01070 { 01071 if (IsUserName("Tim")) 01072 { 01073 TRACE( _T("Skipping unsupported object (type %d, size %d)\n"), 01074 ObjectHeader.Type, 01075 ObjectHeader.Size); 01076 } 01077 01078 // Skip the number of bytes specified in the current object's header 01079 FilePos Pos = DrawFile->tellIn(); 01080 Pos += DataSize; 01081 DrawFile->seekIn(Pos); 01082 BytesRead = Pos; 01083 01084 // No error checking yet 01085 return TRUE; 01086 } 01087 01088 /******************************************************************************************** 01089 01090 > BOOL AcornDrawFilter::ReadObjectData() 01091 01092 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 01093 Created: 18/11/93 01094 Returns: TRUE if the data was read ok, FALSE if not. 01095 Purpose: Read in the data for a Draw object. The data is stored in the buffer 01096 pointed to by the member variable DataBuf. If the buffer is not big enough, 01097 it is automagically expanded. 01098 Errors: Out of memory. 01099 SeeAlso: AcornDrawFilter::ReadObjectHeader 01100 Scope: Private 01101 01102 ********************************************************************************************/ 01103 01104 BOOL AcornDrawFilter::ReadObjectData() 01105 { 01106 // Obtain a buffer to read the data into, if we haven't got one already 01107 if (DataSize > DataBufSize) 01108 { 01109 // Buffer is not big enough - try to expand it. 01110 // Don't overwrite DataBuf pointer unless we know the realloc succeeds, otherwise 01111 // we won't be able to free the old buffer if it fails. 01112 ADDR NewBuf = (ADDR) CCRealloc(DataBuf, DataSize); 01113 01114 // Failed to expand buffer - return error. 01115 ERRORIF(NewBuf == NULL, _R(IDT_DRAW_NOMEMORY), FALSE); 01116 01117 // Buffer was expanded ok - update the buffer pointer/size variables. 01118 DataBufSize = DataSize; 01119 DataBuf = NewBuf; 01120 } 01121 01122 // To get this far, we must have a buffer big enough to hold the object, so read it in... 01123 // NB we check that we read the correct number of bytes. 01124 FilePos BeforePos = DrawFile->tell(); 01125 DrawFile->read(DataBuf, DataSize); 01126 BytesRead += DataSize; 01127 FilePos AfterPos = DrawFile->tell(); 01128 01129 if ((UINT32) (AfterPos-BeforePos) != DataSize) 01130 { 01131 ERROR3_PF(("Bytes read - actual: %d, planned: %d", (AfterPos-BeforePos), DataSize)); 01132 // If EOF found, then an error has occured 01133 ERROR1(FALSE, _R(IDT_DRAW_BADSYNTAX)); 01134 } 01135 01136 // Ok if we got here. 01137 return TRUE; 01138 } 01139 01140 01141 /******************************************************************************************** 01142 01143 > BOOL AcornDrawFilter::AddAttributes(NodePath *pPath, DrawPathHeader *pHeader) 01144 01145 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 01146 Created: 18/11/93 01147 Inputs: pPath - pointer to the NodePath object to add attributes to. 01148 pHeader - pointer to the Draw file object header which describes the path 01149 attributes. 01150 Returns: TRUE if the attributes were added ok, FALSE if not. 01151 Purpose: Add attributes to the path object specified. The attributes are optimised 01152 so that if they are the same as the document's default attributes, they are 01153 not applied. 01154 The attributes applied are line and fill colour, and line style. 01155 Errors: Fails (returns FALSE) if not enough memory to add attributes. 01156 Scope: Private 01157 01158 ********************************************************************************************/ 01159 01160 BOOL AcornDrawFilter::AddAttributes(NodePath *pPath, DrawPathHeader *pHeader) 01161 { 01162 // Add attributes to the path, if they are different from the default... 01163 01164 // First set the current attributes. 01165 01166 // Fill colour 01167 if (pHeader->FillColour.Data.ColourValue == DRAW_TRANSPARENT) 01168 { 01169 pPath->InkPath.IsFilled = FALSE; 01170 } 01171 else 01172 { 01173 pPath->InkPath.IsFilled = TRUE; 01174 01175 DocColour FillColour(pHeader->FillColour.Data.Component.Red, 01176 pHeader->FillColour.Data.Component.Green, 01177 pHeader->FillColour.Data.Component.Blue); 01178 01179 if (!SetFillColour(FillColour)) 01180 return FALSE; 01181 } 01182 01183 // Line colour 01184 if (pHeader->LineColour.Data.ColourValue == DRAW_TRANSPARENT) 01185 { 01186 if (!SetLineColour(DocColour(COLOUR_TRANS))) 01187 return FALSE; 01188 } 01189 else 01190 { 01191 DocColour LineColour(pHeader->LineColour.Data.Component.Red, 01192 pHeader->LineColour.Data.Component.Green, 01193 pHeader->LineColour.Data.Component.Blue); 01194 01195 if (!SetLineColour(LineColour)) 01196 return FALSE; 01197 } 01198 01199 // Line width 01200 01201 // Convert from Draw units (1/640 of a point) to Camelot units (millipoints_ 01202 // Hence it involves multiplying by 1000/640, which equates to 25/16. 01203 pHeader->LineWidth *= 25; 01204 pHeader->LineWidth /= 16; 01205 01206 if (!SetLineWidth(pHeader->LineWidth)) 01207 return FALSE; 01208 01209 // Now add attributes if they are different from the defaults. 01210 01211 // If not filled, then set the ignore bit on the fill attribute. 01212 if (!pPath->InkPath.IsFilled) 01213 CurrentAttrs[ATTR_FILLGEOMETRY].Ignore = TRUE; 01214 01215 // Add attributes to the path, if they are different from the default... 01216 BOOL Result = AttributeManager::ApplyBasedOnDefaults(pPath, CurrentAttrs); 01217 01218 // Enable the fill attribute again 01219 CurrentAttrs[ATTR_FILLGEOMETRY].Ignore = FALSE; 01220 01221 // Return success or failure 01222 return Result; 01223 } 01224 01225 /******************************************************************************************** 01226 01227 > BOOL AcornDrawFilter::DoExport(Operation*, CCLexFile*, PathName*, Document*, BOOL) 01228 01229 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 01230 Created: 28/03/94 01231 Inputs: As base class version. 01232 Returns: FALSE. 01233 Purpose: None; this is a dummy function as we don't export in Acorn Draw format (yet). 01234 SeeAlso: Filter::DoExport; Filter 01235 01236 ********************************************************************************************/ 01237 01238 BOOL AcornDrawFilter::DoExport(Operation*, CCLexFile*, PathName*, Document*, BOOL) 01239 { 01240 // We don't export in Draw format 01241 return FALSE; 01242 } 01243