00001 // $Id: ccobject.cpp 1464 2006-07-18 12:32:26Z gerry $ 00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE 00003 ================================XARAHEADERSTART=========================== 00004 00005 Xara LX, a vector drawing and manipulation program. 00006 Copyright (C) 1993-2006 Xara Group Ltd. 00007 Copyright on certain contributions may be held in joint with their 00008 respective authors. See AUTHORS file for details. 00009 00010 LICENSE TO USE AND MODIFY SOFTWARE 00011 ---------------------------------- 00012 00013 This file is part of Xara LX. 00014 00015 Xara LX is free software; you can redistribute it and/or modify it 00016 under the terms of the GNU General Public License version 2 as published 00017 by the Free Software Foundation. 00018 00019 Xara LX and its component source files are distributed in the hope 00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the 00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00022 See the GNU General Public License for more details. 00023 00024 You should have received a copy of the GNU General Public License along 00025 with Xara LX (see the file GPL in the root directory of the 00026 distribution); if not, write to the Free Software Foundation, Inc., 51 00027 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00028 00029 00030 ADDITIONAL RIGHTS 00031 ----------------- 00032 00033 Conditional upon your continuing compliance with the GNU General Public 00034 License described above, Xara Group Ltd grants to you certain additional 00035 rights. 00036 00037 The additional rights are to use, modify, and distribute the software 00038 together with the wxWidgets library, the wxXtra library, and the "CDraw" 00039 library and any other such library that any version of Xara LX relased 00040 by Xara Group Ltd requires in order to compile and execute, including 00041 the static linking of that library to XaraLX. In the case of the 00042 "CDraw" library, you may satisfy obligation under the GNU General Public 00043 License to provide source code by providing a binary copy of the library 00044 concerned and a copy of the license accompanying it. 00045 00046 Nothing in this section restricts any of the rights you have under 00047 the GNU General Public License. 00048 00049 00050 SCOPE OF LICENSE 00051 ---------------- 00052 00053 This license applies to this program (XaraLX) and its constituent source 00054 files only, and does not necessarily apply to other Xara products which may 00055 in part share the same code base, and are subject to their own licensing 00056 terms. 00057 00058 This license does not apply to files in the wxXtra directory, which 00059 are built into a separate library, and are subject to the wxWindows 00060 license contained within that directory in the file "WXXTRA-LICENSE". 00061 00062 This license does not apply to the binary libraries (if any) within 00063 the "libs" directory, which are subject to a separate license contained 00064 within that directory in the file "LIBS-LICENSE". 00065 00066 00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS 00068 ---------------------------------------------- 00069 00070 Subject to the terms of the GNU Public License (see above), you are 00071 free to do whatever you like with your modifications. However, you may 00072 (at your option) wish contribute them to Xara's source tree. You can 00073 find details of how to do this at: 00074 http://www.xaraxtreme.org/developers/ 00075 00076 Prior to contributing your modifications, you will need to complete our 00077 contributor agreement. This can be found at: 00078 http://www.xaraxtreme.org/developers/contribute/ 00079 00080 Please note that Xara will not accept modifications which modify any of 00081 the text between the start and end of this header (marked 00082 XARAHEADERSTART and XARAHEADEREND). 00083 00084 00085 MARKS 00086 ----- 00087 00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara 00089 designs are registered or unregistered trademarks, design-marks, and/or 00090 service marks of Xara Group Ltd. All rights in these marks are reserved. 00091 00092 00093 Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. 00094 http://www.xara.com/ 00095 00096 =================================XARAHEADEREND============================ 00097 */ 00098 00099 /* 00100 */ 00101 00102 #include "camtypes.h" 00103 00104 #if defined( __WXMSW__ ) 00105 #include <new.h> 00106 #elif defined( __WXMAC__ ) 00107 #include <new> 00108 #endif 00109 00110 //#include "ccobject.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00111 00112 //#include "ensure.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00113 //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00114 //#include "resource.h" 00115 00116 00117 #ifdef _DEBUG 00118 BOOL SimpleCCObject::CheckMemoryFlag = FALSE; 00119 #endif 00120 00122 // SimpleCCObject 00123 00124 00125 /******************************************************************************************** 00126 00127 < struct MemTrackExtra 00128 00129 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00130 Created: 27/8/94 00131 Purpose: Holds the info that we use in the memory tracking code. It is a doubly linked 00132 list that tells us how big a block is, where it was allocated etc 00133 00134 ********************************************************************************************/ 00135 00136 typedef struct MemTrackExtra 00137 { 00138 UINT32 GuardWord; 00139 struct MemTrackExtra* pNext; 00140 struct MemTrackExtra* pPrev; 00141 size_t Size; 00142 void* Start; 00143 char Filename[22]; 00144 INT32 LineNum; 00145 } MemTrackExtra; 00146 00147 #ifdef _DEBUG 00148 // a global pointer to the first item in the memory tracking list 00149 static MemTrackExtra* pHead = NULL; 00150 #endif 00151 00152 // some constants used by the memory tracker 00153 #define GUARDWORD 0xEFBEADDE // DEADBEEF with the byte in intel order 00154 #define DEADGUARD 0xEEFFC000 // 00C0FFEE with the byts in intel order 00155 #define NEWLANDFILL 0xCD // The value to fill new block with 00156 #define OLDLANDFILL 0xAF // The value to fill blocks with as they are deleted 00157 00158 //#define _OUTPUT_DEBUG // Comment this out to disable debug messages during allocation 00159 //#define _OUTPUT_DEBUG_TRACKING // Comment this out to disable debug messages about allocation 00160 00161 #ifdef _OUTPUT_DEBUG 00162 static INT32 TotalMemAllocated = 0; // For tracing memory allocations 00163 #endif 00164 00165 // Static declarations for low memory test 00166 #ifdef _DEBUG 00167 size_t SimpleCCObject::BytesBeforeFail = 0; 00168 BOOL SimpleCCObject::FailingMemory = FALSE; 00169 #endif 00170 00171 // set this to 1 for structure integrity checks on news/deletes. Defaults to using 00172 // the MFC flag for the same purpose 00173 //#define CHECK_MEMORY ( afxMemDF & checkAlwaysMemDF ) 00174 #ifdef _DEBUG 00175 #define CHECK_MEMORY (SimpleCCObject::CheckMemoryFlag) 00176 #else 00177 #define CHECK_MEMORY 0 00178 #endif 00179 00180 /******************************************************************************************** 00181 00182 > BOOL SimpleCCObject::Init() 00183 00184 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00185 Created: 19/4/94 00186 Returns: TRUE if it worked OK, FALSE if not 00187 Purpose: Declares a preference that allows you to clear memory in delete(). 00188 00189 ********************************************************************************************/ 00190 00191 BOOL SimpleCCObject::Init() 00192 { 00193 // return TRUE as we do not want Camelot to fail to start over this 00194 return TRUE; 00195 } 00196 00197 00198 #ifdef _DEBUG 00199 /******************************************************************************************** 00200 > BOOL SimpleCCObject::CheckMemory( BOOL Assert ) 00201 00202 Author: Andy_Pennell (Xara Group Ltd) <camelotdev@xara.com> 00203 Created: 4/1/95 00204 Purpose: Checks the CCObject memory structures, returns TRUE if OK, FALSE if 00205 broken. 00206 If Assert is TRUE then asserts within the function, allowing deeper investigation. 00207 Only exists in debug builds. 00208 ********************************************************************************************/ 00209 BOOL SimpleCCObject::CheckMemory( BOOL Announce ) 00210 { 00211 char *WhyFailed = NULL; 00212 MemTrackExtra *Cur = pHead; 00213 00214 while (Cur) 00215 { 00216 // check guardword 00217 if (Cur->GuardWord != GUARDWORD) 00218 { 00219 WhyFailed = "Guardword missing"; // Debug 00220 break; 00221 } 00222 00223 // get the next one 00224 MemTrackExtra *Next = Cur->pNext; 00225 00226 // check the back pointer 00227 if (Next) 00228 { 00229 if (Next->pPrev != Cur) 00230 { 00231 WhyFailed = "Previous pointer missing"; // Debug 00232 break; 00233 } 00234 } 00235 00236 // try the next block 00237 Cur = Next; 00238 } 00239 00240 // did it work or not? 00241 00242 if (WhyFailed) 00243 { 00244 if (Announce) 00245 ERROR2RAW( WhyFailed ); 00246 return FALSE; 00247 } 00248 else 00249 return TRUE; 00250 } 00251 00252 00253 00254 /******************************************************************************************** 00255 > static void SimpleCCObject::EnableLowMemoryTesting() 00256 00257 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 00258 Created: 16/9/96 00259 Purpose: Turns on the low memory simluator. After this memory allocation will fail 00260 Debug builds only, obviously. 00261 SeeAlso: SimpleCCObject::DisableLowMemoryTesting 00262 SimpleCCObject::SetClaimLimit 00263 ********************************************************************************************/ 00264 void SimpleCCObject::EnableLowMemoryTesting() 00265 { 00266 FailingMemory = TRUE; 00267 TRACE( _T("Low memory simulation ENABLED\n")); 00268 } 00269 00270 00271 00272 /******************************************************************************************** 00273 > static void SimpleCCObject::DisableLowMemoryTesting() 00274 00275 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 00276 Created: 16/9/96 00277 Purpose: Turns off the low memory simluator. After this memory allocation will work 00278 Debug builds only, obviously. 00279 SeeAlso: SimpleCCObject::EnableLowMemoryTesting 00280 SimpleCCObject::SetClaimLimit 00281 ********************************************************************************************/ 00282 void SimpleCCObject::DisableLowMemoryTesting() 00283 { 00284 FailingMemory = FALSE; 00285 TRACE( _T("Low memory simulation DISABLED\n")); 00286 } 00287 00288 00289 00290 /******************************************************************************************** 00291 > static void SimpleCCObject::SetClaimLimit() 00292 00293 Author: Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com> 00294 Created: 16/9/96 00295 Purpose: Sets the number of bytes that will be allocated before memory claims fail. 00296 You must call EnableLowMemoryTesting before claims will fail. 00297 Debug builds only, obviously. 00298 SeeAlso: SimpleCCObject::DisableLowMemoryTesting 00299 SimpleCCObject::EnableLowMemoryTesting 00300 ********************************************************************************************/ 00301 void SimpleCCObject::SetClaimLimit(UINT32 BytesToAllow) 00302 { 00303 BytesBeforeFail = BytesToAllow; 00304 TRACE( _T("Low memory simulation will fail all claims after %d bytes\n") ,BytesBeforeFail); 00305 } 00306 00307 #endif 00308 00309 00310 00311 /******************************************************************************************** 00312 00313 > void SimpleCCObject::MemoryTrackAdd(void* p, LPCSTR FileName, INT32 Line) 00314 00315 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00316 Created: 23/7/93 00317 Inputs: p - pointer to the block of memory that was allocated 00318 FileName - pointer to the string containing the filename 00319 Line - The line at which the allocation happened 00320 Purpose: This functions adds an item into the memory tracking list 00321 and stores the filename and line number if it is passed in. 00322 Both versions of new call this function to handle all there 00323 DEBUG stuff. 00324 00325 ********************************************************************************************/ 00326 00327 #ifdef _DEBUG 00328 void SimpleCCObject::MemoryTrackAdd(void* pStart, LPCSTR FileName, INT32 Line) 00329 { 00330 // Find out how much memory malloc actually gave us 00331 #if !defined(__WXMAC__) 00332 size_t BlockLen = _msize(pStart); 00333 #else 00334 size_t BlockLen = malloc_size(pStart); 00335 #endif 00336 00337 // Fill the block with the Land Fill value 00338 memset(pStart, NEWLANDFILL, BlockLen); 00339 00340 // Find the start of my strange structure 00341 MemTrackExtra* pExtraInfo = (MemTrackExtra*) pStart; 00342 00343 // fill the structure with the extra data 00344 pExtraInfo->GuardWord = GUARDWORD; 00345 pExtraInfo->Size = BlockLen; 00346 pExtraInfo->Start = ((char*)pStart + sizeof(MemTrackExtra)); 00347 00348 // Fill in the details about the file position 00349 if (FileName!=NULL) 00350 { 00351 // copy the string passed in and note the line number 00352 size_t Count = strlen( FileName ); 00353 if (Count>21) 00354 { 00355 // The string was too long, so we have to copy just the last 22 chars in it 00356 FileName += Count - 21; 00357 } 00358 00359 // copy the end of the string into the space I have for it 00360 strcpy( pExtraInfo->Filename, FileName ); 00361 pExtraInfo->LineNum = Line; 00362 } 00363 else 00364 { 00365 // set the fields to null values 00366 strcpy( pExtraInfo->Filename, "Unknown File" ); // Debug only by the smell of things 00367 pExtraInfo->LineNum = 0; 00368 } 00369 00370 // Build the linked list on this node 00371 pExtraInfo->pNext = pHead; 00372 pExtraInfo->pPrev = NULL; 00373 00374 // update the list on the surrounding nodes 00375 if (pExtraInfo->pNext!=NULL) 00376 pExtraInfo->pNext->pPrev = pExtraInfo; 00377 00378 // update the head of list pointer 00379 pHead = pExtraInfo; 00380 00381 // make sure memory is still OK 00382 #ifdef _DEBUG 00383 if (CHECK_MEMORY) 00384 CheckMemory( TRUE ); 00385 #endif 00386 } 00387 #endif 00388 00389 /******************************************************************************************** 00390 00391 > void* SimpleCCObject::operator new(size_t size, LPCSTR FileName, INT32 Line) 00392 00393 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00394 Created: 23/7/93 00395 Inputs: size - Number of bytes required 00396 FileName - The name of the file that caused the allocation 00397 Line - The line number in the file that caused the allocation 00398 Returns: a pointer to the allocated block of memory, or NULL if the 00399 allocation failed 00400 Purpose: A version of the new operator that stores the filename etc 00401 into the memory tracking structure to help in debugging. 00402 This can be activated by including the following line :- 00403 MonoOn #define new CAM_DEBUG_NEW MonoOff 00404 after all the IMPLEMENT_DYNAMIC() etc macros. 00405 00406 ********************************************************************************************/ 00407 00408 void* SimpleCCObject::operator new(size_t Size, LPCSTR FileName, INT32 Line) 00409 { 00410 // First we have to make a note of the function pointer maintained by VC++ thats 00411 // called by malloc if it fails (as it currently throws an exception) 00412 // We have to set it to NULL to stop malloc doing anything when mem runs out 00413 #if !defined(__WXMAC__) 00414 _PNH old_handler = _set_new_handler( NULL ); 00415 #else 00416 new_handler pnh = set_new_handler(NULL); 00417 #endif 00418 00419 #ifdef _OUTPUT_DEBUG 00420 TotalMemAllocated += Size; 00421 TRACE( _T("Allocated %ld\n"),TotalMemAllocated); 00422 #endif 00423 00424 #ifdef _DEBUG 00425 // We actually want more memory to build our list out of 00426 Size += sizeof(MemTrackExtra); 00427 #endif 00428 00429 void* pStart = NULL; 00430 00431 // See if we are supposed to fail this memory claim for low memory simulation 00432 #ifdef _DEBUG 00433 if (FailingMemory) 00434 { 00435 if (Size < BytesBeforeFail) 00436 BytesBeforeFail -= Size; 00437 else 00438 goto Allocated; 00439 } 00440 #endif 00441 00442 // ask for the actual memory 00443 pStart = malloc(Size); 00444 00445 // finally repair the function pointer to its old value and return our pointer 00446 #if !defined(__WXMAC__) 00447 _set_new_handler( old_handler ); 00448 #else 00449 set_new_handler(pnh); 00450 #endif 00451 00452 // Do lots of tracking if in Debug mode 00453 #ifdef _DEBUG 00454 if (pStart!=NULL) 00455 { 00456 // Build in all the extra memory tracking info that we like to have 00457 MemoryTrackAdd(pStart, FileName, Line); 00458 } 00459 00460 Allocated: 00461 // We'll remove the label as well (to get rid of the warning) 00462 #endif 00463 // if the pointer is NULL then we should set the error handler 00464 if (pStart==NULL) 00465 { 00466 TRACE( wxT("ALERT! ALERT! new is about to return NULL, Watch out for unhandled errors\n") ); 00467 Error::SetError(_R(IDS_OUT_OF_MEMORY)); 00468 } 00469 00470 // TRACE( _T("SimpleCCObject::new at 0x%08x (0x%08x)\n"),((char*)pStart) + sizeof(MemTrackExtra), pStart); 00471 00472 #ifdef _DEBUG 00473 // return the pointer to the space after our tracking info 00474 return (((char*)pStart) + sizeof(MemTrackExtra)); 00475 #else 00476 // return the real start of the block 00477 return (pStart); 00478 #endif 00479 } 00480 00481 00482 /******************************************************************************************** 00483 00484 > void *SimpleCCObject::operator new(size_t size) 00485 00486 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00487 Created: 15/7/93 00488 Inputs: size - The number of bytes to allocate 00489 Returns: a pointer to the allocated memory (or NULL if the allocation failed) 00490 Purpose: This function allocates a block of memory to create a new SimpleCCObject 00491 derived thingy. This does not throw an exception, but returns NULL 00492 in the event of a failure. In debug builds it also keeps track of 00493 all allocations and will give a dump of all reamining blobs of memory 00494 when camelot exits 00495 SeeAlso: SimpleCCObject::delete; SimpleCCObject::MemoryDump 00496 00497 ********************************************************************************************/ 00498 00499 void *SimpleCCObject::operator new(size_t Size) 00500 { 00501 // First we have to make a note of the function pointer maintained by VC++ thats 00502 // called by malloc if it fails (as it currently throws an exception) 00503 // We have to set it to NULL to stop malloc doing anything when mem runs out 00504 #if !defined(__WXMAC__) 00505 _PNH old_handler = _set_new_handler( NULL ); 00506 #else 00507 new_handler pnh = set_new_handler(NULL); 00508 #endif 00509 00510 #ifdef _DEBUG 00511 // We actually want more memory to build our list out of 00512 Size += sizeof(MemTrackExtra); 00513 #endif 00514 00515 #ifdef _OUTPUT_DEBUG 00516 TotalMemAllocated += Size; 00517 TRACE( _T("Allocated %ld\n"),TotalMemAllocated); 00518 #endif 00519 00520 // ask for the actual memory 00521 void* pStart = malloc(Size); 00522 00523 // finally repair the function pointer to its old value and return our pointer 00524 #if !defined(__WXMAC__) 00525 _set_new_handler( old_handler ); 00526 #else 00527 set_new_handler(pnh); 00528 #endif 00529 00530 // Do lots of tracking if in Debug mode 00531 #ifdef _DEBUG 00532 // see if we have a NULL value returned from new 00533 if (pStart!=NULL) 00534 { 00535 // Build in all the extra memory tracking info that we like to have 00536 MemoryTrackAdd(pStart, NULL, 0); 00537 } 00538 #endif 00539 00540 // if the pointer is NULL then we should set the error handler 00541 if (pStart==NULL) 00542 { 00543 TRACE( wxT("ALERT! ALERT! new is about to return NULL, Watch out for unhandled errors\n") ); 00544 Error::SetError(_R(IDS_OUT_OF_MEMORY)); 00545 } 00546 00547 // TRACE( _T("SimpleCCObject::new at 0x%08x (0x%08x)\n"),((char*)pStart) + sizeof(MemTrackExtra), pStart); 00548 00549 #ifdef _DEBUG 00550 // return the pointer to the space after our tracking info 00551 return (((char*)pStart) + sizeof(MemTrackExtra)); 00552 #else 00553 // return the real start of the block 00554 return (pStart); 00555 #endif 00556 } 00557 00558 00559 00560 00561 /******************************************************************************************** 00562 00563 > void SimpleCCObject::operator delete(void *p) 00564 00565 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00566 Created: 15/7/93 00567 Inputs: p - pointer to the block of mem to free 00568 Purpose: I think you can work this one out! In debug builds this will also 00569 remove items from the memory tracking list. 00570 Errors: Asserts if it discovers that the block you are trying to delete has 00571 already been deleted, never existed or is otherwise not valid. 00572 00573 ********************************************************************************************/ 00574 00575 void SimpleCCObject::operator delete(void *p) 00576 { 00577 // behave like normal delete 00578 if (p==NULL) 00579 return; 00580 00581 #ifdef _DEBUG 00582 // TRACE( _T("SimpleCCObject::delete at 0x%08x (0x%08x)\n"),p, ((char*)p) - sizeof(MemTrackExtra)); 00583 00584 // Get the real start of the block 00585 p = ((char*)p) - sizeof(MemTrackExtra); 00586 00587 // find out how big the block is 00588 #if !defined(__WXMAC__) 00589 size_t BlockLen = _msize(p); 00590 #else 00591 size_t BlockLen = malloc_size(p); 00592 #endif 00593 00594 #ifdef _OUTPUT_DEBUG 00595 TotalMemAllocated -= BlockLen; 00596 TRACE( _T("DeAllocated %ld\n"),TotalMemAllocated); 00597 #endif 00598 00599 // Find the start of my strange structure 00600 MemTrackExtra* pExtraInfo = (MemTrackExtra*)p; 00601 00602 // make sure that the guard word is still there 00603 if (pExtraInfo->GuardWord == GUARDWORD) 00604 { 00605 // yep, all seems well, so remove this item from the list 00606 // Update the head of the list if needed 00607 if (pExtraInfo == pHead) 00608 pHead = pExtraInfo->pNext; 00609 00610 // Update the next item in the list 00611 if (pExtraInfo->pNext!=NULL) 00612 pExtraInfo->pNext->pPrev = pExtraInfo->pPrev; 00613 00614 // update the previous item in the list 00615 if (pExtraInfo->pPrev!=NULL) 00616 pExtraInfo->pPrev->pNext = pExtraInfo->pNext; 00617 00618 // Write over the block with the dead memory land fill value 00619 memset(p, OLDLANDFILL, BlockLen); 00620 00621 // Destroy the guard word 00622 pExtraInfo->GuardWord = DEADGUARD; 00623 } 00624 else 00625 { 00626 if (pExtraInfo->GuardWord == DEADGUARD) 00627 ENSURE(FALSE, "Memory was de-alloced more than once...\n"); // Debug 00628 else 00629 ENSURE(FALSE, "ALERT!!!! Memory Tracker thinks that memory is toast...\n"); // Debug 00630 00631 // either way, the memory is not there to be freed 00632 return; 00633 } 00634 #endif 00635 00636 // free up the allocation 00637 free(p); 00638 00639 #ifdef _DEBUG 00640 // and check everything is OK 00641 if (CHECK_MEMORY) 00642 CheckMemory( TRUE ); 00643 #endif 00644 } 00645 00646 00647 00648 00649 /******************************************************************************************** 00650 00651 > void SimpleCCObject::MemoryDump() 00652 00653 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00654 Created: 15/7/93 00655 Purpose: Dumps the details of all objects allocated at the time of the call to 00656 the Debug window 00657 00658 ********************************************************************************************/ 00659 00660 void SimpleCCObject::MemoryDump() 00661 { 00662 #ifdef _DEBUG 00663 // somewhere to hold the output string 00664 TCHAR OutputMsg[256]; 00665 00666 // Get a pointer to the head of the list of memory items 00667 MemTrackExtra *pItem = pHead; 00668 if( pItem != NULL ) 00669 TRACE( _T("......Memory Leaks Detected......\n")); 00670 00671 // loop through it 00672 while( pItem != NULL ) 00673 { 00674 PORTNOTE("other","Removed MFC CDumpContext") 00675 #ifndef EXCLUDE_FROM_XARALX 00676 ((CCObject*)(pItem->Start))->Dump(afxDump); 00677 #endif 00678 #if 0 != wxUSE_UNICODE 00679 TCHAR pFilename[22]; 00680 camMbstowcs(pFilename, pItem->Filename, 22); 00681 #else 00682 TCHAR* pFilename = pItem->Filename; 00683 #endif 00684 camSnprintf( OutputMsg, 256, _T("allocated in %s at line %d.\n"), pFilename, pItem->LineNum ); 00685 TRACE(OutputMsg); 00686 00687 // Get the next one along 00688 pItem = pItem->pNext; 00689 if (pItem==NULL) 00690 TRACE( _T("\n......End Of Memory Dump......\n")); 00691 } 00692 #endif 00693 } 00694 00695 00696 00697 00698 /******************************************************************************************** 00699 00700 > void CheckForUsedPointer(void *PtrToCheck) 00701 00702 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00703 Created: 4/9/95 00704 Purpose: Secret-squirrel (global, 'cos ccobject.h is a tad critical) function 00705 called by IndexedColours when they detect that they are "in use". 00706 00707 This function rampages through all CCSimpleObject derived objects 00708 looking for a word which matches the supplied pointer. If such a value 00709 is found, the object containing it is 'Dump'ed. 00710 00711 This allows us to track down the object(s) which reference an IndexedColour 00712 when it is found to be "in use" - with this function we can track down 00713 where references are, and, more importantly, where they were allocated! 00714 00715 Change this function very carefully - it is prototyped in colourix.cpp 00716 and possibly anywhere else that use it. 00717 00718 IMPORTANT 00719 This function is NOT AVAILABLE on debug builds. ONLY call it from 00720 code inside an #ifdef _DEBUG construct. 00721 00722 00723 ********************************************************************************************/ 00724 00725 #ifdef _DEBUG 00726 void CheckForUsedPointer(void *PtrToCheck) 00727 { 00728 // Get a pointer to the head of the list of memory items 00729 MemTrackExtra* pItem = pHead; 00730 00731 // loop through it 00732 while (pItem!=NULL) 00733 { 00734 DWORD *Ptr = (DWORD *) pItem->Start; 00735 for (INT32 Index = 0; Index < (INT32)pItem->Size; Index += sizeof(DWORD)) 00736 { 00737 if (*Ptr == (DWORD_PTR)PtrToCheck) 00738 { 00739 TRACEALL( _T(" UsedPointer: ") ); 00740 PORTNOTE("other","Removed MFC CDumpContext") 00741 #ifndef EXCLUDE_FROM_XARALX 00742 ((CCObject*)(pItem->Start))->Dump(afxDump); 00743 #endif 00744 TRACEALL( _T(" allocated in %s at line %d.\n"), pItem->Filename, pItem->LineNum ); 00745 } 00746 00747 Ptr += 1; // Pointer Arithmetic! 00748 } 00749 00750 // Get the next one along 00751 pItem = pItem->pNext; 00752 } 00753 } 00754 #endif 00755 00756 00757 00758 00759 00760 /******************************\ 00761 ** ** 00762 ** Objects for Runtime Typing ** 00763 ** ** 00764 \******************************/ 00765 00766 // The textual name of CCObject 00767 static TCHAR BASED_CODE szCCObject[] = wxT("CCObject"); 00768 00769 // Special CCRuntimeClass object for CCObject (no base class) 00770 CCRuntimeClass CCObject::cc_classCCObject = 00771 { 00772 szCCObject, // Name of the class 00773 sizeof(CCObject), // Size of an object of this class 00774 0xffff, // Schema number for serialisation (none) 00775 NULL, // Pointer to the default contructor (none) 00776 NULL // Pointer to the CCRuntimeClass object for the base class (none) 00777 }; 00778 00779 // Static CC_CLASSINIT object to ensure CCObject's runtime information is linked 00780 // into CCRuntimeClass's list. 00781 static CC_CLASSINIT _init_CCObject(&CCObject::cc_classCCObject); 00782 00783 /******************************************************************************************** 00784 00785 > BOOL CCRuntimeClass::IsKindOf(const CCRuntimeClass* pClass) const 00786 00787 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00788 Created: 19/7/93 00789 Inputs: pClass - pointer to the CCRuntimeClass object of the class to compare 00790 against. 00791 Returns: TRUE if it is a kind of the specified class; 00792 FALSE if not. 00793 Purpose: This function will return TRUE if the object is of the same class as that 00794 specified by pClass, or if it is derived from the class specified by 00795 pClass. 00796 SeeAlso: CCObject::GetRuntimeClass; CC_RUNTIME_CLASS; CCObject 00797 00798 ********************************************************************************************/ 00799 00800 BOOL CCRuntimeClass::IsKindOf(const CCRuntimeClass* pClass) const 00801 { 00802 // Do some sanity checking 00803 ENSURE( this != NULL, 00804 "CCRuntimeClass::IsKindOf: Object pointer is null"); 00805 00806 // It had better be in valid memory, at least for CCObject size 00807 ENSURE( IsValidAddress(this, sizeof(CCRuntimeClass)), 00808 "CCRuntimeClass::IsKindOf: Object is in invalid memory area"); 00809 00810 // Get the runtime class information for this object 00811 register const CCRuntimeClass* pClassThis = this; 00812 00813 // Sanity checks 00814 ENSURE( pClass != NULL, 00815 "CCRuntimeClass::IsKindOf: pClass pointer is null"); 00816 ENSURE(pClassThis != NULL, 00817 "CCRuntimeClass::IsKindOf: pClassThis pointer is null"); 00818 00819 // Check for objects of the same class, or walk the base class chain until 00820 // it runs out, or we find a match. 00821 while (pClassThis != NULL) 00822 { 00823 if (pClassThis == pClass) 00824 return TRUE; 00825 pClassThis = pClassThis->m_pBaseClass; 00826 } 00827 00828 // No match - these classes are not the same. 00829 return FALSE; 00830 } 00831 00832 /******************************************************************************************** 00833 00834 > CCRuntimeClass* CCObject::GetRuntimeClass() const 00835 00836 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00837 Created: 19/7/93 00838 Inputs: - 00839 Outputs: - 00840 Returns: Pointer to the CCRuntimeClass object associated with CCObject. 00841 Purpose: This function allows access to the CCRuntimeClass object for this class, 00842 which in turn allows dynamic classing and construction. 00843 This function is automatically overridden on derived classes if you use 00844 the CC_DECLARE_... and CC_IMPLEMENT_... macros. 00845 Errors: - 00846 SeeAlso: CCObject; CCRuntimeClass; CCObject::IsKindOf; CCRuntimeClass::CreateObject; 00847 CC_DECLARE_DYNAMIC; CC_IMPLEMENT_DYNAMIC; 00848 CC_DECLARE_DYNCREATE; CC_IMPLEMENT_DYNCREATE; 00849 CC_CLASS_MEMDUMP; CC_DECLARE_MEMDUMP; CC_IMPLEMENT_MEMDUMP; 00850 CCObject::GetRuntimeClass; 00851 00852 ********************************************************************************************/ 00853 00854 CCRuntimeClass* CCObject::GetRuntimeClass() const 00855 { 00856 return &CCObject::cc_classCCObject; 00857 } 00858 00859 // static version of above 00860 00861 CCRuntimeClass* CCObject::GetMyClass() 00862 { 00863 return &CCObject::cc_classCCObject; 00864 } 00865 00866 /******************************************************************************************** 00867 00868 > CCRuntimeClass* CCObject::GetRuntimeClassByName(LPCSTR* pClassName) const 00869 00870 Author: Alex_Bligh (Xara Group Ltd) <camelotdev@xara.com> 00871 Created: 28/07/94 00872 Inputs: Pointer to the string containing the textual class name. 00873 Outputs: - 00874 Returns: Pointer to the CCRuntimeClass object associated with that name, or nul if 00875 not found. 00876 Purpose: This function allows access to the CCRuntimeClass object for this class, 00877 which in turn allows dynamic classing and construction. 00878 This function is automatically overridden on derived classes if you use 00879 the CC_DECLARE_... and CC_IMPLEMENT_... macros. 00880 Errors: - 00881 SeeAlso: CCObject; CCRuntimeClass; CCObject::IsKindOf; CCRuntimeClass::CreateObject; 00882 CC_DECLARE_DYNAMIC; CC_IMPLEMENT_DYNAMIC; 00883 CC_DECLARE_DYNCREATE; CC_IMPLEMENT_DYNCREATE; 00884 CC_CLASS_MEMDUMP; CC_DECLARE_MEMDUMP; CC_IMPLEMENT_MEMDUMP; 00885 CCObject::GetRuntimeClass; 00886 00887 ********************************************************************************************/ 00888 00889 CCRuntimeClass* CCObject::GetRuntimeClassByName(LPCTSTR pClassName) 00890 { 00891 CCRuntimeClass* pClass = CCRuntimeClass::pFirstClass; 00892 do 00893 { 00894 if( 0 == camStrcmp(pClassName,pClass->m_lpszClassName) ) 00895 { 00896 return (pClass); 00897 } 00898 } 00899 while( ( pClass = pClass->m_pNextClass ) != NULL ); 00900 00901 return (NULL); 00902 } 00903 00904 00905 00906 /******************************************************************************************** 00907 00908 > BOOL CCObject::IsKindOf(const CCRuntimeClass* pClass) const 00909 00910 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00911 Created: 19/7/93 00912 Inputs: pClass - pointer to the CCRuntimeClass object of the class to compare 00913 against. 00914 Outputs: - 00915 Returns: - 00916 Purpose: This function will return TRUE if the object is of the same class as that 00917 specified by pClass, or if it is derived from the class specified by 00918 pClass. 00919 Errors: - 00920 SeeAlso: CCObject::GetRuntimeClass; CC_RUNTIME_CLASS; CCObject 00921 00922 ********************************************************************************************/ 00923 /******************************************************************************************** 00924 00925 Technical Notes: 00926 00927 This function relies on the fact that all classes derived from CCObject which have been 00928 declared and defined as having dynamic class support, will have a static CCRuntimeClass 00929 object as a data member. This object will also have been inserted into CCRuntimeClass's 00930 list of CCObject-derived classes (see CC_CLASSINIT). Therefore, this function simply 00931 uses GetRuntimeClass() to get the CCRuntimeClass object for the CCObject-derived object in 00932 question, and compares the pointers - if the objects are of the same class, both pointers 00933 will point to the same static CCRuntimeClass data member. 00934 00935 If the pointers are not the same, the function follows the base class chain backwards 00936 until either the object is found to be derived from the class specified by pClass, or until 00937 the base class chain comes to an end, in which case the objects are not of the same class, 00938 so FALSE is returned. 00939 00940 ********************************************************************************************/ 00941 00942 BOOL CCObject::IsKindOf(const CCRuntimeClass* pClass) const 00943 { 00944 // Do some sanity checking 00945 ENSURE( this != NULL, 00946 "CCObject::IsKindOf: Object pointer is null"); 00947 00948 // It had better be in valid memory, at least for CCObject size 00949 ENSURE( IsValidAddress(this, sizeof(CCObject)), 00950 "CCObject::IsKindOf: Object is in invalid memory area"); 00951 00952 // Get the runtime class information for this object 00953 register CCRuntimeClass* pClassThis = GetRuntimeClass(); 00954 00955 // Sanity checks 00956 ENSURE( pClass != NULL, 00957 "CCObject::IsKindOf: pClass pointer is null"); 00958 ENSURE(pClassThis != NULL, 00959 "CCObject::IsKindOf: pClassThis pointer is null"); 00960 00961 // Check for objects of the same class, or walk the base class chain until 00962 // it runs out, or we find a match. 00963 while (pClassThis != NULL) 00964 { 00965 if (pClassThis == pClass) 00966 return TRUE; 00967 pClassThis = pClassThis->m_pBaseClass; 00968 } 00969 00970 // No match - these classes are not the same. 00971 return FALSE; 00972 } 00973 00974 /******************************************************************************************** 00975 00976 > CCObject* CCRuntimeClass::CreateObject() 00977 00978 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00979 Created: 19/7/93 00980 Inputs: - 00981 Outputs: - 00982 Returns: Pointer to a new object. 00983 Purpose: Dynamic creation of objects. This function should be used when you want to 00984 create an object and you do not know what type it should be until runtime. 00985 An example would be copying another object derived from CCObject. 00986 00987 \i See CCObject and CCRuntimeClass for more details. \i0 00988 00989 Errors: - 00990 SeeAlso: CCObject; CCRuntimeClass; CC_RUNTIME_CLASS; CCObject::IsKindOf 00991 00992 ********************************************************************************************/ 00993 00994 CCObject* CCRuntimeClass::CreateObject() 00995 { 00996 void* pObject = NULL; 00997 00998 // Allocate memory for the new object. 00999 pObject = CCObject::operator new(m_nObjectSize, THIS_FILE, __LINE__); 01000 01001 // Attempt to construct it using dynamic creation facilities 01002 if ((pObject != NULL) && ConstructObject(pObject)) 01003 // All ok - return pointer to new object 01004 return (CCObject*) pObject; 01005 else 01006 { 01007 // Something went wrong... 01008 TRACE0( wxT("Warning: CCRuntimeClass::CreateObject failed\n") ); 01009 01010 // Did the 'new' succeed? If so, deallocate the storage 01011 if (pObject != NULL) 01012 CCObject::operator delete(pObject); // clean up 01013 01014 // Object creation failed. 01015 return NULL; 01016 } 01017 } 01018 01019 /******************************************************************************************** 01020 01021 > BOOL CCRuntimeClass::ConstructObject(void* pThis) 01022 01023 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 01024 Created: 19/7/93 01025 Inputs: - 01026 Outputs: - 01027 Returns: - 01028 Purpose: Dynamically construct an instance of this class in the memory pointed to by 01029 'pThis'. Return FALSE if can't construct (i.e. an abstract class). 01030 01031 \i Do not call this function directly - use CreateObject() instead. \i0 01032 01033 Errors: - 01034 SeeAlso: CCObject::CreateObject 01035 01036 ********************************************************************************************/ 01037 01038 01039 BOOL CCRuntimeClass::ConstructObject(void* pThis) 01040 { 01041 // Make sure memory we've been given is not a brown cylindrical object. 01042 ENSURE( IsValidAddress(pThis, m_nObjectSize), 01043 "CCRuntimeClass::ConstructObject: pThis pointer is invalid"); 01044 01045 // Try to create the object. 01046 if (m_pfnConstruct != NULL) 01047 { 01048 // It's not an abstract class, so call the constructor 01049 (*m_pfnConstruct)(pThis); 01050 return TRUE; 01051 } 01052 else 01053 { 01054 // Error - cannot construct an instance of an abstract class. 01055 TRACE( _T("Error: Trying to construct object of an abstract class %s.\n"), 01056 m_lpszClassName); 01057 return FALSE; 01058 } 01059 } 01060 01061 01062 #ifdef _CAMDLL 01063 // 01064 // For the shared DLL, we build a sub-list of the CRuntimeClasses during 01065 // a single DLL or EXE init. This sub-list gets moved from the 01066 // global 'pFirstClass' to some other place once the DLL or EXE 01067 // is properly initialized. 01068 // 01069 // !!! This has not been implemented yet !!! 01070 // 01071 #endif 01072 01073 // Initialise the list of CCRuntimeClass objects used for dynamic classing. 01074 CCRuntimeClass* CCRuntimeClass::pFirstClass = NULL; 01075 01076 /******************************************************************************************** 01077 01078 > CC_CLASSINIT::CC_CLASSINIT(CCRuntimeClass* pNewClass) 01079 01080 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 01081 Created: 19/7/93 01082 Inputs: pNewClass - pointer to the CCRuntimeClass object associated with the class 01083 that is to be registered. 01084 Outputs: - 01085 Returns: - 01086 Purpose: This constructor adds a given class (which should be derived from CCObject) 01087 to the list of classes that support dynamic classing/creation. 01088 01089 \i Do not use this directly - use the CC_DECLARE/IMPLEMENT macros instead. 01090 \i0 01091 Errors: - 01092 SeeAlso: CCObject; CCRuntimeClass; CCObject::GetRuntimeClass; CCObject::IsKindOf; 01093 CC_RUNTIME_CLASS; CC_DECLARE_DYNAMIC; CC_IMPLEMENT_DYNAMIC; 01094 CC_DECLARE_DYNCREATE; CC_IMPLEMENT_DYNCREATE; CC_CLASS_MEMDUMP; 01095 CC_DECLARE_MEMDUMP; CC_IMPLEMENT_MEMDUMP 01096 01097 ********************************************************************************************/ 01098 01099 CC_CLASSINIT::CC_CLASSINIT(CCRuntimeClass* pNewClass) 01100 { 01101 // Make sure it hasn't been added already 01102 ENSURE( pNewClass->m_pNextClass == NULL, 01103 "CC_CLASSINIT::CC_CLASSINIT: pNewClass has been added already!"); 01104 01105 // Insert the object at the head of the list used by CCRuntimeClass. 01106 pNewClass->m_pNextClass = CCRuntimeClass::pFirstClass; 01107 CCRuntimeClass::pFirstClass = pNewClass; 01108 } 01109 01110 /******************************************************************************************** 01111 01112 > CCAssertValidObject(const CCObject* pOb, LPCSTR lpszFileName, INT32 nLine) 01113 01114 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 01115 Created: 19/7/93 01116 Inputs: pOb - pointer to the object to check. 01117 lpszFileName - filename of the source file this is called from. 01118 nLine - line number of the source file this is called from. 01119 Outputs: - 01120 Returns: - 01121 Purpose: 01122 Errors: Assertion failure if object is not valid, i.e. if: 01123 01124 * pOb is a NULL pointer 01125 01126 * pOb does not point to memory which is valid & writeable for the whole 01127 of the object's area. 01128 01129 * pOb has an illegal virtual function table pointer. 01130 01131 \i Do not use this function directly - use CC_ASSERT_VALID instead. \i0 01132 01133 SeeAlso: CC_ASSERT_VALID 01134 01135 ********************************************************************************************/ 01136 01137 01138 #ifdef _DEBUG 01139 extern "C" void CCAssertValidObject(const CCObject* pOb, LPCSTR lpszFileName, INT32 nLine) 01140 { 01141 if (pOb == NULL) 01142 { 01143 TRACE0( _T("CC_ASSERT_VALID fails with NULL pointer\n") ); 01144 TCHAR pszTmp[256]; 01145 camSnprintf( pszTmp, 256, _T("%s, %d"), lpszFileName, nLine ); 01146 wxFAIL_MSG( pszTmp ); 01147 return; // quick escape 01148 } 01149 01150 #if defined(__WXMSW__) 01151 if( !IsValidAddress( pOb, sizeof(CCObject) ) ) 01152 { 01153 TRACE0( _T("CC_ASSERT_VALID fails with illegal pointer\n") ); 01154 TCHAR pszTmp[256]; 01155 camSnprintf( pszTmp, 256, _T("%s, %d"), lpszFileName, nLine ); 01156 wxFAIL_MSG( pszTmp ); 01157 return; // quick escape 01158 } 01159 01160 #ifndef _M_I86SM 01161 /* // check to make sure the far VTable pointer is valid 01162 ENSURE( sizeof(CCObject) == sizeof(void FAR*), 01163 "VTable pointer is not valid"); 01164 if( !IsValidAddress( *(void FAR**)pOb, sizeof(void FAR*), FALSE ) ) 01165 { 01166 TRACE0( _T("CC_ASSERT_VALID fails with illegal vtable pointer\n")); 01167 char pszTmp[256]; 01168 sprintf( pszTmp, "%s, %d", lpszFileName, nLine ); 01169 wxFAIL_MSG( pszTmp ); 01170 return; // quick escape 01171 } */ 01172 #endif 01173 01174 if( !IsValidAddress( pOb, pOb->GetRuntimeClass()->GetSize() ) ) 01175 { 01176 TRACE0( _T("CC_ASSERT_VALID fails with illegal pointer\n") ); 01177 TCHAR pszTmp[256]; 01178 camSnprintf( pszTmp, 256, _T("%s, %d"), lpszFileName, nLine ); 01179 wxFAIL_MSG( pszTmp ); 01180 return; // quick escape 01181 } 01182 #endif 01183 01184 pOb->AssertValid(); 01185 } 01186 #endif //_DEBUG 01187 01188 /******************************************************************************************** 01189 01190 > void CCObject::AssertValid() const 01191 01192 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 01193 Created: 19/7/93 01194 Inputs: - 01195 Outputs: - 01196 Returns: - 01197 Purpose: Ensures that a an instance of CCObject (or a derived class) is valid. 01198 In the base case, this means that 'this' is not a NULL pointer. 01199 You can override this function to provide whatever validation you want 01200 for your class (preferably using ENSURE/ASSERT). 01201 01202 \i You should bracket this function with #ifdef _DEBUG ... #endif so that it 01203 is not called in retail builds. You will get a link error if you do not 01204 do this, as the function has no definition in retail builds. \i0 01205 Errors: - 01206 SeeAlso: ENSURE 01207 01208 ********************************************************************************************/ 01209 01210 void CCObject::AssertValid() const 01211 { 01212 ENSURE(this != NULL, "CCObject::AssertValid: This pointer is null"); 01213 } 01214 01215 /******************************************************************************************** 01216 01217 > void CCObject::Dump(CDumpContext& dc) const 01218 01219 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 01220 Created: 19/7/93 01221 Inputs: dc - an MFC CDumpContext object that you should direct your output to. 01222 Outputs: - 01223 Returns: - 01224 Purpose: Print out the contents of an object derived from CCObject. 01225 You may override this function to dump whatever information you deem useful 01226 or helpful about this object - it is used, amongst other things, in 01227 diagnostic memory dumps. 01228 The default action if you do not override this function is to print: 01229 01230 "a ClassName at $address" 01231 01232 where ClassName is the name of the class that the object is an instance of, 01233 and address is the value of the 'this' pointer - \i you should provide at 01234 least this level of functionality if you override the function. \i0 01235 01236 Errors: - 01237 SeeAlso: - 01238 01239 ********************************************************************************************/ 01240 01241 PORTNOTE("other","Removed MFC CDumpContext") 01242 #ifndef EXCLUDE_FROM_XARALX 01243 void CCObject::Dump(CDumpContext& dc) const 01244 { 01245 #ifdef _DEBUG 01246 char Msg[256]; 01247 _stprintf(Msg, "%s at %p ", GetRuntimeClass()->m_lpszClassName, (void*)this); 01248 afxDump << Msg; 01249 #else 01250 dc; 01251 #endif //_DEBUG 01252 } 01253 #endif 01254 01255 /******************************************************************************************** 01256 01257 > CCObject::CCObject() 01258 01259 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 01260 Created: 19/7/93 01261 Inputs: - 01262 Outputs: - 01263 Returns: - 01264 Purpose: CCObject constructor - does nothing at present. Ought to be inline. 01265 Errors: - 01266 SeeAlso: CCObject 01267 01268 ********************************************************************************************/ 01269 01270 CCObject::CCObject() 01271 { 01272 } 01273 01274 /******************************************************************************************** 01275 01276 > CCObject::~CCObject() 01277 01278 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 01279 Created: 19/7/93 01280 Inputs: - 01281 Outputs: - 01282 Returns: - 01283 Purpose: CCObject destructor - does nothing at present. Ought to be inline. 01284 Errors: - 01285 SeeAlso: CCObject 01286 01287 ********************************************************************************************/ 01288 01289 CCObject::~CCObject() 01290 { 01291 }