cdrfiltr.cpp

Go to the documentation of this file.
00001 // $Id: cdrfiltr.cpp 1282 2006-06-09 09:46:49Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 // *********CDR file filter
00099 
00100 /*
00101 */
00102 
00103 // this line disables extrudes as they don't *quite* work yet - corel still need some
00104 // interegation about what's going on. It seems the object is pre-transformed by some
00105 // random values. Weird. #define this to include the stuff.
00106 #undef CDR_DOEXTRUDES
00107 
00108 #include "camtypes.h"
00109 #include "cdrfiltr.h"
00110 //#include "oilfltrs.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00111 //#include "ben.h"
00112 //#include "ccfile.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00113 #include "progress.h"
00114 #include "cdrcol.h"
00115 #include "rifffile.h"
00116 #include "cdrform.h"
00117 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00118 #include "nodepath.h"
00119 //#include "group.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00120 #include "page.h"
00121 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00122 #include "nodershp.h"
00123 //#include "resource.h"
00124 //#include "fixst256.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00125 #include "ndoptmz.h"
00126 #include "collist.h"
00127 #include "layer.h"
00128 #include "sglayer.h"
00129 #include "sprdmsg.h"
00130 #include "nodebmp.h"
00131 #include "nodetxts.h"
00132 //#include "textinfo.h"
00133 #include "zoomops.h"
00134 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00135 #include "nodemold.h"
00136 #include "moldshap.h"
00137 #include "ndmldpth.h"
00138 #include "nodemldr.h"
00139 //#include "nev.h"
00140 #include "fontman.h"
00141 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00142 //#include "cmxres.h"
00143 #include "cmxifltr.h"       // so we can pass stuff to it nicely
00144 
00145 DECLARE_SOURCE("$Revision: 1282 $");
00146 
00147 CC_IMPLEMENT_DYNAMIC(CDRFilter, VectorFilter)
00148 CC_IMPLEMENT_MEMDUMP(CDRAttributeStore, List)
00149 CC_IMPLEMENT_MEMDUMP(CDRAttributeStoredItem, ListItem)
00150 CC_IMPLEMENT_MEMDUMP(CDRArrowheadStore, List)
00151 CC_IMPLEMENT_MEMDUMP(CDRArrowheadStoredItem, ListItem)
00152 CC_IMPLEMENT_MEMDUMP(CDRBitmapStore, List)
00153 CC_IMPLEMENT_MEMDUMP(CDRBitmapStoredItem, ListItem)
00154 CC_IMPLEMENT_MEMDUMP(CDRVectorStore, List)
00155 CC_IMPLEMENT_MEMDUMP(CDRVectorStoredItem, ListItem)
00156 CC_IMPLEMENT_MEMDUMP(CDRFontnameStore, List)
00157 CC_IMPLEMENT_MEMDUMP(CDRFontnameStoredItem, ListItem)
00158 CC_IMPLEMENT_MEMDUMP(CDRLayerList, List)
00159 CC_IMPLEMENT_MEMDUMP(CDRLayerListItem, ListItem)
00160 CC_IMPLEMENT_MEMDUMP(CDRPageList, List)
00161 CC_IMPLEMENT_MEMDUMP(CDRPageListItem, ListItem)
00162 CC_IMPLEMENT_MEMDUMP(CDRActionList, List)
00163 CC_IMPLEMENT_DYNAMIC(CDRActionListItem, ListItem)
00164 CC_IMPLEMENT_DYNAMIC(CDRActionTransform, CDRActionListItem)
00165 CC_IMPLEMENT_DYNAMIC(CDRActionGroupEnd, CDRActionListItem)
00166 CC_IMPLEMENT_MEMDUMP(CDRTransformConvertor, CC_CLASS_MEMDUMP)
00167 CC_IMPLEMENT_MEMDUMP(CDRTransformConvertor5, CDRTransformConvertor)
00168 CC_IMPLEMENT_MEMDUMP(CDRTransformConvertor4, CDRTransformConvertor)
00169 CC_IMPLEMENT_MEMDUMP(CDRTransformConvertor3, CDRTransformConvertor)
00170 CC_IMPLEMENT_MEMDUMP(CDRTextOnPathLink, ListItem)
00171 
00172 
00173 #define new CAM_DEBUG_NEW
00174 
00175 #define PROGRESSUPDATE_MASK 0x7f
00176 
00177 INT32 CDRFilter::BitmapNumber = 0;
00178 INT32 CDRFilter::PatternNumber = 0;
00179 
00180 /********************************************************************************************
00181 
00182 >   static void CDRFilter::UpdateProgress(BOOL Now = FALSE)
00183 
00184     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00185     Created:    22 03 95
00186     Inputs:     None
00187     Returns:    None
00188     Purpose:    Updating the progress everysooften - called at every significant place
00189                 to get a nice smooth update on that progress bar thingy
00190     SeeAlso:    Filter
00191 
00192 ********************************************************************************************/
00193 
00194 BOOL CDRFilter::UpdateProgress(BOOL Now)
00195 {
00196     BOOL Result = TRUE;
00197     
00198     if(Now)
00199     {
00200         Result = ContinueSlowJob(RIFF->ProgressNow());
00201         ProgressCount = 0;
00202     }
00203     else
00204     {
00205         if((ProgressCount & PROGRESSUPDATE_MASK) == 0) {
00206             Result = ContinueSlowJob(RIFF->ProgressNow());
00207         }
00208 
00209         ProgressCount++;
00210     }
00211 
00212     if(!Result)
00213     {
00214         Error::ClearError();        // because this may not be handled the first time around
00215         Error::SetError(_R(IDN_USER_CANCELLED));
00216     }
00217     
00218     return Result;
00219 }
00220 
00221 /********************************************************************************************
00222 
00223 >   CDRFilter::CDRFilter(void)
00224 
00225     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00226     Created:    21 03 95
00227     Inputs:     As for the Filter class
00228     Returns:    As for the Filter class
00229     Purpose:    Constructor
00230     SeeAlso:    Filter
00231 
00232 ********************************************************************************************/
00233 
00234 CDRFilter::CDRFilter(void)
00235 {
00236     // Set up filter descriptions.
00237     FilterName.Load(_R(IDT_CDRFILTER_FILTERNAME));
00238     FilterInfo.Load(_R(IDT_CDRFILTER_FILTERINFO));
00239     FilterID = FILTERID_CDR;
00240 
00241     Flags.CanImport = TRUE;
00242     Flags.CanExport = FALSE;
00243 
00244     Version = CDRVERSION_NULL;
00245 }
00246 
00247 
00248 /********************************************************************************************
00249 
00250 >   BOOL CDRFilter::Init(void)
00251 
00252     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00253     Created:    21 03 95
00254     Inputs:     As for the Filter class
00255     Returns:    As for the Filter class
00256     Purpose:    Initialisation
00257     SeeAlso:    Filter
00258 
00259 ********************************************************************************************/
00260 
00261 BOOL CDRFilter::Init(void)
00262 {
00263     // Get the OILFilter object
00264     pOILFilter = new CDROILFilter(this);
00265     if (pOILFilter == NULL)
00266         return FALSE;
00267 
00268     // make sure we'll complain about life if HowCompatable isn't called
00269     Version  = CDRVERSION_NULL;
00270 
00271     // All ok
00272     return TRUE;
00273 }
00274 
00275 /********************************************************************************************
00276 
00277 >   INT32 CDRFilter::HowCompatible(PathName& Filename, ADDR  HeaderStart,
00278         UINT32 HeaderSize, UINT32 FileSize)
00279 
00280     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00281     Created:    21 03 95
00282     Inputs:     As for the Filter class
00283     Returns:    As for the Filter class
00284     Purpose:    Examines a file to see how compatable it is with this filter.
00285     SeeAlso:    Filter
00286 
00287 ********************************************************************************************/
00288 
00289 INT32 CDRFilter::HowCompatible(PathName& Filename, ADDR  HeaderStart,
00290         UINT32 HeaderSize, UINT32 FileSize)
00291 {
00292 PORTNOTE("byteorder", "TODO: Check byte ordering")
00293     BOOL ExtensionMatches = pOILFilter->DoesExtensionOfPathNameMatch(&Filename);
00294 
00295     // check for version 2 files if the extension matches...
00296     if (ExtensionMatches)
00297     {
00298         if(camStrncmp((char *)HeaderStart, "WL", 2) == 0)
00299             return 10;          // a version 2.xx CDR file
00300     }
00301 
00302     // check for version 3 - 5 files...
00303     FOURCC FormType;
00304 
00305     FormType = RIFFFile::CheckRIFFHeader(HeaderStart, FileSize);
00306 
00307     Version  = CDRVERSION_NULL;
00308     
00309     switch (FormType)
00310     {
00311         case cdrT_CDR:
00312             Version = CDRVERSION_3;
00313             break;
00314         
00315         case cdrT_CDR4:
00316         case cdrT_CDST:         // version 4 template
00317             Version = CDRVERSION_4;
00318             break;
00319 
00320         case cdrT_CDR5:
00321         case cdrT_CDT5:
00322             Version = CDRVERSION_5;
00323             break;
00324 
00325         case cdrT_CDR6:
00326         case cdrT_CDT6:
00327             Version = CDRVERSION_6;
00328             break;
00329 
00330         default:
00331             break;
00332     }
00333 
00334     INT32 HowMuchWeLikedThisFile = 0;
00335 
00336     if(Version != CDRVERSION_NULL)
00337     {
00338         HowMuchWeLikedThisFile = 10;        // loved the file
00339 
00340         // check to see if there is a CMX file embedded in there
00341         if(HasCDRFileGotCMXFile(&Filename))
00342         {
00343             HowMuchWeLikedThisFile = 5;     // didn't like it so much then -- let the CMX filter grab it
00344         }
00345     }
00346 
00347     return HowMuchWeLikedThisFile;
00348 }
00349 
00350 /********************************************************************************************
00351 
00352 >   BOOL CDRFilter::DoImport(SelOperation *Op, CCLexFile *pDiskFile, Document *DestDoc, 
00353         BOOL AutoChosen, ImportPosition *Pos,
00354         KernelBitmap** ppImportedBitmap, DocCoord* pPosTranslate, String_256* URL)
00355 
00356     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00357     Created:    21 03 95
00358     Inputs:     As for the Filter class
00359     Returns:    As for the Filter class
00360     Purpose:    Does the import of a CDR (.cdr or .cdt)
00361     SeeAlso:    Filter
00362 
00363 ********************************************************************************************/
00364 
00365 #define CDRFILTER_DI_RETURNERROR {Success = FALSE; return ClearUp();}
00366 
00367 BOOL CDRFilter::DoImport(SelOperation *Op, CCLexFile *pDiskFile, Document *DestDoc, 
00368         BOOL AutoChosen, ImportPosition *Pos,
00369         KernelBitmap** ppImportedBitmap, DocCoord* pPosTranslate, String_256* URL)
00370 {
00371     // check to see if we've got a CMX file in there, but only if we weren't autochosen
00372     if(!AutoChosen && HasCDRFileGotCMXFile(NULL, pDiskFile))
00373     {
00374         TRACEUSER( "Ben", _T(">>> loading CDR file with new CMXImportFilter\n"));
00375         // right, somehow we got here -- probably because the user specifically
00376         // asked to see CorelDRAW files only
00377         CMXImportFilter *pFilter = new CMXImportFilter;
00378 
00379         if(pFilter == NULL)
00380             return FALSE;
00381 
00382         BOOL ok = pFilter->DoImport(Op, pDiskFile, DestDoc, AutoChosen, Pos);
00383 
00384         delete pFilter;
00385         pFilter = NULL;
00386 
00387         return ok;
00388     }
00389 
00390     // normal CDR import stuff
00391     BOOL ExtensionMatches = pOILFilter->DoesExtensionOfFileMatch(pDiskFile);
00392 
00393     RIFFFile RIFFo;
00394 
00395 TRACEUSER( "Ben", _T("In CDRFilter::DoImport\n"));
00396     //ERROR2IF(Version == CDRVERSION_NULL, FALSE, "CDRFilter::HowCompatible failed to set recognised version\n");
00397 
00398     // in debug builds, warn about fills hanging around
00399     ERROR3IF(Fills.IsEmpty() == FALSE, "Fills store not empty");
00400     ERROR3IF(Outlines.IsEmpty() == FALSE, "Outlines store not empty");
00401     ERROR3IF(Styles.IsEmpty() == FALSE, "Styles store not empty");
00402     ERROR3IF(Fonts.IsEmpty() == FALSE, "Fonts store not empty");
00403     ERROR3IF(Arrowheads.IsEmpty() == FALSE, "Arrowheads store not empty");
00404     ERROR3IF(Patterns.IsEmpty() == FALSE, "Patterns store not empty");
00405     ERROR3IF(Bitmaps.IsEmpty() == FALSE, "Bitmap store not empty");
00406     ERROR3IF(Vectors.IsEmpty() == FALSE, "Vector store not empty");
00407     ERROR3IF(TextBBoxes.IsEmpty() == FALSE, "TextBBoxes list not empty");
00408     ERROR3IF(TextV4.IsEmpty() == FALSE, "TextV4 store not empty");
00409     ERROR3IF(TextOnPathLinks.IsEmpty() == FALSE, "TextOnPathLinks not empty");
00410 
00411     // in retail builds, just vape any contents
00412     Fills.DeleteAll();
00413     Outlines.DeleteAll();
00414     Styles.DeleteAll();
00415     Fonts.DeleteAll();
00416     Arrowheads.DeleteAll();
00417     Patterns.DeleteAll();
00418     Bitmaps.DeleteAll();
00419     Vectors.DeleteAll();
00420     TextV4.DeleteAll();
00421     Pages.DeleteAll();
00422     Actions.DeleteAll();
00423     TextBBoxes.DeleteAll();
00424     TextOnPathLinks.DeleteAll();
00425 
00426     // set a few flags and initialise some variables
00427     pDocument = DestDoc;
00428     Success = TRUE;
00429     SlowJobStarted = FALSE;
00430     TranslateByX = 0;
00431     TranslateByY = 0;
00432     PageX = 0;
00433     PageY = 0;
00434     pLevelNodeList = 0;
00435     DoneDoc = FALSE;
00436     DoneMasterPage = FALSE;
00437     InMasterPage = FALSE;
00438     ThisPage = 0;
00439     ThisLayer = 0;
00440     pMadeNode = 0;
00441     ObjectsConverted = 0;
00442     ObjectsFormatWrong = 0;
00443     ObjectsUnknown = 0;
00444     EnvelopesApproximated = 0;
00445     ObjDataBlock = 0;
00446     ObjDataBlockSize = 0;
00447     AttrsAlreadyApplied = FALSE;
00448     TransformChunk = 0;
00449     FontTableV3 = 0;
00450     FontStylesV3 = 0;
00451     LinkTable = 0;
00452     ThisOp = Op;
00453     LinkTransformsExist = FALSE;
00454     TheDocument = DestDoc;
00455 
00456     // if the extension matches, check it for being a 2.xx file
00457     if(ExtensionMatches)
00458     {
00459         // get the first few bytes
00460         TCHAR FirstBit[8];
00461 
00462         if(pDiskFile->read((void *)FirstBit, sizeof(FirstBit)).bad())
00463             return FALSE;
00464 
00465         ERROR1IF(camStrncmp((char *)FirstBit, "WL", 2) == 0, FALSE, _R(IDT_CDRFILTER_ISAV2FILE));
00466     
00467         // let's pop the file back to the beginning
00468         if(pDiskFile->seek(0).bad())
00469             return FALSE;
00470     }
00471 
00472     // sort out the RIFF file
00473     RIFF = &RIFFo;
00474 
00475     FOURCC FormType = RIFF->Init(pDiskFile);
00476 
00477     if(FormType == 1)       // error
00478     {
00479         CDRFILTER_DI_RETURNERROR;
00480     }
00481     
00482     // sort out which version we're on
00483     switch(FormType)
00484     {
00485         case cdrT_CDR:
00486             Version = CDRVERSION_3;
00487             break;
00488         
00489         case cdrT_CDR4:
00490         case cdrT_CDST:         // version 4 template
00491             Version = CDRVERSION_4;
00492             break;
00493 
00494         case cdrT_CDR5:
00495         case cdrT_CDT5:
00496             Version = CDRVERSION_5;
00497             break;
00498 
00499         case cdrT_CDR6:
00500         case cdrT_CDT6:
00501             // version 6 file -- we don't support these
00502             ERROR1(FALSE, _R(IDE_CDRFILTER_CDR6));
00503             break;
00504 
00505         default:
00506 TRACEUSER( "Ben", _T("Attempted to load something which wasn't a CDR file. I don't think so..."));
00507             ERROR1(FALSE, _R(IDE_CDRFILTER_NOTCDR));
00508             break;
00509     }
00510 
00511     // sort out a colour list
00512     ColList = DestDoc->GetIndexedColours();
00513     
00514     // do we want to import with layers?
00515     UseLayers = FALSE;
00516 #ifdef WEBSTER
00517     // In Webster, just use the default preference settings as these should be set to
00518     // ImportWithLayers to False.
00519     if (
00520         (!DestDoc->IsImporting() && Filter::OpenWithLayers) ||
00521         (DestDoc->IsImporting() && Filter::ImportWithLayers)
00522         )
00523         UseLayers = TRUE;
00524 #else
00525     // In Camelot, we must check to see if the document is being imported and if so if
00526     // there are any frames present. If there are then don't use layers, if there are
00527     // then use the preference setting.
00528     if (DestDoc->IsImporting())
00529     {
00530         Spread * pTheSpread = DestDoc->GetSelectedSpread();
00531         Layer * pFrame = NULL;
00532         if (pTheSpread != NULL)
00533             pFrame = pTheSpread->FindFirstFrameLayer();
00534         if (pFrame != NULL)
00535             UseLayers = FALSE;                      // Frames present so do not import layers
00536         else
00537             UseLayers = Filter::ImportWithLayers;   // No frames so use the preference setting
00538     }
00539     else
00540     {
00541         UseLayers = Filter::OpenWithLayers;
00542     }
00543 #endif
00544 
00545     // If importing without layers, make sure there is a layer to put things on, and make one if not
00546     if(UseLayers == FALSE)
00547     {
00548         if (!MakeSureLayerExists(DestDoc))
00549         {
00550             // clean up and return and error
00551             CDRFILTER_DI_RETURNERROR;
00552         }
00553     }
00554 
00555     // For now, position Draw objects on 1st page of spread 1
00556     pSpread = DestDoc->GetSelectedSpread();
00557     pPage = (Page *) pSpread->FindFirstPageInSpread();
00558     
00559     // Use bottom left of page as origin
00560     DocRect PageRect = pPage->GetPageRect();
00561     Origin = PageRect.lo;
00562 
00563     // OK, let's get into the swing of things!
00564     
00565     // Get a default set of attributes for ink objects.
00566     if (!SetUpCurrentAttrs())
00567         return FALSE;
00568 
00569     // Let start off by setting the progress indicatorx
00570     UINT32 id;
00571     switch(Version)
00572     {
00573         case CDRVERSION_4:  id = _R(IDT_IMPORTMSG_CDR4);    break;
00574         case CDRVERSION_5:  id = _R(IDT_IMPORTMSG_CDR5);    break;
00575         default:            id = _R(IDT_IMPORTMSG_CDR3);    break;
00576     }
00577     if(!DestDoc->IsImporting())
00578         id += _R(IDT_OPENMSG_CDR3) - _R(IDT_IMPORTMSG_CDR3);
00579     //String_64 ImportMessage(id);
00580     String_64 ImportMessage = GetImportProgressString(pDiskFile, id);
00581     
00582     // this slow job doesn't have a delay because if the CDR file has a bitmap at the
00583     // beginning, ContinueSlowJob can't be called for rather a long time (sometimes)
00584     // and you get 'Nothing Selected' instead of a message telling you what's happening.
00585     BeginSlowJob(RIFF->ProgressLimit(), FALSE, &ImportMessage);
00586     SlowJobStarted = TRUE;
00587 
00588     // loop through looking at top level lists, and dispatch them to various handlers
00589     do
00590     {
00591         // get the next object in the file
00592         if(!RIFF->NextObject())
00593             CDRFILTER_DI_RETURNERROR;
00594 
00595         if(RIFF->GetObjType() == RIFFOBJECTTYPE_LISTSTART)
00596         {
00597             switch(RIFF->GetObjChunkType())
00598             {
00599                 case cdrT_doc:
00600                     if(!ProcessDoc())
00601                     {
00602 TRACEUSER( "Ben", _T("ProcessDoc returned FALSE\n"));
00603                         CDRFILTER_DI_RETURNERROR;
00604                     }
00605                     break;
00606 
00607                 case cdrT_page:
00608                     if(!ProcessPage())
00609                     {
00610 TRACEUSER( "Ben", _T("ProcessPage returned FALSE\n"));
00611                         CDRFILTER_DI_RETURNERROR;
00612                     }
00613                     break;
00614 
00615                 default:
00616                     // we're not interested in any other root level list, so skip it
00617                     if(!RIFF->SkipToListEnd(RIFF->GetObjLevel()))
00618                         CDRFILTER_DI_RETURNERROR;
00619                     break;
00620             }
00621         }
00622 
00623         if(!UpdateProgress())
00624             return FALSE;
00625     } while(RIFF->GetObjType() != RIFFOBJECTTYPE_FILEEND);
00626 
00627     // make sure we're at the end
00628     ContinueSlowJob(RIFF->ProgressLimit());
00629 
00630     // attach paths to text stories
00631     if(!AttachTextToPaths())
00632         return FALSE;
00633 
00634     // only stick objects into the document if some were converted
00635     if(ObjectsConverted > 0)
00636     {
00637     
00638         // check that there were at least two pages
00639         if(Pages.GetCount() < 1)
00640         {
00641     TRACEUSER( "Ben", _T("not enough pages in file\n"));
00642             CDRFILTER_DI_RETURNERROR;
00643         }
00644     
00645         // get the pointer to the list of levels on the master pages
00646         CDRLayerList *MasterLayers;
00647         CDRPageListItem *En = (CDRPageListItem *)Pages.GetHead();
00648 
00649         if(En == 0)
00650             CDRFILTER_DI_RETURNERROR;
00651 
00652         MasterLayers = &En->Layers;
00653     
00654         // get the list of levels on the actual page
00655         CDRLayerList *PageLayers;
00656         En = (CDRPageListItem *)Pages.GetNext(En);
00657 
00658         if(Version != CDRVERSION_3)
00659         {
00660             if(En == 0)
00661                 CDRFILTER_DI_RETURNERROR;
00662 
00663             PageLayers = &En->Layers;
00664 
00665             // check that they have the same number of layers in their lists
00666             if(MasterLayers->GetCount() != PageLayers->GetCount())
00667             {
00668         TRACEUSER( "Ben", _T("not the same number of layers on master page and on page\n"));
00669                 CDRFILTER_DI_RETURNERROR;
00670             }
00671         } else
00672         {
00673             PageLayers = 0;
00674         }
00675 
00676         if(MasterLayers->GetCount() <= 0)
00677             CDRFILTER_DI_RETURNERROR;
00678 
00679         // if it's a CDR 3 file set the page size and translation things
00680         if(Version == CDRVERSION_3)
00681         {
00682             // set the page size?
00683             if(!DestDoc->IsImporting() && PageX > 0 && PageY > 0)
00684             {
00685 // Make the pasteboard an extra page width either side of the page and an extra
00686 // half page height above and below the page. That should be nicely proportional.
00687 
00688                 INT32 ms = (PageX > PageY)?PageX:PageY;
00689     
00690                 // we're opening the file, so set the page size
00691                 if (pSpread)
00692                 {
00693                     BOOL ok = pSpread->SetPageSize(PageX, PageY, ms, 0, FALSE, TRUE);
00694                     // Must set the origin of the grid to the bottom left corner of the
00695                     // union rectangle of all pages on the spread as this is where the x,y
00696                     // measurements are made from.
00697                     DocRect PagesRect;
00698                     NodeGrid* pGrid = pSpread->FindFirstDefaultGridInSpread();
00699                     ok = ok && pSpread->GetPagesRect(&PagesRect);
00700                     if (pGrid)
00701                         pGrid->SetOrigin(PagesRect.lox, PagesRect.loy);
00702                     
00703                     if (!ok)
00704                         CDRFILTER_DI_RETURNERROR;
00705                 }
00706             }
00707         
00708             DocRect PageRect = pPage->GetPageRect();
00709             Origin = PageRect.lo;
00710 
00711             TranslateByX = Origin.x + (PageX / 2);
00712             TranslateByY = Origin.y + (PageY / 2);
00713         }
00714 
00715         // set up pointers to the layers
00716         CDRLayerListItem *MasterEn = (CDRLayerListItem *)MasterLayers->GetTail();
00717         CDRLayerListItem *PageEn = 0;
00718         if(PageLayers != 0)
00719             PageEn = (CDRLayerListItem *)PageLayers->GetTail();
00720 
00721         EndSlowJob();
00722         BeginSlowJob();
00723 
00724         // insert everything into the document
00725         if(UseLayers)
00726         {
00727             // go through inserting every layer which has sometime on it
00728             while(MasterEn != 0)
00729             {
00730                 // check to see if we have objects to import
00731                 if(MasterEn->Objects != 0 || (PageEn != 0 && PageEn->Objects != 0))
00732                 {
00733                     // OK, we've got some objects to import, create a layer to put them in
00734                     Layer *pLayer = new Layer();
00735 
00736                     if(pLayer == 0)
00737                         CDRFILTER_DI_RETURNERROR;
00738 
00739                     // set it's name and attributes
00740                     pLayer->SetLayerID(MasterEn->Name);
00741                     pLayer->SetVisible(MasterEn->IsVisible);
00742                     pLayer->SetLocked(MasterEn->IsLocked);
00743                     pLayer->SetActive(FALSE);
00744                     pLayer->SetPrintable(TRUE);
00745                     pLayer->SetBackground(FALSE);
00746                     pLayer->SetOutline(FALSE);
00747 
00748                     // stick objects below it
00749                     Node *Objects = 0;
00750 
00751                     if(MasterEn->Objects != 0)
00752                     {
00753                         Objects = MasterEn->Objects;
00754                         MasterEn->LayerInDocument = TRUE;
00755                     }
00756                     else
00757                     {
00758                         Objects = PageEn->Objects;
00759                         PageEn->LayerInDocument = TRUE;
00760                     }
00761 
00762                     ERROR3IF(Objects == 0, "Er, tried to make a layer for objects which didn't exist");
00763 
00764                     // attach the objects to the layer
00765                     Objects->InsertChainSimple(pLayer, FIRSTCHILD);
00766 
00767                     // if it's a CDR 3 file and translate it
00768                     if(Version == CDRVERSION_3)
00769                     {
00770                         Trans2DMatrix Trans(TranslateByX, TranslateByY);
00771                         pLayer->Transform(Trans);
00772                     }
00773                     
00774                     // insert the layer...
00775                     if (!Op->DoInsertNewNode(pLayer, (Node *)pSpread, LASTCHILD, TRUE))
00776                     {
00777                         // It didn't work - delete the sub-tree we just created
00778                         pLayer->CascadeDelete();
00779                         delete pLayer;
00780                         pLayer = NULL;
00781                         CDRFILTER_DI_RETURNERROR;
00782                     }
00783 
00784                     // make sure it's name is unique
00785                     pLayer->EnsureUniqueLayerID();
00786                     
00787                     // ... and finally optimise it's attributes
00788                     if(!pLayer->OptimiseAttributes())
00789                         CDRFILTER_DI_RETURNERROR;
00790                 }
00791     
00792                 // get the next (previous) layer to import
00793                 MasterEn = (CDRLayerListItem *)MasterLayers->GetPrev(MasterEn);
00794                 if(PageEn != 0)
00795                     PageEn = (CDRLayerListItem *)PageLayers->GetPrev(PageEn);
00796             }       
00797 
00798             // get the insertation node set up
00799             DestDoc->ResetInsertionPosition();
00800         }
00801         else 
00802         {
00803             // get a group node to put everything in as we're not using layers here.
00804             NodeGroup *pGroup = new NodeGroup;
00805             if(pGroup == 0)
00806                 CDRFILTER_DI_RETURNERROR;
00807     
00808             // run through the layers putting in the stuff - remember they're in reverse order
00809             while(MasterEn != 0)
00810             {
00811         TRACEUSER( "Ben", _T("Putting layer '%s' into document\n"), (TCHAR *)MasterEn->Name);       
00812         
00813                 // put the master pages objects onto this group
00814                 if(MasterEn->Objects != 0)
00815                 {
00816                     MasterEn->Objects->InsertChainSimple(pGroup, LASTCHILD);
00817         
00818                     MasterEn->LayerInDocument = TRUE;
00819                 }
00820 
00821                 // put the page objects into this group
00822                 if(PageEn != 0 && PageEn->Objects != 0)
00823                 {
00824                     PageEn->Objects->InsertChainSimple(pGroup, LASTCHILD);
00825 
00826                     PageEn->LayerInDocument = TRUE;
00827                 }
00828 
00829         
00830                 // get the next (previous) layer to import
00831                 MasterEn = (CDRLayerListItem *)MasterLayers->GetPrev(MasterEn);
00832                 if(PageEn != 0)
00833                     PageEn = (CDRLayerListItem *)PageLayers->GetPrev(PageEn);
00834             }
00835 
00836             // if it's a CDR 3 file translate it
00837             if(Version == CDRVERSION_3)
00838             {
00839                 Trans2DMatrix Trans(TranslateByX, TranslateByY);
00840                 pGroup->Transform(Trans);
00841             }
00842 
00843             // check to see if the group node has more than one child
00844             // if it doesn't just insert the child and not the group, and then
00845             // delete the group node afterwards
00846             NodeRenderableBounded *InsertNode = pGroup;
00847 
00848             NodeRenderableBounded *FirstChild = (NodeRenderableBounded *)pGroup->FindFirstChild();
00849 
00850             if(FirstChild != 0)
00851             {
00852                 // if the first child hasn't got a sibling, then there's only one
00853                 // child to the group, so just insert the child
00854                 if(FirstChild->FindNext() == 0)
00855                     InsertNode = FirstChild;
00856             }
00857 
00858             // and slap the group into the document
00859             if (!Op->DoInsertNewNode(InsertNode, pSpread, TRUE))
00860             {
00861                 // It didn't work - delete the sub-tree we just created
00862                 pGroup->CascadeDelete();
00863                 delete pGroup;
00864                 pGroup = NULL;
00865                 CDRFILTER_DI_RETURNERROR;
00866             }
00867 
00868             if(InsertNode != pGroup)
00869                 delete pGroup;
00870 
00871             // optimise the attributes in our nice new group
00872             if(!InsertNode->OptimiseAttributes())
00873                 CDRFILTER_DI_RETURNERROR;
00874         }
00875     }
00876     else
00877     {
00878         // if we were opening the document, then we need make a layer and set the insertation node
00879         if(!DestDoc->IsImporting())
00880         {
00881             if (!MakeSureLayerExists(DestDoc))
00882                 CDRFILTER_DI_RETURNERROR;
00883 
00884             DestDoc->ResetInsertionPosition();
00885         }
00886     }
00887 
00888     // add some standard colours
00889     if(!AddStandardColourSet(pDocument))
00890         CDRFILTER_DI_RETURNERROR;
00891 
00892     // do a quick post import on it
00893     DestDoc->PostImport();
00894     
00895     // find out how many dodgy objects were encountered along the way
00896     INT32 ObjNotConv = ObjectsFormatWrong + ObjectsUnknown;
00897 
00898     if(ObjNotConv > 0)
00899     {
00900         // tell the user that some objects couldn't be converted
00901         String_256 WarnMsg;
00902         WarnMsg.MakeMsg((ObjNotConv == 1)?_R(IDT_CDRFILTER_OBJWARNING1):_R(IDT_CDRFILTER_OBJWARNING), ObjNotConv);
00903         Error::SetError(0, WarnMsg, 0);
00904         InformWarning();
00905         Error::ClearError();
00906     }
00907 
00908     if(EnvelopesApproximated > 0)
00909     {
00910         // tell the user that some envelopes were approximated
00911         String_256 WarnMsg;
00912         WarnMsg.MakeMsg((EnvelopesApproximated == 1)?_R(IDT_CDRFILTER_ENVAPPROXWARNING1):_R(IDT_CDRFILTER_ENVAPPROXWARNING), EnvelopesApproximated);
00913         Error::SetError(0, WarnMsg, 0);
00914         InformWarning();
00915         Error::ClearError();
00916     }
00917 
00918 TRACEUSER( "Ben", _T("Do import finished\n"));
00919     return ClearUp();
00920 }
00921 
00922 /********************************************************************************************
00923 
00924 >   BOOL CDRFilter::ProcessDoc(void)
00925 
00926     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00927     Created:    22 03 95
00928     Inputs:     none
00929     Returns:    error flag
00930     Purpose:    Processes the root level doc chunk of a CDR file
00931     SeeAlso:    Filter
00932 
00933 ********************************************************************************************/
00934 
00935 BOOL CDRFilter::ProcessDoc(void)
00936 {
00937     BOOL InFillTable = FALSE;
00938     BOOL InOutlineTable = FALSE;
00939     BOOL InStyleTable = FALSE;
00940     BOOL InFontTable = FALSE;
00941     BOOL InArrowheadTable = FALSE;
00942     BOOL InPatternTable = FALSE;
00943     BOOL InBitmapTable = FALSE;
00944     BOOL GotPageInfo = FALSE;
00945 
00946     ADDR VectorListContents = 0;
00947     INT32 VectorListContentsSize;
00948 
00949 TRACEUSER( "Ben", _T("In ProcessDoc\n"));
00950 
00951     // store the level we're working on
00952     UINT32 StartLevel = RIFF->GetObjLevel();
00953 
00954     do
00955     {
00956         switch(RIFF->GetObjType())
00957         {
00958             case RIFFOBJECTTYPE_LISTSTART:
00959                 // list start - attributes are stored in lists
00960                 switch(RIFF->GetObjChunkType())
00961                 {
00962                     case cdrT_filt:     InFillTable = TRUE;         break;
00963                     case cdrT_otlt:     InOutlineTable = TRUE;      break;
00964                     case cdrT_stlt:     InStyleTable = TRUE;        break;
00965                     case cdrT_fntt:     InFontTable = TRUE;         break;
00966                     case cdrT_arrt:     InArrowheadTable = TRUE;    break;
00967                     case cdrT_bpft:     InPatternTable = TRUE;      break;
00968                     case cdrT_bmpt:     InBitmapTable = TRUE;       break;
00969                     default:                                        break;
00970 
00971                     case cdrT_vect:
00972                         // get the contents of this list for later
00973                         if(!RIFF->GetListContents(&VectorListContents, &VectorListContentsSize))
00974                             return FALSE;
00975 
00976                         // and skip to the end of it
00977                         if(!RIFF->SkipToListEnd(RIFF->GetObjLevel()))
00978                             return FALSE;
00979                         break;
00980                     
00981                     case cdrT_btxt:
00982                         if(Version == CDRVERSION_4)
00983                         {
00984                             // if we're in a version 4 file, this contains text for the paragraph text objects
00985                             if(!ProcessTextList4())
00986                                 return FALSE;
00987                         }
00988                         break;
00989                 }
00990                 break;
00991 
00992             case RIFFOBJECTTYPE_LISTEND:
00993                 switch(RIFF->GetObjChunkType())
00994                 {
00995                     case cdrT_filt:     InFillTable = FALSE;        break;
00996                     case cdrT_otlt:     InOutlineTable = FALSE;     break;
00997                     case cdrT_stlt:     InStyleTable = FALSE;       break;
00998                     case cdrT_fntt:     InFontTable = FALSE;        break;
00999                     case cdrT_arrt:     InArrowheadTable = FALSE;   break;
01000                     case cdrT_bpft:     InPatternTable = FALSE;     break;
01001                     case cdrT_bmpt:     InBitmapTable = FALSE;      break;
01002                     default:                                        break;
01003                 }
01004                 break;
01005 
01006             case RIFFOBJECTTYPE_CHUNK:
01007                 // got a chunk to be interested about!
01008                 switch(RIFF->GetObjChunkType())
01009                 {
01010                     case cdrT_fill:
01011                         if(InFillTable)
01012                             Fills.AddChunkToStore(RIFF);
01013                         break;
01014 
01015                     case cdrT_outl:
01016                         if(InOutlineTable)
01017                             Outlines.AddChunkToStore(RIFF);
01018                         break;
01019 
01020                     case cdrT_styd:
01021                         if(InStyleTable)
01022                             Styles.AddChunkToStore(RIFF);
01023                         break;
01024 
01025                     case cdrT_font:
01026                         if(InFontTable)
01027                             Fonts.AddChunkToStore(RIFF, Version);
01028                         break;
01029 
01030                     case cdrT_arrw:
01031                         if(InArrowheadTable)
01032                             Arrowheads.AddChunkToStore(RIFF);
01033                         break;
01034 
01035                     case cdrT_bmpf:
01036                         if(InPatternTable)
01037                             Patterns.AddChunkToStore(RIFF, TRUE, this);
01038 
01039                         UpdateProgress(TRUE);
01040                         break;
01041 
01042                     case cdrT_bmp:
01043                         // a couple of forced progress updates here to ensure a
01044                         // resonably often updated progress bar
01045                         UpdateProgress(TRUE);
01046 
01047                         if(InBitmapTable)
01048                             Bitmaps.AddChunkToStore(RIFF, FALSE, this);
01049 
01050                         UpdateProgress(TRUE);
01051                         break;
01052 
01053                     case cdrT_mcfg:
01054                         {   // get the chunk and read the page size
01055                             if(GotPageInfo)     // if we've already got it, then there's a problem with the file
01056                             {
01057 TRACEUSER( "Ben", _T("mcfg chunk encountered twice in doc list\n"));                                
01058                                 ERROR1(FALSE, _R(IDE_CDRFILTER_FORMATERROR));
01059                             }
01060 
01061                             if(!RIFF->AquireChunkData())
01062                                 return FALSE;
01063 
01064                             cdrfPageInfo *i = (cdrfPageInfo *)RIFF->GetAquiredData();
01065 
01066                             ERROR3IF(i == 0, "No aquired data returned from RIFF chunk");
01067 
01068                             PageX = CDRDATA_WORD(i->PageX) * CDRCOORDS_TO_MILLIPOINTS;
01069                             PageY = CDRDATA_WORD(i->PageY) * CDRCOORDS_TO_MILLIPOINTS;
01070                             Landscape = (CDRDATA_WORD(i->Orientation) == cdrf_ORIENTATION_LANDSCAPE)?TRUE:FALSE;
01071 
01072                             GotPageInfo = TRUE;
01073                         }
01074                         break;
01075 
01076                     case cdrT_tspc:     // font style table for version 3
01077                         if(Version == CDRVERSION_3)
01078                         {
01079                             // store the font styles
01080                             if((FontStylesV3 = (ADDR)CCMalloc(RIFF->GetObjSize())) == 0)
01081                                 return FALSE;
01082 
01083                             if(!RIFF->GetChunkData(FontStylesV3, RIFF->GetObjSize()))
01084                                 return FALSE;
01085                         }
01086                         break;
01087 
01088                     case cdrT_ftbl:     // font name table for version 3
01089                         if(Version == CDRVERSION_3)
01090                         {
01091                             // store the font names
01092                             if((FontTableV3 = (ADDR)CCMalloc(RIFF->GetObjSize())) == 0)
01093                                 return FALSE;
01094 
01095                             if(!RIFF->GetChunkData(FontTableV3, RIFF->GetObjSize()))
01096                                 return FALSE;
01097 
01098                             // store number of entries
01099                             FontTableEntriesV3 = RIFF->GetObjSize() / sizeof(cdrfFontTableEntryV3);
01100                             
01101                             // cache the font names
01102                             cdrfFontTableEntryV3 *FT = (cdrfFontTableEntryV3 *)FontTableV3;
01103                             for(INT32 l = 0; l < FontTableEntriesV3; l++)
01104                             {
01105                                 if(FT[l].Name[0] != '\0' && FT[l].Name[0] != ' ')
01106                                 {
01107                                     //GetApplication()->GetFontManager()->CacheNamedFont(&String_64((TCHAR *)&