// $Id: cmxexdc.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============================ */ // CMX export device context #include #include "camtypes.h" //#include "ccfile.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "cmxexdc.h" #include "cmxform.h" #include "riffform.h" //#include "docrect.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "colormgr.h" //#include "colmodel.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "camelot.h" #include "cversion.h" #include "prvwflt.h" //#include "extfilts.h" #include "product.h" #include "hardwaremanager.h" using namespace oilHardwareManager; CC_IMPLEMENT_DYNAMIC(CMXFutureUpdater, CCObject); CC_IMPLEMENT_DYNAMIC(CMXFutureLength, CMXFutureUpdater); CC_IMPLEMENT_DYNAMIC(CMXFutureNumber, CMXFutureUpdater); CC_IMPLEMENT_DYNAMIC(CMXFutureIndex, CMXFutureUpdater); CC_IMPLEMENT_DYNAMIC(CMXReferListItem, ListItem); CC_IMPLEMENT_DYNAMIC(CMXReferListItemOffset, CMXReferListItem); CC_IMPLEMENT_DYNAMIC(CMXReferLayer, CMXReferListItemOffset); CC_IMPLEMENT_DYNAMIC(CMXReferMasterIndex, CMXReferListItemOffset); CC_IMPLEMENT_DYNAMIC(CMXReferPage, CMXReferListItemOffset); CC_IMPLEMENT_DYNAMIC(CMXReferMasterLayer, CMXReferListItemOffset); CC_IMPLEMENT_DYNAMIC(CMXReferColour, CMXReferListItem); CC_IMPLEMENT_DYNAMIC(CMXReferDefaultScreen, CMXReferListItem); CC_IMPLEMENT_DYNAMIC(CMXReferDefaultDotDash, CMXReferDotDash); CC_IMPLEMENT_DYNAMIC(CMXReferPen, CMXReferListItem); CC_IMPLEMENT_DYNAMIC(CMXReferArrowheads, CMXReferListItem); CC_IMPLEMENT_DYNAMIC(CMXReferArrow, CMXReferListItem); CC_IMPLEMENT_DYNAMIC(CMXReferLens, CMXReferListItem); CC_IMPLEMENT_DYNAMIC(CMXReferLineStyle, CMXReferListItem); CC_IMPLEMENT_DYNAMIC(CMXReferOutline, CMXReferListItem); CC_IMPLEMENT_DYNAMIC(CMXReferBitmap, CMXReferListItem); CC_IMPLEMENT_DYNAMIC(CMXReferBitmapFill, CMXReferListItem); CC_IMPLEMENT_DYNAMIC(CMXReferDotDash, CMXReferListItem); CC_IMPLEMENT_DYNAMIC(CMXGroupRecord, ListItem); CC_IMPLEMENT_DYNAMIC(CMXNestedTagRecord, ListItem); CC_IMPLEMENT_DYNAMIC(CMXLensBBox, ListItem); /******************************************************************************************** > CMXFutureUpdater::CMXFutureUpdater() Author: Ben_Summers (Xara Group Ltd) Created: 21/06/96 Inputs: none Returns: none Purpose: constructor SeeAlso: ********************************************************************************************/ CMXFutureUpdater::CMXFutureUpdater() { AbsPosition = -1; DataSize = 0; } /******************************************************************************************** > CMXFutureUpdater::CMXFutureUpdater() Author: Ben_Summers (Xara Group Ltd) Created: 21/06/96 Inputs: none Returns: none Purpose: destructor SeeAlso: ********************************************************************************************/ CMXFutureUpdater::~CMXFutureUpdater() { if(AbsPosition >= 0) TRACEUSER( "Ben", _T("AWWOOOOGA! CMXFutureUpdated deleted, but not written\n\n")); } /******************************************************************************************** > BOOL CMXFutureUpdater::Init(CMXExportDC *pDC, INT32 RelativePos, UINT32 DataSize) Author: Ben_Summers (Xara Group Ltd) Created: 21/06/96 Inputs: export dc, relative position (+ve = forwards in file), size of data Returns: none Purpose: initialises a updater object SeeAlso: ********************************************************************************************/ BOOL CMXFutureUpdater::Init(CMXExportDC *pDC, INT32 RelativePos, UINT32 tDataSize) { ERROR2IF(AbsPosition >= 0, FALSE, "Updater already initialised"); ERROR2IF(pDC == 0, FALSE, "No pDC, chaps"); ERROR2IF(DataSize < 0 || DataSize > 4, FALSE, "Bit of a data size problem really"); INT32 CurrentPos = pDC->GetFilePosition(); ERROR2IF(CurrentPos < 0, FALSE, "Whoops -- negative file position here"); AbsPosition = CurrentPos + RelativePos; ERROR2IF(AbsPosition < 0, FALSE, "Serious Bummer -- expected to update a position before the start of the file"); DataSize = tDataSize; return TRUE; } /******************************************************************************************** > BOOL CMXFutureUpdater::WriteValue(CMXExportDC *pDC, INT32 Value) Author: Ben_Summers (Xara Group Ltd) Created: 21/06/96 Inputs: export dc, value Returns: none Purpose: writes a value to the file SeeAlso: ********************************************************************************************/ BOOL CMXFutureUpdater::WriteValue(CMXExportDC *pDC, INT32 Value) { ERROR2IF(pDC == 0, FALSE, "No pDC, chaps"); // write the number if(!pDC->WriteNumber(AbsPosition, DataSize, Value)) return FALSE; // reset everything for the next run, should we want one. AbsPosition = -1; DataSize = 0; Reset(); // get the derivedness to reset itself too. return TRUE; } /******************************************************************************************** > CMXFutureLength::CMXFutureLength() Author: Ben_Summers (Xara Group Ltd) Created: 21/06/96 Inputs: none Returns: none Purpose: constructor SeeAlso: ********************************************************************************************/ CMXFutureLength::CMXFutureLength() { StartPos = -1; } /******************************************************************************************** > BOOL CMXFutureLength::SetLengthStartPos(CMXExportDC *pDC, INT32 RelativePos); Author: Ben_Summers (Xara Group Ltd) Created: 21/06/96 Inputs: export dc, relative position from current position (+ve is forwards) Returns: none Purpose: sets the start position of the length which is to be written SeeAlso: ********************************************************************************************/ BOOL CMXFutureLength::SetLengthStartPos(CMXExportDC *pDC, INT32 RelativePos) { ERROR2IF(StartPos >= 0, FALSE, "Start position already set"); ERROR2IF(pDC == 0, FALSE, "No dc"); StartPos = pDC->GetFilePosition() + RelativePos; return TRUE; } /******************************************************************************************** > void CMXFutureLength::Reset(void) Author: Ben_Summers (Xara Group Ltd) Created: 21/06/96 Inputs: export dc, relative position from current position (+ve is forwards) Returns: none Purpose: resets the future updater object after a write SeeAlso: ********************************************************************************************/ void CMXFutureLength::Reset(void) { StartPos = -1; } /******************************************************************************************** > BOOL CMXFutureLength::Write(CMXExportDC *pDC) Author: Ben_Summers (Xara Group Ltd) Created: 21/06/96 Inputs: export dc Returns: none Purpose: writes the length to the file. The length is the (+ve) value from the start position set earlier to the current position in the file. SeeAlso: ********************************************************************************************/ BOOL CMXFutureLength::Write(CMXExportDC *pDC) { ERROR2IF(pDC == 0, FALSE, "No dc"); ERROR2IF(StartPos < 0, FALSE, "StartPos is negative... has this length been initialised properly?"); INT32 len = pDC->GetFilePosition() - StartPos; ERROR2IF(len < 0, FALSE, "We're talking negative lengths here? I don't think so"); return WriteValue(pDC, len); } /******************************************************************************************** > BOOL CMXFutureIndex::Write(CMXExportDC *pDC) Author: Ben_Summers (Xara Group Ltd) Created: 21/06/96 Inputs: export dc Returns: none Purpose: writes the index to the file. The index is the current file position. SeeAlso: ********************************************************************************************/ BOOL CMXFutureIndex::Write(CMXExportDC *pDC) { ERROR2IF(pDC == 0, FALSE, "No dc"); return WriteValue(pDC, pDC->GetFilePosition()); } /******************************************************************************************** > BOOL CMXFutureIndex::Write(CMXExportDC *pDC) Author: Ben_Summers (Xara Group Ltd) Created: 21/06/96 Inputs: export dc Returns: none Purpose: writes the number to the file SeeAlso: ********************************************************************************************/ BOOL CMXFutureNumber::Write(CMXExportDC *pDC) { ERROR2IF(pDC == 0, FALSE, "No dc"); return WriteValue(pDC, Number); } /******************************************************************************************** > CMXReferListItemOffset::CMXReferListItemOffset(CMXExportDC *pDC) Author: Ben_Summers (Xara Group Ltd) Created: 21/06/96 Inputs: export dc Returns: none Purpose: constructs the refer list item by getting the offset SeeAlso: ********************************************************************************************/ CMXReferListItemOffset::CMXReferListItemOffset(CMXExportDC *pDC) : CMXReferListItem(pDC) { Offset = pDC->GetFilePosition(); // will throw an exception if it goes wrong } /******************************************************************************************** > void CMXReferLayer::SetLayerDetails(WORD Number, String_256 *tName) Author: Ben_Summers (Xara Group Ltd) Created: 26/06/96 Inputs: layer number, name Returns: none Purpose: sets the layer details SeeAlso: ********************************************************************************************/ void CMXReferLayer::SetLayerDetails(WORD Number, String_256 *tName) { LayerNumber = Number; Name = *tName; } /******************************************************************************************** > BOOL CMXReferLayer::WriteInReferenceList(CMXExportDC *pDC) Author: Ben_Summers (Xara Group Ltd) Created: 26/06/96 Inputs: export dc Returns: sucess Purpose: writes the relevant entry in the reference list of the file SeeAlso: ********************************************************************************************/ BOOL CMXReferLayer::WriteInReferenceList(CMXExportDC *pDC) { ERROR2IF(pDC == 0, FALSE, "no DC"); // write the entry cmxRefListEntryRef en; memset(&en, '\0', sizeof(en)); en.Association = cmxREFLISTEN_DESC_COMPONENT; en.Type = cmxREFLISTEN_TYPE_LAYER; en.ReferenceNumber = LayerNumber; pDC->WriteData(&en, sizeof(en)); return TRUE; } /******************************************************************************************** > INT32 CMXReferLayer::IndexEntrySize(CMXExportDC *pDC) Author: Ben_Summers (Xara Group Ltd) Created: 26/06/96 Inputs: none Returns: length of entry we'll write Purpose: gets the length of the entry we'll write in the index SeeAlso: ********************************************************************************************/ INT32 CMXReferLayer::IndexEntrySize(CMXExportDC *pDC) { ERROR2IF(pDC == NULL, 0, "no dc"); INT32 StrLen = Name.Length(); return StrLen + sizeof(WORD) + sizeof(DWORD) * 2 + ((pDC->IsThirtyTwoBit())?sizeof(WORD):0); } /******************************************************************************************** > BOOL CMXReferLayer::WriteInIndex(CMXExportDC *pDC) Author: Ben_Summers (Xara Group Ltd) Created: 26/06/96 Inputs: export dc Returns: none Purpose: writes the layer details in the layer list SeeAlso: ********************************************************************************************/ BOOL CMXReferLayer::WriteInIndex(CMXExportDC *pDC) { // write size in file pDC->WriteSizeInFile(Name.Length() + sizeof(DWORD) * 2); DWORD tOffset = Offset; pDC->WriteData(&tOffset, sizeof(tOffset)); pDC->WriteString(&Name); SDWORD RefList = -1; pDC->WriteData(&RefList, sizeof(RefList)); return TRUE; } /******************************************************************************************** > BOOL CMXReferPage::WriteInIndex(CMXExportDC *pDC) Author: Ben_Summers (Xara Group Ltd) Created: 26/06/96 Inputs: export dc Returns: none Purpose: writes the page details in the layer list SeeAlso: ********************************************************************************************/ BOOL CMXReferPage::WriteInIndex(CMXExportDC *pDC) { // write the entry cmxPageIndexEntry pe; // write size in file pDC->WriteSizeInFile(sizeof(pe)); pe.PageOffset = Offset; pe.LayerTableOffset = LayerTableOffset; pe.ThumbnailOffset = 0; pe.RefListOffset = RefListOffset; if(!pDC->WriteData(&pe, sizeof(pe))) return FALSE; return TRUE; } /******************************************************************************************** > BOOL CMXReferDefaultScreen::WriteInDesc(CMXExportDC *pDC) Author: Ben_Summers (Xara Group Ltd) Created: 26/06/96 Inputs: export dc Returns: none Purpose: writes the default screen list entry -- same as the default one corel writes SeeAlso: ********************************************************************************************/ BOOL CMXReferDefaultScreen::WriteInDesc(CMXExportDC *pDC) { if(pDC->IsThirtyTwoBit()) { cmxScreenDef32 scrdef = {0,0,0,0,0}; if(!pDC->WriteTag(cmxTAG_DescrSection_Screen_Basic, &scrdef, sizeof(scrdef)) || !pDC->WriteMinEndTag()) return FALSE; } else { cmxScreenDef16 scrdef = {0,0,0,0}; if(!pDC->WriteData(&scrdef, sizeof(scrdef))) return FALSE; } return TRUE; } /******************************************************************************************** > BOOL CMXReferDefaultDotDash::WriteInDesc(CMXExportDC *pDC) Author: Ben_Summers (Xara Group Ltd) Created: 26/06/96 Inputs: export dc Returns: none Purpose: writes the default dot dash list entry SeeAlso: ********************************************************************************************/ BOOL CMXReferDefaultDotDash::WriteInDesc(CMXExportDC *pDC) { WORD DotCount = 0; if(!pDC->WriteTag(cmxTAG_DescrSection_Dash, &DotCount, sizeof(DotCount)) || !pDC->WriteMinEndTag()) return FALSE; return TRUE; } /******************************************************************************************** > BOOL CMXReferColour::WriteInDesc(CMXExportDC *pDC) Author: Ben_Summers (Xara Group Ltd) Created: 26/06/96 Inputs: export dc Returns: none Purpose: writes the colour to the DC in a description list SeeAlso: ********************************************************************************************/ BOOL CMXReferColour::WriteInDesc(CMXExportDC *pDC) { ColourModel OutputModel; struct { BYTE ColType; BYTE Palette; } ColH; ColH.Palette = 5; // user palette // Work out which CMX colour type we will export as, and therefore which internal // colour model we should convert the colour to. switch (Colour.GetColourModel()) { case COLOURMODEL_HSVT: OutputModel = COLOURMODEL_HSVT; ColH.ColType = cmxCOLMODEL_HSB; break; case COLOURMODEL_CMYK: OutputModel = COLOURMODEL_CMYK; ColH.ColType = cmxCOLMODEL_CMYK255; break; case COLOURMODEL_GREYT: OutputModel = COLOURMODEL_GREYT; ColH.ColType = cmxCOLMODEL_GREY; break; case COLOURMODEL_RGBT: default: // It's RGB, or we don't know the model, so we'll output it as RGB OutputModel = COLOURMODEL_RGBT; ColH.ColType = cmxCOLMODEL_RGB; break; } // write the header tag if(!pDC->WriteTag(cmxTAG_DescrSection_Color_Base, &ColH, sizeof(ColH))) return FALSE; // Find an appropriate colour context to convert the colour for output ColourContext *OutputCC = ColourManager::GetColourContext(OutputModel); ERROR3IF(OutputCC == NULL, "Can't find a colour context"); // Convert the colour into a packed format ColourPacked Result; OutputCC->ConvertColour(&Colour, &Result); // start the tag if(!pDC->StartTag(cmxTAG_DescrSection_Color_ColorDescr)) return FALSE; // Pull the converted colour out and export it to the CMX file switch (OutputModel) { case COLOURMODEL_HSVT: { /*TRACEUSER( "Ben", _T("HSV colour: hue %d, sat %d, val %d\n"), Result.HSVT.Hue, Result.HSVT.Saturation, Result.HSVT.Value); WORD Hue = Result.HSVT.Hue; pDC->WriteData(&Hue, sizeof(Hue)); pDC->WriteByte(Result.HSVT.Saturation); pDC->WriteByte(Result.HSVT.Value); */ // BODGE because the colour system can't convert HSVT properly yet ColourHSVT GResult; OutputCC->ConvertColour(&Colour, (ColourGeneric *)&GResult); WORD Hue = (WORD)(360.0 * GResult.Hue.MakeDouble()); pDC->WriteData(&Hue, sizeof(Hue)); pDC->WriteByte((BYTE)(255.0 * GResult.Saturation.MakeDouble())); pDC->WriteByte((BYTE)(255.0 * GResult.Value.MakeDouble())); } break; case COLOURMODEL_CMYK: TRACEUSER( "Ben", _T("CMYK colour: cyan %d mag %d yel %d key %d\n"), Result.CMYK.Cyan, Result.CMYK.Magenta, Result.CMYK.Yellow, Result.CMYK.Key); pDC->WriteByte(Result.CMYK.Cyan); pDC->WriteByte(Result.CMYK.Magenta); pDC->WriteByte(Result.CMYK.Yellow); pDC->WriteByte(Result.CMYK.Key); break; case COLOURMODEL_GREYT: TRACEUSER( "Ben", _T("grey colour: grey %d\n"), Result.GreyT.Intensity); pDC->WriteByte(Result.GreyT.Intensity); break; case COLOURMODEL_RGBT: default: TRACEUSER( "Ben", _T("RGB colour: red %d green %d blue %d\n"), Result.RGBT.Red, Result.RGBT.Green, Result.RGBT.Blue); pDC->WriteByte(Result.RGBT.Red); pDC->WriteByte(Result.RGBT.Green); pDC->WriteByte(Result.RGBT.Blue); break; } // end the tag if(!pDC->EndTag()) return FALSE; // write the end tag if(!pDC->WriteMinEndTag()) return FALSE; return TRUE; } /******************************************************************************************** > BOOL CMXReferMasterIndex::WriteInIndex(CMXExportDC *pDC) Author: Ben_Summers (Xara Group Ltd) Created: 26/06/96 Inputs: export dc Returns: none Purpose: writes the index details in the master index SeeAlso: ********************************************************************************************/ BOOL CMXReferMasterIndex::WriteInIndex(CMXExportDC *pDC) { // write the entry cmxMasterIndexEntry me; me.Type = Type; me.Offset = Offset; TRACEUSER( "Ben", _T("Writing entry in master index, type = %d, offset = %x = %d, size = %d\n"), Type, Offset, Offset, sizeof(me)); if(!pDC->WriteData(&me, sizeof(me))) return FALSE; return TRUE; } /******************************************************************************************** > BOOL CMXReferMasterIndex::WriteInIndex(CMXExportDC *pDC) Author: Ben_Summers (Xara Group Ltd) Created: 26/06/96 Inputs: export dc Returns: none Purpose: writes the index details in the master index SeeAlso: ********************************************************************************************/ BOOL CMXReferMasterLayer::WriteInIndex(CMXExportDC *pDC) { // write the entry if(pDC->IsThirtyTwoBit()) { cmxMasterLayerEntry32 le; // note that this is the entire table, not an entry le.TableType = cmxMASTERIN_MASTERLAYER; // quite why we need this is another matter le.SizeInFile = sizeof(DWORD); le.ID = 1; // first page, I presume le.Offset = Offset; // offset... if(!pDC->WriteData(&le, sizeof(le))) return FALSE; } else { cmxMasterLayerEntry16 le; // note that this is the entire table, not an entry le.TableType = cmxMASTERIN_MASTERLAYER; // quite why we need this is another matter le.ID = 1; // first page, I presume le.Offset = Offset; // offset... if(!pDC->WriteData(&le, sizeof(le))) return FALSE; } return TRUE; } /******************************************************************************************** > CMXExportDC::CMXExportDC(Filter *Parent) Author: Ben_Summers (Xara Group Ltd) Created: 18/6/96 Inputs: The filter object associated with this export DC. Purpose: Initialise a DC for exporting EPS. ********************************************************************************************/ CMXExportDC::CMXExportDC(Filter *Parent) : ExportDC(Parent) { } /******************************************************************************************** > BOOL CMXExportDC::Init(CCLexFile* pFile, CMXRenderRegion *pReg, BOOL bThirtyTwoBit) Author: Ben_Summers (Xara Group Ltd) Created: 18/6/96 Inputs: pFile - The file to attach to the DC Returns: TRUE if all went well, FALSE if not Purpose: Calls the base class Init function and then sets up the DC to throw exceptions when it gets errors as that is how the EPS stuff expects errors to be reported. SeeAlso: ExportDC::Init ********************************************************************************************/ BOOL CMXExportDC::Init(CCLexFile* pFile, CMXRenderRegion *pReg, BOOL bThirtyTwoBit, BOOL ClipboardExport) { // First get the base class to do its thing if (!ExportDC::Init(pFile)) return FALSE; // now do what I want done. // We want export files to throw exceptions, and not report errors. ExportFile->SetThrowExceptions(TRUE); ExportFile->SetReportErrors(FALSE); // set the bitness of the file ThirtyTwoBit = bThirtyTwoBit; // mark the fact that we've not actually doing a section at all CurrentSection = CMXSECTION_NONE; // set up a few more variables DoingCommand = FALSE; DoingPage = FALSE; DoingLayer = FALSE; PageRefer = NULL; DoingTag = FALSE; pMatrix = NULL; NestedTagLevel = 0; CurrentInstrFilePosition = -1; pRenderRegion = pReg; DoingRIFFList = FALSE; NumberOfEntriesUsedInCache = 0; // overlapped lenses flag if(!ClipboardExport) { // normal ask the user mode AreIgnoreingOverlappedLenses = FALSE; OverlappedLensesHaveBeenIgnored = FALSE; HaveAskedUserAboutLenses = FALSE; } else { // don't ask the user AreIgnoreingOverlappedLenses = TRUE; OverlappedLensesHaveBeenIgnored = FALSE; HaveAskedUserAboutLenses = TRUE; } for(INT32 i = 0 ; i < CMXFUTUREVALUECACHESIZE ; i++) { // init the write-cache FutureDataCache[i].Location = INT32_MAX; FutureDataCache[i].Data = 0; FutureDataCache[i].DataSize = 0; } // pop in the default screen thingy CMXReferDefaultScreen *pDefScreen = new CMXReferDefaultScreen(this); if(pDefScreen == NULL) return FALSE; // and add it to the list ReferList.AddTail(pDefScreen); // pop in the default dot dash thingy CMXReferDefaultDotDash *pDefdd = new CMXReferDefaultDotDash(this); if(pDefdd == NULL) return FALSE; // and add it to the list ReferList.AddTail(pDefdd); return TRUE; } /******************************************************************************************** > void CMXExportDC::CleanUp(void) Author: Ben_Summers (Xara Group Ltd) Created: 26/06/96 Inputs: none Returns: none Purpose: Cleans up after writing to a file SeeAlso: ********************************************************************************************/ void CMXExportDC::CleanUp(void) { WriteFutureDataCache(); ReferList.DeleteAll(); LensBBoxes.DeleteAll(); } /******************************************************************************************** > BOOL CMXExportDC::StartSection(CMXSectionType Type) Author: Ben_Summers (Xara Group Ltd) Created: 18/6/96 Inputs: The type of section to start Returns: success Purpose: Start writing a section to a CMX file SeeAlso: ********************************************************************************************/ BOOL CMXExportDC::StartSection(CMXSectionType Type) { ERROR2IF(CurrentSection != CMXSECTION_NONE, FALSE, "Tried to start a section without ending the previous one"); // write the riff file header // first, decide what riff chunck id we want DWORD id; BOOL IsAList = FALSE; // whether in fact it's a list switch(Type) { case CMXSECTION_NONE: ERROR2(FALSE, "Tried to start a section of type none. Oh dear"); break; case CMXSECTION_HEADER: id = cmxRIFFCI_Header; break; case CMXSECTION_PAGE: id = cmxRIFFCI_Page; break; case CMXSECTION_REFLIST: id = cmxRIFFCI_ReferenceList; break; case CMXSECTION_INDEX: id = cmxRIFFLIST_Index; IsAList=TRUE; break; case CMXSECTION_TRAILER: id = cmxRIFFLIST_Trail; IsAList=TRUE; break; case CMXSECTION_ARROW: id = cmxRIFFCI_Desc_Arrow; break; case CMXSECTION_ARROWHEADS: id = cmxRIFFCI_Desc_Arrowheads; break; case CMXSECTION_COLOUR: id = cmxRIFFCI_Desc_Colour; break; case CMXSECTION_DOTDASH: id = cmxRIFFCI_Desc_DotDash; break; case CMXSECTION_FONT: id = cmxRIFFCI_Desc_Font; break; case CMXSECTION_OUTLINE: id = cmxRIFFCI_Desc_Outline; break; case CMXSECTION_LINESTYLE: id = cmxRIFFCI_Desc_LineStyle; break; case CMXSECTION_PEN: id = cmxRIFFCI_Desc_Pen; break; case CMXSECTION_LENS: id = cmxRIFFCI_Desc_Lens; break; case CMXSECTION_SCREEN: id = cmxRIFFCI_Desc_Screen; break; case CMXSECTION_IMAGINFO: id = cmxRIFFCI_ImageInfo; break; case CMXSECTION_IMAGDATA: id = cmxRIFFCI_ImageData; break; case CMXSECTION_PROCBITFILL:id = cmxRIFFCI_Procedure; break; case CMXSECTION_PREVIEWBITMAP: id = cmxRIFFCI_Thumbnail; break; default: ERROR2(FALSE, "Unknown section type"); break; } // OK, write the RIFF header RIFFck chdr; chdr.ckID = IsAList?RIFFTYPE_LIST:id; chdr.ckSize = 0; ExportFile->write(&chdr, sizeof(chdr)); // set the future length SectionLengthFuture.Init(this, FUTURE_BACKLOC(&chdr, ckSize), sizeof(chdr.ckSize)); SectionLengthFuture.SetLengthStartPos(this, 0 /* - (INT32)sizeof(chdr)*/); // write the list type, if we're doing a list if(IsAList) ExportFile->write(&id, sizeof(id)); // note which section type we just did CurrentSection = Type; return TRUE; } /******************************************************************************************** > BOOL CMXExportDC::EndSection(void) Author: Ben_Summers (Xara Group Ltd) Created: 24/06/96 Inputs: none Returns: success Purpose: Finish off writing a section to a CMX file SeeAlso: ********************************************************************************************/ BOOL CMXExportDC::EndSection(void) { ERROR2IF(CurrentSection == CMXSECTION_NONE, FALSE, "Tried to end a section which didn't exist"); // write the length SectionLengthFuture.Write(this); // set the section type to none CurrentSection = CMXSECTION_NONE; // word align the file if((GetFilePosition() & 1) != 0) { // put an extra byte in the file ExportFile->put('\0'); } return TRUE; } /******************************************************************************************** > BOOL CMXExportDC::StartRIFFList(INT32 Type) Author: Ben_Summers (Xara Group Ltd) Created: 16/07/96 Inputs: The type of section to start Returns: success Purpose: Start writing a section to a CMX file SeeAlso: ********************************************************************************************/ BOOL CMXExportDC::StartRIFFList(INT32 Type) { ERROR2IF(DoingRIFFList, FALSE, "Tried to start a riff list without ending the previous one"); // write the riff list header RIFFck chdr; chdr.ckID = RIFFTYPE_LIST; chdr.ckSize = 0; ExportFile->write(&chdr, sizeof(chdr)); // set the future length RIFFListLengthFuture.Init(this, FUTURE_BACKLOC(&chdr, ckSize), sizeof(chdr.ckSize)); RIFFListLengthFuture.SetLengthStartPos(this, 0); // write the list type, if we're doing a list DWORD id = Type; ExportFile->write(&id, sizeof(id)); // flag... DoingRIFFList = TRUE; return TRUE; } /******************************************************************************************** > BOOL CMXExportDC::EndRIFFList(void) Author: Ben_Summers (Xara Group Ltd) Created: 16/07/96 Inputs: none Returns: success Purpose: Finish off writing a section to a CMX file SeeAlso: ********************************************************************************************/ BOOL CMXExportDC::EndRIFFList(void) { ERROR2IF(!DoingRIFFList, FALSE, "Tried to end a riff list which didn't exist"); // write the length RIFFListLengthFuture.Write(this); // word align the file if((GetFilePosition() & 1) != 0) { // put an extra byte in the file ExportFile->put('\0'); } // flag DoingRIFFList = FALSE; return TRUE; } /******************************************************************************************** > BOOL CMXExportDC::StartTag(INT32 Tag) Author: Ben_Summers (Xara Group Ltd) Created: 27/06/96 Inputs: Tag for the command Returns: success Purpose: starts writing a tag to the file SeeAlso: ********************************************************************************************/ BOOL CMXExportDC::StartTag(INT32 Tag) { if(!ThirtyTwoBit) return TRUE; // 16 bit files don't have tags ERROR2IF(DoingTag == TRUE, FALSE, "already doing a tag"); // write the tag header cmxTagHdr hdr; hdr.ID = (BYTE)Tag; hdr.Size = 0; ExportFile->write(&hdr, sizeof(hdr)); // initialise the future value TagLengthFuture.Init(this, FUTURE_BACKLOC(&hdr, Size), sizeof(hdr.Size)); TagLengthFuture.SetLengthStartPos(this, 0-(INT32)sizeof(hdr)); // flag DoingTag = TRUE; return TRUE; } /******************************************************************************************** > BOOL CMXExportDC::EndTag(void) Author: Ben_Summers (Xara Group Ltd) Created: 27/06/96 Inputs: none Returns: success Purpose: ends a tag SeeAlso: ********************************************************************************************/ BOOL CMXExportDC::EndTag(void) { if(!ThirtyTwoBit) return TRUE; // 16 bit files don't have tags ERROR2IF(DoingTag == FALSE, FALSE, "not doing a tag"); ERROR2IF(NestedTagLevel != 0, FALSE, "tried to end a main tag when nested tags are active"); // write the length TagLengthFuture.Write(this); // flag DoingTag = FALSE; return TRUE; } /******************************************************************************************** > BOOL CMXExportDC::StartNestedTag(INT32 Tag) Author: Ben_Summers (Xara Group Ltd) Created: 27/06/96 Inputs: Tag for the command Returns: success Purpose: starts writing a nested tag to the file SeeAlso: ********************************************************************************************/ BOOL CMXExportDC::StartNestedTag(INT32 Tag) { if(!ThirtyTwoBit) return TRUE; // 16 bit files don't have tags ERROR2IF(DoingTag == FALSE, FALSE, "tried to start a nested tag outside a tag"); // write the tag header cmxTagHdr hdr; hdr.ID = (BYTE)Tag; hdr.Size = 0; ExportFile->write(&hdr, sizeof(hdr)); // get one of those nested tag record things CMXNestedTagRecord *pRec = new CMXNestedTagRecord; if(pRec == NULL) return FALSE; // initialise the future value pRec->LengthFuture.Init(this, FUTURE_BACKLOC(&hdr, Size), sizeof(hdr.Size)); pRec->LengthFuture.SetLengthStartPos(this, 0-(INT32)sizeof(hdr)); // add the record to the list NestedTagList.AddTail(pRec); // flag NestedTagLevel++; return TRUE; } /******************************************************************************************** > BOOL CMXExportDC::EndNestedTag(void) Author: Ben_Summers (Xara Group Ltd) Created: 04/07/96 Inputs: none Returns: success Purpose: ends a nested tag SeeAlso: ********************************************************************************************/ BOOL CMXExportDC::EndNestedTag(void) { if(!ThirtyTwoBit) return TRUE; // 16 bit files don't have tags ERROR2IF(DoingTag == FALSE, FALSE, "not doing a tag"); ERROR2IF(NestedTagLevel <= 0, FALSE, "not doing a nested tag"); // get the last tag record CMXNestedTagRecord *pRec = (CMXNestedTagRecord *)NestedTagList.GetTail(); // check it's OK ERROR2IF(!IS_A(pRec, CMXNestedTagRecord), FALSE, "tag record not a tag record"); // write the length pRec->LengthFuture.Write(this); // delete the record delete NestedTagList.RemoveTail(); // flag NestedTagLevel--; return TRUE; } /******************************************************************************************** > BOOL CMXExportDC::DoWriteTag(INT32 Tag, void *Data = 0, UINT32 Size = 0, BOOL Nested = FALSE) Author: Ben_Summers (Xara Group Ltd) Created: 27/06/96 Inputs: none Returns: success Purpose: writes a tag in one go SeeAlso: ********************************************************************************************/ BOOL CMXExportDC::DoWriteTag(INT32 Tag, void *Data, UINT32 Size, BOOL Nested) { if(!Nested) { ERROR2IF(DoingTag == TRUE, FALSE, "already doing a tag"); } // if we're not doing a 32 bit file, we just want to export the data if(ThirtyTwoBit) { // write the tag header cmxTagHdr hdr; hdr.ID = (BYTE)Tag; hdr.Size = sizeof(hdr)+Size; ExportFile->write(&hdr, sizeof(hdr)); } // write the data, if required if(Size != 0) ExportFile->write(Data, Size); return TRUE; } /******************************************************************************************** > BOOL CMXExportDC::WriteCommand(UINT32 Tag, void *Data, UINT32 Size) Author: Ben_Summers (Xara Group Ltd) Created: 18/6/96 Inputs: Tag for the command, the data, and the size Returns: success Purpose: Write a command to the file -- one off operation, writes command and data in one go. Use default params for a no-data command. SeeAlso: ********************************************************************************************/ BOOL CMXExportDC::WriteCommand(UINT32 Tag, void *Data, UINT32 Size) { ERROR2IF(DoingCommand != FALSE, FALSE, "Already writing a command"); // write the header cmxInstrHdr hdr = {Size + sizeof(hdr), ThirtyTwoBit?Tag:(0 - (SWORD)Tag)}; // word align the size if((hdr.Size & 1) != 0) hdr.Size++; ExportFile->write(&hdr, sizeof(hdr)); if(Size != 0) { ERROR2IF(Data == 0, FALSE, "didn't get some data"); // write the command ExportFile->write(Data, Size); } Tally++; PageInstructionCount++; LayerInstructionCount++; // word align the file if((/*GetFilePosition()*/ Size & 1) != 0) { // put an extra byte in the file ExportFile->put('\0'); } return TRUE; } /******************************************************************************************** > BOOL CMXExportDC::StartCommand(UINT32 Tag) Author: Ben_Summers (Xara Group Ltd) Created: 21/06/96 Inputs: none Returns: success Purpose: starts writing a command for a command where the data is of indetermant size. Use EndCommand to finish it off SeeAlso: WriteCommand -- use for one off commands ********************************************************************************************/ BOOL CMXExportDC::StartCommand(UINT32 Tag) { ERROR2IF(DoingCommand != FALSE, FALSE, "Already writing a command"); // record the start of the file CurrentInstrFilePosition = GetFilePosition(); // write the header cmxInstrHdr hdr = {0, ThirtyTwoBit?Tag:(0 - (SWORD)Tag)}; ExportFile->write(&hdr, sizeof(hdr)); Tally++; PageInstructionCount++; LayerInstructionCount++; // set the future length CommandLengthFuture.Init(this, FUTURE_BACKLOC(&hdr, Size), sizeof(hdr.Size)); CommandLengthFuture.SetLengthStartPos(this, 0 - (INT32)sizeof(hdr)); // set whether we're doing a command DoingCommand = TRUE; return TRUE; } /******************************************************************************************** > BOOL CMXExportDC::EndCommand(void) Author: Ben_Summers (Xara Group Ltd) Created: 21/06/96 Inputs: none Returns: success Purpose: ends a command SeeAlso: ********************************************************************************************/ BOOL CMXExportDC::EndCommand(void) { ERROR2IF(DoingCommand != TRUE, FALSE, "Already writing a command"); // word align the file if((GetFilePosition() & 1) != 0) { // put an extra byte in the file ExportFile->put('\0'); } CommandLengthFuture.Write(this); DoingCommand = FALSE; CurrentInstrFilePosition = -1; return TRUE; } /******************************************************************************************** > BOOL CMXExportDC::CreateHeader(DocRect *pFileBBox) Author: Ben_Summers (Xara Group Ltd) Created: 21/06/96 Inputs: bounding box of file Returns: success Purpose: Write the file's header, and name notes of the location of things like the relevant sizes and indices and other stuff which can only be written after the export. This fn is called Create rather than Write because it's not finished off properly until the end of the file. SeeAlso: ********************************************************************************************/ BOOL CMXExportDC::CreateHeader(DocRect *pFileBBox) { ERROR2IF(pMatrix == NULL, FALSE, "No matrix yet"); // first of all, think about the riff file header RIFFFile_Header rhdr; rhdr.CK.ckID = RIFFTYPE_RIFF; rhdr.CK.ckSize = 0; rhdr.FormType = cmxRIFFFORMTYPE_CMX; ExportFile->write(&rhdr, sizeof(rhdr)); // set up the future length object FileLengthFuture.Init(this, FUTURE_BACKLOC(&rhdr, CK.ckSize), sizeof(rhdr.CK.ckSize)); FileLengthFuture.SetLengthStartPos(this, /*-((INT32)sizeof(rhdr))*/ -(INT32)sizeof(DWORD)); // start the CMX header section if(!StartSection(CMXSECTION_HEADER)) return FALSE; // write the CMX header cmxHeader fhdr; memset(&fhdr, 0, sizeof(fhdr)); // set everything to zero camStrcpy((char *)fhdr.Id, cmxID); camStrcpy((char *)fhdr.OS, cmxOS); fhdr.ByteOrder = cmxBYTEORDER_INTEL | 0x30; if(ThirtyTwoBit) { fhdr.CoordSize = cmxCOORDSIZE_32 | 0x30; fhdr.Major = cmxMAJOR_32 | 0x30; fhdr.Factor = cmxFACTOR_32; fhdr.Unit = cmxUNIT_MILLIMETER; } else { fhdr.CoordSize = cmxCOORDSIZE_16 | 0x30; fhdr.Major = cmxMAJOR_16 | 0x30; fhdr.Factor = cmxFACTOR_16; fhdr.Unit = cmxUNIT_INCH; } fhdr.Minor = cmxMINOR | 0x30; // bounding box DocRect bb = *pFileBBox; pMatrix->TransformBounds(&bb); fhdr.IBBLeft = bb.lo.x; fhdr.IBBTop = bb.hi.y; fhdr.IBBRight = bb.hi.x; fhdr.IBBBottom = bb.lo.y; fhdr.IThumbnail = -1; ExportFile->write(&fhdr, sizeof(fhdr)); // set up it's future value objects Tally.Init(this, FUTURE_BACKLOC(&fhdr, ITally), sizeof(fhdr.ITally)); Tally = 0; IndexSectionFuture.Init(this, FUTURE_BACKLOC(&fhdr, IIndexSection), sizeof(fhdr.IIndexSection)); TrailerIndexFuture.Init(this, FUTURE_BACKLOC(&fhdr, IInfoSection), sizeof(fhdr.IInfoSection)); ThumbnailIndexFuture.Init(this, FUTURE_BACKLOC(&fhdr, IThumbnail), sizeof(fhdr.IThumbnail)); // end the CMX header section if(!EndSection()) return FALSE; return TRUE; } /******************************************************************************************** > BOOL CMXExportDC::PolishOffThatFile() Author: Ben_Summers (Xara Group Ltd) Created: 21/06/96 Inputs: none Returns: success Purpose: Finish off the file, update indexes and all that SeeAlso: ********************************************************************************************/ BOOL CMXExportDC::PolishOffThatFile() { ERROR2IF(CurrentSection != CMXSECTION_NONE, FALSE, "Didn't end the section before ending the file"); // write some future values if(!Tally.Write(this)) return FALSE; // write the info section if(!TrailerIndexFuture.Write(this)) return FALSE; if(!StartSection(CMXSECTION_TRAILER)) return FALSE; if(!EndSection()) return FALSE; // and pop the length in if(!FileLengthFuture.Write(this)) return FALSE; WriteFutureDataCache(); return TRUE; } /******************************************************************************************** > INT32 CMXExportDC::GetFilePosition(); Author: Ben_Summers (Xara Group Ltd) Created: 21/06/96 Inputs: none Returns: success Purpose: returns the position of the current file pointer in the export file SeeAlso: ********************************************************************************************/ INT32 CMXExportDC::GetFilePosition() { return ExportFile->tell(); } /******************************************************************************************** > BOOL CMXExportDC::WriteBBox(DocRect *BBox, BOOL Transform = TRUE) Author: Ben_Summers (Xara Group Ltd) Created: 21/06/96 Inputs: none Returns: success Purpose: Write a bounding box to the file SeeAlso: ********************************************************************************************/ BOOL CMXExportDC::WriteBBox(DocRect *BBox, BOOL Transform) { ERROR2IF(pMatrix == NULL, FALSE, "No matrix"); if(ThirtyTwoBit) { DocRect bb = *BBox; if(Transform) pMatrix->TransformBounds(&bb); cmxBBox32 b = {bb.lo.x, bb.hi.y, bb.hi.x, bb.lo.y}; ExportFile->write(&b, sizeof(b)); } else { DocRect bb = *BBox; if(Transform) pMatrix->TransformBounds(&bb); cmxBBox16 b = {(SWORD)bb.lo.x, (SWORD)bb.hi.y, (SWORD)bb.hi.x, (SWORD)bb.lo.y}; ExportFile->write(&b, sizeof(b)); } return TRUE; } /******************************************************************************************** > void CMXExportDC::WriteAngle(double theta) Author: Ben_Summers (Xara Group Ltd) Created: 10/07/96 Inputs: angle, in radians Returns: - Purpose: writes an angle to the file SeeAlso: ********************************************************************************************/ void CMXExportDC::WriteAngle ( double theta ) { // Convert theta to be measured in degrees. theta = ( theta * 360.0 ) / ( 2.0 * PI ); // 32-bit export uses a larger scale factor. if(ThirtyTwoBit) { INT32 Angle32 = ( INT32 ) ( theta * 1000000.0 ); ExportFile->write ( &Angle32, sizeof ( Angle32 ) ); } else { short Angle16 = ( short ) ( theta * 10.0); ExportFile->write ( &Angle16, sizeof ( Angle16 ) ); } } /******************************************************************************************** > BOOL CMXExportDC::WriteString(StringBase *Str) Author: Ben_Summers (Xara Group Ltd) Created: 25/06/96 Inputs: none Returns: success Purpose: Write a bounding box to the file SeeAlso: ********************************************************************************************/ BOOL CMXExportDC::WriteString(StringBase *Str) { INT32 StrLen = Str->Length(); cmxString h; h.Length = (WORD)StrLen; ExportFile->write(&h, sizeof(h)); ExportFile->write((TCHAR *)(*Str), StrLen); return TRUE; } /******************************************************************************************** > BOOL CMXExportDC::WriteMatrix(Matrix *pMatrix = NULL) Author: Ben_Summers (Xara Group Ltd) Created: 27/06/96 Inputs: matrix to write, NULL for identity matrix Returns: success Purpose: writes a matrix to the file SeeAlso: ********************************************************************************************/ BOOL CMXExportDC::WriteMatrix(Matrix *pMatrix) { if(pMatrix == NULL) { // write an identity matrix WORD MatrixType = cmxMATRIXTYPE_IDENTITY; ExportFile->write(&MatrixType, sizeof(MatrixType)); } else { // write the matrix cmxMatrix Thingy; FIXED16 abcd[4]; INT32 ef[2]; pMatrix->GetComponents((FIXED16 *)(&abcd), (INT32 *)(&ef)); Thingy.Type = cmxMATRIXTYPE_GENERAL; Thingy.a = abcd[0].MakeDouble(); Thingy.b = abcd[1].MakeDouble(); Thingy.c = abcd[2].MakeDouble(); Thingy.d = abcd[3].MakeDouble(); Thingy.e = (DOUBLE)ef[0]; Thingy.f = (DOUBLE)ef[1]; ExportFile->write(&Thingy, sizeof(Thingy)); } return TRUE; } /******************************************************************************************** > BOOL CMXExportDC::WriteNumber(INT32 Position, UINT32 DataSize, INT32 Value); Author: Claude_Quemerais (Xara Group Ltd) Created: 21/06/96 Inputs: none Returns: success Purpose: Finish off the file, update indexes and all that Fixed by Ben so it doesn't write over the end of the array and screw up the other variables in the class and cause nasty AVs in retail builds which annoy Charles and take me ages to find. ********************************************************************************************/ BOOL CMXExportDC::WriteNumber(INT32 Position, UINT32 DataSize, INT32 Value) { TRACEUSER( "Claude", _T("Writing number %x at %d, size %d\n"), Value, Position, DataSize); // When cache full => Flush it to the file. if(NumberOfEntriesUsedInCache >= (CMXFUTUREVALUECACHESIZE - 1)) WriteFutureDataCache(); // Variable used to find out what entry is to be used INT32 theEntryInCache = 0; // Search for the right place in the cache, i.e. sort the cache as // it's generated while((theEntryInCache < NumberOfEntriesUsedInCache) && (Position > FutureDataCache[theEntryInCache].Location)) theEntryInCache++; TRACEUSER( "Claude", _T("Writing entry %d"), theEntryInCache); if(theEntryInCache < NumberOfEntriesUsedInCache) { // If the entry to use is before the last entry already used in the cache // Push all entries used from the one we want onward. // Variable used to determine which entry is to be pushed // Starting from the end. for(INT32 entrySorting = NumberOfEntriesUsedInCache; entrySorting >= theEntryInCache; entrySorting--) { // Copy the entry onto the next one FutureDataCache[entrySorting+1] = FutureDataCache[entrySorting]; } } // Copy the information into the cache FutureDataCache[theEntryInCache].Location = Position; FutureDataCache[theEntryInCache].Data = Value; FutureDataCache[theEntryInCache].DataSize = DataSize; TRACEUSER( "Claude", _T("Writing number %x at %d, size %d\n"), FutureDataCache[theEntryInCache].Data, FutureDataCache[theEntryInCache].Location, FutureDataCache[theEntryInCache].DataSize); // Put the entry to use on the next one. NumberOfEntriesUsedInCache++; return TRUE; } /******************************************************************************************* > BOOL CMXExportDC::WriteFutureDataCache() Author: Claude_Quemerais (Xara Group Ltd) Created: 15/07/96 Inputs: none Returns: Success Purpose: Write the Numbers from the cache to the file See also: *******************************************************************************************/ BOOL CMXExportDC::WriteFutureDataCache() { // Find out the current position in the file INT32 here = ExportFile->tell(); for(INT32 i = 0 ; i < NumberOfEntriesUsedInCache ; i++) { // write the numbers to file TRACEUSER( "Claude", _T("Writing cache %x at %d, size %d\n"), FutureDataCache[i].Data, FutureDataCache[i].Location, FutureDataCache[i].DataSize); // Get the location where to put the info in the file ExportFile->seek(FutureDataCache[i].Location); if(FutureDataCache[i].DataSize != 0) { // If there is something flush it (there should always be something) switch(FutureDataCache[i].DataSize) { case sizeof(BYTE): { // If it's a BYTE, write a BYTE BYTE Num = (BYTE)FutureDataCache[i].Data; ExportFile->write(&Num, sizeof(Num)); } break; case sizeof(WORD): { // If it's a WORD, write a WORD WORD Num = (WORD)FutureDataCache[i].Data; ExportFile->write(&Num, sizeof(Num)); } break; case sizeof(INT32): { // If it's a INT32, write a INT32 INT32 Num = FutureDataCache[i].Data; ExportFile->write(&Num, sizeof(Num)); } break; default: // If it's anything else, something went wrong ERROR3("OOOKK! Non supported data size"); break; } // Empty that entry of the cache, putting the Location to the maximum possible FutureDataCache[i].Location = INT32_MAX; FutureDataCache[i].Data = 0; FutureDataCache[i].DataSize = 0; } } // Put the file back to wherever it was before we used it ExportFile->seek(here); // reset the cache count thingy NumberOfEntriesUsedInCache = 0; return TRUE; } /******************************************************************************************** > BOOL CMXExportDC::StartPage(Rect *BBox, BOOL IsProcedure = FALSE) Author: Ben_Summers (Xara Group Ltd) Created: 25/06/96 Inputs: none Returns: success Purpose: starts a Page SeeAlso: ********************************************************************************************/ BOOL CMXExportDC::StartPage(DocRect *BBox, BOOL IsProcedure) { ERROR2IF(DoingPage == TRUE, FALSE, "Already doing a page"); if(!IsProcedure) { ////////////////// page version // make the page reference object PageRefer = new CMXReferPage(this); if(PageRefer == NULL) return FALSE; ReferList.AddTail(PageRefer); // start the section StartSection(CMXSECTION_PAGE); // write the page start StartCommand(cmxINSTR_BeginPage); // tag this bit if(!StartTag(cmxTAG_BeginPage_PageSpecification)) return FALSE; cmxInstrPage1 phdr1; phdr1.PageNumber = 1; phdr1.Flags = 0; ExportFile->write(&phdr1, sizeof(phdr1)); // set the future flags value PageFlags.Init(this, FUTURE_BACKLOC(&phdr1, Flags), sizeof(phdr1.Flags)); PageFlags = 0; // write the bbox, transforming the thing of course WriteBBox(BBox); // write the rest of the page command cmxInstrPage2 phdr2; phdr2.EndPageOffset = 0; phdr2.GroupCount = 0; phdr2.InstructionCount = 0; ExportFile->write(&phdr2, sizeof(phdr2)); // set up some future values PageEndIndexFuture.Init(this, FUTURE_BACKLOC(&phdr2, EndPageOffset), sizeof(phdr2.EndPageOffset)); PageGroupCount.Init(this, FUTURE_BACKLOC(&phdr2, GroupCount), sizeof(phdr2.GroupCount)); PageGroupCount = 0; PageInstructionCount.Init(this, FUTURE_BACKLOC(&phdr2, InstructionCount), sizeof(phdr2.InstructionCount)); PageInstructionCount = 1; // to include this instr // end the tag if(!EndTag()) return FALSE; // matrix tag... if(!StartTag(cmxTAG_BeginPage_Matrix)) return FALSE; // write the matrix if(!WriteMatrix()) return FALSE; // end the tag if(!EndTag()) return FALSE; // mapping mode... BYTE MapMode = 0; if(!WriteTag(cmxTAG_BeginPage_MappingMode, &MapMode, sizeof(MapMode))) return FALSE; // end tag if(!WriteMinEndTag()) return FALSE; // end the command EndCommand(); // flag PageIsProc = FALSE; } else { ///////////////////// procedure version // write the procedure start StartCommand(cmxINSTR_BeginProcedure); // tag this bit if(!StartTag(cmxTAG_BeginProcedure_ProcedureSpecification)) return FALSE; cmxInstrProc1 phdr1; phdr1.Flags = 0; ExportFile->write(&phdr1, sizeof(phdr1)); // set the future flags value PageFlags.Init(this, FUTURE_BACKLOC(&phdr1, Flags), sizeof(phdr1.Flags)); PageFlags = 0; // write the bbox, not transforming it as we've already done that WriteBBox(BBox, FALSE); // write the rest of the page command cmxInstrProc2 phdr2; phdr2.EndPageOffset = 0; phdr2.GroupCount = 0; phdr2.InstructionCount = 0; ExportFile->write(&phdr2, sizeof(phdr2)); // set up some future values PageEndIndexFuture.Init(this, FUTURE_BACKLOC(&phdr2, EndPageOffset), sizeof(phdr2.EndPageOffset)); PageGroupCount.Init(this, FUTURE_BACKLOC(&phdr2, GroupCount), sizeof(phdr2.GroupCount)); PageGroupCount = 0; PageInstructionCount.Init(this, FUTURE_BACKLOC(&phdr2, InstructionCount), sizeof(phdr2.InstructionCount)); PageInstructionCount = 1; // to include this instr // end the tag if(!EndTag()) return FALSE; // end tag if(!WriteMinEndTag()) return FALSE; // end the command EndCommand(); // flag PageIsProc = TRUE; } DoingPage = TRUE; LayerNumber = 0; // record the location of the first instruction in the file, which will follow immediately if(!IsProcedure) FirstInstrFilePosition = GetFilePosition(); // write a comment to say where this file came from // return WriteCamComment(); return TRUE; // Graeme (10-2-00) replaced above return with return TRUE. } /******************************************************************************************** > BOOL CMXExportDC::EndPage(void) Author: Ben_Summers (Xara Group Ltd) Created: 25/06/96 Inputs: none Returns: success Purpose: ends a Page SeeAlso: ********************************************************************************************/ BOOL CMXExportDC::EndPage(void) { ERROR2IF(DoingPage == FALSE, FALSE, "Not doing a page"); // write the index of the end page command PageEndIndexFuture.Write(this); // write the end page command if(!PageIsProc) WriteCommand(cmxINSTR_EndPage); else WriteCommand(cmxINSTR_EndSection); // write future values PageFlags.Write(this); PageInstructionCount.Write(this); PageGroupCount.Write(this); // finish the section if(!PageIsProc) EndSection(); DoingPage = FALSE; return TRUE; } /******************************************************************************************** > BOOL CMXExportDC::StartLayer(String_256 &Name) Author: Ben_Summers (Xara Group Ltd) Created: 25/06/96 Inputs: layer name Returns: success Purpose: starts a layer SeeAlso: ********************************************************************************************/ BOOL CMXExportDC::StartLayer(String_256 &Name) { ERROR2IF(DoingPage == FALSE, FALSE, "Layers should be in pages"); ERROR2IF(DoingLayer == TRUE, FALSE, "Already doing a layer"); LayerNumber++; // get a entry for this thingy in the reference list CMXReferLayer *pRL = new CMXReferLayer(this); if(pRL == NULL) return FALSE; pRL->SetLayerDetails(LayerNumber, &Name); ReferList.AddTail(pRL); // add it to the list // start the command StartCommand(cmxINSTR_BeginLayer); // tag if(!StartTag(cmxTAG_BeginLayer_LayerSpecification)) return FALSE; // write the first bit of the instruction cmxInstrLayer1 chdr1; chdr1.PageNumber = 1; chdr1.LayerNumber = (WORD)LayerNumber; chdr1.LayerFlags = 0; chdr1.InstructionCount = 0; ExportFile->write(&chdr1, sizeof(chdr1)); // set up the instruciton count future LayerInstructionCount.Init(this, FUTURE_BACKLOC(&chdr1, InstructionCount), sizeof(chdr1.InstructionCount)); LayerFlags.Init(this, FUTURE_BACKLOC(&chdr1, LayerFlags), sizeof(chdr1.LayerFlags)); LayerFlags = 0; // write it's name out WriteString(&Name); // end the tag if(!EndTag()) return FALSE; // write the second bit of the thingy if(!StartTag(cmxTAG_BeginLayer_Matrix)) return FALSE; if(!WriteMatrix()) return FALSE; if(!EndTag()) return FALSE; // mapping mode... BYTE MapMode = 0; if(!WriteTag(cmxTAG_BeginLayer_MappingMode, &MapMode, sizeof(MapMode))) return FALSE; // end tag if(!WriteMinEndTag()) return FALSE; // end the command EndCommand(); LayerInstructionCount = 1; // to include this one DoingLayer = TRUE; return TRUE; } /******************************************************************************************** > BOOL CMXExportDC::EndLayer(void) Author: Ben_Summers (Xara Group Ltd) Created: 25/06/96 Inputs: none Returns: success Purpose: ends a layer SeeAlso: ********************************************************************************************/ BOOL CMXExportDC::EndLayer(void) { ERROR2IF(DoingLayer == FALSE, FALSE, "Already doing a layer"); // write the end layer command WriteCommand(cmxINSTR_EndLayer); // write the count of instructions in the layer LayerInstructionCount.Write(this); LayerFlags.Write(this); DoingLayer = FALSE; return TRUE; } /******************************************************************************************** > BOOL CMXExportDC::StartGroup(DocRect *BBox) Author: Ben_Summers (Xara Group Ltd) Created: 25/06/96 Inputs: none Returns: success Purpose: starts a group SeeAlso: ********************************************************************************************/ BOOL CMXExportDC::StartGroup(DocRect *BBox, BOOL TransformBBox) { ERROR2IF(DoingLayer == FALSE && !PageIsProc, FALSE, "Groups should be in layers"); // increment the group count PageGroupCount++; // start the command if(!StartCommand(cmxINSTR_BeginGroup)) return FALSE; // start the tag if(!StartTag(cmxTAG_BeginGroup_GroupSpecification)) return FALSE; // write the bounding box if(!WriteBBox(BBox, TransformBBox)) return FALSE; // get a group record object CMXGroupRecord *pGRec = new CMXGroupRecord(this); if(pGRec == NULL) return FALSE; // add the group record object to the list GroupList.AddTail(pGRec); // write a place holder data chunk cmxGroupInfo gi = {0,0,0}; ExportFile->write(&gi, sizeof(gi)); if(!EndTag()) return FALSE; if(!WriteMinEndTag()) return FALSE; // end the command if(!EndCommand()) return FALSE; return TRUE; } /******************************************************************************************** > BOOL CMXExportDC::EndGroup(void) Author: Ben_Summers (Xara Group Ltd) Created: 25/06/96 Inputs: none Returns: success Purpose: ends a group SeeAlso: ********************************************************************************************/ BOOL CMXExportDC::EndGroup(void) { // get the last entry off the group list CMXGroupRecord *pGRec = (CMXGroupRecord *)GroupList.GetTail(); // get it to write itself if(!pGRec->Write(this)) return FALSE; // delete the group record delete GroupList.RemoveTail(); // write the end group command if(!WriteCommand(cmxINSTR_EndGroup)) return FALSE; return TRUE; } /******************************************************************************************** > CMXGroupRecord::CMXGroupRecord(CMXExportDC *pDC) Author: Ben_Summers (Xara Group Ltd) Created: 26/06/96 Inputs: a CMXExportDC Returns: none Purpose: initialises the group record SeeAlso: ********************************************************************************************/ CMXGroupRecord::CMXGroupRecord(CMXExportDC *pDC) { Offset = pDC->GetFilePosition(); TallyAtStart = pDC->GetInstructionTally(); GroupCountAtStart = pDC->GetGroupCount(); } /******************************************************************************************** > CMXGroupRecord::CMXGroupRecord(CMXExportDC *pDC) Author: Ben_Summers (Xara Group Ltd) Created: 26/06/96 Inputs: a CMXExportDC Returns: sucess Purpose: writes the info in the start of the group command SeeAlso: ********************************************************************************************/ BOOL CMXGroupRecord::Write(CMXExportDC *pDC) { // write the group count if(!pDC->WriteNumber(Offset, sizeof(WORD), pDC->GetGroupCount() - GroupCountAtStart)) return FALSE; // write the instruction count if(!pDC->WriteNumber(Offset + sizeof(WORD), sizeof(DWORD), pDC->GetInstructionTally() - TallyAtStart)) return FALSE; // write the group end location if(!pDC->WriteNumber(Offset + sizeof(WORD) + sizeof(DWORD), sizeof(DWORD), pDC->GetFilePosition())) return FALSE; return TRUE; } /******************************************************************************************** > BOOL CMXExportDC::WriteReferenceList(void) Author: Ben_Summers (Xara Group Ltd) Created: 25/06/96 Inputs: none Returns: success Purpose: writes the reference list for the page we've just done SeeAlso: ********************************************************************************************/ BOOL CMXExportDC::WriteReferenceList(void) { // first, find the number of entries in this list WORD RefListEntries = 0; CMXReferListItem *pEn = (CMXReferListItem *)ReferList.GetHead(); while(pEn != 0) { ERROR3IF(!pEn->IsKindOf(CC_RUNTIME_CLASS(CMXReferListItem)), "Entry in the refer list isn't a correct list item"); if(pEn->IsInReferenceList()) RefListEntries++; pEn = (CMXReferListItem *)ReferList.GetNext(pEn); } // set the location in the page reference item ERROR2IF(PageRefer == NULL, FALSE, "no page reference item"); PageRefer->SetRefListOffset(GetFilePosition()); RefListOffset = GetFilePosition(); // start the section if(!StartSection(CMXSECTION_REFLIST)) return FALSE; // write the number of entries in the list ExportFile->write(&RefListEntries, sizeof(RefListEntries)); // write the entries pEn = (CMXReferListItem *)ReferList.GetHead(); while(pEn != 0) { ERROR3IF(!pEn->IsKindOf(CC_RUNTIME_CLASS(CMXReferListItem)), "Entry in the refer list isn't a correct list item"); if(!pEn->WriteInReferenceList(this)) return FALSE; pEn = (CMXReferListItem *)ReferList.GetNext(pEn); } // end the section if(!EndSection()) return FALSE; return TRUE; } /******************************************************************************************** > BOOL CMXExportDC::WriteIndex(void) Author: Ben_Summers (Xara Group Ltd) Created: 25/06/96 Inputs: none Returns: success Purpose: writes the index for the file SeeAlso: ********************************************************************************************/ BOOL CMXExportDC::WriteIndex(void) { // start the section if(!StartSection(CMXSECTION_INDEX)) return FALSE; // write the layer index if(!WriteAnIndex(cmxINDEX_LAYER)) return FALSE; // write the master layer index if(!WriteAnIndex(cmxINDEX_MASTERLAYER)) return FALSE; // write the page index if(!WriteAnIndex(cmxINDEX_PAGE)) return FALSE; // write the procedure index if(!WriteAnIndex(cmxINDEX_PROCEDURE)) return FALSE; // write the embedded file index if(!WriteAnIndex(cmxINDEX_EMBEDFILE)) return FALSE; // write the embedded file index if(!WriteAnIndex(cmxINDEX_ARROW)) return FALSE; // write the master index if(!WriteAnIndex(cmxINDEX_MASTERINDEX)) return FALSE; // end the section if(!EndSection()) return FALSE; return TRUE; } /******************************************************************************************** > BOOL CMXExportDC::WriteCamComment(void) Author: Ben_Summers (Xara Group Ltd) Created: 01/08/96 Inputs: none Returns: success Purpose: writes a helpful comment so we can see where dodgy cam cmx files come from SeeAlso: ********************************************************************************************/ BOOL CMXExportDC::WriteCamComment(void) { if(PageIsProc) return TRUE; // only write comments in pages CCamApp* Application; String_64 Text; String_256 TheText = String_256("saved from " PRODUCT_NAME " "); // WEBSTER - markn 26/11/96 // munge an info string together Application = (CCamApp*) AfxGetApp(); // Find our main application object Application->GetCamelotVersion(&Text); Text += TEXT("(v"); Text += TEXT(PRODUCT_VERSION_NO); Text += TEXT(")"); TheText += Text; // Text.MakeMsg(_R(IDS_CAMVERSION), &Text1); Text._MakeMsg(TEXT(" (#1%d) "), (INT32) CAMELOT_VERSION_MINOR); TheText += Text; Application->GetCamelotType(&Text); TheText += Text; TheText += " on "; Application->GetHostOSName(&Text); // ... plonk info from it into the dlog TheText += Text; TRACEUSER( "Ben", _T("setting comment = %s\n"), (TCHAR *)TheText); // now start a command and a tag if(!StartCommand(cmxINSTR_Comment) || !StartTag(cmxTAG_Comment_CommentSpecification)) return FALSE; WORD Size = TheText.Length(); ExportFile->write(&Size, sizeof(Size)); ExportFile->write((TCHAR *)TheText, Size); // end the command if(!EndTag() || !WriteMinEndTag() || !EndCommand()) return FALSE; return TRUE; } /******************************************************************************************** > BOOL CMXExportDC::WriteReferSections(void) Author: Ben_Summers (Xara Group Ltd) Created: 12/07/96 Inputs: none Returns: success Purpose: gets all refer list items which are sections to write themselves SeeAlso: ********************************************************************************************/ BOOL CMXExportDC::WriteReferSections(void) { // wander through the list CMXReferListItem *pEn = (CMXReferListItem *)ReferList.GetHead(); while(pEn != 0) { ERROR3IF(!pEn->IsKindOf(CC_RUNTIME_CLASS(CMXReferListItem)), "unexpected type of entry in refer list"); if(pEn->IsASection()) { if(!pEn->WriteSection(this)) return FALSE; } pEn = (CMXReferListItem *)ReferList.GetNext(pEn); } return TRUE; } /******************************************************************************************** > BOOL CMXExportDC::WriteAnIndex(INT32 Which) Author: Ben_Summers (Xara Group Ltd) Created: 25/06/96 Inputs: none Returns: success Purpose: writes the a particular index to the file SeeAlso: ********************************************************************************************/ BOOL CMXExportDC::WriteAnIndex(INT32 Which) { // size of the table -- special actions may add some stuff to it INT32 TableSize = sizeof(WORD); // for record count // get some types and sort out the master index entry for this table // and do any special actions for certain index types INT32 id; CMXReferMasterIndex *pMIE = new CMXReferMasterIndex(this); if(pMIE == NULL) return FALSE; BOOL NoMIE = FALSE; switch(Which) { case cmxINDEX_LAYER: { ERROR2IF(PageRefer == NULL, FALSE, "no page refer set up"); PageRefer->SetLayerTableOffset(GetFilePosition()); id = cmxRIFFCI_LayerIndex; NoMIE = TRUE; TableSize += sizeof(WORD); // for page number // add an entry for the master layer table CMXReferMasterLayer *pML = new CMXReferMasterLayer(this); if(pML == NULL) return FALSE; ReferList.AddTail(pML); // add it -- nothing else to set } break; case cmxINDEX_PAGE: id = cmxRIFFCI_PageIndex; pMIE->SetType(cmxMASTERIN_PAGE); break; case cmxINDEX_MASTERINDEX: // note the start of the index section in the file header IndexSectionFuture.Write(this); TableSize += sizeof(cmxMasterIndexHeader); id = cmxRIFFCI_MasterIndex; pMIE->SetType(cmxMASTERIN_MASTERIN); break; case cmxINDEX_MASTERLAYER: // remember this is single entry table and is fudged id = cmxRIFFCI_MasterLayerIndex; // in the refer list object pMIE->SetType(cmxMASTERIN_MASTERLAYER); break; case cmxINDEX_PROCEDURE: id = cmxRIFFCI_ProcIndex; pMIE->SetType(cmxMASTERIN_PROCEDURE); break; case cmxINDEX_EMBEDFILE: id = cmxRIFFCI_EmbeddedFileIndex; pMIE->SetType(cmxMASTERIN_EMBEDFILE); break; case cmxINDEX_ARROW: id = cmxRIFFCI_ArrowIndex; pMIE->SetType(cmxMASTERIN_ARROW); TableSize += sizeof(cmxArrowIndexHeader) + (ThirtyTwoBit?sizeof(WORD):0); break; default: ERROR3("Don't know what type of index to write!"); } if(NoMIE) { delete pMIE; // don't need this } else { ReferList.AddTail(pMIE); } // scan the refer list and see how many entries we've got, and how long they are WORD Entries = 0; CMXReferListItem *pEn = (CMXReferListItem *)ReferList.GetHead(); while(pEn != 0) { ERROR3IF(!pEn->IsKindOf(CC_RUNTIME_CLASS(CMXReferListItem)), "unexpected type of entry in refer list"); if(pEn->IsInWhichIndex() == Which) { Entries++; TableSize += pEn->IndexEntrySize(this); } pEn = (CMXReferListItem *)ReferList.GetNext(pEn); } if(Entries == 0) { // nothing to write -- go away now after removing the entry from the master index delete ReferList.RemoveItem(pMIE); return TRUE; } // write the header RIFFck ck; ck.ckID = id; ck.ckSize = TableSize; ExportFile->write(&ck, sizeof(ck)); if(Which == cmxINDEX_MASTERINDEX) { // write it's special header cmxMasterIndexHeader mih = {cmxMASTERIN_MASTERIN, ThirtyTwoBit?0xfff:0x18}; ExportFile->write(&mih, sizeof(mih)); } ExportFile->write(&Entries, sizeof(Entries)); // write record count // do specials switch(Which) { case cmxINDEX_LAYER: { WORD PageNumber = 1; ExportFile->write(&PageNumber, sizeof(PageNumber)); } break; case cmxINDEX_ARROW: { cmxArrowIndexHeader aih; WriteSizeInFile(sizeof(cmxArrowIndexEntry)); aih.Type = cmxARROWINDEXTYPE; ExportFile->write(&aih, sizeof(aih)); } break; default: break; } // write the entries pEn = (CMXReferListItem *)ReferList.GetHead(); while(pEn != 0) { ERROR3IF(!pEn->IsKindOf(CC_RUNTIME_CLASS(CMXReferListItem)), "unexpected type of entry in refer list"); if(pEn->IsInWhichIndex() == Which) { if(!pEn->WriteInIndex(this)) return FALSE; } pEn = (CMXReferListItem *)ReferList.GetNext(pEn); } // if necessary, word align the thingy if((GetFilePosition() & 1) != 0) { // put an extra byte in the file ExportFile->put('\0'); } // done return TRUE; } /******************************************************************************************** > void CMXExportDC::SetCMXFlag(INT32 flag) Author: Ben_Summers (Xara Group Ltd) Created: 25/07/96 Inputs: none Returns: none Purpose: sets a flag for pages, layers SeeAlso: ********************************************************************************************/ void CMXExportDC::SetCMXFlag(INT32 flag) { PageFlags = ((INT32)PageFlags) | flag; LayerFlags = ((INT32)LayerFlags) | flag; } /******************************************************************************************** > BOOL CMXExportDC::WriteDescriptionSections(void) Author: Ben_Summers (Xara Group Ltd) Created: 27/06/96 Inputs: none Returns: success Purpose: writes the descption sections SeeAlso: ********************************************************************************************/ #define WRITEDESC(h) if(!WriteADesc(h)) return FALSE; BOOL CMXExportDC::WriteDescriptionSections(void) { WRITEDESC(cmxDESC_ARROW) WRITEDESC(cmxDESC_ARROWHEADS) WRITEDESC(cmxDESC_DOTDASH) WRITEDESC(cmxDESC_FONT) WRITEDESC(cmxDESC_OUTLINE) WRITEDESC(cmxDESC_LINESTYLE) WRITEDESC(cmxDESC_PEN) WRITEDESC(cmxDESC_SCREEN) WRITEDESC(cmxDESC_COLOUR) return TRUE; } /******************************************************************************************** > BOOL CMXExportDC::WriteADesc(INT32 Which) Author: Ben_Summers (Xara Group Ltd) Created: 25/06/96 Inputs: none Returns: success Purpose: writes the a particular index to the file SeeAlso: ********************************************************************************************/ BOOL CMXExportDC::WriteADesc(INT32 Which) { // get some types and sort out the master index entry for this table // and do any special actions for certain index types INT32 Section; CMXReferMasterIndex *pMIE = new CMXReferMasterIndex(this); if(pMIE == NULL) return FALSE; BOOL NoMIE = FALSE; BOOL HasRecordCount = TRUE; BOOL CanOmit = FALSE; switch(Which) { case cmxDESC_ARROW: Section = CMXSECTION_ARROW; CanOmit = TRUE; pMIE->SetType(cmxMASTERIN_ARROW); HasRecordCount = FALSE; break; case cmxDESC_ARROWHEADS: Section = CMXSECTION_ARROWHEADS; pMIE->SetType(cmxMASTERIN_ARROWHEADS); break; case cmxDESC_COLOUR: Section = CMXSECTION_COLOUR; pMIE->SetType(cmxMASTERIN_COLOUR); break; case cmxDESC_DOTDASH: Section = CMXSECTION_DOTDASH; pMIE->SetType(cmxMASTERIN_DOTDASH); break; case cmxDESC_FONT: Section = CMXSECTION_FONT; pMIE->SetType(cmxMASTERIN_FONT); CanOmit = TRUE; HasRecordCount = FALSE; break; /* case cmxDESC_IMAGE: Section = CMXSECTION_IMAGE; pMIE->SetType(cmxMASTERIN_IMAGE); CanOmit = TRUE; HasRecordCount = FALSE; break; */ case cmxDESC_OUTLINE: Section = CMXSECTION_OUTLINE; pMIE->SetType(cmxMASTERIN_OUTLINE); break; case cmxDESC_LINESTYLE: Section = CMXSECTION_LINESTYLE; pMIE->SetType(cmxMASTERIN_LINESTYLE); break; case cmxDESC_PEN: Section = CMXSECTION_PEN; pMIE->SetType(cmxMASTERIN_PEN); break; case cmxDESC_SCREEN: Section = CMXSECTION_SCREEN; pMIE->SetType(cmxMASTERIN_SCREEN); break; default: ERROR3("Don't know what type of desc to write!"); } // scan the refer list and see how many entries we've got, and how long they are WORD Entries = 0; CMXReferListItem *pEn = (CMXReferListItem *)ReferList.GetHead(); while(pEn != 0) { ERROR3IF(!pEn->IsKindOf(CC_RUNTIME_CLASS(CMXReferListItem)), "unexpected type of entry in refer list"); if(pEn->IsInWhichDesc() == Which) { Entries++; } pEn = (CMXReferListItem *)ReferList.GetNext(pEn); } // do we need to save this section? if(Entries == 0 && CanOmit) { delete pMIE; // delete the record return TRUE; // don't do anything } // add this section to the master entry list if(NoMIE) { delete pMIE; // don't need this } else { ReferList.AddTail(pMIE); } // start the section, and maybe write a record count if(!StartSection((CMXExportDC::CMXSectionType)Section)) return FALSE; if(HasRecordCount) ExportFile->write(&Entries, sizeof(Entries)); // write record count // write the entries pEn = (CMXReferListItem *)ReferList.GetHead(); while(pEn != 0) { ERROR3IF(!pEn->IsKindOf(CC_RUNTIME_CLASS(CMXReferListItem)), "unexpected type of entry in refer list"); if(pEn->IsInWhichDesc() == Which) { if(!pEn->WriteInDesc(this)) return FALSE; } pEn = (CMXReferListItem *)ReferList.GetNext(pEn); } // end the section if(!EndSection()) return FALSE; // done return TRUE; } /******************************************************************************************** > BOOL CMXReferDotDash::WriteInDesc(CMXExportDC *pDC) Author: Ben_Summers (Xara Group Ltd) Created: 25/07/96 Inputs: none Returns: success Purpose: writes a dot dash pattern to the description section SeeAlso: ********************************************************************************************/ BOOL CMXReferDotDash::WriteInDesc(CMXExportDC *pDC) { pDash->CheckAndFix(); // just in case // start the tag if(!pDC->StartTag(cmxTAG_DescrSection_Dash)) return FALSE; // dot count WORD DotCount = (WORD)pDash->Elements; if(!pDC->WriteData(&DotCount, sizeof(DotCount))) return FALSE; // write the elements for(INT32 l = 0; l < pDash->Elements; l++) { WORD Element = (WORD)((pDash->ElementData[l] + 4) / pDash->LineWidth); if(Element <= 0) Element = 1; Element *= 4; if(!pDC->WriteData(&Element, sizeof(Element))) return FALSE; } // end the tag and write the end tag if(!pDC->EndTag() || !pDC->WriteMinEndTag()) return FALSE; return TRUE; } /******************************************************************************************** > BOOL CMXReferArrow::WriteInDesc(CMXExportDC *pDC) Author: Ben_Summers (Xara Group Ltd) Created: 25/07/96 Inputs: none Returns: success Purpose: writes a arrowhead definition to the description section SeeAlso: ********************************************************************************************/ BOOL CMXReferArrow::WriteInDesc(CMXExportDC *pDC) { // store the position of this thingy ArrowFilePosition = pDC->GetFilePosition(); // start a tag if(!pDC->StartTag(cmxTAG_DescrSection_Arrow)) return FALSE; // get some details about the path of the arrowhead Path *pPath = pArrow->GetArrowPath(); ERROR2IF(pPath == NULL, FALSE, "no arrow path"); INT32 NumCoords = pPath->GetNumCoords(); DocCoord *Coords = pPath->GetCoordArray(); PathVerb *Verbs = pPath->GetVerbArray(); DocRect ArrowBBox; pDC->CalcCorelBBox(Coords, NumCoords, &ArrowBBox); // work out a matrix for transforming the arrowhead path DocCoord ArrowCentre = pArrow->GetArrowCentre(); // this bounding box needs to be scaled so that it's in the required range INT32 dl = abs(ArrowCentre.x - ArrowBBox.lo.x); INT32 dr = abs(ArrowBBox.hi.x - ArrowCentre.x); INT32 db = abs(ArrowCentre.y - ArrowBBox.lo.y); INT32 dt = abs(ArrowBBox.hi.y - ArrowCentre.y); INT32 maxdist = (dl > dr)?dl:dr; maxdist = (maxdist > db)?maxdist:db; maxdist = (maxdist > dt)?maxdist:dt; // maxdist is the greatest distance from the centre point -- this is // the distance which determines the scaling factor double ScaleFactor = ((double)(pDC->IsThirtyTwoBit()?cmxARROWDEF_MAXCOORD32:cmxARROWDEF_MAXCOORD16)) / ((double)maxdist); Matrix Mat((FIXED16)ScaleFactor, 0, 0, (FIXED16)ScaleFactor, - ArrowCentre.x, - ArrowCentre.y); // export the path, transforming each coordinate as we go along // do we need to add an extra point? BOOL BungInExtraPoint = FALSE; if(Coords[0] != Coords[NumCoords - 1]) BungInExtraPoint = TRUE; // write the point count WORD Count = (WORD)NumCoords + (BungInExtraPoint?1:0); pDC->WriteData(&Count, sizeof(Count)); // run through the coords writing and transforming INT32 l; for(l = 0; l < NumCoords; l++) { DocCoord Coord = Coords[l]; Mat.transform(&Coord); // write it... if(pDC->IsThirtyTwoBit()) { cmxPoint32 p = {Coord.x, Coord.y}; pDC->WriteData(&p, sizeof(p)); } else { cmxPoint16 p = {(SWORD)Coord.x, (SWORD)Coord.y}; pDC->WriteData(&p, sizeof(p)); } } if(BungInExtraPoint) { DocCoord Coord = Coords[0]; Mat.transform(&Coord); // write it... if(pDC->IsThirtyTwoBit()) { cmxPoint32 p = {Coord.x, Coord.y}; pDC->WriteData(&p, sizeof(p)); } else { cmxPoint16 p = {(SWORD)Coord.x, (SWORD)Coord.y}; pDC->WriteData(&p, sizeof(p)); } } // run through the verbs writing point types INT32 BezCount = 0; // for counting Bez for(l = 0; l < NumCoords; l++) { BYTE Type; switch(Verbs[l] & (PT_LINETO | PT_MOVETO | PT_BEZIERTO)) { case PT_MOVETO: { Type = CMXNODETYPE_TYPE_MOVE | CMXNODETYPE_USER; // wibble forwards through the verbs to see if the correspondingness is closed for(INT32 lp = l + 1; lp < NumCoords; lp++) { // OK, is this a move? if((Verbs[lp] & (PT_LINETO | PT_MOVETO | PT_BEZIERTO)) == PT_MOVETO) break; // is closefigure set? if((Verbs[lp] & PT_CLOSEFIGURE) != 0) { Type |= CMXNODETYPE_CLOSED; break; } } } BezCount = 0; break; case PT_LINETO: Type = CMXNODETYPE_TYPE_LINE | CMXNODETYPE_USER; BezCount = 0; break; case PT_BEZIERTO: // in CMX, the control points have type ARC, and the end points // have type CURVE. This code does the trickery. if(BezCount == 2) { Type = CMXNODETYPE_TYPE_CURVE | CMXNODETYPE_USER; } else { Type = CMXNODETYPE_TYPE_ARC; } BezCount++; if(BezCount > 2) BezCount = 0; // so that only the end points of beziers get user flag break; default: ERROR3("Unknown node type"); break; } if((Verbs[l] & PT_CLOSEFIGURE) != 0) { if(!BungInExtraPoint || l != (NumCoords - 1)) Type |= CMXNODETYPE_CLOSED; } if(l == (NumCoords - 1) && !BungInExtraPoint) Type |= CMXNODETYPE_CLOSED; pDC->WriteData(&Type, sizeof(Type)); } if(BungInExtraPoint) { BYTE Type = CMXNODETYPE_TYPE_LINE | CMXNODETYPE_USER | CMXNODETYPE_CLOSED; pDC->WriteData(&Type, sizeof(Type)); } // write the line offset DWORD LineOffset = 0; if(!pDC->WriteData(&LineOffset, sizeof(LineOffset))) return FALSE; // end the tag if(!pDC->EndTag() || !pDC->WriteMinEndTag()) return FALSE; return TRUE; } /******************************************************************************************** > BOOL CMXReferArrow::WriteInDesc(CMXExportDC *pDC) Author: Ben_Summers (Xara Group Ltd) Created: 25/07/96 Inputs: none Returns: success Purpose: writes the index entry for the arrowhead SeeAlso: ********************************************************************************************/ BOOL CMXReferArrow::WriteInIndex(CMXExportDC *pDC) { // make the entry cmxArrowIndexEntry En; En.FilePosition = ArrowFilePosition; // write it... return pDC->WriteData(&En, sizeof(En)); } /******************************************************************************************** > BOOL CMXExportDC::WritePreviewBitmap(void) Author: Ben_Summers (Xara Group Ltd) Created: 29/08/96 Inputs: none Returns: success Purpose: writes a preview bitmap type thing SeeAlso: ********************************************************************************************/ BOOL CMXExportDC::WritePreviewBitmap(void) { Filter* pFilter = NULL; pFilter = Filter::GetFirst(); while ((pFilter != NULL) && (pFilter->FilterID != FILTERID_PREVIEW_BMP)) { // Try the next filter pFilter = Filter::GetNext(pFilter); } // Make sure that we found the preview bitmap filter if ((pFilter != NULL) && (pFilter->IS_KIND_OF(BaseBitmapFilter))) { // write the index of this thumbnail section ThumbnailIndexFuture.Write(this); // start the section if(!StartSection(CMXSECTION_PREVIEWBITMAP)) return FALSE; // write a number DWORD Eight = 8; Eight = NativetoLE(Eight); ExportFile->write(&Eight, sizeof(Eight)); // fudge things a bit INT32 Start = ExportFile->tell(); BITMAPFILEHEADER hdr; ExportFile->seek(Start - sizeof(hdr)); ExportFile->read(&hdr, sizeof(hdr)); ExportFile->seek(Start - sizeof(hdr)); //WEBSTER-Martin-03/01/97 // force the Preview to a fixed size INT32 OldPreviewSize = PreviewFilter::PreviewBitmapSize; // Set the Preview to be just over an inch accross PreviewFilter::PreviewBitmapSize = 96000; // Get as Bitmap Filter and set it up BaseBitmapFilter* pBitmapFilter = (BaseBitmapFilter*) pFilter; pBitmapFilter->SetPreviewBitmap(TRUE); // Export the Preview to the file BOOL ok = pFilter->DoExport(pOp, ExportFile, pPath, TheDocument); // If the Preview bitmap failed to export then we still need to clean up // Set it back pBitmapFilter->SetPreviewBitmap(FALSE); // Set the Preview back to its default setting PreviewFilter::PreviewBitmapSize = OldPreviewSize; // replace the data which was overwritten INT32 Here = ExportFile->tell(); ExportFile->seek(Start - sizeof(hdr)); ExportFile->write(&hdr, sizeof(hdr)); ExportFile->seek(Here); // finish the section if(!EndSection()) return FALSE; return ok; } return TRUE; } /******************************************************************************************** > static double CMXExportDC::Round ( double ToRound ) Author: Graeme_Sutherland (Xara Group Ltd) Created: 8/5/00 Inputs: ToRound - The value to be rounded up. Returns: double - The rounded value. Purpose: Rounds a value up or down to the nearest integer. ********************************************************************************************/ double CMXExportDC::Round ( double ToRound ) { // Add 0.5 to the value, and floor it. This will return the nearest integer. return floor ( ToRound + 0.5 ); }