// $Id: cdrfiltr.cpp 1282 2006-06-09 09:46:49Z alex $ /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE ================================XARAHEADERSTART=========================== Xara LX, a vector drawing and manipulation program. Copyright (C) 1993-2006 Xara Group Ltd. Copyright on certain contributions may be held in joint with their respective authors. See AUTHORS file for details. LICENSE TO USE AND MODIFY SOFTWARE ---------------------------------- This file is part of Xara LX. Xara LX is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. Xara LX and its component source files are distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Xara LX (see the file GPL in the root directory of the distribution); if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ADDITIONAL RIGHTS ----------------- Conditional upon your continuing compliance with the GNU General Public License described above, Xara Group Ltd grants to you certain additional rights. The additional rights are to use, modify, and distribute the software together with the wxWidgets library, the wxXtra library, and the "CDraw" library and any other such library that any version of Xara LX relased by Xara Group Ltd requires in order to compile and execute, including the static linking of that library to XaraLX. In the case of the "CDraw" library, you may satisfy obligation under the GNU General Public License to provide source code by providing a binary copy of the library concerned and a copy of the license accompanying it. Nothing in this section restricts any of the rights you have under the GNU General Public License. SCOPE OF LICENSE ---------------- This license applies to this program (XaraLX) and its constituent source files only, and does not necessarily apply to other Xara products which may in part share the same code base, and are subject to their own licensing terms. This license does not apply to files in the wxXtra directory, which are built into a separate library, and are subject to the wxWindows license contained within that directory in the file "WXXTRA-LICENSE". This license does not apply to the binary libraries (if any) within the "libs" directory, which are subject to a separate license contained within that directory in the file "LIBS-LICENSE". ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS ---------------------------------------------- Subject to the terms of the GNU Public License (see above), you are free to do whatever you like with your modifications. However, you may (at your option) wish contribute them to Xara's source tree. You can find details of how to do this at: http://www.xaraxtreme.org/developers/ Prior to contributing your modifications, you will need to complete our contributor agreement. This can be found at: http://www.xaraxtreme.org/developers/contribute/ Please note that Xara will not accept modifications which modify any of the text between the start and end of this header (marked XARAHEADERSTART and XARAHEADEREND). MARKS ----- Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara designs are registered or unregistered trademarks, design-marks, and/or service marks of Xara Group Ltd. All rights in these marks are reserved. Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. http://www.xara.com/ =================================XARAHEADEREND============================ */ // *********CDR file filter /* */ // this line disables extrudes as they don't *quite* work yet - corel still need some // interegation about what's going on. It seems the object is pre-transformed by some // random values. Weird. #define this to include the stuff. #undef CDR_DOEXTRUDES #include "camtypes.h" #include "cdrfiltr.h" //#include "oilfltrs.h" - in camtypes.h [AUTOMATICALLY REMOVED] //#include "ben.h" //#include "ccfile.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "progress.h" #include "cdrcol.h" #include "rifffile.h" #include "cdrform.h" //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "nodepath.h" //#include "group.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "page.h" //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "nodershp.h" //#include "resource.h" //#include "fixst256.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "ndoptmz.h" #include "collist.h" #include "layer.h" #include "sglayer.h" #include "sprdmsg.h" #include "nodebmp.h" #include "nodetxts.h" //#include "textinfo.h" #include "zoomops.h" //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "nodemold.h" #include "moldshap.h" #include "ndmldpth.h" #include "nodemldr.h" //#include "nev.h" #include "fontman.h" //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED] //#include "cmxres.h" #include "cmxifltr.h" // so we can pass stuff to it nicely DECLARE_SOURCE("$Revision: 1282 $"); CC_IMPLEMENT_DYNAMIC(CDRFilter, VectorFilter) CC_IMPLEMENT_MEMDUMP(CDRAttributeStore, List) CC_IMPLEMENT_MEMDUMP(CDRAttributeStoredItem, ListItem) CC_IMPLEMENT_MEMDUMP(CDRArrowheadStore, List) CC_IMPLEMENT_MEMDUMP(CDRArrowheadStoredItem, ListItem) CC_IMPLEMENT_MEMDUMP(CDRBitmapStore, List) CC_IMPLEMENT_MEMDUMP(CDRBitmapStoredItem, ListItem) CC_IMPLEMENT_MEMDUMP(CDRVectorStore, List) CC_IMPLEMENT_MEMDUMP(CDRVectorStoredItem, ListItem) CC_IMPLEMENT_MEMDUMP(CDRFontnameStore, List) CC_IMPLEMENT_MEMDUMP(CDRFontnameStoredItem, ListItem) CC_IMPLEMENT_MEMDUMP(CDRLayerList, List) CC_IMPLEMENT_MEMDUMP(CDRLayerListItem, ListItem) CC_IMPLEMENT_MEMDUMP(CDRPageList, List) CC_IMPLEMENT_MEMDUMP(CDRPageListItem, ListItem) CC_IMPLEMENT_MEMDUMP(CDRActionList, List) CC_IMPLEMENT_DYNAMIC(CDRActionListItem, ListItem) CC_IMPLEMENT_DYNAMIC(CDRActionTransform, CDRActionListItem) CC_IMPLEMENT_DYNAMIC(CDRActionGroupEnd, CDRActionListItem) CC_IMPLEMENT_MEMDUMP(CDRTransformConvertor, CC_CLASS_MEMDUMP) CC_IMPLEMENT_MEMDUMP(CDRTransformConvertor5, CDRTransformConvertor) CC_IMPLEMENT_MEMDUMP(CDRTransformConvertor4, CDRTransformConvertor) CC_IMPLEMENT_MEMDUMP(CDRTransformConvertor3, CDRTransformConvertor) CC_IMPLEMENT_MEMDUMP(CDRTextOnPathLink, ListItem) #define new CAM_DEBUG_NEW #define PROGRESSUPDATE_MASK 0x7f INT32 CDRFilter::BitmapNumber = 0; INT32 CDRFilter::PatternNumber = 0; /******************************************************************************************** > static void CDRFilter::UpdateProgress(BOOL Now = FALSE) Author: Ben_Summers (Xara Group Ltd) Created: 22 03 95 Inputs: None Returns: None Purpose: Updating the progress everysooften - called at every significant place to get a nice smooth update on that progress bar thingy SeeAlso: Filter ********************************************************************************************/ BOOL CDRFilter::UpdateProgress(BOOL Now) { BOOL Result = TRUE; if(Now) { Result = ContinueSlowJob(RIFF->ProgressNow()); ProgressCount = 0; } else { if((ProgressCount & PROGRESSUPDATE_MASK) == 0) { Result = ContinueSlowJob(RIFF->ProgressNow()); } ProgressCount++; } if(!Result) { Error::ClearError(); // because this may not be handled the first time around Error::SetError(_R(IDN_USER_CANCELLED)); } return Result; } /******************************************************************************************** > CDRFilter::CDRFilter(void) Author: Ben_Summers (Xara Group Ltd) Created: 21 03 95 Inputs: As for the Filter class Returns: As for the Filter class Purpose: Constructor SeeAlso: Filter ********************************************************************************************/ CDRFilter::CDRFilter(void) { // Set up filter descriptions. FilterName.Load(_R(IDT_CDRFILTER_FILTERNAME)); FilterInfo.Load(_R(IDT_CDRFILTER_FILTERINFO)); FilterID = FILTERID_CDR; Flags.CanImport = TRUE; Flags.CanExport = FALSE; Version = CDRVERSION_NULL; } /******************************************************************************************** > BOOL CDRFilter::Init(void) Author: Ben_Summers (Xara Group Ltd) Created: 21 03 95 Inputs: As for the Filter class Returns: As for the Filter class Purpose: Initialisation SeeAlso: Filter ********************************************************************************************/ BOOL CDRFilter::Init(void) { // Get the OILFilter object pOILFilter = new CDROILFilter(this); if (pOILFilter == NULL) return FALSE; // make sure we'll complain about life if HowCompatable isn't called Version = CDRVERSION_NULL; // All ok return TRUE; } /******************************************************************************************** > INT32 CDRFilter::HowCompatible(PathName& Filename, ADDR HeaderStart, UINT32 HeaderSize, UINT32 FileSize) Author: Ben_Summers (Xara Group Ltd) Created: 21 03 95 Inputs: As for the Filter class Returns: As for the Filter class Purpose: Examines a file to see how compatable it is with this filter. SeeAlso: Filter ********************************************************************************************/ INT32 CDRFilter::HowCompatible(PathName& Filename, ADDR HeaderStart, UINT32 HeaderSize, UINT32 FileSize) { PORTNOTE("byteorder", "TODO: Check byte ordering") BOOL ExtensionMatches = pOILFilter->DoesExtensionOfPathNameMatch(&Filename); // check for version 2 files if the extension matches... if (ExtensionMatches) { if(camStrncmp((char *)HeaderStart, "WL", 2) == 0) return 10; // a version 2.xx CDR file } // check for version 3 - 5 files... FOURCC FormType; FormType = RIFFFile::CheckRIFFHeader(HeaderStart, FileSize); Version = CDRVERSION_NULL; switch (FormType) { case cdrT_CDR: Version = CDRVERSION_3; break; case cdrT_CDR4: case cdrT_CDST: // version 4 template Version = CDRVERSION_4; break; case cdrT_CDR5: case cdrT_CDT5: Version = CDRVERSION_5; break; case cdrT_CDR6: case cdrT_CDT6: Version = CDRVERSION_6; break; default: break; } INT32 HowMuchWeLikedThisFile = 0; if(Version != CDRVERSION_NULL) { HowMuchWeLikedThisFile = 10; // loved the file // check to see if there is a CMX file embedded in there if(HasCDRFileGotCMXFile(&Filename)) { HowMuchWeLikedThisFile = 5; // didn't like it so much then -- let the CMX filter grab it } } return HowMuchWeLikedThisFile; } /******************************************************************************************** > BOOL CDRFilter::DoImport(SelOperation *Op, CCLexFile *pDiskFile, Document *DestDoc, BOOL AutoChosen, ImportPosition *Pos, KernelBitmap** ppImportedBitmap, DocCoord* pPosTranslate, String_256* URL) Author: Ben_Summers (Xara Group Ltd) Created: 21 03 95 Inputs: As for the Filter class Returns: As for the Filter class Purpose: Does the import of a CDR (.cdr or .cdt) SeeAlso: Filter ********************************************************************************************/ #define CDRFILTER_DI_RETURNERROR {Success = FALSE; return ClearUp();} BOOL CDRFilter::DoImport(SelOperation *Op, CCLexFile *pDiskFile, Document *DestDoc, BOOL AutoChosen, ImportPosition *Pos, KernelBitmap** ppImportedBitmap, DocCoord* pPosTranslate, String_256* URL) { // check to see if we've got a CMX file in there, but only if we weren't autochosen if(!AutoChosen && HasCDRFileGotCMXFile(NULL, pDiskFile)) { TRACEUSER( "Ben", _T(">>> loading CDR file with new CMXImportFilter\n")); // right, somehow we got here -- probably because the user specifically // asked to see CorelDRAW files only CMXImportFilter *pFilter = new CMXImportFilter; if(pFilter == NULL) return FALSE; BOOL ok = pFilter->DoImport(Op, pDiskFile, DestDoc, AutoChosen, Pos); delete pFilter; pFilter = NULL; return ok; } // normal CDR import stuff BOOL ExtensionMatches = pOILFilter->DoesExtensionOfFileMatch(pDiskFile); RIFFFile RIFFo; TRACEUSER( "Ben", _T("In CDRFilter::DoImport\n")); //ERROR2IF(Version == CDRVERSION_NULL, FALSE, "CDRFilter::HowCompatible failed to set recognised version\n"); // in debug builds, warn about fills hanging around ERROR3IF(Fills.IsEmpty() == FALSE, "Fills store not empty"); ERROR3IF(Outlines.IsEmpty() == FALSE, "Outlines store not empty"); ERROR3IF(Styles.IsEmpty() == FALSE, "Styles store not empty"); ERROR3IF(Fonts.IsEmpty() == FALSE, "Fonts store not empty"); ERROR3IF(Arrowheads.IsEmpty() == FALSE, "Arrowheads store not empty"); ERROR3IF(Patterns.IsEmpty() == FALSE, "Patterns store not empty"); ERROR3IF(Bitmaps.IsEmpty() == FALSE, "Bitmap store not empty"); ERROR3IF(Vectors.IsEmpty() == FALSE, "Vector store not empty"); ERROR3IF(TextBBoxes.IsEmpty() == FALSE, "TextBBoxes list not empty"); ERROR3IF(TextV4.IsEmpty() == FALSE, "TextV4 store not empty"); ERROR3IF(TextOnPathLinks.IsEmpty() == FALSE, "TextOnPathLinks not empty"); // in retail builds, just vape any contents Fills.DeleteAll(); Outlines.DeleteAll(); Styles.DeleteAll(); Fonts.DeleteAll(); Arrowheads.DeleteAll(); Patterns.DeleteAll(); Bitmaps.DeleteAll(); Vectors.DeleteAll(); TextV4.DeleteAll(); Pages.DeleteAll(); Actions.DeleteAll(); TextBBoxes.DeleteAll(); TextOnPathLinks.DeleteAll(); // set a few flags and initialise some variables pDocument = DestDoc; Success = TRUE; SlowJobStarted = FALSE; TranslateByX = 0; TranslateByY = 0; PageX = 0; PageY = 0; pLevelNodeList = 0; DoneDoc = FALSE; DoneMasterPage = FALSE; InMasterPage = FALSE; ThisPage = 0; ThisLayer = 0; pMadeNode = 0; ObjectsConverted = 0; ObjectsFormatWrong = 0; ObjectsUnknown = 0; EnvelopesApproximated = 0; ObjDataBlock = 0; ObjDataBlockSize = 0; AttrsAlreadyApplied = FALSE; TransformChunk = 0; FontTableV3 = 0; FontStylesV3 = 0; LinkTable = 0; ThisOp = Op; LinkTransformsExist = FALSE; TheDocument = DestDoc; // if the extension matches, check it for being a 2.xx file if(ExtensionMatches) { // get the first few bytes TCHAR FirstBit[8]; if(pDiskFile->read((void *)FirstBit, sizeof(FirstBit)).bad()) return FALSE; ERROR1IF(camStrncmp((char *)FirstBit, "WL", 2) == 0, FALSE, _R(IDT_CDRFILTER_ISAV2FILE)); // let's pop the file back to the beginning if(pDiskFile->seek(0).bad()) return FALSE; } // sort out the RIFF file RIFF = &RIFFo; FOURCC FormType = RIFF->Init(pDiskFile); if(FormType == 1) // error { CDRFILTER_DI_RETURNERROR; } // sort out which version we're on switch(FormType) { case cdrT_CDR: Version = CDRVERSION_3; break; case cdrT_CDR4: case cdrT_CDST: // version 4 template Version = CDRVERSION_4; break; case cdrT_CDR5: case cdrT_CDT5: Version = CDRVERSION_5; break; case cdrT_CDR6: case cdrT_CDT6: // version 6 file -- we don't support these ERROR1(FALSE, _R(IDE_CDRFILTER_CDR6)); break; default: TRACEUSER( "Ben", _T("Attempted to load something which wasn't a CDR file. I don't think so...")); ERROR1(FALSE, _R(IDE_CDRFILTER_NOTCDR)); break; } // sort out a colour list ColList = DestDoc->GetIndexedColours(); // do we want to import with layers? UseLayers = FALSE; #ifdef WEBSTER // In Webster, just use the default preference settings as these should be set to // ImportWithLayers to False. if ( (!DestDoc->IsImporting() && Filter::OpenWithLayers) || (DestDoc->IsImporting() && Filter::ImportWithLayers) ) UseLayers = TRUE; #else // In Camelot, we must check to see if the document is being imported and if so if // there are any frames present. If there are then don't use layers, if there are // then use the preference setting. if (DestDoc->IsImporting()) { Spread * pTheSpread = DestDoc->GetSelectedSpread(); Layer * pFrame = NULL; if (pTheSpread != NULL) pFrame = pTheSpread->FindFirstFrameLayer(); if (pFrame != NULL) UseLayers = FALSE; // Frames present so do not import layers else UseLayers = Filter::ImportWithLayers; // No frames so use the preference setting } else { UseLayers = Filter::OpenWithLayers; } #endif // If importing without layers, make sure there is a layer to put things on, and make one if not if(UseLayers == FALSE) { if (!MakeSureLayerExists(DestDoc)) { // clean up and return and error CDRFILTER_DI_RETURNERROR; } } // For now, position Draw objects on 1st page of spread 1 pSpread = DestDoc->GetSelectedSpread(); pPage = (Page *) pSpread->FindFirstPageInSpread(); // Use bottom left of page as origin DocRect PageRect = pPage->GetPageRect(); Origin = PageRect.lo; // OK, let's get into the swing of things! // Get a default set of attributes for ink objects. if (!SetUpCurrentAttrs()) return FALSE; // Let start off by setting the progress indicatorx UINT32 id; switch(Version) { case CDRVERSION_4: id = _R(IDT_IMPORTMSG_CDR4); break; case CDRVERSION_5: id = _R(IDT_IMPORTMSG_CDR5); break; default: id = _R(IDT_IMPORTMSG_CDR3); break; } if(!DestDoc->IsImporting()) id += _R(IDT_OPENMSG_CDR3) - _R(IDT_IMPORTMSG_CDR3); //String_64 ImportMessage(id); String_64 ImportMessage = GetImportProgressString(pDiskFile, id); // this slow job doesn't have a delay because if the CDR file has a bitmap at the // beginning, ContinueSlowJob can't be called for rather a long time (sometimes) // and you get 'Nothing Selected' instead of a message telling you what's happening. BeginSlowJob(RIFF->ProgressLimit(), FALSE, &ImportMessage); SlowJobStarted = TRUE; // loop through looking at top level lists, and dispatch them to various handlers do { // get the next object in the file if(!RIFF->NextObject()) CDRFILTER_DI_RETURNERROR; if(RIFF->GetObjType() == RIFFOBJECTTYPE_LISTSTART) { switch(RIFF->GetObjChunkType()) { case cdrT_doc: if(!ProcessDoc()) { TRACEUSER( "Ben", _T("ProcessDoc returned FALSE\n")); CDRFILTER_DI_RETURNERROR; } break; case cdrT_page: if(!ProcessPage()) { TRACEUSER( "Ben", _T("ProcessPage returned FALSE\n")); CDRFILTER_DI_RETURNERROR; } break; default: // we're not interested in any other root level list, so skip it if(!RIFF->SkipToListEnd(RIFF->GetObjLevel())) CDRFILTER_DI_RETURNERROR; break; } } if(!UpdateProgress()) return FALSE; } while(RIFF->GetObjType() != RIFFOBJECTTYPE_FILEEND); // make sure we're at the end ContinueSlowJob(RIFF->ProgressLimit()); // attach paths to text stories if(!AttachTextToPaths()) return FALSE; // only stick objects into the document if some were converted if(ObjectsConverted > 0) { // check that there were at least two pages if(Pages.GetCount() < 1) { TRACEUSER( "Ben", _T("not enough pages in file\n")); CDRFILTER_DI_RETURNERROR; } // get the pointer to the list of levels on the master pages CDRLayerList *MasterLayers; CDRPageListItem *En = (CDRPageListItem *)Pages.GetHead(); if(En == 0) CDRFILTER_DI_RETURNERROR; MasterLayers = &En->Layers; // get the list of levels on the actual page CDRLayerList *PageLayers; En = (CDRPageListItem *)Pages.GetNext(En); if(Version != CDRVERSION_3) { if(En == 0) CDRFILTER_DI_RETURNERROR; PageLayers = &En->Layers; // check that they have the same number of layers in their lists if(MasterLayers->GetCount() != PageLayers->GetCount()) { TRACEUSER( "Ben", _T("not the same number of layers on master page and on page\n")); CDRFILTER_DI_RETURNERROR; } } else { PageLayers = 0; } if(MasterLayers->GetCount() <= 0) CDRFILTER_DI_RETURNERROR; // if it's a CDR 3 file set the page size and translation things if(Version == CDRVERSION_3) { // set the page size? if(!DestDoc->IsImporting() && PageX > 0 && PageY > 0) { // Make the pasteboard an extra page width either side of the page and an extra // half page height above and below the page. That should be nicely proportional. INT32 ms = (PageX > PageY)?PageX:PageY; // we're opening the file, so set the page size if (pSpread) { BOOL ok = pSpread->SetPageSize(PageX, PageY, ms, 0, FALSE, TRUE); // Must set the origin of the grid to the bottom left corner of the // union rectangle of all pages on the spread as this is where the x,y // measurements are made from. DocRect PagesRect; NodeGrid* pGrid = pSpread->FindFirstDefaultGridInSpread(); ok = ok && pSpread->GetPagesRect(&PagesRect); if (pGrid) pGrid->SetOrigin(PagesRect.lox, PagesRect.loy); if (!ok) CDRFILTER_DI_RETURNERROR; } } DocRect PageRect = pPage->GetPageRect(); Origin = PageRect.lo; TranslateByX = Origin.x + (PageX / 2); TranslateByY = Origin.y + (PageY / 2); } // set up pointers to the layers CDRLayerListItem *MasterEn = (CDRLayerListItem *)MasterLayers->GetTail(); CDRLayerListItem *PageEn = 0; if(PageLayers != 0) PageEn = (CDRLayerListItem *)PageLayers->GetTail(); EndSlowJob(); BeginSlowJob(); // insert everything into the document if(UseLayers) { // go through inserting every layer which has sometime on it while(MasterEn != 0) { // check to see if we have objects to import if(MasterEn->Objects != 0 || (PageEn != 0 && PageEn->Objects != 0)) { // OK, we've got some objects to import, create a layer to put them in Layer *pLayer = new Layer(); if(pLayer == 0) CDRFILTER_DI_RETURNERROR; // set it's name and attributes pLayer->SetLayerID(MasterEn->Name); pLayer->SetVisible(MasterEn->IsVisible); pLayer->SetLocked(MasterEn->IsLocked); pLayer->SetActive(FALSE); pLayer->SetPrintable(TRUE); pLayer->SetBackground(FALSE); pLayer->SetOutline(FALSE); // stick objects below it Node *Objects = 0; if(MasterEn->Objects != 0) { Objects = MasterEn->Objects; MasterEn->LayerInDocument = TRUE; } else { Objects = PageEn->Objects; PageEn->LayerInDocument = TRUE; } ERROR3IF(Objects == 0, "Er, tried to make a layer for objects which didn't exist"); // attach the objects to the layer Objects->InsertChainSimple(pLayer, FIRSTCHILD); // if it's a CDR 3 file and translate it if(Version == CDRVERSION_3) { Trans2DMatrix Trans(TranslateByX, TranslateByY); pLayer->Transform(Trans); } // insert the layer... if (!Op->DoInsertNewNode(pLayer, (Node *)pSpread, LASTCHILD, TRUE)) { // It didn't work - delete the sub-tree we just created pLayer->CascadeDelete(); delete pLayer; pLayer = NULL; CDRFILTER_DI_RETURNERROR; } // make sure it's name is unique pLayer->EnsureUniqueLayerID(); // ... and finally optimise it's attributes if(!pLayer->OptimiseAttributes()) CDRFILTER_DI_RETURNERROR; } // get the next (previous) layer to import MasterEn = (CDRLayerListItem *)MasterLayers->GetPrev(MasterEn); if(PageEn != 0) PageEn = (CDRLayerListItem *)PageLayers->GetPrev(PageEn); } // get the insertation node set up DestDoc->ResetInsertionPosition(); } else { // get a group node to put everything in as we're not using layers here. NodeGroup *pGroup = new NodeGroup; if(pGroup == 0) CDRFILTER_DI_RETURNERROR; // run through the layers putting in the stuff - remember they're in reverse order while(MasterEn != 0) { TRACEUSER( "Ben", _T("Putting layer '%s' into document\n"), (TCHAR *)MasterEn->Name); // put the master pages objects onto this group if(MasterEn->Objects != 0) { MasterEn->Objects->InsertChainSimple(pGroup, LASTCHILD); MasterEn->LayerInDocument = TRUE; } // put the page objects into this group if(PageEn != 0 && PageEn->Objects != 0) { PageEn->Objects->InsertChainSimple(pGroup, LASTCHILD); PageEn->LayerInDocument = TRUE; } // get the next (previous) layer to import MasterEn = (CDRLayerListItem *)MasterLayers->GetPrev(MasterEn); if(PageEn != 0) PageEn = (CDRLayerListItem *)PageLayers->GetPrev(PageEn); } // if it's a CDR 3 file translate it if(Version == CDRVERSION_3) { Trans2DMatrix Trans(TranslateByX, TranslateByY); pGroup->Transform(Trans); } // check to see if the group node has more than one child // if it doesn't just insert the child and not the group, and then // delete the group node afterwards NodeRenderableBounded *InsertNode = pGroup; NodeRenderableBounded *FirstChild = (NodeRenderableBounded *)pGroup->FindFirstChild(); if(FirstChild != 0) { // if the first child hasn't got a sibling, then there's only one // child to the group, so just insert the child if(FirstChild->FindNext() == 0) InsertNode = FirstChild; } // and slap the group into the document if (!Op->DoInsertNewNode(InsertNode, pSpread, TRUE)) { // It didn't work - delete the sub-tree we just created pGroup->CascadeDelete(); delete pGroup; pGroup = NULL; CDRFILTER_DI_RETURNERROR; } if(InsertNode != pGroup) delete pGroup; // optimise the attributes in our nice new group if(!InsertNode->OptimiseAttributes()) CDRFILTER_DI_RETURNERROR; } } else { // if we were opening the document, then we need make a layer and set the insertation node if(!DestDoc->IsImporting()) { if (!MakeSureLayerExists(DestDoc)) CDRFILTER_DI_RETURNERROR; DestDoc->ResetInsertionPosition(); } } // add some standard colours if(!AddStandardColourSet(pDocument)) CDRFILTER_DI_RETURNERROR; // do a quick post import on it DestDoc->PostImport(); // find out how many dodgy objects were encountered along the way INT32 ObjNotConv = ObjectsFormatWrong + ObjectsUnknown; if(ObjNotConv > 0) { // tell the user that some objects couldn't be converted String_256 WarnMsg; WarnMsg.MakeMsg((ObjNotConv == 1)?_R(IDT_CDRFILTER_OBJWARNING1):_R(IDT_CDRFILTER_OBJWARNING), ObjNotConv); Error::SetError(0, WarnMsg, 0); InformWarning(); Error::ClearError(); } if(EnvelopesApproximated > 0) { // tell the user that some envelopes were approximated String_256 WarnMsg; WarnMsg.MakeMsg((EnvelopesApproximated == 1)?_R(IDT_CDRFILTER_ENVAPPROXWARNING1):_R(IDT_CDRFILTER_ENVAPPROXWARNING), EnvelopesApproximated); Error::SetError(0, WarnMsg, 0); InformWarning(); Error::ClearError(); } TRACEUSER( "Ben", _T("Do import finished\n")); return ClearUp(); } /******************************************************************************************** > BOOL CDRFilter::ProcessDoc(void) Author: Ben_Summers (Xara Group Ltd) Created: 22 03 95 Inputs: none Returns: error flag Purpose: Processes the root level doc chunk of a CDR file SeeAlso: Filter ********************************************************************************************/ BOOL CDRFilter::ProcessDoc(void) { BOOL InFillTable = FALSE; BOOL InOutlineTable = FALSE; BOOL InStyleTable = FALSE; BOOL InFontTable = FALSE; BOOL InArrowheadTable = FALSE; BOOL InPatternTable = FALSE; BOOL InBitmapTable = FALSE; BOOL GotPageInfo = FALSE; ADDR VectorListContents = 0; INT32 VectorListContentsSize; TRACEUSER( "Ben", _T("In ProcessDoc\n")); // store the level we're working on UINT32 StartLevel = RIFF->GetObjLevel(); do { switch(RIFF->GetObjType()) { case RIFFOBJECTTYPE_LISTSTART: // list start - attributes are stored in lists switch(RIFF->GetObjChunkType()) { case cdrT_filt: InFillTable = TRUE; break; case cdrT_otlt: InOutlineTable = TRUE; break; case cdrT_stlt: InStyleTable = TRUE; break; case cdrT_fntt: InFontTable = TRUE; break; case cdrT_arrt: InArrowheadTable = TRUE; break; case cdrT_bpft: InPatternTable = TRUE; break; case cdrT_bmpt: InBitmapTable = TRUE; break; default: break; case cdrT_vect: // get the contents of this list for later if(!RIFF->GetListContents(&VectorListContents, &VectorListContentsSize)) return FALSE; // and skip to the end of it if(!RIFF->SkipToListEnd(RIFF->GetObjLevel())) return FALSE; break; case cdrT_btxt: if(Version == CDRVERSION_4) { // if we're in a version 4 file, this contains text for the paragraph text objects if(!ProcessTextList4()) return FALSE; } break; } break; case RIFFOBJECTTYPE_LISTEND: switch(RIFF->GetObjChunkType()) { case cdrT_filt: InFillTable = FALSE; break; case cdrT_otlt: InOutlineTable = FALSE; break; case cdrT_stlt: InStyleTable = FALSE; break; case cdrT_fntt: InFontTable = FALSE; break; case cdrT_arrt: InArrowheadTable = FALSE; break; case cdrT_bpft: InPatternTable = FALSE; break; case cdrT_bmpt: InBitmapTable = FALSE; break; default: break; } break; case RIFFOBJECTTYPE_CHUNK: // got a chunk to be interested about! switch(RIFF->GetObjChunkType()) { case cdrT_fill: if(InFillTable) Fills.AddChunkToStore(RIFF); break; case cdrT_outl: if(InOutlineTable) Outlines.AddChunkToStore(RIFF); break; case cdrT_styd: if(InStyleTable) Styles.AddChunkToStore(RIFF); break; case cdrT_font: if(InFontTable) Fonts.AddChunkToStore(RIFF, Version); break; case cdrT_arrw: if(InArrowheadTable) Arrowheads.AddChunkToStore(RIFF); break; case cdrT_bmpf: if(InPatternTable) Patterns.AddChunkToStore(RIFF, TRUE, this); UpdateProgress(TRUE); break; case cdrT_bmp: // a couple of forced progress updates here to ensure a // resonably often updated progress bar UpdateProgress(TRUE); if(InBitmapTable) Bitmaps.AddChunkToStore(RIFF, FALSE, this); UpdateProgress(TRUE); break; case cdrT_mcfg: { // get the chunk and read the page size if(GotPageInfo) // if we've already got it, then there's a problem with the file { TRACEUSER( "Ben", _T("mcfg chunk encountered twice in doc list\n")); ERROR1(FALSE, _R(IDE_CDRFILTER_FORMATERROR)); } if(!RIFF->AquireChunkData()) return FALSE; cdrfPageInfo *i = (cdrfPageInfo *)RIFF->GetAquiredData(); ERROR3IF(i == 0, "No aquired data returned from RIFF chunk"); PageX = CDRDATA_WORD(i->PageX) * CDRCOORDS_TO_MILLIPOINTS; PageY = CDRDATA_WORD(i->PageY) * CDRCOORDS_TO_MILLIPOINTS; Landscape = (CDRDATA_WORD(i->Orientation) == cdrf_ORIENTATION_LANDSCAPE)?TRUE:FALSE; GotPageInfo = TRUE; } break; case cdrT_tspc: // font style table for version 3 if(Version == CDRVERSION_3) { // store the font styles if((FontStylesV3 = (ADDR)CCMalloc(RIFF->GetObjSize())) == 0) return FALSE; if(!RIFF->GetChunkData(FontStylesV3, RIFF->GetObjSize())) return FALSE; } break; case cdrT_ftbl: // font name table for version 3 if(Version == CDRVERSION_3) { // store the font names if((FontTableV3 = (ADDR)CCMalloc(RIFF->GetObjSize())) == 0) return FALSE; if(!RIFF->GetChunkData(FontTableV3, RIFF->GetObjSize())) return FALSE; // store number of entries FontTableEntriesV3 = RIFF->GetObjSize() / sizeof(cdrfFontTableEntryV3); // cache the font names cdrfFontTableEntryV3 *FT = (cdrfFontTableEntryV3 *)FontTableV3; for(INT32 l = 0; l < FontTableEntriesV3; l++) { if(FT[l].Name[0] != '\0' && FT[l].Name[0] != ' ') { //GetApplication()->GetFontManager()->CacheNamedFont(&String_64((TCHAR *)&FT[l].Name)); Fonts.AddFontToStore(FT[l].Reference, (TCHAR *)&FT[l].Name); } } } break; case cdrT_lnkt: // store the link table - it's a pretty useful piece of kit if((LinkTable = (ADDR)CCMalloc(RIFF->GetObjSize())) == 0) return FALSE; if(!RIFF->GetChunkData(LinkTable, RIFF->GetObjSize())) return FALSE; // generate the links from paths to text text from it if(!MakeTextOnPathLinkList()) return FALSE; break; default: break; } break; default: break; } UpdateProgress(); if(!RIFF->NextObject()) return FALSE; ERROR3IF(RIFF->GetObjType() == RIFFOBJECTTYPE_FILEEND, "Unexpected end of RIFF file in ProcessDoc"); } while(RIFF->GetObjType() != RIFFOBJECTTYPE_LISTEND || RIFF->GetObjLevel() > StartLevel); // process the vector list, if we got one if(VectorListContents != 0) { if(!ProcessVectorList(VectorListContents, VectorListContentsSize)) { CCFree(VectorListContents); return FALSE; } CCFree(VectorListContents); } // if this isn't a version 3 file, check that we got some page info if(Version != CDRVERSION_3) { if(GotPageInfo == FALSE) { TRACEUSER( "Ben", _T("mcfg chunk not found in doc list\n")); ERROR1(FALSE, _R(IDE_CDRFILTER_FORMATERROR)); } // set the page size? if(!pDocument->IsImporting() && PageX > 0 && PageY > 0) { // Make the pasteboard an extra page width either side of the page and an extra // half page height above and below the page. That should be nicely proportional. INT32 ms = (PageX > PageY)?PageX:PageY; // we're opening the file, so set the page size if (pSpread) { BOOL ok = pSpread->SetPageSize(PageX, PageY, ms, 0, FALSE, TRUE); // Must set the origin of the grid to the bottom left corner of the // union rectangle of all pages on the spread as this is where the x,y // measurements are made from. DocRect PagesRect; NodeGrid* pGrid = pSpread->FindFirstDefaultGridInSpread(); ok = ok && pSpread->GetPagesRect(&PagesRect); if (pGrid) pGrid->SetOrigin(PagesRect.lox, PagesRect.loy); if (!ok) return FALSE; } } // Use bottom left of page as origin DocRect PageRect = pPage->GetPageRect(); Origin = PageRect.lo; // set the translation variables to position the bottom left hand corner of the page // at the bottom left hand corner of the page we're importing onto. The origin of // a CDR file is in the centre of the page TranslateByX = Origin.x + (PageX / 2); TranslateByY = Origin.y + (PageY / 2); } TRACEUSER( "Ben", _T("PageX = %d, PageY = %d\n"), PageX, PageY); return TRUE; } /******************************************************************************************** > BOOL CDRFilter::ProcessPage(void) Author: Ben_Summers (Xara Group Ltd) Created: 22 03 95 Inputs: none Returns: error flag Purpose: Processes a page list of a CDR file SeeAlso: Filter ********************************************************************************************/ BOOL CDRFilter::ProcessPage(void) { TRACEUSER( "Ben", _T("In ProcessPage\n")); // first of all, create a new page item in the page list ERROR3IF(ThisPage != 0, "ThisPage is not null - ProcessPage called in wrong context"); ThisPage = new CDRPageListItem; if(ThisPage == 0) return FALSE; // link it into the page list Pages.AddTail(ThisPage); // set the master page flag if(DoneMasterPage == FALSE) InMasterPage = TRUE; // go through the page list processing the layers // store the level we're working on UINT32 StartLevel = RIFF->GetObjLevel(); do { if(RIFF->GetObjType() == RIFFOBJECTTYPE_LISTSTART && RIFF->GetObjChunkType() == cdrT_layr) { // it's a layer, process it if(!ProcessLayer()) { TRACEUSER( "Ben", _T("ProcessLayer returned FALSE\n")); return FALSE; } } // if we're doing a version 3 file, have we got a page // size chunk to play with? if(Version == CDRVERSION_3 && RIFF->GetObjType() == RIFFOBJECTTYPE_CHUNK && RIFF->GetObjChunkType() == cdrT_mcfg) { if(!RIFF->AquireChunkData()) return FALSE; cdrfPageInfoV3 *i = (cdrfPageInfoV3 *)RIFF->GetAquiredData(); // in a CDR 3 file, the page size is half what it should be PageX = CDRDATA_WORD(i->PageX) * CDRCOORDS_TO_MILLIPOINTS * 2; PageY = CDRDATA_WORD(i->PageY) * CDRCOORDS_TO_MILLIPOINTS * 2; Landscape = FALSE; } UpdateProgress(); if(!RIFF->NextObject()) return FALSE; ERROR3IF(RIFF->GetObjType() == RIFFOBJECTTYPE_FILEEND, "Unexpected end of RIFF file in ProcessDoc"); } while(RIFF->GetObjType() != RIFFOBJECTTYPE_LISTEND || RIFF->GetObjLevel() > StartLevel); // finally make ThisPage as not used ThisPage = 0; // sort out master page flags if(InMasterPage) { InMasterPage = FALSE; DoneMasterPage = TRUE; } TRACEUSER( "Ben", _T("End ProcessPage\n")); return TRUE; } /******************************************************************************************** > BOOL CDRFilter::ProcessLayer(void) Author: Ben_Summers (Xara Group Ltd) Created: 24 03 95 Inputs: none Returns: error flag Purpose: Processes a layer list of a CDR file. This is the function which actually grabs objects to convert. SeeAlso: ********************************************************************************************/ BOOL CDRFilter::ProcessLayer(void) { TRACEUSER( "Ben", _T("In ProcessLayer\n")); // first of all, create a new layer item in the page list ERROR3IF(ThisLayer != 0, "ThisLayer is not null - ProcessLayer called in wrong context"); ThisLayer = new CDRLayerListItem; if(ThisLayer == 0) return FALSE; // link it into the layer list on the page we're working on ThisPage->Layers.AddTail(ThisLayer); // store the level we're working on UINT32 StartLevel = RIFF->GetObjLevel(); ThisLayer->Objects = 0; ThisLayer->IsVisible = TRUE; ThisLayer->IsLocked = FALSE; // set up the pointer to the node list to add to ERROR3IF(pLevelNodeList != 0, "Level node list is not empty"); pLevelNodeList = 0; // if we're on the master page, find the layer name if(InMasterPage) { BOOL Done = FALSE; FOURCC LookingFor = (Version == CDRVERSION_3)?cdrT_lobj:cdrT_loda; do { if(RIFF->GetObjType() == RIFFOBJECTTYPE_CHUNK && RIFF->GetObjChunkType() == LookingFor) { // found the interesting chunk of data if(!RIFF->AquireChunkData()) return FALSE; cdrfMasterLayerInfo *i = (cdrfMasterLayerInfo *)RIFF->GetAquiredData(); if(i == 0) // data couldn't be got return FALSE; if(i->Size != RIFF->GetObjSize()) { TRACEUSER( "Ben", _T("level data in master page has wrong size\n")); ERROR1(FALSE, _R(IDE_CDRFILTER_FORMATERROR)); } // different format of layer info for version 3 if(Version == CDRVERSION_3) { cdrfMasterLayerInfoV3 *ii = (cdrfMasterLayerInfoV3 *)RIFF->GetAquiredData(); TRACEUSER( "Ben", _T("name of layer = %s\n"), ii->Name); ThisLayer->Name = (char *)ii->Name; } else { TRACEUSER( "Ben", _T("name of layer = %s\n"), i->Name); ThisLayer->Name = (char *)i->Name; } Done = TRUE; } else if(RIFF->GetObjType() == RIFFOBJECTTYPE_CHUNK && RIFF->GetObjChunkType() == cdrT_flgs) { // look at the flags of the layer... if(!RIFF->AquireChunkData()) return FALSE; WORD *pFlags = (WORD *)RIFF->GetAquiredData(); ERROR3IF(pFlags == 0, "RIFF class shouldn't have done that"); INT32 Flags = CDRDATA_WORD(*pFlags); if((Flags & cdrfLAYERFLAGS_INVISIBLE) != 0) ThisLayer->IsVisible = FALSE; if((Flags & cdrfLAYERFLAGS_LOCKED) != 0) ThisLayer->IsLocked = TRUE; } if(!RIFF->NextObject()) return FALSE; } while(Done == FALSE && (RIFF->GetObjType() != RIFFOBJECTTYPE_LISTEND || RIFF->GetObjLevel() > StartLevel)); if(Done == FALSE) { TRACEUSER( "Ben", _T("Reached level end in master page layer without finding layer attributes\n")); ERROR1(FALSE, _R(IDE_CDRFILTER_FORMATERROR)); } } else { ThisLayer->Name = ""; } // go through the layer list processing the objects if(!ProcessObjectTree(StartLevel)) return FALSE; // put the nodes we got onto the layer we're processing ThisLayer->Objects = pLevelNodeList; pLevelNodeList = 0; // finally mark ThisLayer as not used ThisLayer = 0; TRACEUSER( "Ben", _T("End ProcessLayer\n")); return TRUE; } /******************************************************************************************** > BOOL CDRFilter::ProcessObjectTree(void) Author: Ben_Summers (Xara Group Ltd) Created: 19/04/95 Inputs: the RIFF level the list we're processing starts at Returns: error flag Purpose: process objects from the CDR file - they end up linked to pLevelNodeList. SeeAlso: Filter, CDRFilter::ProcessLayer, CDRFilter::ProcessVectorList ********************************************************************************************/ BOOL CDRFilter::ProcessObjectTree(UINT32 Level) { do { switch(RIFF->GetObjType()) { case RIFFOBJECTTYPE_LISTSTART: // see if it's anything we're interested in switch(RIFF->GetObjChunkType()) { case cdrT_obj: // found an object if(!ProcessObject()) return FALSE; break; case cdrT_grp: // found a group type objects if(!ProcessGroup(RIFF->GetObjLevel())) return FALSE; break; case cdrT_lnkg: // found a link object - treated as the same as a group, but searched for a // transformation matrix if(!ProcessLink()) return FALSE; break; default: break; } break; case RIFFOBJECTTYPE_LISTEND: // check to see if any actions are associated with this list end if(!Actions.IsEmpty()) { CDRActionListItem *Act, *Previous; Act = (CDRActionListItem *)Actions.GetTail(); // perform the actions which end on this level while(Act != 0) { if(Act->GetLevel() >= RIFF->GetObjLevel()) { // the last action ended on this level - perform the action if(!Act->DoAction(this)) return FALSE; // get the previous item Previous = (CDRActionListItem *)Actions.GetPrev(Act); // remove and delete the action we just performed delete Actions.RemoveTail(); // and set up the pointer to the next action to look at Act = Previous; } else { // the action shouldn't be performed yet - stop looking break; } } } break; default: break; } if(!UpdateProgress()) return FALSE; if(!RIFF->NextObject()) return FALSE; ERROR3IF(RIFF->GetObjType() == RIFFOBJECTTYPE_FILEEND, "Unexpected end of RIFF file in ProcessLayer"); } while(RIFF->GetObjType() != RIFFOBJECTTYPE_LISTEND || RIFF->GetObjLevel() > Level); return TRUE; } /******************************************************************************************** > BOOL CDRFilter::ProcessGroup(UINT32 Level, BOOL FromLink = FALSE) Author: Ben_Summers (Xara Group Ltd) Created: 26 03 95 Inputs: none Returns: error flag Purpose: Sets up a group end action and alters the level node list to be a new list SeeAlso: ********************************************************************************************/ BOOL CDRFilter::ProcessGroup(UINT32 Level, BOOL FromLink) { // if it's a CDR3 file we need a transform action if(Version == CDRVERSION_3) { // see if there's a transform object around BOOL Found = FALSE; do { if(!RIFF->NextObject()) return FALSE; FOURCC id = RIFF->GetObjChunkType(); // the group need not have a transform chunk, so we've got to be a little careful if(id == cdrT_grp || id == cdrT_lnkg || id == cdrT_obj) { // oh dear, it didn't - make sure this object we've just run onto is seen again RIFF->RepeatCurrent(); break; } if(id == cdrT_lobj && RIFF->GetObjType() == RIFFOBJECTTYPE_CHUNK) { // found a transform chunk Found = TRUE; } } while(Found == FALSE); // if there is, set up a post transform action if(Found) { TRACEUSER( "Ben", _T("Setting transform for CDR3 group at level %d\n"), Level); CDRActionTransform *TAct = new CDRActionTransform; if(TAct == 0) return FALSE; // initialise my new action, giving it the RIFFFile we're using // it takes the current chunk as it's data. if(!TAct->Init(RIFF, Version)) return FALSE; // set it to act on the same level ending as the group TAct->SetLevel(Level); // add my new action to the action list Actions.AddTail(TAct); } } else if(!FromLink) { // see if there's a transform chunk, and if there is, whether it's got a non matrix transform in it or not BOOL Found = FALSE; do { if(!RIFF->NextObject()) return FALSE; FOURCC id = RIFF->GetObjChunkType(); // the group need not have a transform chunk, so we've got to be a little careful if(id == cdrT_grp || id == cdrT_lnkg || id == cdrT_obj) { // oh dear, it didn't - make sure this object we've just run onto is seen again RIFF->RepeatCurrent(); break; } if(id == cdrT_trfl && RIFF->GetObjType() == RIFFOBJECTTYPE_LISTSTART) { // found a transform list Found = TRUE; } } while(Found == FALSE); // if there is, set up a post transform action if(Found) { CDRActionTransform *Act = new CDRActionTransform; if(Act == 0) return FALSE; // initialise my new action, giving it the RIFFFile we're using // it takes the current chunk as it's data. if(!Act->Init(RIFF, Version)) return FALSE; // check to see if the transform contains a non-matrix thingy if(IsTransformJustMatrices(Act->Chunk, Act->ChunkSize)) { // just matrices - don't do this action delete Act; } else { // set it to act on the same level ending as the group Act->SetLevel(Level); // set it to ignore matrices Act->SetIsAGroupTransform(TRUE); // add my new action to the action list Actions.AddTail(Act); } } } CDRActionGroupEnd *Act = new CDRActionGroupEnd; if(Act == 0) return FALSE; // store this levels node list Act->pOldLevelNodeList = pLevelNodeList; // set up the level it's interested in Act->SetLevel(Level); // and start a new level node list for this group pLevelNodeList = 0; Actions.AddTail(Act); return TRUE; } /******************************************************************************************** > BOOL CDRActionGroupEnd::DoAction(CDRFilter *C) Author: Ben_Summers (Xara Group Ltd) Created: 26 03 95 Inputs: none Returns: error flag Purpose: does some funcky stuff to put objects in a group SeeAlso: ********************************************************************************************/ BOOL CDRActionGroupEnd::DoAction(CDRFilter *C) { // make sure we have some objects to put in a group if(C->pLevelNodeList == 0) { // restore the pointer C->pLevelNodeList = pOldLevelNodeList; // and exit return TRUE; } // make a new group node NodeGroup *pGroup = new NodeGroup; if(pGroup == 0) return FALSE; // OK, pop everything on the level node list onto this nice new group C->pLevelNodeList->InsertChainSimple(pGroup, LASTCHILD); // restore the old pointer C->pLevelNodeList = pOldLevelNodeList; // and attach! if(C->pLevelNodeList == 0) { C->pLevelNodeList = pGroup; } else { pGroup->AttachNode(C->pLevelNodeList, PREV); C->pLevelNodeList = pGroup; } // and that's it return TRUE; } /******************************************************************************************** > void CDRActionGroupEnd::ImportFailure(CDRFilter *C) Author: Ben_Summers (Xara Group Ltd) Created: 26 03 95 Inputs: none Returns: error flag Purpose: ensures no memory leaks if the import fails SeeAlso: ********************************************************************************************/ void CDRActionGroupEnd::ImportFailure(CDRFilter *C) { if(pOldLevelNodeList != 0) { // delete all the entries stored in this action C->DeleteNodeList(pOldLevelNodeList); } } /******************************************************************************************** > BOOL CDRFilter::ProcessLink(void) Author: Ben_Summers (Xara Group Ltd) Created: 26 03 95 Inputs: none Returns: error flag Purpose: Sets up a group end action and a post transform action and alters the level node list to be a new list SeeAlso: ********************************************************************************************/ BOOL CDRFilter::ProcessLink(void) { // store the level we're on UINT32 GroupLevel = RIFF->GetObjLevel(); // only search for a transform block if this isn't a CDR3 file - ProcessGroup // takes care of it in that case if(Version != CDRVERSION_3) { // we want to set up the transform object first so that it's done *after* the group end // object as the transform object acts on the last object converted // see if there's a transform object around BOOL Found = FALSE; do { if(!RIFF->NextObject()) return FALSE; FOURCC id = RIFF->GetObjChunkType(); // the group need not have a transform chunk, so we've got to be a little careful if(id == cdrT_grp || id == cdrT_lnkg || id == cdrT_obj) { // oh dear, it didn't - make sure this object we've just run onto is seen again RIFF->RepeatCurrent(); break; } if(id == cdrT_trfl && RIFF->GetObjType() == RIFFOBJECTTYPE_LISTSTART) { // found a transform list Found = TRUE; } } while(Found == FALSE); // if there is, set up a post transform action if(Found) { CDRActionTransform *Act = new CDRActionTransform; if(Act == 0) return FALSE; // initialise my new action, giving it the RIFFFile we're using // it takes the current chunk as it's data. if(!Act->Init(RIFF, Version)) return FALSE; // set it to act on the same level ending as the group Act->SetLevel(GroupLevel); // set up link translation things Act->LinkTrans = TRUE; LinkTransformsExist = TRUE; // add my new action to the action list Actions.AddTail(Act); } } // set up a group end action if(!ProcessGroup(GroupLevel, TRUE)) return FALSE; return TRUE; } /******************************************************************************************** > BOOL CDRActionTransform::Init(RIFFFile *RIFF, CDRVersion Version) Author: Ben_Summers (Xara Group Ltd) Created: 27 03 95 Inputs: none Returns: error flag Purpose: sets up a transform action - stored given chunk SeeAlso: ********************************************************************************************/ BOOL CDRActionTransform::Init(RIFFFile *RIFF, CDRVersion Version) { if(Version == CDRVERSION_3) { // it's a version 3 file, so get the chunk ERROR3IF(RIFF->GetObjType() != RIFFOBJECTTYPE_CHUNK, "CDRActionTransform::Init called with RIFFFile in wrong state"); ERROR3IF(Chunk != 0, "CDRActionTransform::Init called more than once"); // claim some memory to put the transform in if((Chunk = (ADDR)CCMalloc(RIFF->GetObjSize())) == 0) return FALSE; // and get the chunk data into this nice block if(!RIFF->GetChunkData(Chunk, RIFF->GetObjSize())) return FALSE; } else { // it's a version 5 file, so get the list contents ERROR3IF(RIFF->GetObjType() != RIFFOBJECTTYPE_LISTSTART, "CDRActionTransform::Init called with RIFFFile in wrong state"); ERROR3IF(Chunk != 0, "CDRActionTransform::Init called more than once"); // get the list contents if(!RIFF->GetListContents(&Chunk, &ChunkSize)) return FALSE; } // that's it for now return TRUE; } /******************************************************************************************** > BOOL CDRActionTransform::DoAction(CDRFilter *C) Author: Ben_Summers (Xara Group Ltd) Created: 27 03 95 Inputs: none Returns: error flag Purpose: transforms the last object converted SeeAlso: ********************************************************************************************/ BOOL CDRActionTransform::DoAction(CDRFilter *C) { ERROR3IF(Chunk == 0, "CDRActionTransform not initialised"); if(LinkTrans) { return TRUE; } ADDR Transform = Chunk; // if this is a version 3 file we need to find the transform in the data - it's in // a standard offset header if(C->Version == CDRVERSION_3) { cdrfOffsetHeader *Header = (cdrfOffsetHeader *)Chunk; // if there isn't a transform, then we're not worried if((Transform = C->FindDataInObject(Header, cdrfOBJOFFSETTYPE_TRANSFORM_V3)) == 0) return TRUE; } // transform the last node created // unlink it from the tree first... Node *pNext = C->pLevelNodeList->FindNext(); C->pLevelNodeList->UnlinkNodeFromTree(); // we don't want to scale it to translate the origin because it's already been done if(!LinkTrans && C->pLevelNodeList != 0) C->TransformConvertedObject(&C->pLevelNodeList, Transform, ChunkSize, FALSE, IsAGroupTransform, TRUE); // relink it in if(pNext != 0) C->pLevelNodeList->AttachNode(pNext, PREV); return TRUE; } /******************************************************************************************** > void CDRActionTransform::ImportFailure(CDRFilter *C) Author: Ben_Summers (Xara Group Ltd) Created: 27 03 95 Inputs: none Returns: error flag Purpose: don't actually need to do anything - the chunk will be deleted on object destruction SeeAlso: ********************************************************************************************/ void CDRActionTransform::ImportFailure(CDRFilter *C) { } /******************************************************************************************** > CDRActionTransform::~CDRActionTransform Author: Ben_Summers (Xara Group Ltd) Created: 27 03 95 Inputs: none Returns: error flag Purpose: destructor SeeAlso: ********************************************************************************************/ CDRActionTransform::~CDRActionTransform() { CCFree(Chunk); } /******************************************************************************************** > BOOL CDRFiler::ConvertColour(cdrfColour *Col, DocColour *Out) Author: Ben_Summers (Xara Group Ltd) Created: 28 03 95 Inputs: cdr colour and a DocColour to put it into Returns: error flag Purpose: converts a colour from the CDR definition taking into account the version SeeAlso: Filter ********************************************************************************************/ BOOL CDRFilter::ConvertColour(cdrfColour *Col, DocColour *Out) { ERROR3IF(Col == 0 || Out == 0, "Null pointers passed to ConvertColour"); ImportedNewColour ICol; switch(Version) { case CDRVERSION_5: CDRColour::Convert5(Col, &ICol); break; case CDRVERSION_4: CDRColour::Convert4(Col, &ICol); break; default: CDRColour::Convert3(Col, &ICol); break; } IndexedColour *NewCol = new IndexedColour(ICol.Model, &ICol.Colour); if(NewCol == 0) return FALSE; ColList->GetUnnamedColours()->AddTail(NewCol); Out->MakeRefToIndexedColour(NewCol); return TRUE; } /******************************************************************************************** > BOOL CDRFilter::ProcessObject(void) Author: Ben_Summers (Xara Group Ltd) Created: 24 03 95 Inputs: none Returns: error flag Purpose: Converts an object. If there's a problem with the object, then it's skipped rather than reporting an error, and the count of problem objects incremented SeeAlso: ********************************************************************************************/ BOOL CDRFilter::ProcessObject(void) { UINT32 StartLevel = RIFF->GetObjLevel(); // set the made node to none pMadeNode = 0; // set the already applied flag AttrsAlreadyApplied = FALSE; // set the is text things to make sure bodges don't happen IsText = FALSE; IsTextStory = FALSE; // find the loda (4 or 5) or lobj (3) chunk... contains the object header BOOL Found = FALSE; FOURCC LookingFor = (Version == CDRVERSION_3)?cdrT_lobj:cdrT_loda; do { // is the serial number? if(RIFF->GetObjType() == RIFFOBJECTTYPE_CHUNK && RIFF->GetObjChunkType() == cdrT_spnd) { // got the serial number block - get it... if(!RIFF->AquireChunkData()) return FALSE; WORD *Data = (WORD *)RIFF->GetAquiredData(); if(Data == 0) return FALSE; // store it... SerialNumber = CDRDATA_WORD(*Data); } if(RIFF->GetObjType() == RIFFOBJECTTYPE_CHUNK && RIFF->GetObjChunkType() == LookingFor) { Found = TRUE; break; } if(!UpdateProgress()) return FALSE; if(!RIFF->NextObject()) return FALSE; } while(RIFF->GetObjType() != RIFFOBJECTTYPE_LISTEND || RIFF->GetObjLevel() > StartLevel); // if we didn't find anything, then the object has a wrong format if(Found == FALSE) { TRACEUSER( "Ben", _T("Could not find loda (or lobj) chunk in object\n")); ObjectsFormatWrong++; return TRUE; } // get the header - but get it into our block, not the one in RIFFFile as we need // to refer to it later. It shouldn't be too big to make this inefficient... cdrfOffsetHeader *Header; // ensure we have a block big enough if(ObjDataBlock == 0 || ObjDataBlockSize < RIFF->GetObjSize()) { // free the old one CCFree(ObjDataBlock); // size? INT32 Size = RIFF->GetObjSize(); if((ObjDataBlock = (ADDR)CCMalloc(Size)) == 0) return FALSE; ObjDataBlockSize = Size; } if(!RIFF->GetChunkData(ObjDataBlock, ObjDataBlockSize)) return FALSE; Header = (cdrfOffsetHeader *)ObjDataBlock; // look at the type and dispatch to appropriate processing function FormatError = FALSE; INT32 ObjectType = CDRDATA_WORD(Header->ObjectType); // if this is a version 3 object, alter it's type if(Version == CDRVERSION_3) ObjectType += cdrfOBJTYPE_V3ADD; switch(ObjectType) { case cdrfOBJTYPE_RECTANGLE: if(!ConvertRectangle(Header)) return FALSE; break; case cdrfOBJTYPE_ELLIPSE: if(!ConvertEllipse(Header)) return FALSE; break; case cdrfOBJTYPE_PATH: if(!ConvertPath(Header)) return FALSE; break; case cdrfOBJTYPE_TEXT: case cdrfOBJTYPE_TEXTSTORY: if(!ConvertText(Header)) return FALSE; break; case cdrfOBJTYPE_BITMAP: if(!ConvertBitmap(Header)) return FALSE; break; default: // unknown object type ObjectsUnknown++; RIFF->SkipToListEnd(StartLevel); return TRUE; break; } // check to see if the format was OK if(FormatError) { TRACEUSER( "Ben", _T("A convert object function returned a format error\n")); ObjectsFormatWrong++; if(TransformChunk != 0) { CCFree(TransformChunk); TransformChunk = 0; } return TRUE; } ERROR3IF(pMadeNode == 0, "No node made, but still nothing errored\n"); // think about lenses BOOL UnsetTransparency = FALSE; if(Version == CDRVERSION_5) { cdrfLensDefn *Lens = (cdrfLensDefn *)FindDataInObject(Header, cdrfOBJOFFSETTYPE_LENS); if(Lens != 0) { // we have a lens to worry about... what type is it? if(Lens->Type == cdrfLENSTYPE_TRANSPARENT) { // check the percentage UINT32 Percent = CDRDATA_WORD(Lens->Percent) / 10; if(Percent <= 100) { // munge the percentage a bit to get it to a Camelot definition Percent = 256 - ((Percent * 256) / 100); // what subtype is it? switch(Lens->SubType) { case cdrfTRANSPARENTTYPE_MIX: SetFlatTranspFill(T_REFLECTIVE, Percent); UnsetTransparency = TRUE; break; case cdrfTRANSPARENTTYPE_STAINED: SetFlatTranspFill(T_SUBTRACTIVE, Percent); UnsetTransparency = TRUE; break; case cdrfTRANSPARENTTYPE_BLEACH: SetFlatTranspFill(T_ADDITIVE, Percent); UnsetTransparency = TRUE; break; default: break; } } } } } // find the transform chunk - it's in a seperate chunk for version 4 or 5 file, // and in the data chunk for version 3 files ADDR TransformData = 0; INT32 TransformDataSize = 0; if(TransformChunk != 0) { // if something had to move forward in the file (for example, text objects) // past the transform chunk, it will have stored it here. TransformData = TransformChunk; TransformDataSize = TransformChunkSize; } else if(Version == CDRVERSION_3) { TransformData = FindDataInObject(Header, cdrfOBJOFFSETTYPE_TRANSFORM_V3); } else { Found = FALSE; do { if(RIFF->GetObjType() == RIFFOBJECTTYPE_LISTSTART && RIFF->GetObjChunkType() == cdrT_trfl) { Found = TRUE; break; } UpdateProgress(); if(!RIFF->NextObject()) return FALSE; } while(RIFF->GetObjType() != RIFFOBJECTTYPE_LISTEND || RIFF->GetObjLevel() > StartLevel); // if we didn't find anything, then the object has a wrong format if(Found == FALSE) { TRACEUSER( "Ben", _T("Could not find trfd chunk in object\n")); ObjectsFormatWrong++; // delete the current node delete pMadeNode; return TRUE; } // aquire the chunk data if(!RIFF->AquireListContents(&TransformDataSize)) { delete pMadeNode; return FALSE; } TransformData = RIFF->GetAquiredData(); } if(TransformData == 0) { ObjectsFormatWrong++; // delete the current node delete pMadeNode; return TRUE; } // go through any link transforms which may exist if(Version != CDRVERSION_3) { if(LinkTransformsExist) { BOOL FoundSome = FALSE; CDRActionListItem *Act = (CDRActionListItem *)Actions.GetTail(); while(Act != 0) { if(IS_A(Act, CDRActionTransform)) { CDRActionTransform *Tran = (CDRActionTransform *)Act; if(Tran->LinkTrans) { // set the flag to say we found a link transform FoundSome = TRUE; // transform the converte object if(!TransformConvertedObject(&pMadeNode, Tran->Chunk, Tran->ChunkSize, FALSE)) { delete pMadeNode; return FALSE; } } } Act = (CDRActionListItem *)Actions.GetPrev(Act); } LinkTransformsExist = FoundSome; } } // apply the transform to the converted node if(!TransformConvertedObject(&pMadeNode, TransformData, TransformDataSize)) { delete pMadeNode; return FALSE; } // apply attributes if(AttrsAlreadyApplied == FALSE) { // look at fill attributes if(!SetFillAttr(Header)) return FALSE; // look at line attributes if(!SetLineAttr(Header)) return FALSE; } BOOL Result; if(AttrsAlreadyApplied == FALSE) { // apply the attributes to the object // If not filled, then set the ignore bit on the fill attribute. if (ObjFilled == FALSE) CurrentAttrs[ATTR_FILLGEOMETRY].Ignore = TRUE; // Add attributes to the path, if they are different from the default... Result = AttributeManager::ApplyBasedOnDefaults(pMadeNode, CurrentAttrs); // Enable the fill attribute again CurrentAttrs[ATTR_FILLGEOMETRY].Ignore = FALSE; } else { Result = TRUE; } if(!Result) return FALSE; if(UnsetTransparency) { SetNoTranspFill(); } // attach the node to the level list if(pLevelNodeList != 0) pMadeNode->AttachNode(pLevelNodeList, PREV); pLevelNodeList = pMadeNode; // set the made node pointer to zero to prevent accidents pMadeNode = 0; // increment the count of converted objects ObjectsConverted++; // if necessary, get rid of any transform chunk if(TransformChunk != 0) { CCFree(TransformChunk); TransformChunk = 0; } return TRUE; } /******************************************************************************************** > BOOL CDRFilter::ConvertPath(void) Author: Ben_Summers (Xara Group Ltd) Created: 24 03 95 Inputs: none Returns: error flag Purpose: actually converts a path object to a node. If the object has an unexpected format, then FormatError is set and it return *TRUE* - the return value only indicated environmental errors such as lack of memory SeeAlso: ********************************************************************************************/ BOOL CDRFilter::ConvertPath(cdrfOffsetHeader *Header) { // find the address of the coordinates in the header cdrfPathCoordHeader *CHdr = (cdrfPathCoordHeader *)FindDataInObject(Header, cdrfOBJOFFSETTYPE_COORDS); // it has got some coords, hasn't it? if(CHdr == 0) { FormatError = TRUE; return TRUE; } // find the address of the types and the coordinates cdrfCoord *Coords = (cdrfCoord *)(CHdr + 1); // and the address of the types UINT32 NCoords = CDRDATA_WORD(CHdr->NCoords); BYTE *Types = (BYTE *)(Coords + NCoords); // check the path a little if((NCoords * (sizeof(cdrfCoord) + sizeof(BYTE))) > CDRDATA_WORD(Header->Size) || NCoords < 2) { FormatError = TRUE; return TRUE; } // knock up a path node NodePath *pPath = new NodePath; if(pPath == 0 || (!pPath->SetUpPath())) { delete pPath; return FALSE; // no room to create it } // position the new elements at the beginning of the path pPath->InkPath.FindStartOfPath(); // flag the initial status of the fill/stokedness of the path ObjFilled = FALSE; ObjStroked = TRUE; if(!AddElementsToPath(&pPath->InkPath, NCoords, Coords, Types, &ObjFilled)) goto NoMemory; // check that the path is OK if(!pPath->InkPath.EnsureValid()) { // no, it's completely knackered delete pPath; FormatError = TRUE; return TRUE; } // finish off the path pPath->InvalidateBoundingRect(); pPath->InkPath.IsFilled = ObjFilled; // save node pointer pMadeNode = pPath; // check to see if text goes along this... { CDRTextOnPathLink *Item = (CDRTextOnPathLink *)TextOnPathLinks.GetHead(); while(Item != 0) { // does this link refer to this text story? if(SerialNumber == Item->PathSerialNumber) { // yep - store a pointer to this path Item->pPath = pPath; } // next! Item = (CDRTextOnPathLink *)TextOnPathLinks.GetNext(Item); } } // everything was nice return TRUE; NoMemory: // get rid of any path which is in the process of being created if(pPath != 0) pPath->CascadeDelete(); delete pPath; return FALSE; } /******************************************************************************************** > BOOL CDRFilter::AddElementsToPath(Path *pPath, INT32 NCoords, cdrfCoord *Coords, BYTE *Types, BOOL *IsClosed); Author: Ben_Summers (Xara Group Ltd) Created: 06/05/95 Inputs: path to add too, number of coords, pointer to coord data, pointer to types Returns: error flag Purpose: Adds elements to a path from a CDR path data SeeAlso: ********************************************************************************************/ BOOL CDRFilter::AddElementsToPath(Path *pPath, INT32 NCoords, cdrfCoord *Coords, BYTE *Types, BOOL *IsClosed) { // go through the coordinates in the CDR path adding them to the Camelot path INT32 c; // coord counter UINT32 CoordType; // type of this coordinate UINT32 Control1 = 0; // number of first control point UINT32 Control2 = 0; // of second DocCoord co, cn1, cn2; // coordinates PathFlags Flags; BOOL NeedMoveTo = TRUE; if(IsClosed != 0) (*IsClosed) = FALSE; // go though converting all the coords for(c = 0; c < NCoords; c++) { CoordType = Types[c] & cdrfPATHCOORDTYPE_MASK; co.x = CDRDATA_SWORD(Coords[c].X) * CDRCOORDS_TO_MILLIPOINTS; co.y = CDRDATA_SWORD(Coords[c].Y) * CDRCOORDS_TO_MILLIPOINTS; // add in a move to if necessary if(NeedMoveTo && CoordType != cdrfPATHCOORDTYPE_MOVE) { if(!pPath->InsertMoveTo(co)) return FALSE; } NeedMoveTo = FALSE; // process the coordinate switch(CoordType) { case cdrfPATHCOORDTYPE_MOVE: // add a move to this path if(!pPath->InsertMoveTo(co)) return FALSE; break; case cdrfPATHCOORDTYPE_LINETO: // add a line to this coord to the path if(!pPath->InsertLineTo(co)) return FALSE; break; case cdrfPATHCOORDTYPE_CURVE: // check we have some control points for this curve // a control point cannot be the first coord, so it's OK to check against 0 if(Control1 == 0 || Control2 == 0) { TRACEUSER( "Ben", _T("No control points for curve element\n")); break; } // convert the control points cn1.x = CDRDATA_SWORD(Coords[Control1].X) * CDRCOORDS_TO_MILLIPOINTS; cn1.y = CDRDATA_SWORD(Coords[Control1].Y) * CDRCOORDS_TO_MILLIPOINTS; cn2.x = CDRDATA_SWORD(Coords[Control2].X) * CDRCOORDS_TO_MILLIPOINTS; cn2.y = CDRDATA_SWORD(Coords[Control2].Y) * CDRCOORDS_TO_MILLIPOINTS; // create the curve Flags.IsSelected = FALSE; Flags.IsSmooth = Flags.IsRotate = ((Types[c] & cdrfPATHCOORDATTR_SMOOTH) != 0)?TRUE:FALSE; Flags.IsEndPoint; // insert it into the path if(!pPath->InsertCurveTo(cn1, cn2, co, &Flags)) return FALSE; break; case cdrfPATHCOORDTYPE_CONTROL: // shuffle the control points we've already got and add the new one Control1 = Control2; Control2 = c; break; default: // can't get here as mask won't allow any other value than the ones above. break; } // is this a close subpath situtation? if((Types[c] & cdrfPATHCOORDATTR_CLOSE) != 0) { if(IsClosed != 0) (*IsClosed) = TRUE; // path has at least one closed element and should be filled // close the sub path if(CoordType != cdrfPATHCOORDTYPE_MOVE) { if(!pPath->CloseSubPath()) return FALSE; // ensure that the next coord is a moveto NeedMoveTo = TRUE; } } } return TRUE; } /******************************************************************************************** > BOOL CDRFilter::ConvertRectangle(cdrfOffsetHeader *Header) Author: Ben_Summers (Xara Group Ltd) Created: 27 03 95 Inputs: pointer to header Returns: error flag Purpose: generates a rectangle object SeeAlso: ********************************************************************************************/ #define RECTANGLE_CORNER_MAGIC (1.0 - 0.552) #define RECT_MOVE(px, py) {co.x = (px); co.y = (py); if(!pPath->InkPath.InsertMoveTo(co)) goto NoMemory;} #define RECT_LINE(px, py) {co.x = (px); co.y = (py); if(!pPath->InkPath.InsertLineTo(co)) goto NoMemory;} #define RECT_CURVE(cx1, cy1, cx2, cy2, px, py) {cn1.x = (cx1); cn1.y = (cy1); cn2.x = (cx2); cn2.y = (cy2); \ co.x = (px); co.y = (py); if(!pPath->InkPath.InsertCurveTo(cn1, cn2, co)) goto NoMemory;} #define RECT_CLOSE {if(!pPath->InkPath.CloseSubPath()) goto NoMemory;} BOOL CDRFilter::ConvertRectangle(cdrfOffsetHeader *Header) { // find the address of the coordinates in the header cdrfRectangleData *Size = (cdrfRectangleData *)FindDataInObject(Header, cdrfOBJOFFSETTYPE_COORDS); // it has got some coords, hasn't it? if(Size == 0) { FormatError = TRUE; return TRUE; } // get the dimensions from the object INT32 Width = CDRDATA_SWORD(Size->Width) * CDRCOORDS_TO_MILLIPOINTS; INT32 Height = CDRDATA_SWORD(Size->Height) * CDRCOORDS_TO_MILLIPOINTS; INT32 CornerRadius = CDRDATA_SWORD(Size->CornerRadius) * CDRCOORDS_TO_MILLIPOINTS; if(CornerRadius < 0) CornerRadius = 0 - CornerRadius; // make a rectangle quickshape... NodeRegularShape *NewShape = new (NodeRegularShape); if ((NewShape == NULL) || !NewShape->SetUpShape() ) { ERROR1(FALSE, _R(IDS_OUT_OF_MEMORY)); } INT32 AWidth = Width; INT32 AHeight = Height; if(AWidth < 0) AWidth = 0 - AWidth; if(AHeight < 0) AHeight = 0 - AHeight; if(!NewShape->MakeRectangle(AWidth, AHeight, CornerRadius)) return FALSE; // translate it a bit so the corner is on the origin, not the thingy Trans2DMatrix Trans(Width / 2, Height / 2); NewShape->Transform(Trans); // finish off the shape NewShape->InvalidateBoundingRect(); // set up an attribute or two ObjFilled = TRUE; ObjStroked = TRUE; // set the made node pMadeNode = NewShape; return TRUE; } /******************************************************************************************** > BOOL CDRFilter::ConvertEllipse(cdrfOffsetHeader *Header) Author: Ben_Summers (Xara Group Ltd) Created: 27 03 95 Inputs: pointer to header Returns: error flag Purpose: generates an ellipse object SeeAlso: ********************************************************************************************/ BOOL CDRFilter::ConvertEllipse(cdrfOffsetHeader *Header) { // find the address of the coordinates in the header cdrfEllipseData *Size = (cdrfEllipseData *)FindDataInObject(Header, cdrfOBJOFFSETTYPE_COORDS); // it has got some coords, hasn't it? if(Size == 0) { FormatError = TRUE; return TRUE; } // Create the ellipse NodeRegularShape *NewShape = new (NodeRegularShape); if ((NewShape == NULL) || !NewShape->SetUpShape() ) { ERROR1(FALSE, _R(IDS_OUT_OF_MEMORY)); } // fill it all in for an ellipse NewShape->SetNumSides(4); INT32 Width = CDRDATA_SWORD(Size->Width) * CDRCOORDS_TO_MILLIPOINTS; INT32 Height = CDRDATA_SWORD(Size->Height) * CDRCOORDS_TO_MILLIPOINTS; DocCoord co; co.x = Width / 2; // centre - it all starts at (0,0) co.y = Height / 2; NewShape->SetCentrePoint(co); co.x = Width; NewShape->SetMajorAxes(co); co.x /= 2; co.y = Height; NewShape->SetMinorAxes(co); NewShape->SetCircular(TRUE); NewShape->SetStellated(FALSE); NewShape->SetPrimaryCurvature(TRUE); NewShape->SetStellationCurvature(FALSE); // finish off the path NewShape->InvalidateBoundingRect(); // set up an attribute or two ObjFilled = TRUE; ObjStroked = TRUE; // set the made node pMadeNode = NewShape; return TRUE; } /******************************************************************************************** > BOOL CDRFilter::ConvertBitmap(cdrfOffsetHeader *Header) Author: Ben_Summers (Xara Group Ltd) Created: 12/04/95 Inputs: pointer to header Returns: error flag Purpose: generates a bitmap object SeeAlso: ********************************************************************************************/ #define BITM_MOVE(px, py) {co.x = (px); co.y = (py); if(!pPath->InkPath.InsertMoveTo(co)) return FALSE;} #define BITM_LINE(px, py) {co.x = (px); co.y = (py); if(!pPath->InkPath.InsertLineTo(co)) return FALSE;} #define BITM_CLOSE {if(!pPath->InkPath.CloseSubPath()) return FALSE;} BOOL CDRFilter::ConvertBitmap(cdrfOffsetHeader *Header) { // find the address of the coordinates in the header cdrfBitmapData *BInfo = (cdrfBitmapData *)FindDataInObject(Header, cdrfOBJOFFSETTYPE_COORDS); // it has got some object data, hasn't it? if(BInfo == 0) { FormatError = TRUE; return TRUE; } // OK, let's get the information in a nice structure to start off with struct { DWORD Reference; INT32 SizeX; INT32 SizeY; INT32 Left; // cropping coordinates INT32 Right; INT32 Bottom; INT32 Top; } Info; // choose the right reference - it's in a slightly different place in CDR 3 files if(Version != CDRVERSION_3) { Info.Reference = CDRDATA_WORD(BInfo->BitmapReference); Info.SizeX = CDRDATA_SWORD(BInfo->SizeX) * CDRCOORDS_TO_MILLIPOINTS; Info.SizeY = CDRDATA_SWORD(BInfo->SizeY) * CDRCOORDS_TO_MILLIPOINTS; Info.Left = CDRDATA_SWORD(BInfo->Left) * CDRCOORDS_TO_MILLIPOINTS; Info.Right = CDRDATA_SWORD(BInfo->Right) * CDRCOORDS_TO_MILLIPOINTS; Info.Bottom = CDRDATA_SWORD(BInfo->Bottom) * CDRCOORDS_TO_MILLIPOINTS; Info.Top = CDRDATA_SWORD(BInfo->Top) * CDRCOORDS_TO_MILLIPOINTS; } else { cdrfBitmapData3 *B3Info = (cdrfBitmapData3 *)BInfo; Info.Reference = CDRDATA_WORD(B3Info->BitmapReference); Info.SizeX = CDRDATA_SWORD(B3Info->SizeX) * CDRCOORDS_TO_MILLIPOINTS; Info.SizeY = CDRDATA_SWORD(B3Info->SizeY) * CDRCOORDS_TO_MILLIPOINTS; Info.Left = CDRDATA_SWORD(B3Info->Left) * CDRCOORDS_TO_MILLIPOINTS; Info.Right = CDRDATA_SWORD(B3Info->Right) * CDRCOORDS_TO_MILLIPOINTS; Info.Bottom = CDRDATA_SWORD(B3Info->Bottom) * CDRCOORDS_TO_MILLIPOINTS; Info.Top = CDRDATA_SWORD(B3Info->Top) * CDRCOORDS_TO_MILLIPOINTS; } // find that there bitmap KernelBitmap *pBitmap = Bitmaps.FindBitmap(Info.Reference); if(pBitmap == 0) { FormatError = TRUE; return TRUE; } // find a bounding box for the bitmap on the page DocRect BoundsRect; if(Info.SizeX > 0) { BoundsRect.lo.x = 0; BoundsRect.hi.x = Info.SizeX; } else { BoundsRect.lo.x = Info.SizeX; BoundsRect.hi.x = 0; } if(Info.SizeY > 0) { BoundsRect.lo.y = 0; BoundsRect.hi.y = Info.SizeY; } else { BoundsRect.lo.y = Info.SizeY; BoundsRect.hi.y = 0; } // OK, if the bitmap isn't cropped, create a bitmap object, otherwise // create a rectangle which is the right size and pop a bitmap fill on it if(Info.Left == 0 && Info.Right == Info.SizeX && Info.Top == 0 && Info.Bottom == Info.SizeY) { // create a bitmap object NodeBitmap *NewBitmap = new NodeBitmap; if((NewBitmap == NULL) || !NewBitmap->SetUpPath()) return FALSE; NewBitmap->CreateShape(BoundsRect); // set the reference to the bitmap NewBitmap->GetBitmapRef()->Attach(pBitmap, GetDocument()); if (NewBitmap->GetBitmap() != pBitmap) { // It didn't use the bitmap we gave it, so we can delete it delete pBitmap; } // apply a few nice attributes to it NewBitmap->ApplyDefaultBitmapAttrs(0); // invalidate the bounding rectangle NewBitmap->InvalidateBoundingRect(); // cool. ObjFilled = FALSE; ObjStroked = FALSE; // we don't want any of those fancy attributes things on this object. AttrsAlreadyApplied = TRUE; // set the made node pMadeNode = NewBitmap; } else { // create a rectangular path object... // generate a path NodePath *pPath = new NodePath; if(pPath == 0 || (!pPath->SetUpPath())) { delete pPath; return FALSE; // no room to create it } // position the new elements at the beginning of the path pPath->InkPath.FindStartOfPath(); DocCoord co, cn1, cn2; // make the rectangle shape BITM_MOVE(Info.Left, Info.Bottom) BITM_LINE(Info.Right, Info.Bottom) BITM_LINE(Info.Right, Info.Top) BITM_LINE(Info.Left, Info.Top) BITM_LINE(Info.Left, Info.Bottom) BITM_CLOSE // finish off the path pPath->InvalidateBoundingRect(); pPath->InkPath.IsFilled = TRUE; // set up an attribute or two ObjFilled = TRUE; ObjStroked = FALSE; // set up a nice attribute for this thingy if(!SetLineColour(DocColour(COLOUR_TRANS))) return FALSE; // set a nice bitmap fill DocCoord Start = DocCoord(BoundsRect.lo.x, BoundsRect.lo.y); DocCoord End1 = DocCoord(BoundsRect.hi.x, BoundsRect.lo.y); DocCoord End2 = DocCoord(BoundsRect.lo.x, BoundsRect.hi.y); if(!SetBitmapFill(pBitmap, Start, End1, End2)) return FALSE; // apply attributes SetPathFilled(TRUE); CurrentAttrs[ATTR_FILLGEOMETRY].Ignore = FALSE; if(!AttributeManager::ApplyBasedOnDefaults(pPath, CurrentAttrs)) return FALSE; // don't apply attributes later AttrsAlreadyApplied = TRUE; // set the made node pMadeNode = pPath; } return TRUE; } /******************************************************************************************** > ADDR CDRFilter::FindDataInObject(cdrfOffsetHeader *Header, WORD Type) Author: Ben_Summers (Xara Group Ltd) Created: 25 03 95 Inputs: none Returns: error flag Purpose: returns the address of data of the given type in an objects with a standard offset header SeeAlso: Filter ********************************************************************************************/ ADDR CDRFilter::FindDataInObject(cdrfOffsetHeader *Header, WORD Type) { WORD *Types; WORD *Offsets; Types = (WORD *)(((BYTE *)Header) + CDRDATA_WORD(Header->TypesOffset)); Offsets = (WORD *)(((BYTE *)Header) + CDRDATA_WORD(Header->OffsetsOffset)); UINT32 l; for(l = 0; l < CDRDATA_WORD(Header->NOffsets); l++) { if(CDRDATA_WORD(Types[l]) == Type) { UINT32 Off = CDRDATA_WORD(Offsets[Header->NOffsets - l - 1]); if(Off > CDRDATA_WORD(Header->Size)) return 0; return (ADDR)(((BYTE *)Header) + Off); } } return 0; } /******************************************************************************************** > BOOL CDRFilter::GetMatrixFromTransform(Matrix *M, ADDR Trans, INT32 Size, BOOL TranslateForPage) Author: Ben_Summers (Xara Group Ltd) Created: 25 03 95 Inputs: the node to transform, and the trfd chunk to transform it by Returns: error flag Purpose: given some transform data, works out a matrix. This ignores any 3D transforms, TransformConvertedObject should be used in preference. SeeAlso: Filter ********************************************************************************************/ BOOL CDRFilter::GetMatrixFromTransform(Matrix *M, ADDR Trans, INT32 Size, BOOL TranslateForPage) { // set up a matrix conversion object CDRTransformConvertor *Conv; // putting the convertors here is probably more efficicent than allocating // a new one in the heap as they're not very big at all CDRTransformConvertor5 Conv5; CDRTransformConvertor4 Conv4; CDRTransformConvertor3 Conv3; switch(Version) { case CDRVERSION_5: Conv = &Conv5; break; case CDRVERSION_4: Conv = &Conv4; break; case CDRVERSION_3: Conv = &Conv3; break; default: return FALSE; break; } // initialise the convertor object Conv->Init(Trans, Size); // set up the initial matrix which just converts to millipoints // note that these elements are in Corel order cdrMatrix Ma, Mb, Mt; BOOL DoneFirst = FALSE; // apply all the transformations in the chunk INT32 t; for(t = Conv->GetNTransforms() - 1; t >= 0; t--) { // check that the transform is a matrix - for now we can only do matrices if(Conv->GetTransformType(t) != CDRTRANSFORMTYPE_MATRIX) continue; if(DoneFirst) { // done the first matrix, so we need get the matrix into another one and then combine. // get the matrix if(!Conv->GetMatrix(&Mb, t)) return FALSE; // and combine it with the matrix we've already got Mt.a = (Mb.a * Ma.a) + (Mb.d * Ma.b); Mt.b = (Mb.b * Ma.a) + (Mb.e * Ma.b); Mt.c = (Mb.c * Ma.a) + (Mb.f * Ma.b) + Ma.c; Mt.d = (Mb.a * Ma.d) + (Mb.d * Ma.e); Mt.e = (Mb.b * Ma.d) + (Mb.e * Ma.e); Mt.f = (Mb.c * Ma.d) + (Mb.f * Ma.e) + Ma.f; Ma = Mt; } else { // just get the matrix if(!Conv->GetMatrix(&Ma, t)) return FALSE; DoneFirst = TRUE; } } // if we didn't get a matrix at all, knock up a quick dummy one if(!DoneFirst) { cdrMatrix Mx = {1, 0, 0, 0, 1, 0}; Ma = Mx; } // add in the translation bit if(TranslateForPage) { Ma.c += TranslateByX; Ma.f += TranslateByY; } // convert the final matrix into a Camelot matrix *M = Matrix(Ma.a, Ma.d, Ma.b, Ma.e, (INT32)Ma.c, (INT32)Ma.f); return TRUE; } /******************************************************************************************** > BOOL CDRFilter::IsTransformJustMatrices(ADDR Trans) Author: Ben_Summers (Xara Group Ltd) Created: 22/05/95 Inputs: trfd chunk to examine Returns: error flag Purpose: scans a transform chunk. Returns TRUE if the transform was just composed of matrices and unknown transforms. SeeAlso: Filter ********************************************************************************************/ BOOL CDRFilter::IsTransformJustMatrices(ADDR Trans, INT32 Size) { // set up a matrix conversion object CDRTransformConvertor *Conv; // putting the convertors here is probably more efficicent than allocating // a new one in the heap as they're not very big at all CDRTransformConvertor5 Conv5; CDRTransformConvertor4 Conv4; CDRTransformConvertor3 Conv3; switch(Version) { case CDRVERSION_5: Conv = &Conv5; break; case CDRVERSION_4: Conv = &Conv4; break; case CDRVERSION_3: Conv = &Conv3; break; default: return FALSE; break; } // initialise the convertor object Conv->Init(Trans, Size); // check all the transformations in the chunk for(INT32 t = Conv->GetNTransforms() - 1; t >= 0; t--) { switch(Conv->GetTransformType(t)) { case CDRTRANSFORMTYPE_MATRIX: case CDRTRANSFORMTYPE_UNKNOWN: break; default: return FALSE; break; } } return TRUE; } /******************************************************************************************** > BOOL CDRFilter::TransformConvertedObject(NodeRenderable **N, cdrfTransform *Trans, BOOL TranslateForPage = TRUE, BOOL IsAGroupTransform = FALSE, BOOL WorkAtOrigin = FALSE) Author: Ben_Summers (Xara Group Ltd) Created: 25 03 95 Inputs: the node to transform, and the trfd chunk to transform it by Returns: error flag Purpose: transforms an object we converted, given a trfd chunk. If TranslateForPage is true (defaults to TRUE) then the object will also be translated to get the origin in the right place. The pointer may be modified to be a pointer to a different object. WorkAtOrigin causes the object to be translated back to the origin before being hacked apon, except if it's in a CDR3 file when it's ignored as the file is mass-translated at the end of the conversion.. SeeAlso: Filter ********************************************************************************************/ BOOL CDRFilter::TransformConvertedObject(NodeRenderable **N, ADDR Trans, INT32 Size, BOOL TranslateForPage, BOOL IsAGroupTransform, BOOL WorkAtOrigin) { if(IsText) { (*N)->OptimiseAttributes(); } // make sure the WorkAtOrigin flag is set correctly - we mustn't use it if we're fiddling with a v3 file if(Version == CDRVERSION_3) WorkAtOrigin = FALSE; // transform it back to the origin if necessary if(WorkAtOrigin) { Trans2DMatrix Trans(-TranslateByX, -TranslateByY); (*N)->Transform(Trans); } // set up a transform conversion object CDRTransformConvertor *Conv; // putting the convertors here is probably more efficicent than allocating // a new one in the heap as they're not very big at all CDRTransformConvertor5 Conv5; CDRTransformConvertor4 Conv4; CDRTransformConvertor3 Conv3; switch(Version) { case CDRVERSION_5: Conv = &Conv5; break; case CDRVERSION_4: Conv = &Conv4; break; case CDRVERSION_3: Conv = &Conv3; break; default: return FALSE; break; } // initialise the convertor object Conv->Init(Trans, Size); // note that these elements are in Corel order cdrMatrix Ma, Mb, Mt; BOOL HaveMatrix = FALSE; BOOL ApplyMatrices = IsAGroupTransform?FALSE:TRUE; #ifdef CDR_DOEXTRUDE for(UINT32 g = 0; g < Conv->GetNTransforms(); g++) { CDRTransformType Type = Conv->GetTransformType(t); if(Type == CDRTRANSFORMTYPE_EXTRUDE) ApplyMatrices = FALSE; } #endif // apply all the transformations in the chunk for(UINT32 t = 0; t < Conv->GetNTransforms(); t++) { CDRTransformType Type = Conv->GetTransformType(t); // check that the transform is something we know about if(Type == CDRTRANSFORMTYPE_UNKNOWN) continue; // if it's a matrix, then append it to the previous one, if any if(Type == CDRTRANSFORMTYPE_MATRIX) { if(ApplyMatrices) { if(HaveMatrix) { // done the first matrix, so we need get the matrix into another one and then combine. // get the matrix if(!Conv->GetMatrix(&Mb, t)) return FALSE; // and combine it with the matrix we've already got Mt.a = (Ma.a * Mb.a) + (Ma.d * Mb.b); Mt.b = (Ma.b * Mb.a) + (Ma.e * Mb.b); Mt.c = (Ma.c * Mb.a) + (Ma.f * Mb.b) + Mb.c; Mt.d = (Ma.a * Mb.d) + (Ma.d * Mb.e); Mt.e = (Ma.b * Mb.d) + (Ma.e * Mb.e); Mt.f = (Ma.c * Mb.d) + (Ma.f * Mb.e) + Mb.f; Ma = Mt; } else { // just get the matrix if(!Conv->GetMatrix(&Ma, t)) return FALSE; HaveMatrix = TRUE; } } } else { // wasn't a matrix - apply a matrix if we've got one if(HaveMatrix) { // apply it if(!ApplyMatrices) { if(!TransformConvertedObjectDoMatrix(N, &Ma, FALSE)) return FALSE; } } // unset the flag HaveMatrix = FALSE; // deal with the transformation ERROR3IF(Type == CDRTRANSFORMTYPE_MATRIX, "Matrix got through in TransformConvertedObject") switch(Type) { case CDRTRANSFORMTYPE_PERSPECTIVE: { // convert the perpective cdrPerspective P; if(!Conv->GetPerspective(&P, t)) return FALSE; // apply it to the object if(!TransformConvertedObjectDoPerspective(N, &P, IsAGroupTransform)) return FALSE; } break; case CDRTRANSFORMTYPE_ENVELOPE: if(!(Version != CDRVERSION_3 && IsTextStory)) // text stories don't get enveloped - this is used as the frame shape { // convert the envelope into a path DocRect OBBox; Path *Shape = 0; INT32 Corners[4]; if(Conv->GetEnvelope(&Shape, &OBBox, (INT32 *)&Corners, t)) { // apply to object if(!TransformConvertedObjectDoEnvelope(N, Shape, &OBBox, (INT32 *)&Corners, IsAGroupTransform)) return FALSE; // delete the shape delete Shape; } } break; case CDRTRANSFORMTYPE_EXTRUDE: { cdrExtrudeInfo Info; if(Conv->GetExtrude(&Info, t)) { // apply to object if(!TransformConvertedObjectDoExtrude(N, &Info, IsAGroupTransform)) return FALSE; } ApplyMatrices = TRUE; // start applying the matrices... } break; default: break; } if(Version == CDRVERSION_5) { // we want to apply matrices from now on ApplyMatrices = TRUE; } } } // if we've got a matrix still to do... if(HaveMatrix) { // apply it if(ApplyMatrices) { if(!TransformConvertedObjectDoMatrix(N, &Ma, TranslateForPage)) return FALSE; } } else if(!HaveMatrix && TranslateForPage) { // we need to apply an identity matrix which then gets translated, but only if we need to cdrMatrix Mi = {1, 0, 0, 0, 1, 0}; // apply it if(!TransformConvertedObjectDoMatrix(N, &Mi, TranslateForPage)) return FALSE; } // reverse the effect of the previous translation if(WorkAtOrigin) { Trans2DMatrix Trans(TranslateByX, TranslateByY); (*N)->Transform(Trans); } return TRUE; } /******************************************************************************************** > BOOL CDRFilter::TransformConvertedObjectDoMatrix(NodeRenderable **N, cdrMatrix *Ma, BOOL TranslateForPage) Author: Ben_Summers (Xara Group Ltd) Created: 18/05/95 Inputs: the node to transform, and the trfd chunk to transform it by Returns: error flag Purpose: transforms an object given a CDR matrix SeeAlso: Filter ********************************************************************************************/ BOOL CDRFilter::TransformConvertedObjectDoMatrix(NodeRenderable **N, cdrMatrix *Ma, BOOL TranslateForPage) { // make a camelot matrix Matrix M(Ma->a, Ma->d, Ma->b, Ma->e, (INT32)Ma->c + (TranslateForPage?TranslateByX:0), (INT32)Ma->f + (TranslateForPage?TranslateByY:0)); // if it's a text story node, then it needs to be dealt with differently, and it's got // an associated bounding box which need transforming if(IS_A(*N, TextStory)) { // find it's bounding box DocRect *BBox = TextBBoxes.Find(*N); // transform it with the unmodifed matrix Trans2DMatrix TTransform(M); if(BBox != 0) TTransform.GetMatrix().TransformBounds(BBox); // if it's a text story, not just an artisitic text then don't scale it, but scale the import width if(IsTextStory) { // work out the scale factors along the axes double ScaleX = sqrt((Ma->a * Ma->a) + (Ma->b * Ma->b)); double ScaleY = sqrt((Ma->d * Ma->d) + (Ma->e * Ma->e)); // knock up a new matrix which isn't scaled along these axes M = Matrix(Ma->a / ScaleX, Ma->d / ScaleY, Ma->b / ScaleX, Ma->e / ScaleY, (INT32)Ma->c + (TranslateForPage?TranslateByX:0), (INT32)Ma->f + (TranslateForPage?TranslateByY:0)); // get the import format width scaled nicely TextStory *TSNode = (TextStory *)(*N); double Width = ((double)TSNode->GetImportFormatWidth()) * ScaleX; TSNode->SetImportFormatWidth((INT32)Width); } } // transform the node Trans2DMatrix Transform(M); (*N)->Transform(Transform); return TRUE; } /******************************************************************************************** > CDRFilter::TransformConvertedObjectDoPerspective(NodeRenderable *N, cdrPerspective *P, BOOL TranslateShapeForPage = FALSE) Author: Ben_Summers (Xara Group Ltd) Created: 18/05/95 Inputs: the node to transform, and the trfd chunk to transform it by Returns: error flag Purpose: transforms an object given a CDR perspective SeeAlso: Filter ********************************************************************************************/ #define PERS_MOVE(co) {if(!pShape->InkPath.InsertMoveTo(co)) return FALSE;} #define PERS_LINE(co) {if(!pShape->InkPath.InsertLineTo(co)) return FALSE;} #define PERS_CLOSE {if(!pShape->InkPath.CloseSubPath()) return FALSE;} BOOL CDRFilter::TransformConvertedObjectDoPerspective(NodeRenderable **N, cdrPerspective *P, BOOL TranslateShapeForPage) { TRACEUSER( "Ben", _T("applying perspective\n")); // create a mould parent and insert it in the tree NodeMould* pMouldParent = new NodeMould; if (pMouldParent == 0) return FALSE; // give the parent mould object a shape and mould space to work with and stick it // in the tree if(!pMouldParent->CreateGeometry(MOULDSPACE_PERSPECTIVE)) { delete pMouldParent; return FALSE; } // create a nice shape to mould into NodePath *pShape = new NodePath; if(pShape == 0 || (!pShape->SetUpPath())) { delete pMouldParent; return FALSE; } // position the new elements at the beginning of the path pShape->InkPath.FindStartOfPath(); // make a nice shape out of the corners DocCoord co; PERS_MOVE(P->NewCorners[0]) PERS_LINE(P->NewCorners[1]) PERS_LINE(P->NewCorners[2]) PERS_LINE(P->NewCorners[3]) PERS_LINE(P->NewCorners[0]) PERS_CLOSE // maybe translate it a bit DocRect OriginalBBox = P->OriginalBBox; if(TranslateShapeForPage) { Trans2DMatrix Transform(Matrix(TranslateByX, TranslateByY)); pShape->Transform(Transform); OriginalBBox.Translate(TranslateByX, TranslateByY); } // Create and add a mould shape object NodeMouldPath* pNodeMPath = pMouldParent->AddNewMouldShape(&pShape->InkPath, 0, NULL); if (!pNodeMPath) return FALSE; // set the geometry using this new mould shape if(!pMouldParent->GetGeometry()->Define(&(pNodeMPath->InkPath), &OriginalBBox)) return FALSE; // now create the mould group object NodeMouldGroup* pMouldGroup = pMouldParent->AddNewMouldGroup(NULL); if (!pMouldGroup) return FALSE; // and attach the node to the molder group (*N)->AttachNode((Node *) pMouldGroup, FIRSTCHILD, FALSE); // set the node to the converted one *N = pMouldParent; // delete the shape delete pShape; return TRUE; } /******************************************************************************************** > BOOL CDRFilter::TransformConvertedObjectDoEnvelope(NodeRenderable **N, Path *P, DocRect *OriginalBBox, INT32 *Corners, BOOL TranslateShapeForPage = FALSE); Author: Ben_Summers (Xara Group Ltd) Created: 23/05/95 Inputs: the node to transform, and the trfd chunk to transform it by Returns: error flag Purpose: transforms an object given a path to envelope into SeeAlso: Filter ********************************************************************************************/ BOOL CDRFilter::TransformConvertedObjectDoEnvelope(NodeRenderable **N, Path *P, DocRect *pOriginalBBox, INT32 *Corners, BOOL TranslateShapeForPage) { TRACEUSER( "Ben", _T("applying envelope\n")); // create a mould parent and insert it in the tree NodeMould* pMouldParent = new NodeMould; if (pMouldParent == 0) return FALSE; // give the parent mould object a shape and mould space to work with and stick it // in the tree if(!pMouldParent->CreateGeometry(MOULDSPACE_ENVELOPE)) { delete pMouldParent; return FALSE; } // validate the path a bit, and get a good one if this is duff Path *Shape = P; UINT32 errID; if(pMouldParent->GetGeometry()->Validate(Shape,errID) == FALSE) { // OK, it's not suitiable so try to create an approximation which is Path *NewShape; if(!pMouldParent->GetGeometry()->MakeValidFrom(&NewShape, Shape, Corners)) { // couldn't make a proper one, so return TRUE to ignore the moulding return TRUE; } Shape = NewShape; // inc count of approximated envelopes so the user can be warned later EnvelopesApproximated++; } // maybe translate it a bit DocRect OriginalBBox = *pOriginalBBox; if(TranslateShapeForPage) { Shape->Translate(TranslateByX, TranslateByY); OriginalBBox.Translate(TranslateByX, TranslateByY); } // Create and add a mould shape object NodeMouldPath* pNodeMPath = pMouldParent->AddNewMouldShape(Shape, 0, NULL); if (!pNodeMPath) return FALSE; // set the geometry using this new mould shape if(!pMouldParent->GetGeometry()->Define(&(pNodeMPath->InkPath), &OriginalBBox)) return FALSE; // now create the mould group object NodeMouldGroup* pMouldGroup = pMouldParent->AddNewMouldGroup(NULL); if (!pMouldGroup) return FALSE; // and attach the node to the molder group (*N)->AttachNode((Node *) pMouldGroup, FIRSTCHILD, FALSE); // set the node to the converted one *N = pMouldParent; // delete any created paths if(Shape != P) delete Shape; return TRUE; } /******************************************************************************************** > BOOL CDRFilter::TransformConvertedObjectDoExtrude(NodeRenderable **N, cdrExtrudeInfo *Info, BOOL TranslateShapeForPage = FALSE); Author: Ben_Summers (Xara Group Ltd) Created: 08/01/96 Inputs: node to transform, extrude info Returns: error flag Purpose: performs a extrude transform SeeAlso: CDRFilter ********************************************************************************************/ BOOL CDRFilter::TransformConvertedObjectDoExtrude(NodeRenderable **N, cdrExtrudeInfo *Info, BOOL TranslateShapeForPage) { // the plan here is to create a new group, and slap the node onto it (it could possibly be // a group with lots of other stuff under it, but we won't worry about that for the moment) // Then, wander down the sub-tree attempting to convert all NodeRenderableInk object into // NodePaths. This will hopefully result in a load of object which can then be transformed // first, get one of them there group thingynesseses. NodeGroup *pTempGroup = new NodeGroup; if(pTempGroup == 0) return FALSE; // no room, oh dear. // now attach the thing to it. It isn't attached to anything, so it's easy. (*N)->AttachNode(pTempGroup, FIRSTCHILD); // scan the tree converting non-NodePaths to NodePaths where possible BecomeA ParamBecomeA(BECOMEA_REPLACE, CC_RUNTIME_CLASS(NodePath), NULL); // find the first node to think about Node* Current = (*N); while (Current->FindFirstChild() != NULL && !(Current->FindFirstChild())->IsKindOf(CC_RUNTIME_CLASS(TextStory))) { Current = Current->FindFirstChild(); } // check each renderable node for not being a path while(Current != 0) { if(Current->IsKindOf(CC_RUNTIME_CLASS(NodeRenderableInk)) && !Current->IsKindOf(CC_RUNTIME_CLASS(NodePath))) { if (Current->CanBecomeA(&ParamBecomeA)) { // is it a text story? if (Current->IsKindOf(CC_RUNTIME_CLASS(TextStory))) { // give formatting it a go ((TextStory *)Current)->FormatAndChildren(); } if (!(Current)->DoBecomeA(&ParamBecomeA)) { return FALSE; } } } // get the next one Current = Current->FindNextDepthFirst(*N); } // now wander through the tree doing the funky transform - find the first one again Current = pTempGroup; while (Current->FindFirstChild() != NULL) { Current = Current->FindFirstChild(); } // transform each NodePath while(Current != 0) { if(IS_A(Current, NodePath)) { if(!TransformConvertedObjectDoExtrudeTransPath((NodePath *)Current, Info)) return FALSE; // something very wrong happened } // get the next one Current = Current->FindNextDepthFirst(pTempGroup); } // update the *N pointer to the node (*N) = (NodeRenderable *)pTempGroup->FindFirstChild(); ERROR2IF((*N) == 0, FALSE, "Oi! there that node just vanished"); ERROR2IF(!(*N)->IsKindOf(CC_RUNTIME_CLASS(NodeRenderable)), FALSE, "Oh! Mr. Node changing into something non-renderable"); // remove it from the group (*N)->UnlinkNodeFromTree(); // finally, vape that temperary group delete pTempGroup; return TRUE; } /******************************************************************************************** > BOOL CDRFilter::TransformConvertedObjectDoExtrudeTransPath(NodePath *pPath, cdrExtrudeInfo *Info) Author: Ben_Summers (Xara Group Ltd) Created: 09/01/96 Inputs: path to transform, info about the transform Returns: error flag Purpose: does the extrude transform on a path SeeAlso: CDRFilter ********************************************************************************************/ BOOL CDRFilter::TransformConvertedObjectDoExtrudeTransPath(NodePath *pPath, cdrExtrudeInfo *Info) { // check the inputs ERROR2IF(pPath == 0 || Info == 0, FALSE, "Null something supplied where a raspberry is required"); ERROR2IF(!IS_A(pPath, NodePath), FALSE, "Oi! I asked for a NodePath you silly person"); // get some useful info about that there path DocCoord *Coords = pPath->InkPath.GetCoordArray(); ERROR2IF(Coords == 0, FALSE, "Hmmm. I think that path is a bit of a dodgy one really"); INT32 NCoords = pPath->InkPath.GetNumCoords(); // mild sanity check... if(Info->Camera.z == 0) return TRUE; // don't try this one at home, kiddies // prepare a few handy values FLOAT8 projA = - Info->Camera.x / Info->Camera.z; FLOAT8 projB = - Info->Camera.y / Info->Camera.z; FLOAT8 projC = - 1 / Info->Camera.z; // run through that path transforming all those lovely cheeky little coordinates for(INT32 c = 0; c < NCoords; c++) { FLOAT8 x = (FLOAT8)Coords[c].x, y = (FLOAT8)Coords[c].y; FLOAT8 alpha = x * Info->Trans.cf11 + y * Info->Trans.cf21 + Info->Trans.cf41; FLOAT8 beta = x * Info->Trans.cf12 + y * Info->Trans.cf22 + Info->Trans.cf42; FLOAT8 gamma = x * Info->Trans.cf13 + y * Info->Trans.cf23 + Info->Trans.cf43; FLOAT8 norm = gamma * projC + 1; Coords[c].x = (INT32)((alpha + gamma * projA) / norm); Coords[c].y = (INT32)((beta + gamma * projB) / norm); } // well, wasn't that squishy? return TRUE; } /******************************************************************************************** > BOOL CDRTransformConvertor5::Init(ADDR Data, INT32 Size) Author: Ben_Summers (Xara Group Ltd) Created: 06/06/95 Inputs: pointer to trfl list and it's size Returns: whether the contents are OK Purpose: intialises this convertor SeeAlso: CDRFilter ********************************************************************************************/ BOOL CDRTransformConvertor5::Init(ADDR Data, INT32 Size) { List = Data; ListSize = Size; ADDR TransformData; if(!RIFFFile::FindChunkWithinListContents(List, ListSize, cdrT_trfd, 0, &TransformData, 0)) return 0; Trans = (cdrfTransform *)TransformData; return TRUE; } /******************************************************************************************** > BOOL CDRTransformConvertor4::Init(ADDR Data, INT32 Size) Author: Ben_Summers (Xara Group Ltd) Created: 06/06/95 Inputs: pointer to trfl list and it's size Returns: whether the contents are OK Purpose: intialises this convertor SeeAlso: CDRFilter ********************************************************************************************/ BOOL CDRTransformConvertor4::Init(ADDR Data, INT32 Size) { List = Data; ListSize = Size; ADDR TransformData; if(!RIFFFile::FindChunkWithinListContents(List, ListSize, cdrT_trfd, 0, &TransformData, 0)) return 0; Trans = (cdrfTransformV4 *)TransformData; return TRUE; } /******************************************************************************************** > CDRTransformType CDRTransformConvertor5::GetTransformType(UINT32 n) Author: Ben_Summers (Xara Group Ltd) Created: 26 03 95 Inputs: transform number Returns: a transform type Purpose: gets a transform type from an trfd chunk SeeAlso: CDRFilter ********************************************************************************************/ CDRTransformType CDRTransformConvertor5::GetTransformType(UINT32 n) { if(n >= CDRDATA_WORD(Trans->NTransforms)) return CDRTRANSFORMTYPE_UNKNOWN; cdrfTransformHeader *Hdr = (cdrfTransformHeader *)(((ADDR)Trans) + CDRDATA_WORD(Trans->TransformOffsets[n])); switch(CDRDATA_WORD(Hdr->Type)) { case cdrfTRANSFORMTYPE_MATRIX: return CDRTRANSFORMTYPE_MATRIX; break; case cdrfTRANSFORMTYPE_PERSPECTIVE: return CDRTRANSFORMTYPE_PERSPECTIVE; break; #ifdef CDR_DOEXTRUDE case cdrfTRANSFORMTYPE_EXTRUDE: return CDRTRANSFORMTYPE_EXTRUDE; break; #endif case cdrfTRANSFORMTYPE_ENVELOPE: return CDRTRANSFORMTYPE_ENVELOPE; break; default: TRACEUSER( "Ben", _T("[] Unknown v5 transform type\n")); break; } return CDRTRANSFORMTYPE_UNKNOWN; } /******************************************************************************************** > CDRTransformType CDRTransformConvertor4::GetTransformType(UINT32 n) Author: Ben_Summers (Xara Group Ltd) Created: 26 03 95 Inputs: transform number Returns: a transform type Purpose: gets a transform type from an trfd chunk SeeAlso: CDRFilter ********************************************************************************************/ CDRTransformType CDRTransformConvertor4::GetTransformType(UINT32 n) { if(n >= CDRDATA_WORD(Trans->NTransforms)) return CDRTRANSFORMTYPE_UNKNOWN; WORD *Offsets = (WORD *)(((ADDR)Trans) + CDRDATA_WORD(Trans->OffsetsStart)); cdrfTransformHeader *Hdr = (cdrfTransformHeader *)(((ADDR)Trans) + CDRDATA_WORD(Offsets[n])); switch(CDRDATA_WORD(Hdr->Type)) { case cdrfTRANSFORMTYPE_MATRIX: return CDRTRANSFORMTYPE_MATRIX; break; case cdrfTRANSFORMTYPE_PERSPECTIVE: return CDRTRANSFORMTYPE_PERSPECTIVE; break; #ifdef CDR_DOEXTRUDE case cdrfTRANSFORMTYPE_EXTRUDE: return CDRTRANSFORMTYPE_EXTRUDE; break; #endif case cdrfTRANSFORMTYPE_ENVELOPE: return CDRTRANSFORMTYPE_ENVELOPE; break; default: TRACEUSER( "Ben", _T("[] Unknown v4 transform type\n")); break; } return CDRTRANSFORMTYPE_UNKNOWN; } /******************************************************************************************** > BOOL CDRTransformConvertor5::GetMatrix(cdrMatrix *M, UINT32 n) Author: Ben_Summers (Xara Group Ltd) Created: 26 03 95 Inputs: matrix to convert into, transform number Returns: a transform type Purpose: converts a matrix from position N SeeAlso: CDRFilter ********************************************************************************************/ BOOL CDRTransformConvertor5::GetMatrix(cdrMatrix *M, UINT32 n) { if(n >= CDRDATA_WORD(Trans->NTransforms)) return FALSE; cdrfTransformHeader *Hdr = (cdrfTransformHeader *)(((ADDR)Trans) + CDRDATA_WORD(Trans->TransformOffsets[n])); ERROR3IF(CDRDATA_WORD(Hdr->Type) != cdrfTRANSFORMTYPE_MATRIX, "GetMatrix called for a non matrix trfd entry"); ERROR3IF((sizeof(FLOAT8) / 2) != sizeof(DWORD) || sizeof(DWORD) != 4, "Non valid sizeof assumptions"); // OK, so apparently either PCs or Acorns store them the wrong way round. Oh well. FLOAT8 *TData = (FLOAT8 *)(Hdr + 1); FLOAT8 *Out = (FLOAT8 *)M; INT32 l; for(l = 0; l < 6; l++) { Out[l] = CDRDATA_FLOAT8(TData[l]); } // change the translation vector to be in millipoints M->c *= CDRCOORDS_TO_MILLIPOINTS; M->f *= CDRCOORDS_TO_MILLIPOINTS; return TRUE; } /******************************************************************************************** > BOOL CDRTransformConvertor::ConvertPerspective(cdrPerspective *P, cdrfPerspectiveTransform *Trans) Author: Ben_Summers (Xara Group Ltd) Created: 18/05/95 Inputs: perspective to convert into, transform number Returns: a transform type Purpose: converts corel perspective - used by all the convertors SeeAlso: CDRFilter ********************************************************************************************/ BOOL CDRTransformConvertor::ConvertPerspective(cdrPerspective *P, cdrfPerspectiveTransform *Tran) { // knock up the bbox INT32 x0, y0, y1, x1; x0 = CDRDATA_SWORD(Tran->Ox0) * CDRCOORDS_TO_MILLIPOINTS; y0 = CDRDATA_SWORD(Tran->Oy0) * CDRCOORDS_TO_MILLIPOINTS; x1 = CDRDATA_SWORD(Tran->Ox1) * CDRCOORDS_TO_MILLIPOINTS; y1 = CDRDATA_SWORD(Tran->Oy1) * CDRCOORDS_TO_MILLIPOINTS; if(x0 > x1) { INT32 t = x1; x1 = x0; x0 = t; } if(y0 > y1) { INT32 t = y1; y1 = y0; y0 = t; } P->OriginalBBox.lo.x = x0; P->OriginalBBox.lo.y = y0; P->OriginalBBox.hi.x = x1; P->OriginalBBox.hi.y = y1; // and the new corners for(INT32 l = 0; l < 4; l++) { P->NewCorners[l].x = CDRDATA_SWORD(Tran->NewCorners[l].X) * CDRCOORDS_TO_MILLIPOINTS; P->NewCorners[l].y = CDRDATA_SWORD(Tran->NewCorners[l].Y) * CDRCOORDS_TO_MILLIPOINTS; } return TRUE; } /******************************************************************************************** > BOOL CDRTransformConvertor5::GetPerspective(cdrPerspective *P, UINT32 n) Author: Ben_Summers (Xara Group Ltd) Created: 18/05/95 Inputs: perspective to convert into, transform number Returns: a transform type Purpose: converts a perspective from position N SeeAlso: CDRFilter ********************************************************************************************/ BOOL CDRTransformConvertor5::GetPerspective(cdrPerspective *P, UINT32 n) { if(n >= CDRDATA_WORD(Trans->NTransforms)) return FALSE; cdrfTransformHeader *Hdr = (cdrfTransformHeader *)(((ADDR)Trans) + CDRDATA_WORD(Trans->TransformOffsets[n])); ERROR3IF(CDRDATA_WORD(Hdr->Type) != cdrfTRANSFORMTYPE_PERSPECTIVE, "GetPerspective called for a non matrix trfd entry"); cdrfPerspectiveEntry *Per = (cdrfPerspectiveEntry *)Hdr; return ConvertPerspective(P, &Per->Trans); } /******************************************************************************************** > BOOL CDRTransformConvertor4::GetPerspective(cdrPerspective *P, UINT32 n) Author: Ben_Summers (Xara Group Ltd) Created: 18/05/95 Inputs: perspective to convert into, transform number Returns: a transform type Purpose: converts a perspective from position N SeeAlso: CDRFilter ********************************************************************************************/ BOOL CDRTransformConvertor4::GetPerspective(cdrPerspective *P, UINT32 n) { if(n >= Trans->NTransforms) return FALSE; WORD *Offsets = (WORD *)(((ADDR)Trans) + Trans->OffsetsStart); cdrfTransformHeader *Hdr = (cdrfTransformHeader *)(((ADDR)Trans) + Offsets[n]); ERROR3IF(Hdr->Type != cdrfTRANSFORMTYPE_PERSPECTIVE, "GetPerspective called for a non matrix trfd entry"); cdrfPerspectiveEntry *Per = (cdrfPerspectiveEntry *)Hdr; return ConvertPerspective(P, & Per->Trans); } /******************************************************************************************** > CDRTransformType CDRTransformConvertor4::GetMatrix(cdrMatrix *M, UINT32 n) Author: Ben_Summers (Xara Group Ltd) Created: 26 03 95 Inputs: matrix to convert into, transform number Returns: a transform type Purpose: converts a matrix from position N SeeAlso: CDRFilter ********************************************************************************************/ BOOL CDRTransformConvertor4::GetMatrix(cdrMatrix *M, UINT32 n) { if(n >= Trans->NTransforms) return FALSE; WORD *Offsets = (WORD *)(((ADDR)Trans) + Trans->OffsetsStart); cdrfTransformHeader *Hdr = (cdrfTransformHeader *)(((ADDR)Trans) + Offsets[n]); ERROR3IF(Hdr->Type != cdrfTRANSFORMTYPE_MATRIX, "GetMatrix called for a non matrix trfd entry"); // unsigned word pointer WORD *TDataUS = (WORD *)(Hdr + 1); // signed word pointer SWORD *TDataS = (SWORD *)(Hdr + 1); // signed dword pointer SDWORD *TDDataS = (SDWORD *)(Hdr + 1); // convert the matrix - an interesting mix of 16.16 fixed point values and a // signed double word translation vector M->a = (FLOAT8)CDRDATA_SWORD(TDataS[1]) + ((FLOAT8)CDRDATA_WORD(TDataUS[0]) / 0xffff); M->b = (FLOAT8)CDRDATA_SWORD(TDataS[3]) + ((FLOAT8)CDRDATA_WORD(TDataUS[2]) / 0xffff); M->c = (FLOAT8)(CDRDATA_DSWORD(TDDataS[2]) * CDRCOORDS_TO_MILLIPOINTS); M->d = (FLOAT8)CDRDATA_SWORD(TDataS[7]) + ((FLOAT8)CDRDATA_WORD(TDataUS[6]) / 0xffff); M->e = (FLOAT8)CDRDATA_SWORD(TDataS[9]) + ((FLOAT8)CDRDATA_WORD(TDataUS[8]) / 0xffff); M->f = (FLOAT8)(CDRDATA_DSWORD(TDDataS[5]) * CDRCOORDS_TO_MILLIPOINTS); return TRUE; } /******************************************************************************************** > CDRTransformType CDRTransformConvertor3::GetTransformType(UINT32 n) Author: Ben_Summers (Xara Group Ltd) Created: 03/04/95 Inputs: transform number Returns: a transform type Purpose: gets a transform type from an trfd chunk SeeAlso: CDRFilter ********************************************************************************************/ CDRTransformType CDRTransformConvertor3::GetTransformType(UINT32 n) { if(n >= CDRDATA_WORD(Trans->NTransforms)) return CDRTRANSFORMTYPE_UNKNOWN; cdrfTransformEntryV3 *En = (cdrfTransformEntryV3 *)(Trans + 1); switch(CDRDATA_WORD(En[n].Type)) { case cdrfTRANSFORMTYPE_MATRIX_V3: return CDRTRANSFORMTYPE_MATRIX; break; case cdrfTRANSFORMTYPE_PERSPECTIVE_V3: return CDRTRANSFORMTYPE_PERSPECTIVE; break; case cdrfTRANSFORMTYPE_ENVELOPE_V3: return CDRTRANSFORMTYPE_ENVELOPE; break; #ifdef CDR_DOEXTRUDE case cdrfTRANSFORMTYPE_EXTRUDE_V3: return CDRTRANSFORMTYPE_EXTRUDE; break; #endif default: TRACEUSER( "Ben", _T("[] Unknown v3 transform type %x\n"), En[n].Type); break; } return CDRTRANSFORMTYPE_UNKNOWN; } /******************************************************************************************** > BOOL CDRTransformConvertor3::GetExtrude(cdrExtrudeInfo *Info, UINT32 n); Author: Ben_Summers (Xara Group Ltd) Created: 08/01/96 Inputs: extrude info to convert to, transform number Returns: a transform type Purpose: converts a matrix from position N SeeAlso: CDRFilter ********************************************************************************************/ BOOL CDRTransformConvertor3::GetExtrude(cdrExtrudeInfo *Info, UINT32 n) { if(n >= CDRDATA_WORD(Trans->NTransforms)) return FALSE; cdrfTransformEntryV3 *En = (cdrfTransformEntryV3 *)(Trans + 1); cdrfTransformExtrudeV3 *Data = (cdrfTransformExtrudeV3 *)(((BYTE *)Trans) + En[n].Offset); Info->Trans.cf11 = (FLOAT8)CDRDATA_SWORD(Data->cf11b) + ((FLOAT8)CDRDATA_WORD(Data->cf11a) / 0xffff); Info->Trans.cf12 = (FLOAT8)CDRDATA_SWORD(Data->cf12b) + ((FLOAT8)CDRDATA_WORD(Data->cf12a) / 0xffff); Info->Trans.cf13 = (FLOAT8)CDRDATA_SWORD(Data->cf13b) + ((FLOAT8)CDRDATA_WORD(Data->cf13a) / 0xffff); Info->Trans.cf21 = (FLOAT8)CDRDATA_SWORD(Data->cf21b) + ((FLOAT8)CDRDATA_WORD(Data->cf21a) / 0xffff); Info->Trans.cf22 = (FLOAT8)CDRDATA_SWORD(Data->cf22b) + ((FLOAT8)CDRDATA_WORD(Data->cf22a) / 0xffff); Info->Trans.cf23 = (FLOAT8)CDRDATA_SWORD(Data->cf23b) + ((FLOAT8)CDRDATA_WORD(Data->cf23a) / 0xffff); Info->Trans.cf31 = (FLOAT8)CDRDATA_SWORD(Data->cf31b) + ((FLOAT8)CDRDATA_WORD(Data->cf31a) / 0xffff); Info->Trans.cf32 = (FLOAT8)CDRDATA_SWORD(Data->cf32b) + ((FLOAT8)CDRDATA_WORD(Data->cf32a) / 0xffff); Info->Trans.cf33 = (FLOAT8)CDRDATA_SWORD(Data->cf33b) + ((FLOAT8)CDRDATA_WORD(Data->cf33a) / 0xffff); Info->Trans.cf41 = (FLOAT8)CDRDATA_FLOAT4(Data->f41); Info->Trans.cf42 = (FLOAT8)CDRDATA_FLOAT4(Data->f42); Info->Trans.cf43 = (FLOAT8)CDRDATA_FLOAT4(Data->f43); Info->Camera.x = CDRDATA_SWORD(Data->Cx) * CDRCOORDS_TO_MILLIPOINTS; Info->Camera.y = CDRDATA_SWORD(Data->Cy) * CDRCOORDS_TO_MILLIPOINTS; Info->Camera.z = CDRDATA_DWORD(Data->Cz) * CDRCOORDS_TO_MILLIPOINTS; return TRUE; } /******************************************************************************************** > BOOL CDRTransformConvertor::ConvertExtrudeInfo(cdrfTransformExtrude *pTransform, cdrExtrudeInfo *pInfo) Author: Ben_Summers (Xara Group Ltd) Created: 12/01/96 Inputs: pointer to transform from file, extrude info to convert to Returns: error flag Purpose: converts an extrude thingy from a v4,5,6 file SeeAlso: CDRFilter ********************************************************************************************/ BOOL CDRTransformConvertor::ConvertExtrudeInfo(cdrfTransformExtrude *pTransform, cdrExtrudeInfo *Info) { Info->Trans.cf11 = (FLOAT8)CDRDATA_SWORD(pTransform->cf11b) + ((FLOAT8)CDRDATA_WORD(pTransform->cf11a) / 0xffff); Info->Trans.cf12 = (FLOAT8)CDRDATA_SWORD(pTransform->cf12b) + ((FLOAT8)CDRDATA_WORD(pTransform->cf12a) / 0xffff); Info->Trans.cf13 = (FLOAT8)CDRDATA_SWORD(pTransform->cf13b) + ((FLOAT8)CDRDATA_WORD(pTransform->cf13a) / 0xffff); Info->Trans.cf21 = (FLOAT8)CDRDATA_SWORD(pTransform->cf21b) + ((FLOAT8)CDRDATA_WORD(pTransform->cf21a) / 0xffff); Info->Trans.cf22 = (FLOAT8)CDRDATA_SWORD(pTransform->cf22b) + ((FLOAT8)CDRDATA_WORD(pTransform->cf22a) / 0xffff); Info->Trans.cf23 = (FLOAT8)CDRDATA_SWORD(pTransform->cf23b) + ((FLOAT8)CDRDATA_WORD(pTransform->cf23a) / 0xffff); Info->Trans.cf31 = (FLOAT8)CDRDATA_SWORD(pTransform->cf31b) + ((FLOAT8)CDRDATA_WORD(pTransform->cf31a) / 0xffff); Info->Trans.cf32 = (FLOAT8)CDRDATA_SWORD(pTransform->cf32b) + ((FLOAT8)CDRDATA_WORD(pTransform->cf32a) / 0xffff); Info->Trans.cf33 = (FLOAT8)CDRDATA_SWORD(pTransform->cf33b) + ((FLOAT8)CDRDATA_WORD(pTransform->cf33a) / 0xffff); Info->Trans.cf41 = (FLOAT8)CDRDATA_DWORD(pTransform->f41); Info->Trans.cf42 = (FLOAT8)CDRDATA_DWORD(pTransform->f42); Info->Trans.cf43 = (FLOAT8)CDRDATA_DWORD(pTransform->f43); Info->Camera.x = CDRDATA_SWORD(pTransform->Cx) * CDRCOORDS_TO_MILLIPOINTS; Info->Camera.y = CDRDATA_SWORD(pTransform->Cy) * CDRCOORDS_TO_MILLIPOINTS; Info->Camera.z = CDRDATA_DWORD(pTransform->Cz) * CDRCOORDS_TO_MILLIPOINTS; return TRUE; } /******************************************************************************************** > BOOL CDRTransformConvertor4::GetExtrude(cdrExtrudeInfo *Info, UINT32 n); Author: Ben_Summers (Xara Group Ltd) Created: 08/01/96 Inputs: extrude info to convert to, transform number Returns: a transform type Purpose: converts a matrix from position N SeeAlso: CDRFilter ********************************************************************************************/ BOOL CDRTransformConvertor4::GetExtrude(cdrExtrudeInfo *Info, UINT32 n) { if(n >= Trans->NTransforms) return FALSE; WORD *Offsets = (WORD *)(((ADDR)Trans) + Trans->OffsetsStart); cdrfTransformHeader *Hdr = (cdrfTransformHeader *)(((ADDR)Trans) + Offsets[n]); return ConvertExtrudeInfo((cdrfTransformExtrude *)Hdr, Info); } /******************************************************************************************** > BOOL CDRTransformConvertor5::GetExtrude(cdrExtrudeInfo *Info, UINT32 n); Author: Ben_Summers (Xara Group Ltd) Created: 08/01/96 Inputs: extrude info to convert to, transform number Returns: a transform type Purpose: converts a matrix from position N SeeAlso: CDRFilter ********************************************************************************************/ BOOL CDRTransformConvertor5::GetExtrude(cdrExtrudeInfo *Info, UINT32 n) { if(n >= CDRDATA_WORD(Trans->NTransforms)) return FALSE; cdrfTransformHeader *Hdr = (cdrfTransformHeader *)(((ADDR)Trans) + CDRDATA_WORD(Trans->TransformOffsets[n])); return ConvertExtrudeInfo((cdrfTransformExtrude *)Hdr, Info); } /******************************************************************************************** > CDRTransformType CDRTransformConvertor3::GetMatrix(cdrMatrix *M, UINT32 n) Author: Ben_Summers (Xara Group Ltd) Created: 03/04/95 Inputs: matrix to convert into, transform number Returns: a transform type Purpose: converts a matrix from position N SeeAlso: CDRFilter ********************************************************************************************/ BOOL CDRTransformConvertor3::GetMatrix(cdrMatrix *M, UINT32 n) { if(n >= CDRDATA_WORD(Trans->NTransforms)) return FALSE; cdrfTransformEntryV3 *En = (cdrfTransformEntryV3 *)(Trans + 1); BYTE *Data = ((BYTE *)Trans) + En[n].Offset; // unsigned word pointer WORD *TDataUS = (WORD *)Data; // signed word pointer SWORD *TDataS = (SWORD *)Data; // signed dword pointer SDWORD *TDDataS = (SDWORD *)Data; // convert the matrix - an interesting mix of 16.16 fixed point values and a // signed double word translation vector M->a = (FLOAT8)CDRDATA_SWORD(TDataS[1]) + ((FLOAT8)CDRDATA_WORD(TDataUS[0]) / 0xffff); M->b = (FLOAT8)CDRDATA_SWORD(TDataS[3]) + ((FLOAT8)CDRDATA_WORD(TDataUS[2]) / 0xffff); M->c = (FLOAT8)(CDRDATA_DSWORD(TDDataS[2]) * CDRCOORDS_TO_MILLIPOINTS); M->d = (FLOAT8)CDRDATA_SWORD(TDataS[7]) + ((FLOAT8)CDRDATA_WORD(TDataUS[6]) / 0xffff); M->e = (FLOAT8)CDRDATA_SWORD(TDataS[9]) + ((FLOAT8)CDRDATA_WORD(TDataUS[8]) / 0xffff); M->f = (FLOAT8)(CDRDATA_DSWORD(TDDataS[5]) * CDRCOORDS_TO_MILLIPOINTS); return TRUE; } /******************************************************************************************** > BOOL CDRTransformConvertor3::GetPerspective(cdrPerspective *P, UINT32 n) Author: Ben_Summers (Xara Group Ltd) Created: 18/05/95 Inputs: perspective to convert into, transform number Returns: a transform type Purpose: converts a perspective from position N SeeAlso: CDRFilter ********************************************************************************************/ BOOL CDRTransformConvertor3::GetPerspective(cdrPerspective *P, UINT32 n) { if(n >= CDRDATA_WORD(Trans->NTransforms)) return FALSE; cdrfTransformEntryV3 *En = (cdrfTransformEntryV3 *)(Trans + 1); BYTE *Data = ((BYTE *)Trans) + En[n].Offset; return ConvertPerspective(P, (cdrfPerspectiveTransform *)Data); } /******************************************************************************************** > BOOL CDRTransformConvertor::ConvertEnvelopeBBox(ADDR Entry, DocRect *BBox, INT32 *Corners) Author: Ben_Summers (Xara Group Ltd) Created: 06/06/95 Inputs: Pointer to entry in transform chunk and an output DocRect Returns: sucess Purpose: converts a envelope original bounding box SeeAlso: CDRFilter ********************************************************************************************/ BOOL CDRTransformConvertor::ConvertEnvelopeBBox(ADDR Entry, DocRect *BBox, INT32 *Corners) { // get the bounding box; cdrfTransformEnvelope *En = (cdrfTransformEnvelope *)Entry; INT32 x0, y0, y1, x1; x0 = CDRDATA_SWORD(En->Ox0) * CDRCOORDS_TO_MILLIPOINTS; y0 = CDRDATA_SWORD(En->Oy0) * CDRCOORDS_TO_MILLIPOINTS; x1 = CDRDATA_SWORD(En->Ox1) * CDRCOORDS_TO_MILLIPOINTS; y1 = CDRDATA_SWORD(En->Oy1) * CDRCOORDS_TO_MILLIPOINTS; if(x0 > x1) { INT32 t = x1; x1 = x0; x0 = t; } if(y0 > y1) { INT32 t = y1; y1 = y0; y0 = t; } BBox->lo.x = x0; BBox->lo.y = y0; BBox->hi.x = x1; BBox->hi.y = y1; // fill in the corners for(INT32 l = 0; l < 4; l++) { Corners[l] = CDRDATA_WORD(En->Corners[l]); } return TRUE; } /******************************************************************************************** > BOOL CDRTransformConvertor::ConvertEnvelopePath(ADDR List, INT32 ListSize, INT32 Entry, Path **ppPath); Author: Ben_Summers (Xara Group Ltd) Created: 06/06/95 Inputs: pointer to list, list size, entry number to get and a pointer to a path to fill in Returns: sucess Purpose: converts a envelope path SeeAlso: CDRFilter ********************************************************************************************/ BOOL CDRTransformConvertor::ConvertEnvelopePath(ADDR List, INT32 ListSize, INT32 Entry, Path **ppPath) { // find the envd chunk we're interested in ADDR Chunk; INT32 ChunkSize; if(!RIFFFile::FindChunkWithinListContents(List, ListSize, cdrT_envd, Entry, &Chunk, &ChunkSize)) return FALSE; // right, got the thingy... cdrfOffsetHeader *Hdr = (cdrfOffsetHeader *)Chunk; INT32 NCoords = CDRDATA_WORD(Hdr->ObjectType); // hold the number of coords... // find the things within the chunk ADDR Coords = CDRFilter::FindDataInObject(Hdr, cdrfENVELOPEOFFSETTYPE_COORDS); ADDR Types = CDRFilter::FindDataInObject(Hdr, cdrfENVELOPEOFFSETTYPE_TYPES); if(Coords == 0 || Types == 0) return FALSE; // make a path from this all... // knock up a path node Path *pPath = new Path; if(pPath == 0 || (!pPath->Initialise())) { delete pPath; return FALSE; // no room to create it } // position the new elements at the beginning of the path pPath->FindStartOfPath(); if(!CDRFilter::AddElementsToPath(pPath, NCoords, (cdrfCoord *)Coords, Types, 0)) return FALSE; // check that the path is OK if(!pPath->EnsureValid()) { // no, it's completely knackered delete pPath; return FALSE; } // return it... (*ppPath) = pPath; return TRUE; } /******************************************************************************************** > BOOL CDRTransformConvertor5::GetEnvelope(Path **P, DocRect *OriginalBBox, INT32 *Corners, UINT32 n) Author: Ben_Summers (Xara Group Ltd) Created: 23/05/95 Inputs: pointer to a pointer to a nodepath to fill in, a docrect for the orignial BBox and the position Returns: a transform type Purpose: converts a envelope from position N SeeAlso: CDRFilter ********************************************************************************************/ BOOL CDRTransformConvertor5::GetEnvelope(Path **P, DocRect *OriginalBBox, INT32 *Corners, UINT32 n) { if(n >= CDRDATA_WORD(Trans->NTransforms)) return FALSE; cdrfTransformHeader *Hdr; // run through to this entry counting the number of entries before this one INT32 EnvelopesSoFar = 0; for(UINT32 l = 0; l <= n; l++) { Hdr = (cdrfTransformHeader *)(((ADDR)Trans) + CDRDATA_WORD(Trans->TransformOffsets[l])); // increment the number of envelopes so far... if(CDRDATA_WORD(Hdr->Type) == cdrfTRANSFORMTYPE_ENVELOPE) EnvelopesSoFar++; } ERROR2IF(EnvelopesSoFar <= 0, FALSE, "No envelopes found!"); // OK, convert this entry... if(!ConvertEnvelopeBBox((ADDR)Hdr, OriginalBBox, Corners)) return FALSE; if(!ConvertEnvelopePath(List, ListSize, EnvelopesSoFar - 1, P)) return FALSE; return TRUE; } /******************************************************************************************** > BOOL CDRTransformConvertor4::GetEnvelope(Path **P, DocRect *OriginalBBox, INT32 *Corners, UINT32 n) Author: Ben_Summers (Xara Group Ltd) Created: 23/05/95 Inputs: pointer to a pointer to a nodepath to fill in, a docrect for the orignial BBox and the position Returns: a transform type Purpose: converts a envelope from position N SeeAlso: CDRFilter ********************************************************************************************/ BOOL CDRTransformConvertor4::GetEnvelope(Path **P, DocRect *OriginalBBox, INT32 *Corners, UINT32 n) { if(n >= CDRDATA_WORD(Trans->NTransforms)) return FALSE; cdrfTransformHeader *Hdr; WORD *Offsets = (WORD *)(((ADDR)Trans) + Trans->OffsetsStart); // run through to this entry counting the number of entries before this one INT32 EnvelopesSoFar = 0; for(UINT32 l = 0; l <= n; l++) { Hdr = (cdrfTransformHeader *)(cdrfTransformHeader *)(((ADDR)Trans) + Offsets[l]); // increment the number of envelopes so far... if(CDRDATA_WORD(Hdr->Type) == cdrfTRANSFORMTYPE_ENVELOPE) EnvelopesSoFar++; } ERROR2IF(EnvelopesSoFar <= 0, FALSE, "No envelopes found!"); // OK, convert this entry... if(!ConvertEnvelopeBBox((ADDR)Hdr, OriginalBBox, Corners)) return FALSE; if(!ConvertEnvelopePath(List, ListSize, EnvelopesSoFar - 1, P)) return FALSE; return TRUE; } /******************************************************************************************** > BOOL CDRTransformConvertor3::GetEnvelope(Path **P, DocRect *OriginalBBox, INT32 *Corners, UINT32 n) Author: Ben_Summers (Xara Group Ltd) Created: 23/05/95 Inputs: pointer to a pointer to a nodepath to fill in, a docrect for the orignial BBox and the position Returns: a transform type Purpose: converts a envelope from position N SeeAlso: CDRFilter ********************************************************************************************/ #define ENVV3_NCOORDS 25 BOOL CDRTransformConvertor3::GetEnvelope(Path **P, DocRect *OriginalBBox, INT32 *Corners, UINT32 n) { if(n >= CDRDATA_WORD(Trans->NTransforms)) return FALSE; cdrfTransformEntryV3 *En = (cdrfTransformEntryV3 *)(Trans + 1); BYTE *Data = ((BYTE *)Trans) + En[n].Offset; // make a pointer to the interesting data cdrfTransformEnvelopeV3 *Env = (cdrfTransformEnvelopeV3 *)Data; // convert the original bbox INT32 x0, y0, y1, x1; x0 = CDRDATA_SWORD(Env->Ox0) * CDRCOORDS_TO_MILLIPOINTS; y0 = CDRDATA_SWORD(Env->Oy0) * CDRCOORDS_TO_MILLIPOINTS; x1 = CDRDATA_SWORD(Env->Ox1) * CDRCOORDS_TO_MILLIPOINTS; y1 = CDRDATA_SWORD(Env->Oy1) * CDRCOORDS_TO_MILLIPOINTS; if(x0 > x1) { INT32 t = x1; x1 = x0; x0 = t; } if(y0 > y1) { INT32 t = y1; y1 = y0; y0 = t; } OriginalBBox->lo.x = x0; OriginalBBox->lo.y = y0; OriginalBBox->hi.x = x1; OriginalBBox->hi.y = y1; // get the coords DocCoord Co[ENVV3_NCOORDS]; INT32 l; for(l = 0; l < ENVV3_NCOORDS; l++) { Co[l].x = CDRDATA_SWORD(Env->Coords[l].X) * CDRCOORDS_TO_MILLIPOINTS; Co[l].y = CDRDATA_SWORD(Env->Coords[l].Y) * CDRCOORDS_TO_MILLIPOINTS; } // create the path Path *pShape = new Path; if(pShape == 0 || (!pShape->Initialise())) { delete pShape; return FALSE; } // position the new elements at the beginning of the path pShape->FindStartOfPath(); // make a nice shape out of the corners if(!pShape->InsertMoveTo(Co[0])) return FALSE; for(INT32 c = 1; c < ENVV3_NCOORDS; c += 3) { if(!pShape->InsertCurveTo(Co[c], Co[c + 1], Co[c + 2])) return FALSE; } if(!pShape->CloseSubPath()) return FALSE; *P = pShape; // fill in the corners Corners[0] = 0; Corners[1] = 6; Corners[2] = 12; Corners[3] = 18; return TRUE; } /******************************************************************************************** > BOOL CDRFilter::ClearUp(void) Author: Ben_Summers (Xara Group Ltd) Created: 21 03 95 Inputs: Returns: Purpose: Clears up after an CDR file import SeeAlso: Filter ********************************************************************************************/ BOOL CDRFilter::ClearUp(void) { Version = CDRVERSION_NULL; if(SlowJobStarted == TRUE) EndSlowJob(); if(Success == FALSE) { // get rid of the actions list while(!Actions.IsEmpty()) { CDRActionListItem *Act = (CDRActionListItem *)Actions.GetTail(); ERROR3IF(Act == 0, "Returned tail in a non-empty Action list is 0"); Act->ImportFailure(this); delete Actions.RemoveItem(Act); } // get rid of the level's list of nodes DeleteNodeList(pLevelNodeList); // tell everyone about some new layers, if we were doing them if(UseLayers) { LayerSGallery::MakeTopLayerActive(pSpread); BROADCAST_TO_ALL(SpreadMsg(pSpread, SpreadMsg::LAYERCHANGES)); } } TRACEUSER( "Ben", _T("At CDRFilter::ClearUp(), Fills has %d entries\n"), Fills.GetCount()); TRACEUSER( "Ben", _T("At CDRFilter::ClearUp(), Outlines has %d entries\n"), Outlines.GetCount()); TRACEUSER( "Ben", _T("At CDRFilter::ClearUp(), Styles has %d entries\n"), Styles.GetCount()); TRACEUSER( "Ben", _T("At CDRFilter::ClearUp(), Fonts has %d entries\n"), Fonts.GetCount()); TRACEUSER( "Ben", _T("At CDRFilter::ClearUp(), Arrowheads has %d entries\n"), Arrowheads.GetCount()); TRACEUSER( "Ben", _T("At CDRFilter::ClearUp(), Patterns has %d entries\n"), Patterns.GetCount()); TRACEUSER( "Ben", _T("At CDRFilter::ClearUp(), Bitmaps has %d entries\n"), Bitmaps.GetCount()); TRACEUSER( "Ben", _T("At CDRFilter::ClearUp(), Vectors has %d entries\n"), Vectors.GetCount()); TRACEUSER( "Ben", _T("At CDRFilter::ClearUp(), TextV4 has %d entries\n"), TextV4.GetCount()); TRACEUSER( "Ben", _T("At CDRFilter::ClearUp(), Pages has %d entries\n"), Pages.GetCount()); TRACEUSER( "Ben", _T("At CDRFilter::ClearUp(), Actions has %d entries\n"), Actions.GetCount()); TRACEUSER( "Ben", _T("At CDRFilter::ClearUp(), TextBBoxes has %d entries\n"), TextBBoxes.GetCount()); TRACEUSER( "Ben", _T("At CDRFilter::ClearUp(), TextOnPathLinks has %d entries\n"), TextOnPathLinks.GetCount()); TRACEUSER( "Ben", _T("ObjectsConverted = %d\nObjectsFormatWrong = %d\nObjectsUnknown = %d\nEnvelopesApproximated = %d\n"), ObjectsConverted, ObjectsFormatWrong, ObjectsUnknown, EnvelopesApproximated); ERROR3IF(Success == TRUE && Actions.GetCount() != 0, "Not all actions used at the end of a successful CDR convert!"); Fills.DeleteAll(); Outlines.DeleteAll(); Styles.DeleteAll(); Fonts.DeleteAll(); Arrowheads.DeleteAll(); Patterns.DeleteAll(); Bitmaps.DeleteAll(); Vectors.DeleteAll(); TextV4.DeleteAll(); Pages.DeleteAll(); Actions.DeleteAll(); TextBBoxes.DeleteAll(); TextOnPathLinks.DeleteAll(); // avoid indexedcolour in uses ColourCMYK CNullCol; CNullCol.Cyan = 1; CNullCol.Magenta = 1; CNullCol.Yellow = 1; CNullCol.Key = 1; DocColour NullCol = DocColour(COLOURMODEL_CMYK, (ColourGeneric *)&CNullCol); SetLineColour(NullCol); SetFillColour(NullCol); // delete the current attributes DeleteCurrentAttrs(); // free a few data blocks CCFree(ObjDataBlock); CCFree(FontTableV3); CCFree(FontStylesV3); CCFree(LinkTable); TRACEUSER( "Ben", _T("ClearUp finished - import of CDR over\n")); return Success; } /******************************************************************************************** > static void CDRFilter::DeleteNodeList(Node *Start) Author: Ben_Summers (Xara Group Ltd) Created: 27 03 95 Inputs: Returns: Purpose: Deletes a linked list of nodes (forward direction only) SeeAlso: Filter ********************************************************************************************/ void CDRFilter::DeleteNodeList(Node *Start) { Node *This, *Next; This = Start; while(This != 0) { Next = This->FindNext(); This->CascadeDelete(); delete This; This = Next; } } /******************************************************************************************** > BOOL CDRFilter::DoExport(Operation*, CCLexFile*, PathName*, Document*); Author: Ben_Summers (Xara Group Ltd) Created: 21 03 95 Inputs: As for the Filter class Returns: As for the Filter class Purpose: Refuses to export a Corel Palette file SeeAlso: Filter ********************************************************************************************/ BOOL CDRFilter::DoExport(Operation*, CCLexFile*, PathName*, Document*, BOOL) { // No exporting here return FALSE; } /******************************************************************************************** > BOOL CDRAttributeStore::AddChunkToStore(RIFFFile *RIFF) Author: Ben_Summers (Xara Group Ltd) Created: 22 03 95 Inputs: A RIFFFile object Returns: error flag Purpose: Stores attibute chunks for the CDRFilter class SeeAlso: CDRFilter ********************************************************************************************/ BOOL CDRAttributeStore::AddChunkToStore(RIFFFile *RIFF) { if(RIFF->GetObjType() != RIFFOBJECTTYPE_CHUNK) { ERROR2(FALSE, "CDRAttributeStore::AddChunkToStore called without a chunk in the RIFFFile"); } // get a new item obect CDRAttributeStoredItem *Item = new CDRAttributeStoredItem; if(Item == 0) return FALSE; // get the data of the RIFF chunk if(!Item->Aquire(RIFF)) { delete Item; return FALSE; } Item->Size = RIFF->GetObjSize(); // and add the new item to the list AddTail(Item); return TRUE; } /******************************************************************************************** > BOOL CDRAttributeStore::Find(DWORD Reference, INT32 *Size) Author: Ben_Summers (Xara Group Ltd) Created: 22 03 95 Inputs: reference to the object (DWORD) Returns: error flag Purpose: Finds a chunk in the store of objects using the reference given SeeAlso: CDRFilter ********************************************************************************************/ ADDR CDRAttributeStore::Find(DWORD Reference, INT32 *Size) { CDRAttributeStoredItem *Item; if(IsEmpty()) return 0; // no items in the list Item = (CDRAttributeStoredItem *)GetHead(); // scan though the list looking for the reference while(Item != 0) { if(CDRDATA_DWORD(*((DWORD *)(Item->Block))) == Reference) { *Size = Item->Size; return Item->Block; } Item = (CDRAttributeStoredItem *)GetNext(Item); } return 0; } /******************************************************************************************** > BOOL CDRAttributeStore::Find(WORD Reference, INT32 *Size) Author: Ben_Summers (Xara Group Ltd) Created: 22 03 95 Inputs: reference to the object (WORD) Returns: error flag Purpose: Finds a chunk in the store of objects using the reference given SeeAlso: CDRFilter ********************************************************************************************/ ADDR CDRAttributeStore::Find(WORD Reference, INT32 *Size) { CDRAttributeStoredItem *Item; if(IsEmpty()) return 0; // no items in the list Item = (CDRAttributeStoredItem *)GetHead(); // scan though the list looking for the reference while(Item != 0) { if(CDRDATA_WORD(*((WORD *)(Item->Block))) == Reference) { *Size = Item->Size; return Item->Block; } Item = (CDRAttributeStoredItem *)GetNext(Item); } return 0; } /******************************************************************************************** > CDRAttributeStoredItem::CDRAttributeStoredItem(void) Author: Ben_Summers (Xara Group Ltd) Created: 22 03 95 Inputs: Returns: Purpose: Constructor SeeAlso: CDRAttributeStore ********************************************************************************************/ CDRAttributeStoredItem::CDRAttributeStoredItem(void) { Block = 0; } /******************************************************************************************** > CDRAttributeStoredItem::~CDRAttributeStoredItem(void) Author: Ben_Summers (Xara Group Ltd) Created: 22 03 95 Inputs: Returns: Purpose: Destructor SeeAlso: CDRAttributeStore ********************************************************************************************/ CDRAttributeStoredItem::~CDRAttributeStoredItem(void) { CCFree(Block); } /******************************************************************************************** > BOOL CDRAttributeStoredItem::~CDRAttributeStoredItem(void) Author: Ben_Summers (Xara Group Ltd) Created: 22 03 95 Inputs: Returns: Purpose: Destructor SeeAlso: CDRAttributeStore ********************************************************************************************/ BOOL CDRAttributeStoredItem::Aquire(RIFFFile *RIFF) { ERROR3IF(Block != 0, "CDRAttributeStoredItem already has data"); Size = RIFF->GetObjSize(); // get a block of memory if((Block = (ADDR)CCMalloc(Size)) == 0) return FALSE; // get the data of the object into it if(!RIFF->GetChunkData(Block, Size)) return FALSE; // bye return TRUE; } /******************************************************************************************** > CDRLayerListItem::CDRLayerListItem() Author: Ben_Summers (Xara Group Ltd) Created: 24 03 95 Inputs: Returns: Purpose: Constructor SeeAlso: CDRLayerList ********************************************************************************************/ CDRLayerListItem::CDRLayerListItem() { Objects = 0; LayerInDocument = FALSE; IsVisible = TRUE; IsLocked = FALSE; } /******************************************************************************************** > CDRLayerListItem::~CDRLayerListItem() Author: Ben_Summers (Xara Group Ltd) Created: 24 03 95 Inputs: Returns: Purpose: Destructor SeeAlso: CDRLayerList ********************************************************************************************/ CDRLayerListItem::~CDRLayerListItem() { Node *Previous; Node *This; This = Objects; if(LayerInDocument == FALSE) { // delete the tree if it hasn't been used in the document while(This != 0) { // check that the node we're about to delete hasn't got a next pointer // as it jolly well shouldn't have one as we create the tree backwards ERROR3IF(This->FindNext() != 0, "Node in layer has next pointer during deletion"); // find the previous node Previous = This->FindPrevious(); // delete the current one's children This->CascadeDelete(); // and delete the current one delete This; // shuffle backwards This = Previous; } Objects = 0; } } /******************************************************************************************** > CDRLayerList::CDRLayerList() Author: Ben_Summers (Xara Group Ltd) Created: 24 03 95 Inputs: Returns: Purpose: Constructor SeeAlso: CDRLayerList ********************************************************************************************/ CDRLayerList::CDRLayerList() { } /******************************************************************************************** > CDRLayerList::~CDRLayerList() Author: Ben_Summers (Xara Group Ltd) Created: 24 03 95 Inputs: Returns: Purpose: Destructor so we can delete all the pages with one DeleteAll call SeeAlso: CDRLayerList ********************************************************************************************/ CDRLayerList::~CDRLayerList() { DeleteAll(); } /******************************************************************************************** > CDRPageList::CDRPageList() Author: Ben_Summers (Xara Group Ltd) Created: 24 03 95 Inputs: Returns: Purpose: Constructor SeeAlso: CDRLayerList ********************************************************************************************/ CDRPageList::CDRPageList() { } /******************************************************************************************** > CDRPageList::~CDRPageList() Author: Ben_Summers (Xara Group Ltd) Created: 24 03 95 Inputs: Returns: Purpose: Destructor SeeAlso: CDRLayerList ********************************************************************************************/ CDRPageList::~CDRPageList() { } /******************************************************************************************** > CDRPageListItem::CDRPageListItem() Author: Ben_Summers (Xara Group Ltd) Created: 24 03 95 Inputs: Returns: Purpose: Constructor SeeAlso: CDRLayerList ********************************************************************************************/ CDRPageListItem::CDRPageListItem() { } /******************************************************************************************** > CDRPageListItem::~CDRPageListItem() Author: Ben_Summers (Xara Group Ltd) Created: 24 03 95 Inputs: Returns: Purpose: Destructor SeeAlso: CDRLayerList ********************************************************************************************/ CDRPageListItem::~CDRPageListItem() { } /******************************************************************************************** > static BOOL CDRFilter::HasCDRFileGotCMXFile(PathName *FileName, CCDiskFile *pFile = NULL) Author: Ben_Summers (Xara Group Ltd) Created: 20/08/96 Inputs: pathname of file to check, or pointer to disk file Returns: whether it has got a cmx file embedded in it Purpose: to find out whether a CDR file has got a CMX file in it, and therefore whether the CMX filter should grab it instead of this one ********************************************************************************************/ BOOL CDRFilter::HasCDRFileGotCMXFile(PathName *FileName, CCLexFile *pFile) { CCDiskFile oTheFile; CCLexFile *pTheFile; INT32 pos; if(pFile == NULL) { if (!(oTheFile.open(*FileName, ios::in | ios::binary))) { TRACEUSER( "Ben", _T("couldn't open file to check it for CMX\n")); return FALSE; } pTheFile = &oTheFile; } else { pTheFile = pFile; pos = pFile->tellIn(); } // read in the file header, and check it's a riff file RIFFFile_Header Hdr; pTheFile->read(&Hdr, sizeof(Hdr)); if(Hdr.CK.ckID != RIFFTYPE_RIFF) return FALSE; // file is not a riff form UINT32 loc = sizeof(Hdr); // run through the thingys BOOL Found = FALSE; while(loc < Hdr.CK.ckSize) { RIFFck ck; pTheFile->read(&ck, sizeof(ck)); loc += sizeof(ck); if(ck.ckID == cdrT_cmx1) { // found the cmx section Found = TRUE; break; // we can stop now } // skip to start of next chunk loc += ck.ckSize; pTheFile->seekIn(loc); } // close it or clear up... if(pFile == NULL) { oTheFile.close(); } else { pFile->seekIn(pos); } return Found; }