00001 // $Id: cxftfile.cpp 1679 2006-08-08 09:47:27Z gerry $ 00002 // Implementation of the CXaraTemplateFile class 00003 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE 00004 ================================XARAHEADERSTART=========================== 00005 00006 Xara LX, a vector drawing and manipulation program. 00007 Copyright (C) 1993-2006 Xara Group Ltd. 00008 Copyright on certain contributions may be held in joint with their 00009 respective authors. See AUTHORS file for details. 00010 00011 LICENSE TO USE AND MODIFY SOFTWARE 00012 ---------------------------------- 00013 00014 This file is part of Xara LX. 00015 00016 Xara LX is free software; you can redistribute it and/or modify it 00017 under the terms of the GNU General Public License version 2 as published 00018 by the Free Software Foundation. 00019 00020 Xara LX and its component source files are distributed in the hope 00021 that it will be useful, but WITHOUT ANY WARRANTY; without even the 00022 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00023 See the GNU General Public License for more details. 00024 00025 You should have received a copy of the GNU General Public License along 00026 with Xara LX (see the file GPL in the root directory of the 00027 distribution); if not, write to the Free Software Foundation, Inc., 51 00028 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00029 00030 00031 ADDITIONAL RIGHTS 00032 ----------------- 00033 00034 Conditional upon your continuing compliance with the GNU General Public 00035 License described above, Xara Group Ltd grants to you certain additional 00036 rights. 00037 00038 The additional rights are to use, modify, and distribute the software 00039 together with the wxWidgets library, the wxXtra library, and the "CDraw" 00040 library and any other such library that any version of Xara LX relased 00041 by Xara Group Ltd requires in order to compile and execute, including 00042 the static linking of that library to XaraLX. In the case of the 00043 "CDraw" library, you may satisfy obligation under the GNU General Public 00044 License to provide source code by providing a binary copy of the library 00045 concerned and a copy of the license accompanying it. 00046 00047 Nothing in this section restricts any of the rights you have under 00048 the GNU General Public License. 00049 00050 00051 SCOPE OF LICENSE 00052 ---------------- 00053 00054 This license applies to this program (XaraLX) and its constituent source 00055 files only, and does not necessarily apply to other Xara products which may 00056 in part share the same code base, and are subject to their own licensing 00057 terms. 00058 00059 This license does not apply to files in the wxXtra directory, which 00060 are built into a separate library, and are subject to the wxWindows 00061 license contained within that directory in the file "WXXTRA-LICENSE". 00062 00063 This license does not apply to the binary libraries (if any) within 00064 the "libs" directory, which are subject to a separate license contained 00065 within that directory in the file "LIBS-LICENSE". 00066 00067 00068 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS 00069 ---------------------------------------------- 00070 00071 Subject to the terms of the GNU Public License (see above), you are 00072 free to do whatever you like with your modifications. However, you may 00073 (at your option) wish contribute them to Xara's source tree. You can 00074 find details of how to do this at: 00075 http://www.xaraxtreme.org/developers/ 00076 00077 Prior to contributing your modifications, you will need to complete our 00078 contributor agreement. This can be found at: 00079 http://www.xaraxtreme.org/developers/contribute/ 00080 00081 Please note that Xara will not accept modifications which modify any of 00082 the text between the start and end of this header (marked 00083 XARAHEADERSTART and XARAHEADEREND). 00084 00085 00086 MARKS 00087 ----- 00088 00089 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara 00090 designs are registered or unregistered trademarks, design-marks, and/or 00091 service marks of Xara Group Ltd. All rights in these marks are reserved. 00092 00093 00094 Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. 00095 http://www.xara.com/ 00096 00097 =================================XARAHEADEREND============================ 00098 */ 00099 00100 #include "camtypes.h" 00101 00102 #include "cxftfile.h" 00103 //#include "cxfrec.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00104 //#include "cxfrech.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00105 //#include "cxfdefs.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00106 #include "cxfmap.h" 00107 00108 //#include "ccfile.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00109 //#include "progress.h" 00110 //#include "filtrres.h" 00111 00112 #include "ccpanose.h" 00113 00114 #include "bmpsrc.h" // BitmapSource 00115 #include "ccbuffil.h" 00116 00117 #include "cxftags.h" // The tag definitions 00118 //#include "cxfdefs.h" // The constants - in camtypes.h [AUTOMATICALLY REMOVED] 00119 #include "zutil.h" // ZLIB_VERSIONNO 00120 00121 //#include "camfiltr.h" // BaseCamelotFilter - in camtypes.h [AUTOMATICALLY REMOVED] 00122 00123 #include "fttyplis.h" 00124 00125 #include "fileutil.h" 00126 00127 #include "ccbhfile.h" // include the translating file proxy 00128 00129 //#include "fthelper.h" 00130 00131 //----------------------------------------------- 00132 00133 CC_IMPLEMENT_DYNAMIC(CXaraTemplateFile, CXaraFile); 00134 00135 // This will get Camelot to display the filename and linenumber of any memory allocations 00136 // that are not released at program exit 00137 // Declare smart memory handling in Debug builds 00138 #define new CAM_DEBUG_NEW 00139 00140 /******************************************************************************************** 00141 00142 > CXaraTemplateFile::CXaraTemplateFile() 00143 00144 Author: Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com> 00145 Created: 09/07/97 00146 Purpose: Default constructor 00147 SeeAlso: - 00148 00149 ********************************************************************************************/ 00150 00151 CXaraTemplateFile::CXaraTemplateFile() 00152 { 00153 m_pTempFile = NULL; 00154 m_pBinHexFile = NULL; 00155 m_pOrigCCFile = NULL; 00156 } 00157 00158 00159 00160 /******************************************************************************************** 00161 00162 > BOOL CXaraTemplateFile::OpenToWrite(CCLexFile* pThisCCFile) 00163 00164 Author: Mark_Neves (Xara Group Ltd) <camelotdev@xara.com> 00165 Created: 20/5/96 00166 Inputs: pThisCCFile = ptr to the file to write to 00167 Returns: TRUE if the the system is ready to write to the file 00168 FALSE otherwise 00169 Purpose: Opens the CXaraFile object ready for writing. 00170 It uses the given CCFile object as the file to write to. 00171 00172 NOTE: It is assumed that the supplied CCFile has already been opened for writing. 00173 00174 Errors: - 00175 SeeAlso: Close() 00176 00177 ********************************************************************************************/ 00178 00179 BOOL CXaraTemplateFile::OpenToWrite(CCLexFile* pThisCCFile) 00180 { 00181 // Check entry params 00182 ERROR2IF(pThisCCFile == NULL,FALSE,"pThisCCFile is NULL"); 00183 00184 // pCCFile should be NULL at this point 00185 ERROR3IF(pCCFile != NULL,"pThisCCFile is NULL"); 00186 00187 // Set our ptr the the CCFile to the one provided 00188 pCCFile = pThisCCFile; 00189 00190 // Try to create a CCBinHexFile for later 00191 00192 m_pBinHexFile = new CCBinHexFile(pCCFile, FALSE, FALSE); 00193 00194 if (m_pBinHexFile == NULL) 00195 return(FALSE); 00196 00197 // Reset the write vars 00198 RecordNumber = 0; 00199 NumBytesWritten = 0; 00200 00201 BOOL ok = TRUE; 00202 00203 // The first 8 bytes should be our unique ID sequence 00204 if (ok) ok = pCCFile->write("FLARETEXT\r\n", 11).good(); 00205 00206 return ok; 00207 } 00208 00209 00210 00211 /******************************************************************************************** 00212 00213 > BOOL CXaraTemplateFile::OpenToRead(CCLexFile* pThisCCFile) 00214 00215 Author: Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com> 00216 Created: 20/07/97 00217 Inputs: pThisCCFile = ptr to the file to read from 00218 Returns: TRUE if the the system is ready to read from the file 00219 FALSE otherwise 00220 Purpose: Opens the CXaraFile object ready for reading. 00221 It actually uses the given CCFile object as the file to read from. 00222 00223 NOTE: It is assumed that the supplied CCFile has already been opened for reading 00224 from the start of the file. This function will return FALSE if the initial 00225 10 bytes do not contain the file header sequence. 00226 Errors: - 00227 SeeAlso: Close() 00228 00229 ********************************************************************************************/ 00230 00231 BOOL CXaraTemplateFile::OpenToRead(CCLexFile* pThisCCFile) 00232 { 00233 PORTNOTETRACE("other","CXaraTemplateFile::OpenToRead - do nothing"); 00234 #ifndef EXCLUDE_FROM_XARALX 00235 // Check entry params 00236 ERROR2IF(pThisCCFile == NULL,FALSE,"pThisCCFile is NULL"); 00237 00238 // pCCFile should be NULL at this point 00239 ERROR3IF(pCCFile != NULL,"pThisCCFile is NULL"); 00240 00241 // Remember the original file 00242 m_pOrigCCFile = pThisCCFile; 00243 00244 // Translate the file 00245 CCLexFile* pNewFile = FlareTemplateHelper::ConvertFile(pThisCCFile); 00246 00247 if (pNewFile == NULL) 00248 { 00249 return(FALSE); 00250 } 00251 00252 // And call the base class to do the rest 00253 return(CXaraFile::OpenToRead(pNewFile)); 00254 #else 00255 return false; 00256 #endif 00257 } 00258 00259 00260 00261 /******************************************************************************************** 00262 00263 > BOOL CXaraTemplateFile::Close() 00264 00265 Author: Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com> 00266 Created: 14/7/97 00267 Inputs: - 00268 Returns: TRUE if the the system closed down correctly 00269 FALSE otherwise 00270 Purpose: This closes the CXaraFile object. 00271 You should call this func at the very end of reading from or writing to the file 00272 00273 NOTE: The supplied pCCFile passed to OpenToWrite() and OpenToRead() is NOT 00274 closed. The calling code will have to handle the low level closing of the file. 00275 00276 Errors: - 00277 SeeAlso: OpenToWrite(), OpenToRead() 00278 00279 ********************************************************************************************/ 00280 00281 BOOL CXaraTemplateFile::Close() 00282 { 00283 // Reset all handlers that we set up via SetUpHandlers() 00284 ResetHandlers(); 00285 00286 if (m_pBinHexFile != NULL) 00287 { 00288 delete m_pBinHexFile; 00289 m_pBinHexFile = NULL; 00290 } 00291 00292 // We must not delete this but we must delete the CCFile that we created 00293 if (m_pOrigCCFile != NULL) 00294 { 00295 if (pCCFile) 00296 { 00297 PathName TempPath = pCCFile->GetPathName(); 00298 delete pCCFile; // delete the CCFile (closes it) 00299 PORTNOTETRACE("other","Removed FileUtil::DeleteFile usage"); 00300 #ifndef EXCLUDE_FROM_XARALX 00301 FileUtil::DeleteFile(&TempPath); // delete the actual file 00302 #endif 00303 } 00304 pCCFile = m_pOrigCCFile; 00305 m_pOrigCCFile = NULL; 00306 } 00307 00308 return TRUE; 00309 } 00310 00311 /******************************************************************************************** 00312 00313 > virtual CCLexFile* CXaraTemplateFile::GetCCFile() const 00314 00315 Author: Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com> 00316 Created: 09/07/97 00317 Inputs: - 00318 Returns: The CCLexFile that is being used to export the data. 00319 Purpose: Function to give public access to the underlying CCLexFile that is being used 00320 to save out the data. 00321 00322 This either returns a special proxy CCFile which translates the data 00323 or a temporary disk file (during streamed records) 00324 00325 ********************************************************************************************/ 00326 00327 CCLexFile* CXaraTemplateFile::GetCCFile() const 00328 { 00329 // TRACEUSER( "Gerry", _T("CXaraTemplateFile::GetCCFile()\n")); 00330 00331 if (m_pOrigCCFile) 00332 return(pCCFile); 00333 00334 if (m_pTempFile) 00335 return(m_pTempFile); 00336 else 00337 return(m_pBinHexFile); 00338 } 00339 00340 00341 00342 /******************************************************************************************** 00343 00344 > INT32 CXaraTemplateFile::StartRecord(UINT32 Tag,INT32 Size) 00345 00346 Author: Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com> 00347 Created: 14/7/97 00348 Inputs: Tag = the tag for the record 00349 Size = the size of the data section of the record in bytes, or CXF_UNKNOWN_SIZE 00350 Returns: The record number of the record being written to the file. 00351 If the function fails, 0 will be returned 00352 Purpose: Prepares a record ready for writing to the file. 00353 00354 This function prepares a record that is buffered in memory before being 00355 written out to file. 00356 00357 After this call all Write() functions write to the data section of the record. 00358 The complete record (inc. the tag & size fields) is written out when EndRecord() is called. 00359 00360 If you know the exact size in bytes of the record you are writing, supply this 00361 value via the Size parameter. This allows the write functions to provide additional 00362 error checking for you (e.g. if you try and write extra bytes) 00363 00364 If you are not sure of the exact number of bytes that will be written to the data 00365 section, set the Size param to CXF_UNKNOWN_SIZE. EndRecord() will ensure that the 00366 written record will have its size field set to the number of bytes that were written. 00367 00368 Errors: - 00369 SeeAlso: EndRecord() 00370 00371 ********************************************************************************************/ 00372 00373 INT32 CXaraTemplateFile::StartRecord(UINT32 Tag,INT32 Size) 00374 { 00375 if (EndRecord()) 00376 { 00377 // Inc the record number 00378 RecordNumber++; 00379 00380 // Create a new record, & initialise it 00381 pRecord = new CXaraFileRecord(Tag, Size); 00382 00383 WriteToRecord = (pRecord != NULL && pRecord->Init()); 00384 00385 if (WriteToRecord) 00386 { 00387 pRecord->SetRecordNumber(RecordNumber); 00388 return RecordNumber; 00389 } 00390 } 00391 00392 return 0; 00393 } 00394 00395 00396 INT32 CXaraTemplateFile::StartStreamedRecord(UINT32 Tag,INT32 Size) 00397 { 00398 // TRACEUSER( "Gerry", _T("StartStreamed %d, %d\n"), Tag, Size); 00399 00400 ERROR2IF(WritingStreamedRecord,0,"Already writing a streamed record. Forgot to call EndRecord()?"); 00401 00402 ERROR3IF(m_pTempFile != NULL, "TempFile is non-NULL!!!"); 00403 00404 WritingStreamedRecord = TRUE; 00405 WriteToRecord = FALSE; 00406 00407 // Don't do any compression stuff 00408 // CompOffDueToStreamedRecord = IsCompressionOn(); 00409 // BOOL ok = StopCompression(); 00410 00411 // And don't do any of this rampant poking of length values 00412 // StartOfStreamedRecord = GetFilePos(); 00413 00414 // All streamed records have labels stuck on them (for now), 00415 // have length set to zero and consist of one BINH data item 00416 char Buf[64]; 00417 INT32 Num = sprintf(Buf, "%%R%d%%{%d,%d,BINH(", (RecordNumber+1), Tag, 0); 00418 00419 // make sure we write directly to the file 00420 BOOL ok = pCCFile->write(Buf, Num).good(); 00421 00422 if (!ok) 00423 return(0); 00424 00425 // Now we create a temporary file which GetCCFile 00426 // will return until EndStreamedRecord is called 00427 PORTNOTETRACE("other","Removed FileUtil::GetTemporaryPathName usage"); 00428 #ifndef EXCLUDE_FROM_XARALX 00429 m_TempPath = FileUtil::GetTemporaryPathName(); 00430 #endif 00431 m_pTempFile = new CCDiskFile(m_TempPath, ios::out | ios::binary | ios::trunc); 00432 00433 if (m_pTempFile == NULL || m_pTempFile->bad()) 00434 return(0); 00435 00436 RecordNumber++; 00437 return(RecordNumber); 00438 } 00439 00440 00441 /******************************************************************************************** 00442 00443 > BOOL CXaraTemplateFile::EndRecord() 00444 00445 Author: Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com> 00446 Created: 14/7/97 00447 Inputs: - 00448 Returns: TRUE if the the system wrote out the record 00449 FALSE otherwise 00450 Purpose: Ends the current record. 00451 00452 If the record was started by StartRecord(), this call will write out the entire 00453 buffered record (record header and data section) to the file. 00454 00455 Errors: - 00456 SeeAlso: StartRecord() 00457 00458 ********************************************************************************************/ 00459 00460 BOOL CXaraTemplateFile::EndRecord() 00461 { 00462 ERROR3IF(WriteToRecord && pRecord == NULL,"Writing to a NULL record!"); 00463 00464 BOOL ok = TRUE; 00465 00466 if (WritingStreamedRecord) 00467 { 00468 // Not interested in the result, but we will pass through a variable anyway 00469 // Complete the process of writing out the streamed record 00470 UINT32 RecordSize = 0L; 00471 return EndStreamedRecord(&RecordSize); 00472 } 00473 00474 if (WriteToRecord && pRecord != NULL) 00475 { 00476 WriteToRecord = FALSE; 00477 00478 ERROR3IF(!pRecord->IsDataSectionFull(),"Data section of the record has not been filled"); 00479 00480 // if (ok) ok = Write(pRecord->GetTag()); 00481 // if (ok) ok = Write(pRecord->GetSize()); 00482 // if (ok) ok = Write(pRecord->GetBuffer(),pRecord->GetSize()); 00483 00484 delete pRecord; 00485 pRecord = NULL; 00486 } 00487 00488 return (ok); 00489 } 00490 00491 /******************************************************************************************** 00492 00493 > BOOL CXaraTemplateFile::EndStreamedRecord(UINT32 *RecordSize) 00494 00495 Author: Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com> 00496 Created: 14/7/97 00497 Inputs: - 00498 Outputs: RecordSize - the size of the record just written 00499 Returns: TRUE if the the system wrote out the record 00500 FALSE otherwise 00501 Purpose: Ends the current streamed record. 00502 00503 If the record was started by StartStreamedRecord(), this call will do all 00504 that is necessary to clean up the streamed record. 00505 This mainly involves:- 00506 Fixing the size in the record header to be correct. 00507 Starting up compression, if required 00508 00509 Errors: - 00510 SeeAlso: StartRecord() 00511 00512 ********************************************************************************************/ 00513 00514 BOOL CXaraTemplateFile::EndStreamedRecord(UINT32 *RecordSize) 00515 { 00516 ERROR3IF(!WritingStreamedRecord,"Trying to end a non-streamed record!"); 00517 if (!WritingStreamedRecord) 00518 return FALSE; 00519 00520 BOOL ok = TRUE; 00521 // We must reset WritingStreamedRecord to FALSE immediately, to prevent stack overflow 00522 // due to recursion via the StartCompression() call below 00523 WritingStreamedRecord = FALSE; 00524 00525 UINT32 SizeOfFile = 0; 00526 00527 if (m_pTempFile == NULL) 00528 return(FALSE); 00529 00530 m_pTempFile->close(); 00531 delete m_pTempFile; 00532 m_pTempFile = NULL; 00533 00534 m_pTempFile = new CCDiskFile(CCFILE_DEFAULTSIZE, FALSE, FALSE); 00535 if (m_pTempFile == NULL) 00536 return(FALSE); 00537 if(!m_pTempFile->open(m_TempPath, ios::in | ios::binary)) 00538 return(FALSE); 00539 00540 BYTE Buffer[BinHexMaxLineLength * 10]; // Currently 1000 00541 size_t left = m_pTempFile->Size(); 00542 UINT32 len = BinHexMaxLineLength * 10; 00543 00544 while (m_pTempFile->good() && m_pBinHexFile->good() && len > 0) 00545 { 00546 if (len > left) 00547 len = left; 00548 m_pTempFile->read( Buffer, len ); 00549 00550 if (m_pTempFile->fail()) 00551 TRACEUSER( "Gerry", _T("read from temp file failed!!!\n")); 00552 00553 m_pBinHexFile->write(Buffer, len); 00554 00555 left -= len; 00556 } 00557 00558 // Close and delete the temp file 00559 m_pTempFile->close(); 00560 delete m_pTempFile; 00561 m_pTempFile = NULL; 00562 PORTNOTETRACE("other","Removed FileUtil::DeleteFile usage"); 00563 #ifndef EXCLUDE_FROM_XARALX 00564 FileUtil::DeleteFile(&m_TempPath); 00565 #endif 00566 00567 if (m_pBinHexFile->fail()) 00568 return(FALSE); 00569 00570 // Try to finish the record... 00571 if (pCCFile->write(")}\r\n", 4).fail()) 00572 return(FALSE); 00573 00574 // If we are passed a pointer then return the size to the caller 00575 if (RecordSize) 00576 *RecordSize = SizeOfFile; 00577 00578 // Add this number to the number of bytes written 00579 // TRACEUSER( "Gerry", _T("EndStreamedRecord update size by %d\n"), SizeOfFile); 00580 IncNumBytesWritten(SizeOfFile); 00581 00582 // Reset the streamed record vars 00583 StartOfStreamedRecord = 0; 00584 CompOffDueToStreamedRecord = FALSE; 00585 00586 return ok; 00587 } 00588 00589 /******************************************************************************************** 00590 00591 > virtual BOOL CXaraTemplateFile::FixStreamedRecordHeader(UINT32 *RecordSize) 00592 00593 Author: Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com> 00594 Created: 14/7/97 00595 Inputs: - 00596 Outputs: RecordSize - the size of the record just written 00597 Returns: True if worked ok, False otherwise. 00598 Purpose: Fixes up the previously saved record header for a streamed record. 00599 The RecordSize is the size of the data section of the record and so does not 00600 include the 8 bytes in the header. 00601 Errors: - 00602 SeeAlso: - 00603 00604 ********************************************************************************************/ 00605 00606 BOOL CXaraTemplateFile::FixStreamedRecordHeader(UINT32 *RecordSize) 00607 { 00608 ERROR2IF(pCCFile == NULL,FALSE,"CXaraFile::FixStreamedRecordHeader NULL pCCFile"); 00609 ERROR2IF(StartOfStreamedRecord == 0,FALSE,"CXaraFile::FixStreamedRecordHeader StartOfStreamedRecord == 0"); 00610 00611 // Dont do nuthin' 'ere 'cos we can't get the current file postion to determine the 00612 // length of the streamed record 00613 00614 return(TRUE); 00615 } 00616 00617 00618 /******************************************************************************************** 00619 00620 > UINT32 CXaraTemplateFile::WriteRecordHeader(UINT32 Tag, INT32 Size) 00621 00622 Author: Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com> 00623 Created: 14/7/97 00624 Inputs: Tag - the tag for this record 00625 Size - the size of the record 00626 Returns: The record number of this record in the file. 00627 If an error occurs, 0 is returned 00628 Purpose: Writes out a record header directly to the file. 00629 It expects the caller to handle other aspects of the record writing. 00630 This should only be used by people who know what they are doing e.g. compression 00631 It should not be required for template files but we'll see 00632 Errors: - 00633 SeeAlso: - 00634 00635 ********************************************************************************************/ 00636 00637 UINT32 CXaraTemplateFile::WriteRecordHeader(UINT32 Tag, INT32 Size) 00638 { 00639 // TRACEUSER( "Gerry", _T("WriteRecordHeader %d, %d\n"), Tag, Size); 00640 00641 BOOL ok = TRUE; 00642 00643 char Buf[32]; 00644 INT32 Num = sprintf(Buf, "{%d,%d", Tag, Size); 00645 00646 // make sure we write directly to the file 00647 ok = pCCFile->write(Buf, Num).good(); 00648 00649 // Inc the record number 00650 RecordNumber++; 00651 00652 if (ok) 00653 return RecordNumber; 00654 else 00655 return 0; 00656 } 00657 00658 00659 00660 /******************************************************************************************** 00661 00662 > virtual BOOL CXaraTemplateFile::Write(BYTE b) 00663 00664 Author: Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com> 00665 Created: 14/7/97 00666 Inputs: pRecord = ptr to a record to write out to file 00667 Returns: The record number of this record in the file. 00668 If an error occurs, 0 is returned 00669 Purpose: Writes out the record to the file. Uses WriteAsText to do the work 00670 SeeAlso: WriteAsText() 00671 00672 ********************************************************************************************/ 00673 00674 BOOL CXaraTemplateFile::Write(BYTE b) 00675 { 00676 ERROR2IF(GetCCFile() == NULL,FALSE,"Can't write a BYTE with no pCCFile"); 00677 00678 BOOL ok = TRUE; 00679 00680 // If we are writing to a record then let it handle the translation 00681 if (WriteToRecord && pRecord != NULL) 00682 ok = pRecord->WriteBYTE(b); 00683 else 00684 { 00685 // For streamed records we need to use our proxy CCFile 00686 GetCCFile()->write((void const*)&b); 00687 IncNumBytesWritten(1); 00688 } 00689 00690 return ok; 00691 } 00692 00693 00694 00695 /******************************************************************************************** 00696 00697 > UINT32 CXaraTemplateFile::Write(CXaraFileRecord* pRecord) 00698 00699 Author: Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com> 00700 Created: 14/7/97 00701 Inputs: pRecord = ptr to a record to write out to file 00702 Returns: The record number of this record in the file. 00703 If an error occurs, 0 is returned 00704 Purpose: Writes out the record to the file. Uses WriteAsText to do the work 00705 SeeAlso: WriteAsText() 00706 00707 ********************************************************************************************/ 00708 00709 UINT32 CXaraTemplateFile::Write(CXaraFileRecord* pRecord) 00710 { 00711 ERROR2IF(pRecord == NULL,FALSE,"pRecord param is NULL"); 00712 00713 BOOL ok = EndRecord(); 00714 00715 ERROR3IF(!pRecord->IsDataSectionFull(),"Data section of the record has not been filled"); 00716 00717 if (ok) ok = WriteAsText(pRecord); 00718 00719 // Inc the record number 00720 RecordNumber++; 00721 00722 if (ok) 00723 return RecordNumber; 00724 else 00725 return 0; 00726 } 00727 00728 00729 /******************************************************************************************** 00730 00731 > UINT32 CXaraTemplateFile::WriteDefinitionRecord(CXaraFileRecord* pRecord) 00732 00733 Author: Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com> 00734 Created: 17/07/97 00735 Inputs: pRecord = ptr to a record to write out to file 00736 Returns: The record number of this record in the file. 00737 If an error occurs, 0 is returned 00738 Purpose: Writes out the record to the file 00739 This version writes a label to the file 00740 00741 ********************************************************************************************/ 00742 00743 UINT32 CXaraTemplateFile::WriteDefinitionRecord(CXaraFileRecord* pRecord) 00744 { 00745 ERROR2IF(pRecord == NULL,FALSE,"pRecord param is NULL"); 00746 00747 BOOL ok = EndRecord(); 00748 00749 ERROR3IF(!pRecord->IsDataSectionFull(),"Data section of the record has not been filled"); 00750 00751 if (ok) ok = WriteLabel(); 00752 if (ok) ok = WriteAsText(pRecord); 00753 00754 // Inc the record number 00755 RecordNumber++; 00756 00757 if (ok) 00758 return RecordNumber; 00759 else 00760 return 0; 00761 } 00762 00763 00764 /******************************************************************************************** 00765 00766 > BOOL CXaraTemplateFile::WriteLabel(void) 00767 00768 Author: Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com> 00769 Created: 17/07/97 00770 Inputs: - 00771 Returns: FALSE if fails 00772 Purpose: Writes a label to the file of the form %R<RecordNumber>% 00773 00774 ********************************************************************************************/ 00775 00776 BOOL CXaraTemplateFile::WriteLabel(void) 00777 { 00778 // TODOG: Well, not yet it doesn't... 00779 00780 char Buffer[32]; 00781 00782 UINT32 Num = sprintf(Buffer, "%%R%d%%", (RecordNumber+1)); 00783 00784 return(pCCFile->write(Buffer, Num).good()); 00785 } 00786 00787 00788 /******************************************************************************************** 00789 00790 > BOOL CXaraTemplateFile::WriteAsText(CXaraFileRecord* pRecord) 00791 00792 Author: Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com> 00793 Created: 12/07/97 00794 Inputs: pRec - pointer to record to write 00795 Purpose: Writes the record in text format 00796 00797 Notes: This function is not particularly elegant (mainly due to time restrictions) 00798 00799 ********************************************************************************************/ 00800 00801 BOOL CXaraTemplateFile::WriteAsText(CXaraFileRecord* pRecord) 00802 { 00803 ERROR3IF(pRecord == NULL, "NULL record in CXaraTemplateFile::WriteAsText"); 00804 00805 if (pRecord == NULL) 00806 return(FALSE); 00807 00808 char Buffer[256]; // Allocate a buffer on the stack for now 00809 Buffer[0] = 0; // and make it empty 00810 INT32 Num; 00811 00812 FTTypeList* pTypeList = pRecord->GetTypeList(); 00813 00814 // Write the "record header" 00815 Num = sprintf(Buffer, "{%d,%d", pRecord->GetTag(), pRecord->GetSize()); 00816 BOOL ok = pCCFile->write(Buffer, Num).good(); 00817 00818 if (ok && 00819 pTypeList != NULL && 00820 pTypeList->GetCount() > 0) 00821 { 00822 BYTE* pBinPtr = pRecord->GetBuffer(); 00823 BYTE* pPtr = pTypeList->GetBuffer(); 00824 DWORD Count = pTypeList->GetCount(); 00825 DWORD Index; 00826 for (Index = 0; ok && (Index < Count); Index++) 00827 { 00828 // char* pType = NULL; 00829 Num = 0; // Nothing to write 00830 00831 // Now we fill the buffer and set Num to the number of bytes to write 00832 // or just write it ourselves and set Num to zero 00833 00834 switch (pPtr[Index]) 00835 { 00836 case FTT_BYTE: 00837 { 00838 BYTE ByteVal = *pBinPtr; 00839 TRACEUSER( "Gerry", _T("Byte : %d\n"), ByteVal); 00840 Num = sprintf(Buffer, ",B(%u)", ByteVal); 00841 pBinPtr+=1; 00842 break; 00843 } 00844 00845 case FTT_UINT32: 00846 { 00847 UINT32 ULongVal = *((UINT32*)pBinPtr); 00848 TRACEUSER( "Gerry", _T("ULong : %u\n"), ULongVal); 00849 Num = sprintf(Buffer, ",U(%u)", ULongVal); 00850 pBinPtr+=4; 00851 break; 00852 } 00853 00854 case FTT_INT32: 00855 { 00856 INT32 LongVal = *((INT32*)pBinPtr); 00857 TRACEUSER( "Gerry", _T("Long : %d\n"), LongVal); 00858 Num = sprintf(Buffer, ",L(%d)", LongVal); 00859 pBinPtr+=4; 00860 break; 00861 } 00862 00863 case FTT_UINT16: 00864 { 00865 WORD WordVal = *((WORD*)pBinPtr); 00866 TRACEUSER( "Gerry", _T("UINT16 : %hu\n"), WordVal); 00867 Num = sprintf(Buffer, ",W(%hu)", WordVal); 00868 pBinPtr+=2; 00869 break; 00870 } 00871 00872 case FTT_INT16: 00873 { 00874 INT16 ShortVal = *((INT16*)pBinPtr); 00875 TRACEUSER( "Gerry", _T("INT16 : %hd\n"), ShortVal); 00876 Num = sprintf(Buffer, ",I(%hd)", ShortVal); 00877 pBinPtr+=2; 00878 break; 00879 } 00880 00881 case FTT_FLOAT: 00882 { 00883 double DoubleVal = *((FLOAT*)pBinPtr); 00884 TRACEUSER( "Gerry", _T("Float : %g\n"), DoubleVal); 00885 Num = sprintf(Buffer, ",F(%g)", DoubleVal); 00886 pBinPtr+=4; 00887 break; 00888 } 00889 00890 case FTT_DOUBLE: 00891 { 00892 double DoubleVal = *((double*)pBinPtr); 00893 TRACEUSER( "Gerry", _T("Double : %g\n"), DoubleVal); 00894 Num = sprintf(Buffer, ",D(%g)", DoubleVal); 00895 pBinPtr+=8; 00896 break; 00897 } 00898 00899 case FTT_REFERENCE: 00900 { 00901 INT32 LongVal = *((INT32*)pBinPtr); 00902 TRACEUSER( "Gerry", _T("Long : %d\n"), LongVal); 00903 if (LongVal <= 0) 00904 { 00905 // then write it as an INT32 00906 Num = sprintf(Buffer, ",L(%d)", LongVal); 00907 } 00908 else 00909 { 00910 // Otherwise write a label reference 00911 Num = sprintf(Buffer, ",R(R%d)", LongVal); 00912 } 00913 pBinPtr+=4; 00914 break; 00915 } 00916 00917 case FTT_WCHAR: 00918 { 00919 TRACEUSER( "Gerry", _T("WCHAR : %d items\n"), Count - Index); 00920 UINT32 NumChars = WriteMultipleWCHARs(&(pPtr[Index]), Count - Index, (UINT16*)pBinPtr); 00921 if (NumChars == 0) 00922 ok = FALSE; 00923 pBinPtr += (NumChars * sizeof(WCHAR)); // Skip the pointerand 00924 Index += NumChars; // index on by NumChars 00925 break; 00926 } 00927 00928 case FTT_COORD: 00929 { 00930 INT32* pLong = (INT32*)pBinPtr; 00931 // TRACEUSER( "Gerry", _T("Coord : %d, %d\n"), pLong[0], pLong[1]); 00932 Num = sprintf(Buffer, ",C(%d,%d)", pLong[0], pLong[1]); 00933 pBinPtr += 8; 00934 break; 00935 } 00936 00937 case FTT_INTCOORD: 00938 { 00939 INT32 x = (pBinPtr[0] << 24); 00940 INT32 y = (pBinPtr[1] << 24); 00941 x += (pBinPtr[2] << 16); 00942 y += (pBinPtr[3] << 16); 00943 x += (pBinPtr[4] << 8); 00944 y += (pBinPtr[5] << 8); 00945 x += (pBinPtr[6] << 0); 00946 y += (pBinPtr[7] << 0); 00947 TRACEUSER( "Gerry", _T("IntCoord : %d, %d\n"), x, y); 00948 Num = sprintf(Buffer, ",K(%d,%d)", x, y); 00949 pBinPtr += 8; 00950 break; 00951 } 00952 00953 case FTT_ASCII: 00954 { 00955 // Use ,ASC("String") 00956 size_t len = strlen((char*)pBinPtr) + 1; 00957 TRACEUSER("Gerry", _T("ASCII %d"), len); 00958 ok = WriteSimpleASCII((char*)pBinPtr); 00959 pBinPtr += len; 00960 break; 00961 } 00962 00963 case FTT_UNICODE: 00964 { 00965 UINT32 len = 1; 00966 UINT16* pCh = (UINT16*)pBinPtr; 00967 while (*pCh++ != 0) 00968 len++; 00969 TRACEUSER("Gerry", _T("Unicode %d"), len); 00970 if (IsSimpleUnicode((UINT16*)pBinPtr)) 00971 { 00972 ok = WriteSimpleUnicode((UINT16*)pBinPtr); 00973 } 00974 else 00975 { 00976 ok = WriteBinHex(pBinPtr, len); 00977 } 00978 pBinPtr += len; 00979 break; 00980 } 00981 00982 case FTT_BINHEX: 00983 { 00984 UINT32 len = *((DWORD*)(pPtr+Index+1)); // Get the length (BYTE pointer arithmetic) 00985 TRACEUSER("Gerry", _T("BinHex %d"), len); 00986 Index += 4; 00987 ok = WriteBinHex(pBinPtr, len); 00988 pBinPtr += len; 00989 break; 00990 } 00991 default: 00992 { 00993 ok = FALSE; 00994 break; 00995 } 00996 } 00997 00998 if (ok && Num > 0) 00999 { 01000 // TRACEUSER( "Gerry", _T("Writing buffer %d\n"), Num); 01001 if (ok) ok = pCCFile->write(Buffer, Num).good(); 01002 } 01003 } 01004 } 01005 01006 if (ok) ok = pCCFile->write("}\r\n", 3).good(); 01007 01008 return(ok); 01009 } 01010 01011 01012 /******************************************************************************************** 01013 01014 > BOOL CXaraTemplateFile::WriteBinHex(BYTE* pBuf, UINT32 BufSize) 01015 01016 Author: Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com> 01017 Created: 12/07/97 01018 Inputs: pBuf - pointer to buffer to write 01019 BufSize - number of bytes to write 01020 Purpose: Writes the record in text format 01021 01022 Notes: This function is not particularly elegant (mainly due to time restrictions) 01023 01024 ********************************************************************************************/ 01025 01026 BOOL CXaraTemplateFile::WriteBinHex(BYTE* pBuf, UINT32 BufSize) 01027 { 01028 // TRACEUSER( "Gerry", _T("Writing BinHex %d\n"), BufSize); 01029 01030 // Write the type specifier 01031 BOOL ok = pCCFile->write(",BINH(", 6).good(); 01032 // And get our special CCFile to translate it 01033 if (ok) ok = m_pBinHexFile->write(pBuf, BufSize).good(); 01034 if (ok) ok = pCCFile->write(")", 1).good(); 01035 01036 return(ok); 01037 } 01038 01039 01040 01041 /******************************************************************************************** 01042 01043 > BOOL CXaraTemplateFile::IsSimpleUnicode(UINT16* pStr) 01044 01045 Author: Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com> 01046 Created: 12/07/97 01047 Inputs: pStr - pointer to UNICODE string 01048 Purpose: Determines if UNICODE is safe as ASCII 01049 01050 ********************************************************************************************/ 01051 01052 BOOL CXaraTemplateFile::IsSimpleUnicode(UINT16* pStr) 01053 { 01054 if (pStr == NULL) 01055 return(FALSE); 01056 01057 while (*pStr != 0) 01058 { 01059 if (((*pStr) > 126) || 01060 ((*pStr) < 32)) 01061 { 01062 return(FALSE); 01063 } 01064 pStr++; 01065 } 01066 01067 return(TRUE); 01068 } 01069 01070 01071 /******************************************************************************************** 01072 01073 > BOOL CXaraTemplateFile::WriteSimpleUnicode(WCHAR* pStr) 01074 01075 Author: Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com> 01076 Created: 12/07/97 01077 Inputs: pBuf - pointer to buffer to write 01078 BufSize - number of bytes to write 01079 Purpose: Writes the record in text format 01080 01081 Notes: This function is not particularly elegant (mainly due to time restrictions) 01082 01083 ********************************************************************************************/ 01084 01085 BOOL CXaraTemplateFile::WriteSimpleUnicode(UINT16* pStr) 01086 { 01087 if (pStr == NULL) 01088 return(FALSE); 01089 01090 // Write the type specifier 01091 BOOL ok = pCCFile->write(",UNC(\"", 6).good(); 01092 01093 while (ok && *pStr != 0) 01094 { 01095 // Write a single byte 01096 ok = pCCFile->write(pStr).good(); 01097 01098 // If it's a quote then double it up 01099 if (ok && *pStr == '"') 01100 ok = pCCFile->write(pStr).good(); 01101 01102 // Advance to next UINT16 01103 pStr++; 01104 } 01105 01106 if (ok) ok = pCCFile->write("\")", 2).good(); 01107 01108 return(ok); 01109 } 01110 01111 01112 01113 /******************************************************************************************** 01114 01115 > BOOL CXaraTemplateFile::WriteSimpleASCII(char* pStr) 01116 01117 Author: Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com> 01118 Created: 12/07/97 01119 Inputs: pBuf - pointer to buffer to write 01120 BufSize - number of bytes to write 01121 Purpose: Writes the record in text format 01122 01123 Notes: This function is not particularly elegant (mainly due to time restrictions) 01124 01125 ********************************************************************************************/ 01126 01127 BOOL CXaraTemplateFile::WriteSimpleASCII(char* pStr) 01128 { 01129 if (pStr == NULL) 01130 return(FALSE); 01131 01132 // Write the type specifier 01133 BOOL ok = pCCFile->write(",ASC(\"", 6).good(); 01134 01135 while (ok && *pStr != 0) 01136 { 01137 // Write a single byte 01138 ok = pCCFile->write(pStr).good(); 01139 01140 // If it's a quote then double it up 01141 if (ok && *pStr == '"') 01142 ok = pCCFile->write(pStr).good(); 01143 01144 // Advance to next char 01145 pStr++; 01146 } 01147 01148 if (ok) ok = pCCFile->write("\")", 2).good(); 01149 01150 return(ok); 01151 } 01152 01153 01154 01155 /******************************************************************************************** 01156 01157 > UINT32 CXaraTemplateFile::WriteMultipleWCHARs(BYTE* pTypes, DWORD Count, UINT16* pChars) 01158 01159 Author: Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com> 01160 Created: 12/07/97 01161 Inputs: pTypes - pointer to array of types 01162 Count - Size of type array 01163 pChars - pointer to actual WCHARs 01164 Purpose: Writes out one or more WCHARs using fancy concatenation to make the 01165 output more readable 01166 01167 ********************************************************************************************/ 01168 01169 UINT32 CXaraTemplateFile::WriteMultipleWCHARs(BYTE* pTypes, DWORD Count, UINT16* pChars) 01170 { 01171 TRACEUSER( "Gerry", _T("WriteMultipleWCHARs %d\n"), Count); 01172 01173 ERROR3IF(pTypes == NULL, "NULL type array"); 01174 ERROR3IF(pChars == NULL, "NULL chars array"); 01175 ERROR3IF(pTypes[0] != FTT_WCHAR, "First type isn't a WCHAR"); 01176 ERROR3IF(Count == 0, "No characters"); 01177 01178 if (Count == 0) 01179 return(0); 01180 01181 WCHAR ch = pChars[0]; 01182 if (Count == 1 || pTypes[1] != FTT_WCHAR) 01183 return(WriteSingleWCHAR(ch) ? 1 : 0); 01184 01185 // Flag for type of current string 01186 BOOL bAscii = IsPrint(ch); 01187 BOOL ok = TRUE; 01188 01189 // Indices where things change 01190 UINT32 ThisItem = 0; 01191 UINT32 NextItem = 1; 01192 UINT32 bContinue = TRUE; 01193 UINT32 NumWritten = 0; 01194 01195 // While we should continue 01196 while (bContinue) 01197 { 01198 // While we have a next item, 01199 while (ok && 01200 (NextItem < Count) && 01201 (pTypes[NextItem] == FTT_WCHAR) && 01202 (IsPrint(pChars[NextItem]) == bAscii)) 01203 { 01204 NextItem++; 01205 } 01206 01207 // Now the sense has changed or we are at the end... 01208 // So write out the data item 01209 if ((NextItem - ThisItem) == 1) 01210 { 01211 ok = WriteSingleWCHAR(pChars[ThisItem]); 01212 } 01213 else 01214 { 01215 if (bAscii) 01216 { 01217 // Write the type specifier 01218 ok = pCCFile->write(",WCS(\"", 6).good(); 01219 UINT32 i; 01220 for (i = ThisItem; ok && (i < NextItem); i++) 01221 { 01222 // Write a single byte 01223 ok = pCCFile->write(&(pChars[i])).good(); 01224 01225 // If it's a quote then double it up 01226 if (ok && pChars[i] == '"') 01227 ok = pCCFile->write(&(pChars[i])).good(); 01228 } 01229 01230 if (ok) ok = pCCFile->write("\")", 2).good(); 01231 if (ok) NumWritten += NextItem - ThisItem; 01232 } 01233 else 01234 { 01235 ok = WriteBinHex((BYTE*)&(pChars[ThisItem]), (NextItem - ThisItem) * sizeof(WCHAR)); 01236 if (ok) NumWritten += (NextItem - ThisItem); 01237 } 01238 01239 } // if ((NextItem - ThisItem) == 1) 01240 01241 01242 if (ok && 01243 (NextItem < Count) && 01244 (pTypes[NextItem] == FTT_WCHAR)) 01245 { 01246 01247 // Point at next item 01248 ThisItem = NextItem; 01249 // And then increment NextItem 01250 NextItem++; 01251 // Set correct sense for the next item 01252 bAscii = IsPrint(pChars[ThisItem]); 01253 } 01254 else 01255 bContinue = FALSE; // Otherwise flag to stop 01256 } 01257 01258 if (!ok) 01259 NumWritten = 0; 01260 01261 return(NumWritten); 01262 } 01263 01264 01265 /******************************************************************************************** 01266 01267 > BOOL CXaraTemplateFile::WriteSingleWCHAR(WCHAR ch) 01268 01269 Author: Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com> 01270 Created: 12/07/97 01271 Inputs: ch - WCHAR to write 01272 Purpose: Writes a single WCHAR as a complete data item 01273 It uses WC() when the character is printable ascii otherwise it uses W() 01274 output more readable 01275 01276 ********************************************************************************************/ 01277 01278 BOOL CXaraTemplateFile::WriteSingleWCHAR(WCHAR ch) 01279 { 01280 BOOL ok = TRUE; 01281 char Buffer[16]; 01282 UINT32 Num = 0; 01283 01284 if (ch == '"') 01285 { 01286 // Special case the doubled up quotes 01287 memcpy(Buffer, ",WC(\"\"\"\")", 9); 01288 } 01289 else if (IsPrint(ch)) 01290 { 01291 Num = sprintf(Buffer, ",WC(\"%c\")", (char)(ch & 0xFF)); 01292 } 01293 else 01294 { 01295 Num = sprintf(Buffer, ",W(%hu)", (INT16)(ch & 0xFFFF)); 01296 } 01297 01298 ok = pCCFile->write(Buffer, Num).good(); 01299 01300 return(ok); 01301 }