sgscan.cpp

Go to the documentation of this file.
00001 // $Id: sgscan.cpp 1282 2006-06-09 09:46:49Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 
00099 // Gallery library FILE SCANNING classes
00100 
00101 /*
00102 */
00103 
00104 #include "camtypes.h"
00105 //#include "sgscan.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00106 #include <string.h>
00107 #include <io.h>
00108 #include <fcntl.h>
00109 #include <sys\stat.h>
00110 #include "sgscanf.h"
00111 //#include "bitmap.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00112 //#include "ccfile.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00113 //#include "pathname.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00114 //#include "thumb.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00115 //#include "resource.h"
00116 //#include "richard.h"
00117 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00118 //#include "app.h"      // for pref stuff... - in camtypes.h [AUTOMATICALLY REMOVED]
00119 #include "progress.h"
00120 //#include "sgallery.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00121 #include "sglib.h"
00122 //#include "sgtree.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00123 #include "sgfonts.h"
00124 #include "sglcart.h"
00125 #include "sglfills.h"
00126 #include "sglbase.h"
00127 #include "sgindgen.h"
00128 #include "sgliboil.h"
00129 //#include "simon.h"        // _R(IDS_CONTINUE)
00130 #include "atminst.h"
00131 //#include "richard2.h"
00132 #include "camnet.h"
00133 #include "pathnmex.h"
00134 
00135 DECLARE_SOURCE("$Revision: 1282 $");
00136 
00137 CC_IMPLEMENT_DYNCREATE(Library, ListItem)
00138 
00139 #define new CAM_DEBUG_NEW
00140 
00141 using namespace InetUtils;
00142 
00143 // Field cache static
00144 INT32 Library::MaxFieldCacheEntries = 25;
00145 
00146 // Background redraw the libraries ?
00147 BOOL Library::BackgroundRedraw = TRUE;
00148 
00149 // Should we eat loads of memory up by caching the index files ?
00150 BOOL Library::CacheIndexFile = TRUE;
00151 
00152 // Enable 'remote' library indexes if target media is read-only...
00153 BOOL Library::RemoteIndexes = TRUE;
00154 
00155 // Location for 'remote' library indexes (if empty, use temp)...
00156 String_256 Library::RemoteIndexLocation = "";
00157 
00158 // >>webster (adrian 17/12/96)
00159 // Base URL for web folders
00160 String_256 Library::URLBase = _T("");
00161 // <<webster
00162 
00163 // Quick index stuff - use same indexes in ..\xarainfo, as opposed to \xarainfo
00164 BOOL Library::QuickIndex = TRUE;
00165 
00166 // If non-null, ProgressBar->Update() will be called during bits which could take time
00167 // such as de-virtualising a group
00168 Progress *Library::ProgressBar = NULL;
00169 
00170 // Only define this if you want field caching...
00171 #define FIELDCACHE
00172 
00173 // Should we report problems with indexes in debug builds
00174 #define DONT_REPORT_KNOWN_CLIPART_PROBLEMS
00175 
00176 // Only define if you want the 'SaveIndex' code for the button compiled...
00177 #define SAVEINDEX
00178 
00179 // Store for the cached settings
00180 String_256 Library::g_ClipartLibraryPath    = TEXT("");
00181 String_256 Library::g_WebThemeLibraryPath   = TEXT("");
00182 String_256 Library::g_FontLibraryPath       = TEXT("");
00183 String_256 Library::g_FillsLibraryPath      = TEXT("");
00184 
00185 /***********************************************************************************************
00186 
00187 >   Library::Library()
00188 
00189     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
00190     Created:    22/2/95
00191 
00192     Purpose:    Constructor
00193 
00194 ***********************************************************************************************/
00195 
00196 Library::Library()
00197 {
00198     ParentGallery = NULL;
00199     ParentGroup = NULL;
00200 
00201     Title = NULL;
00202     IndexFile = NULL;
00203     Thumbnails = NULL;
00204     SubLibPath = NULL;
00205     SynonymFile = NULL;
00206                         
00207     ItemCount = 0;
00208     Type = SGLib_Blank;
00209 
00210     FirstLineOffset = LastLineOffset = 0;
00211 
00212     for(INT32 i=0; i<3; i++)
00213     {
00214         PreviewX[i] = 64;                       // Widths of thumbnails
00215         PreviewY[i] = 64;                       // Heights of thumbnails
00216     }
00217 
00218     // Add in a field cache for the library
00219 #ifdef FIELDCACHE
00220     FieldCache = NULL;
00221     CacheInit(MaxFieldCacheEntries);
00222 #endif
00223     
00224     // No sub index cached yet...
00225     //CachedSubIndex = NULL;
00226     CachedSubIndexBuf = NULL;
00227     CachedBufLength = 0;
00228 
00229     // Datestamp of last index cached
00230     IndexDateStamp = 0;
00231 
00232     // Quick Index stuff...
00233     QuickIndexEnabled = FALSE;
00234     QuickIndexFile = NULL;
00235 
00236     // Progress bar stuff
00237     ProgressBar = NULL;
00238     //>> webster (Adrian 02/01/97)
00239     m_nModified = 0;
00240     m_bIsWebLib = FALSE;
00241     m_lOldIndex = 0;
00242     //<< webster
00243 }
00244 
00245 
00246 
00247 /***********************************************************************************************
00248 
00249 >   Library::~Library()
00250 
00251     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
00252     Created:    18/2/95
00253 
00254     Purpose:    Time to die...
00255 
00256 ***********************************************************************************************/
00257 
00258 Library::~Library()
00259 {
00260     TRACEUSER( "Richard", _T("~Library called\n"));
00261 
00262     // Ensure our parent gallery is no longer displaying us
00263     if (ParentGallery != NULL)
00264     {
00265         ParentGallery->RemoveLibraryGroup(this);
00266         ParentGallery = NULL;
00267     }
00268 
00269     if(Title != NULL)
00270     {
00271         delete Title;
00272         Title = NULL;
00273     }
00274 
00275     if(IndexFile != NULL)
00276     {
00277         delete IndexFile;
00278         IndexFile = NULL;
00279     }
00280 
00281     if(Thumbnails != NULL)
00282     {
00283         delete Thumbnails;
00284         Thumbnails = NULL;
00285     }
00286     
00287     if(SubLibPath != NULL)
00288     {
00289         delete SubLibPath;
00290         SubLibPath = NULL;
00291     }
00292 
00293     if(SynonymFile != NULL)
00294     {
00295         delete SynonymFile;
00296         SynonymFile = NULL;
00297     }
00298 
00299     // Reclaim field cache memory                       
00300 #ifdef FIELDCACHE
00301     CacheKill();
00302 #endif
00303 
00304     // Free the CachedSubIndex file buffer
00305     if(CachedSubIndexBuf != NULL)
00306     {
00307         CCFree((void *)CachedSubIndexBuf);
00308         CachedSubIndexBuf = NULL;
00309     }
00310 
00311     CachedBufLength = 0;
00312 
00313 
00314     // And reclaim all memory used by the cached subindex itself
00315 //  if(CachedSubIndex != NULL)
00316 //  {
00317 //      CachedSubIndex->DeinitLexer();  
00318 //      if(CachedSubIndex->isOpen())
00319 //          CachedSubIndex->close();
00320 //      delete CachedSubIndex;
00321 //  }
00322 
00323 
00324     if(QuickIndexFile != NULL)
00325         delete QuickIndexFile;
00326 }
00327 
00328 /***********************************************************************************************
00329 
00330 >   BOOL Library::FreeCachedIndexes(void)
00331 
00332     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
00333     Created:    1/6/95
00334 
00335     Returns:    TRUE if succesful and previously cached indexes are no more...
00336 
00337     Purpose:    Free some memory when we close a gallery by freeing all the cached index
00338                 files...
00339 
00340 ***********************************************************************************************/
00341 
00342 BOOL Library::FreeCachedIndexes(void)
00343 {
00344     // Reclaim field cache memory
00345 #ifdef FIELDCACHE
00346     CacheKill();
00347 #endif
00348 
00349     // Free the CachedSubIndex file buffer
00350     if(CachedSubIndexBuf != NULL)
00351     {
00352         CCFree((void *)CachedSubIndexBuf);
00353         CachedSubIndexBuf = NULL;
00354         CachedBufLength = 0;
00355         return TRUE;
00356     }
00357 
00358     return FALSE;
00359 }
00360 
00361 
00362 /***********************************************************************************************
00363 
00364 >   BOOL Library::ReCacheIndexes(void)
00365 
00366     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
00367     Created:    1/6/95
00368 
00369     Returns:    TRUE if succesful and indexes have been (re-)cached...
00370                 FALSE if problems
00371                 
00372     Purpose:    Re-caches the indexes when opening a gallery...
00373 
00374 ***********************************************************************************************/
00375 
00376 BOOL Library::ReCacheIndexes(void)
00377 {
00378     // Don't recache indexes if group is v-d out...
00379     if(ParentGroup != NULL && ParentGroup->IsVirtualised())
00380         return TRUE;
00381 
00382     // Sort out the field cache
00383 #ifdef FIELDCACHE
00384     CacheKill();
00385     CacheInit(MaxFieldCacheEntries);
00386 #endif
00387 
00388     // Recache the indexes
00389     if(CachedSubIndexBuf == NULL && CacheIndexFile && IndexFile != NULL)
00390     {
00391         // Check the index file still exists
00392         //if(!SGLibOil::FileExists(IndexFile))
00393         //  return FALSE;
00394 
00395         // See if the index file has changed...
00396         //UINT32 NewIndexStamp = SGLibOil::FileModified(IndexFile);
00397         //if(IndexDateStamp != NewIndexStamp)
00398         //  return FALSE;
00399 
00400         if(CacheSubIndex(IndexFile))
00401         {
00402             // Whizz through index, inserting 0's for commas and sorting out spaces, etc...
00403             return ScanRestOfFile(CachedSubIndexBuf, FirstLineOffset, CachedBufLength, FALSE);
00404         }
00405         else
00406         {
00407             return FALSE;
00408         }
00409     }
00410 
00411     return TRUE;
00412 }
00413 
00414 /***********************************************************************************************
00415 
00416 >   BOOL Library::CacheSubIndex(PathName *IndexFile)
00417 
00418     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
00419     Created:    14/4/95
00420 
00421     Inputs:     IndexFile - Pathname of index file which we want to cache as a memfile
00422     Outputs:
00423     Returns:    TRUE if the file was successfully cached and opened
00424 
00425     Purpose:    Creates a CCMemTextFile with the given file in, and opens it. The idea
00426                 being that reading from a file in memory will be quicker than off a
00427                 very slow single speed CD ROM drive.
00428 
00429     Notes:      There are three ways of getting at the information in the library sub
00430                 index at the moment, a field cache, this index file cache and then lexing
00431                 over the diskfile itself. Obviously the first two are the most desirable,
00432                 but take memory up. The field cache we use is fairly good, once the items
00433                 have been read. This initial reading of the items is the slow bit, so that's
00434                 why we've got the option to cache the entire index file in memory as well.
00435 
00436     SeeAlso:    Library::GetSingleField, Library::Init
00437 
00438 ***********************************************************************************************/
00439 
00440 BOOL Library::CacheSubIndex(PathName *IndexFile)
00441 {
00442     BOOL OpenedOK = FALSE;
00443 
00444     // Doesn't bother with modified calls anymore, uses file size...
00445     INT32 NewFileSize = 0;
00446     
00447     if(QuickIndexEnabled)
00448         NewFileSize = SGLibOil::FileSize(QuickIndexFile);
00449     else
00450         NewFileSize = SGLibOil::FileSize(IndexFile);
00451 
00452     if(NewFileSize == 0)
00453         return FALSE;
00454 
00455     if(IndexDateStamp != 0 && IndexDateStamp != (UINT32)NewFileSize)
00456         return FALSE;
00457     IndexDateStamp = (UINT32)NewFileSize;
00458 
00459     CachedBufLength = NewFileSize;
00460     CachedSubIndexBuf = (TCHAR *)CCMalloc(CachedBufLength + 4);
00461 
00462     if(CachedSubIndexBuf != NULL)
00463     {
00464         CCDiskFile TmpDiskFile;
00465         TRY
00466         {
00467             if(QuickIndexEnabled)
00468                 OpenedOK = TmpDiskFile.open(*QuickIndexFile, ios::in);
00469             else
00470                 OpenedOK = TmpDiskFile.open(*IndexFile, ios::in);
00471 
00472             if(!OpenedOK)
00473             {
00474                 ERROR3("Couldn't open disk file for mem file");
00475                 if(CachedSubIndexBuf != NULL)
00476                     CCFree(CachedSubIndexBuf);
00477                 CachedSubIndexBuf = NULL;
00478                 CachedBufLength = 0;
00479                 return FALSE;
00480             }
00481 
00482             TmpDiskFile.read(CachedSubIndexBuf, CachedBufLength);       
00483             TmpDiskFile.close();
00484         }
00485         CATCH(CFileException, e)
00486         {   
00487             if(CachedSubIndexBuf != NULL)
00488                 CCFree(CachedSubIndexBuf);
00489             CachedSubIndexBuf = NULL;
00490             CachedBufLength = 0;
00491             if(TmpDiskFile.isOpen())
00492                 TmpDiskFile.close();
00493             return FALSE;
00494         }
00495         END_CATCH
00496     }
00497     else
00498     {
00499         CachedBufLength = 0;
00500         ERROR3("Couldn't allocate space for cached subindex file");
00501         return FALSE;
00502     }
00503     return TRUE;
00504 /* FIX */
00505 }
00506 
00507 /***********************************************************************************************
00508 
00509 >   INT32 Library::Init(SuperGallery *ParentGal, PathName *Path, String_64 *SLTitle,
00510                     StringBase *SubI, SGLibType SLType, BOOL Updated = FALSE,
00511                     BOOL AllowedToCreateVirtualised = FALSE)
00512 
00513     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
00514     Created:    18/2/95
00515 
00516     Inputs:     ParentGal   - The parent gallery into which the group should be added.
00517                 Path        - The pathname of the library directory - C:\testlib\animals
00518                 SLTitle     - The title text for this sublibrary
00519                 SubI        - The SubIndex filename - XaraClip.txt
00520                 SLType      - The expected type of the sublibrary
00521                 Updated     - True if index has just been updated
00522                 AllowedToCreateVirtualised - if set to FALSE we won't create a virtualised-out group
00523 
00524     Returns:    0 if an error occurred, -1 if the group was created in a virtualised out stage
00525                 (in which case we'll need to be initialised again to create the items), else a
00526                 count of the number of items in this library
00527                 
00528 
00529     Purpose:    Given a specified sublibrary index, scan it and create a supergallery
00530                 display group for it, containing display items for all of the items in
00531                 the index.
00532 
00533                 If the group already exists in the gallery, it will be replaced (recreated).
00534 
00535     Notes:      If you want the Quiet button code to work you need to call
00536                     LibraryGallery->SetQuietStatus(FALSE);
00537                 before calling this. Note that a large stream of new additions should call this
00538                 just once for the first item. If you don't do this you won't get retry capability
00539                 if the user's CD isn't in the drive...
00540 
00541                 For the sake of progress bars and delayed hourglass popping up, we now call
00542                 ProgressBar->Update(), if the static Library::ProgressBar is non-null... 
00543 
00544 ***********************************************************************************************/
00545                 
00546 INT32 Library::Init(SuperGallery *ParentGal, PathName *Path, String_64 *SLTitle,
00547                     StringBase *SubI, SGLibType SLType, BOOL Updated, BOOL AllowedToCreateVirtualised)
00548 {
00549     if(ParentGal == NULL || Path == NULL || SLTitle == NULL || SubI == NULL)
00550     {
00551         ERROR3("Library::Library - NULL parameters are illegal");
00552         return 0;
00553     }
00554 
00555 //  String_256 P(Path->GetPath());
00556 //  ERROR3_PF(("LibraryInitPath = %s", (TCHAR *)P));
00557 //  ERROR3_PF(("LibraryInit SubI = %s", (TCHAR *)*SubI));
00558     if(ProgressBar != NULL) ProgressBar->Update();
00559 
00560     // Set up some of the member variables for this library object
00561     if(!SetUpMembers(ParentGal, Path, SLTitle, SubI, SLType))
00562         return 0;
00563 
00564     // Should we be creating items, etc at this point ?
00565     if(SGLibGroup::LibraryVirtualisingEnabled && ParentGroup == NULL && AllowedToCreateVirtualised)
00566     {
00567         ParentGroup = (SGLibGroup *)ParentGallery->AddLibraryGroup(this, -1);
00568         ParentGroup->SetVirtualisedState(TRUE);
00569         return -1;
00570     }
00571 
00572     // Sort the Quick Index members out. This doesn't need doing for virtualised out groups
00573     QuickIndexEnabled = SetupQuickIndexMembers(Path, TRUE);
00574 
00575     CCLexFile *SubIndex = NULL;
00576     BOOL CachedSubIndex = FALSE;
00577     BOOL OpenedOK = FALSE;
00578     BOOL Retry = FALSE;
00579 
00580     // 'Quiet' button handling when no indexes found...
00581     BOOL Quiet = FALSE;
00582     LibraryGallery *LG = NULL;
00583     if(ParentGal->IsKindOf(CC_RUNTIME_CLASS(LibraryGallery)))
00584         LG = (LibraryGallery *)ParentGal;
00585     else
00586     {
00587         ERROR3("Library::Init called with a non-library gallery gallery");
00588         return 0;
00589     }
00590 
00591     // Extra bit of code added to let the user 'retry' for their CD if we can't find it.
00592     do
00593     {
00594         Retry = FALSE;
00595 
00596         // Try to cache the index file for quicker access later on
00597         if(CacheIndexFile && !CachedSubIndex)
00598             CachedSubIndex = CacheSubIndex(IndexFile);
00599         
00600         TRY
00601         {
00602             // Use a disk file for this bit
00603             SubIndex = new CCDiskFile(1024, FALSE, TRUE);
00604             if(SubIndex != NULL)
00605             {
00606                 if(QuickIndexEnabled)
00607                     OpenedOK = ((CCDiskFile *)SubIndex)->open(*QuickIndexFile, ios::in);
00608                 else
00609                     OpenedOK = ((CCDiskFile *)SubIndex)->open(*IndexFile, ios::in);
00610             }
00611             else
00612             {
00613                 ERROR3("Library::Init SubIndex not created properly");
00614                 return(0);
00615             }
00616         }
00617 
00618         if(ProgressBar != NULL) ProgressBar->Update();
00619 
00620         CATCH(CFileException, e)
00621         {
00622             // Looks like the index file doesn't exist - or we can't get to it anyhow...
00623             // This only happens on first opening the gallery at the moment. Since this
00624             // is a pretty good candidate for not having the CD present, the below code was
00625             // added. Of course we don't know it's the CD that's not present, they could
00626             // have vaped their TEMP directory, or done something else obscenely stupid (well,
00627             // sensible really)... Who knows... Anything can and does happen...
00628             if(SubIndex != NULL)
00629             {
00630                 INT32 LastButtonPressed = 1;
00631 
00632                 Quiet = LG->GetQuietStatus();
00633             
00634                 if(!Quiet)
00635                 {
00636                     String_256 WarnMsg;
00637 
00638                     if(!SGLibGroup::LibraryVirtualisingEnabled)
00639                     {
00640                         // Old system where groups and items are all created when the gallery is opened
00641                         WarnMsg.MakeMsg(_R(IDS_LIBRARY_CANT_FIND_INDEX), (const TCHAR *)Path->GetFileName(FALSE));
00642                         Error::SetError(0, WarnMsg, 0);
00643                         LastButtonPressed = InformWarning(0, _R(IDS_CONTINUE), _R(IDS_RETRY), _R(IDS_QUIET), NULL, 2, 1);
00644                         Retry  = (LastButtonPressed == 2);
00645                         Quiet  = (LastButtonPressed == 3);
00646                     }
00647                     else
00648                     {
00649                         // New system when this will only be called when de-virtualising all groups
00650                         WarnMsg.MakeMsg(_R(IDS_LIBRARY_CANT_FIND_INDEX_SKIP), (const TCHAR *)Path->GetFileName(FALSE));
00651                         Error::SetError(0, WarnMsg, 0);
00652                         LastButtonPressed = InformWarning(0, _R(IDS_SKIP), _R(IDS_RETRY), _R(IDS_QUIET), NULL, 2, 1);
00653                         Retry  = (LastButtonPressed == 2);
00654                         Quiet  = (LastButtonPressed == 3);
00655                     }
00656 
00657                     LG->SetQuietStatus(Quiet);
00658                 }
00659                 if (SubIndex->isOpen())
00660                     SubIndex->close();
00661                 delete SubIndex;
00662                 SubIndex = NULL;
00663             }
00664             Error::ClearError();
00665             if(!Retry)
00666                 return 0;
00667         }
00668         END_CATCH
00669 
00670         // This can't happen, but just in case !
00671         if(Quiet && Retry)
00672             Retry = FALSE;
00673     } while(Retry);
00674 
00675     if(ProgressBar != NULL) ProgressBar->Update();
00676 
00677     // Subindex seeking required
00678     if (!SubIndex->InitLexer(TRUE))
00679     {
00680         ERROR3("Library::Init InitLexer failed");
00681         if(SubIndex->isOpen())
00682             SubIndex->close();
00683         delete SubIndex;
00684         return FALSE;
00685     }
00686 
00687     SubIndex->SetWhitespace("");            // Setting this to blank lets us read non-"'d strings
00688     SubIndex->SetDelimiters(",");       // ,s delimit our fields
00689     SubIndex->SetCommentMarker('#');        // #'d lines are commented out
00690     SubIndex->SetStringDelimiters("");  // No string delimiters
00691 
00692     if(OpenedOK)
00693     {
00694         // Read the header
00695         INT32 NumItems = ReadHeaderInfo(SubIndex);      
00696 
00697         if(ProgressBar != NULL) ProgressBar->Update();
00698 
00699         if (NumItems > 0)
00700         {
00701             // Remove any pre-existing groups with the same index file
00702             ((LibraryGallery *)ParentGal)->RemoveSimilarLibraryGroups(SubLibPath, (String_256 *)SubI, TRUE, FALSE, this);
00703 
00704             // Create/find the required group in the parent gallery
00705             ParentGroup = (SGLibGroup *)ParentGallery->AddLibraryGroup(this, NumItems);
00706             ParentGroup->SetVirtualisedState(FALSE);
00707 
00708             if (ParentGroup == NULL)        // Couldn't get a display group! Argh!
00709             {
00710                 // reclaim lexer-buffer memory
00711                 SubIndex->DeinitLexer();    
00712 
00713                 // and close the file...
00714                 if(SubIndex->isOpen())
00715                     SubIndex->close();
00716 
00717                 // and reclaim the diskfile memory...
00718                 delete SubIndex;
00719                 return FALSE;
00720             }
00721 
00722             if(ProgressBar != NULL) ProgressBar->Update();
00723 
00724             // And construct all the items...
00725             if(CachedSubIndexBuf == NULL)
00726                 ScanRestOfFile(SubIndex);
00727             else
00728                 ScanRestOfFile(CachedSubIndexBuf, FirstLineOffset, CachedBufLength);
00729 
00730             if(ProgressBar != NULL) ProgressBar->Update();
00731 
00732 #ifdef _DEBUG
00733             if(NumItems != ItemCount)
00734             {
00735                 String_256 Warn;
00736                 PathName Loc(IndexFile->GetLocation(FALSE));
00737                 PathName Loc2(Loc.GetLocation(FALSE));
00738                 String_256 FNameWarn(Loc2.GetFileName());
00739 
00740                 BOOL DoWarning = TRUE;
00741                 
00742 #ifdef DONT_REPORT_KNOWN_CLIPART_PROBLEMS
00743                 // Don't warn if doing Studio and only 1 off - The Infamous Rolex Bodge !
00744                 if((ItemCount == (NumItems - 1)) && FNameWarn == (String_256)"Studio")
00745                     DoWarning = FALSE;
00746 
00747                 // Corel Xara CD (rel 1) bodges
00748                 if(ItemCount == 50 && NumItems == 48 && FNameWarn == (String_256)"Xara")
00749                     DoWarning = FALSE;
00750                 if(ItemCount == 329 && NumItems == 330 && FNameWarn == (String_256)"ANIMALS")
00751                     DoWarning = FALSE;
00752                 if(ItemCount == 470 && NumItems == 474 && FNameWarn == (String_256)"PEOPLE")
00753                     DoWarning = FALSE;
00754 #endif
00755                 if(DoWarning)
00756                 {
00757                     ERROR3_PF(("Dodgy checksum for '%s' index file. Header value should read %d.", (TCHAR *)FNameWarn, ItemCount));
00758                 }
00759             }
00760 #endif
00761         }
00762     }
00763     else
00764     {
00765         // Failed to read the sub index file...
00766         ERROR3("Library::Library couldn't open sub index file");
00767     }
00768 
00769     if(ProgressBar != NULL) ProgressBar->Update();
00770 
00771     // reclaim lexer-buffer memory
00772     SubIndex->DeinitLexer();    
00773 
00774     // and close the file...
00775     if(SubIndex->isOpen())
00776         SubIndex->close();
00777 
00778     // and reclaim the diskfile memory...
00779     delete SubIndex;
00780 
00781     // Thumbnail cache class
00782     Thumbnails = NULL;
00783 
00784 //  String_256 IndexPath(IndexFile->GetPath());
00785 //  ERROR3_PF(("IndexPath = %s", (TCHAR *)IndexPath));
00786         
00787     // Path for thumbnails - this is INCORRECT !!!
00788 //  String_256 ThuF(Path->GetPath(TRUE));
00789     
00790 //  PathName IndexP(IndexFile);
00791     String_256 ThuF(IndexFile->GetLocation(FALSE));
00792     LibraryFile::TidyUpSubPath(&ThuF);
00793     SGLibOil::AppendSlashIfNotPresent(&ThuF);
00794 
00795     ThuF += String_16(_R(IDS_LIBRARIES_XARAINFO_DIRNAME));
00796     PathName ThumbPath(ThuF);
00797     if(!ThumbPath.IsValid())
00798     {
00799         ERROR3("Library::Init ThumbPath is invalid");
00800         return 0;
00801     }
00802 
00803 //  ERROR3_PF(("Path = %s, SubLibPath = %s, IndexFile = %s", Path->GetPath(), SubLibPath->GetPath(), IndexFile->GetPath()));
00804 
00805     // Allocate memory for new thumbnail cache and point to it
00806     Thumbnails = new SGThumbs(&ThumbPath, SLType, SGThumb_Small);
00807 
00808     return(ItemCount);
00809 }
00810 
00811 
00812 /***********************************************************************************************
00813 
00814 >   INT32 Library::CreateItems(void)
00815 
00816     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
00817     Created:    5/1/96
00818 
00819     Returns:    0 if an error occurred, else a count of the items added
00820 
00821     Purpose:    Mainly for use by the de-virtualise function... Init MUST have been called
00822                 previously for this to work !
00823 
00824     Notes:      If you want the Quiet button code to work you need to call
00825                     LibraryGallery->SetQuietStatus(FALSE);
00826                 before calling this. Note that a large stream of new additions should call this
00827                 just once for the first item. If you don't do this you won't get retry capability
00828                 if the user's CD isn't in the drive...
00829 
00830 ***********************************************************************************************/
00831 
00832 INT32 Library::CreateItems(void)
00833 {
00834     // Don't do this it the group isn't v'd out
00835     if(ParentGroup != NULL && ParentGroup->IsVirtualised())
00836     {
00837         String_256 SubI;
00838         SubI = IndexFile->GetFileName();
00839         PathName pathOldIndex(IndexFile->GetPath());
00840         pathOldIndex.SetType(_T("old"));
00841         INT32 hOldIndex = _open(pathOldIndex.GetPath(), _O_RDONLY | _O_BINARY, _S_IREAD);
00842         if (hOldIndex != -1)
00843         {
00844             m_lOldIndex = _filelength(hOldIndex);
00845             _close(hOldIndex);
00846         }
00847         INT32 ItemCount = Init(ParentGallery, SubLibPath, Title, &SubI, Type);
00848         return ItemCount;
00849     }
00850 
00851     return 0;
00852 }
00853 
00854 /***********************************************************************************************
00855 
00856 >   BOOL Library::SetUpMembers(SuperGallery *ParentGal, PathName *Path, String_64 *SLTitle,
00857                     StringBase *SubI, SGLibType SLType)
00858 
00859     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
00860     Created:    9/5/95
00861 
00862     Inputs:     ParentGal   - The parent gallery into which the group should be added.
00863                 Path        - The pathname of the library directory - C:\testlib\animals
00864                 SLTitle     - The title text for this sublibrary
00865                 SubI        - The SubIndex filename - XaraClip.txt
00866                 SLType      - The expected type of the sublibrary
00867 
00868     Returns:    TRUE if things went OK...
00869 
00870     Purpose:    Fill in the member variables with the required paths, and things...
00871                 Should only be called from ::Init
00872 
00873 ***********************************************************************************************/
00874                 
00875 BOOL Library::SetUpMembers(SuperGallery *ParentGal, PathName *Path, String_64 *SLTitle,
00876                     StringBase *SubI, SGLibType SLType)
00877 {
00878     ERROR3IF(ParentGal == NULL || Path == NULL || SLTitle == NULL || SubI == NULL, "Library::SetUpMembers - NULL parameters are illegal");
00879 
00880 //  String_256 P(Path->GetPath());
00881 //  ERROR3_PF(("Path = %s", (TCHAR *)P));
00882 
00883     ParentGallery = ParentGal;
00884 
00885     // Number of (active) items in sub-lib
00886     ItemCount = 0;
00887 
00888     // Field string found at the head of the sub-index 
00889     FieldString = "";
00890 
00891     // Type of Sub-Library
00892     Type = SLType;
00893 
00894     // Title text as given in main index file (used for the group name)
00895     // "A group containing pictures of animals" for example
00896     if(Title == NULL)
00897     {
00898         Title = new String_64(*SLTitle);
00899         if (Title == NULL)
00900             return FALSE;
00901     }
00902 
00903     // Add index path to index filename
00904     String_256 General(Path->GetPath(TRUE));
00905     General += String_16(_R(IDS_LIBRARIES_XARAINFO_DIRNAME));
00906     General += TEXT("\\");
00907     General += *SubI;
00908 
00909     // IndexFile now contains the full path to the index filename
00910     // "C:\testlib\animals\xarainfo\xaraclip.txt" for example
00911     if(IndexFile == NULL)
00912     {
00913         IndexFile = new PathName(General);
00914         if (IndexFile == NULL)
00915             return FALSE;
00916     }
00917 
00918     if(!IndexFile->IsValid())
00919     {
00920         ERROR3("Library::SetUpMembers indexfile is invalid");
00921         return FALSE;
00922     }
00923 
00924     // Full path of library directory -> C:\testlib\animals
00925     if(SubLibPath == NULL)
00926     {
00927         SubLibPath = new PathName(*Path);
00928         if(SubLibPath == NULL)
00929             return FALSE;
00930     }
00931 
00932     if(!SubLibPath->IsValid())
00933     {
00934         ERROR3("Library::SetUpMembers SubLibPath is invalid");
00935         return FALSE;
00936     }
00937 
00938     // For checking the Offsets...
00939     FirstLineOffset = 0;
00940     LastLineOffset = 0;
00941 
00942     return TRUE;
00943 }
00944 
00945 
00946 
00947 /***********************************************************************************************
00948 
00949 >   BOOL Library::SetupQuickIndexMembers(PathName *Path, BOOL CheckTheyExist)
00950 
00951     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
00952     Created:    19/1/96
00953 
00954     Inputs:     Path            - Path for normal index
00955                 CheckTheyExist  - Checks with the filesystem for the file's existance
00956 
00957     Returns:    TRUE if paths set up and files found
00958                 Note: We will ALWAYS return FALSE if CheckTheyExist is FALSE
00959 
00960     Purpose:    Given a normal index file path, set up members to a 'quick index file'. The
00961                 idea is for groups of library directories to have copies of all their indexes
00962                 in some common folder so that loading them in doesn't thrash the CD drive too
00963                 much.
00964 
00965 ***********************************************************************************************/
00966 
00967 BOOL Library::SetupQuickIndexMembers(PathName *Path, BOOL CheckTheyExist)
00968 {
00969     QuickIndexEnabled = FALSE;
00970 
00971     // Quick indexes are just a slight bodge for speeding up the gallery opening times with
00972     // CD's... Basically instead of hunting all over the place for indexes, we stick all the
00973     // indexes down the XaraInfo directory (with the main index.txt), and open these instead
00974     // of the normal ones... If these don't exist, then obviously we can't use them...
00975     if(Library::QuickIndex)
00976     {
00977         // Work out Quick path
00978         PathName QuickPath(Path->GetPath());
00979         String_256 QuickPathLoc(QuickPath.GetLocation(FALSE));
00980         QuickPathLoc += TEXT("\\") + String_16(_R(IDS_LIBRARIES_XARAINFO_DIRNAME)) + TEXT("\\");
00981         QuickPathLoc += Path->GetFileName(FALSE);
00982         QuickPathLoc += TEXT(".txt");
00983         QuickPath.SetPathName(QuickPathLoc);
00984         
00985         if(CheckTheyExist && SGLibOil::FileExists(&QuickPath))
00986         {
00987             if(QuickIndexFile == NULL)
00988             {
00989                 QuickIndexFile = new PathName(QuickPathLoc);
00990                         
00991                 if(QuickIndexFile != NULL)
00992                     QuickIndexEnabled = TRUE;
00993             }
00994         }
00995 
00996         Error::ClearError();
00997     }
00998 
00999     return QuickIndexEnabled;
01000 }
01001 
01002 
01003 /***********************************************************************************************
01004 
01005 >   INT32 Library::ReadHeaderInfo(CCLexFile *pSubIndex)
01006 
01007     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
01008     Created:    18/2/95
01009 
01010     Inputs:     pSubIndex - the index file to read the header from
01011 
01012     Returns:    The number of items that should be found in this index file
01013                 Returns 0 if there are no items, or if there was an error
01014 
01015     Purpose:    Read the no of items, field text and line pSubIndex up with the first
01016                 proper index line
01017 
01018     Notes:      On Exit, the file pointer in pSubIndex will point at the first line
01019                 of the index body
01020 
01021 ***********************************************************************************************/
01022 
01023 INT32 Library::ReadHeaderInfo(CCLexFile *pSubIndex)
01024 {   
01025     ERROR3IF(pSubIndex == NULL, "Library::ReadHeaderInfo - NULL params are illegal");
01026 
01027     BOOL ok = TRUE;
01028     BOOL retok = TRUE;
01029     INT32 Items = 0;
01030 
01031     LexTokenType TT = TOKEN_EOL;
01032     UINT32 NonGarbageLineNumber = 0;        
01033     BOOL HitStart = FALSE;
01034     while(ok && retok && !HitStart/*NonGarbageLineNumber < 5*/)
01035     {
01036         if (!pSubIndex->GetToken()) break;
01037 
01038         // Keep reading tokens until we hit a normal one... (skips line ends and
01039         // comments for us
01040         TT = pSubIndex->GetTokenType();     
01041 
01042         while (TT != TOKEN_NORMAL && ok)
01043         {
01044             // Bodge so that lines starting #DESCRIPTION: case us to jump out...
01045             if(TT == TOKEN_COMMENT)
01046             {
01047                 // Optional header extras - Must have their name followed by a ':' then the item
01048                 if(camStrchr((TCHAR *) pSubIndex->GetTokenBuf(), _T(':')))
01049                 {
01050                     // We assume these lines aren't going to be bigger than 256 chars
01051                     String_256 TokenBufU(pSubIndex->GetTokenBuf());
01052                     TokenBufU.toUpper();
01053     
01054                     INT32 Offset = TokenBufU.Sub(String_16(_R(IDS_LIBRARIES_INDEX_DESCRITION)));
01055 
01056                     if(Offset > -1 && Offset < 2)
01057                     {
01058                         // Need to set 'title'
01059                         if(Title)
01060                         {
01061                             String_256 TokenBuf(pSubIndex->GetTokenBuf());
01062                             TokenBuf.Right(Title, TokenBuf.Length() - (12 + Offset));               
01063                             LibraryFile::KillLeadingSpaces(Title);
01064                         }
01065                     }
01066                 }
01067             }
01068 
01069             ok = pSubIndex->GetToken();
01070             if(!ok) break;
01071             TT = pSubIndex->GetTokenType();     
01072             ok = (TT != TOKEN_EOF);
01073             if(!ok) break;
01074         }
01075         if(!ok) break;
01076 
01077         NonGarbageLineNumber++;     
01078         
01079         switch(NonGarbageLineNumber)
01080         {
01081             case 0: // Something nasty's happened
01082                 ERROR3("Library ReadHeader - Something nasty has happened");
01083                 break;
01084 
01085             case 1: // Number of files described by index
01086                 Items = _ttoi(pSubIndex->GetTokenBuf());
01087                 break;
01088 
01089             case 2: // Synonym filename
01090                 {
01091                     String_256 KPS; // %s\\XaraInfo\\%s
01092                     KPS = SubLibPath->GetPath(TRUE);
01093                     KPS += String_16(_R(IDS_LIBRARIES_XARAINFO_DIRNAME));
01094                     KPS += TEXT("\\") + String_64(pSubIndex->GetTokenBuf());
01095                     SynonymFile = new PathName(KPS);
01096                     
01097                     // We can carry on from these two situations...
01098                     if(SynonymFile == NULL)
01099                     {
01100                         ERROR3("Library::ReadHeaderInfo not enough memory to create a SynonymFile path");
01101                         break;
01102                     }
01103 
01104                     if(!SynonymFile->IsValid())
01105                     {
01106                         ERROR3("Library::ReadHeaderInfo SynonymFile is invalid");
01107                         break;
01108                     }
01109                 }
01110                 break;
01111 
01112             case 3: // Thumbnail sizes
01113                 {
01114                     for(INT32 i = 0; i < 3; i++)
01115                     {
01116                         PreviewX[i] = _ttoi((TCHAR *)pSubIndex->GetTokenBuf());
01117                         
01118                         ok = pSubIndex->GetToken(); // Skip ','
01119                         if(!ok) break;
01120                         TT = pSubIndex->GetTokenType();
01121                         if(TT == TOKEN_EOL) break;
01122 
01123                         ok = pSubIndex->GetToken();
01124                         if(!ok) break;
01125                         TT = pSubIndex->GetTokenType();
01126                         if(TT == TOKEN_EOL) break;
01127 
01128                         PreviewY[i] = _ttoi((TCHAR *)pSubIndex->GetTokenBuf());
01129 
01130                         ok = pSubIndex->GetToken(); // Skip ','
01131                         if(!ok) break;
01132                         TT = pSubIndex->GetTokenType();
01133                         if(TT == TOKEN_EOL) break;
01134 
01135                         ok = pSubIndex->GetToken();
01136                         if(!ok) break;
01137                         TT = pSubIndex->GetTokenType();
01138                         if(TT == TOKEN_EOL) break;
01139 
01140                     }
01141                 }
01142                 break;
01143                     
01144             case 4: // Field titles
01145                 FieldString = pSubIndex->GetTokenBuf();
01146 
01147                 // loop through rest of line adding the info to the buffer
01148                 ok = pSubIndex->GetLineToken();
01149                 if(!ok) break;
01150 
01151                 TT = pSubIndex->GetTokenType();
01152                 if(TT == TOKEN_LINE)
01153                     FieldString += pSubIndex->GetTokenBuf();
01154                 else
01155                 {
01156                     retok = FALSE;
01157                     ERROR3("Library ReadHeader: Field line appears to be shorter than expected");
01158                 }
01159 
01160                 break;
01161 
01162 
01163 
01164             default:
01165 
01166                 // Optional header extras - Must have their name followed by a ':' then the item
01167                 if(camStrchr((TCHAR *) pSubIndex->GetTokenBuf(), _T(':')))
01168                 {
01169                     // We assume these lines aren't going to be bigger than 256 chars
01170                     String_256 TokenBufU(pSubIndex->GetTokenBuf());
01171                     TokenBufU.toUpper();
01172     
01173                     // Description for group
01174                     INT32 Offset = TokenBufU.Sub(String_16(_R(IDS_LIBRARIES_INDEX_DESCRITION)));
01175                     if(Offset > -1 && Offset < 2)
01176                     {
01177                         // Need to set 'title'
01178                         if(Title)
01179                         {
01180                             String_256 TokenBuf(pSubIndex->GetTokenBuf());
01181                             TokenBuf.Right(Title, TokenBuf.Length() - (12 + Offset));               
01182                             LibraryFile::KillLeadingSpaces(Title);
01183                         }
01184                     }
01185 
01186                     // Remote files location
01187                     Offset = TokenBufU.Sub(String_16(_R(IDS_LIBRARIES_INDEX_FILES)));
01188                     if(Offset == 0)
01189                     {
01190                         TRACEUSER( "Richard", _T("Remote files in use\n"));
01191 
01192                         // Need to set 'SubLibPath'
01193                         if(!SubLibPath)
01194                             SubLibPath = new PathName;
01195                             
01196                         if(SubLibPath != NULL)
01197                         {
01198                             PathName OldPath(*SubLibPath);
01199                             String_256 ThePath;
01200                             String_256 TokenBuf(pSubIndex->GetTokenBuf());
01201                             TokenBuf.Right(&ThePath, TokenBuf.Length() - (6 + Offset));
01202                             LibraryFile::KillLeadingSpaces(&ThePath);
01203 
01204                             SubLibPath->SetPathName(ThePath);
01205                             if(!SubLibPath->IsValid())
01206                             {
01207                                 *SubLibPath = OldPath;
01208                             }
01209                         }
01210                     }
01211                 }
01212 
01213                 // No further header entries, anything following the start line is a proper
01214                 // line of library text...
01215                 if(!camStrcmp((TCHAR *) pSubIndex->GetTokenBuf(), (TCHAR *)(String_16(_R(IDS_LIBRARIES_INDEX_START)))))
01216                 {
01217                     // Read until end of line
01218                     do {
01219                         ok = pSubIndex->GetToken();
01220                         if(!ok) break;
01221                         TT = pSubIndex->GetTokenType();     
01222                     } while (TT != TOKEN_EOF && TT != TOKEN_EOL && ok);
01223 
01224                     // We have reached the end of the header - exit immediately leaving
01225                     // the file pointer at the start of the file "body"
01226                     HitStart = TRUE;
01227                 }
01228                 break;
01229         }
01230 
01231         if(!ok) break;
01232 
01233         // Search for EOF or EOL after reading a line
01234         TT = pSubIndex->GetTokenType();     
01235 
01236         while (TT != TOKEN_EOF && TT != TOKEN_EOL && TT != TOKEN_LINE && TT != TOKEN_COMMENT && ok)
01237         {
01238             ok = pSubIndex->GetToken();
01239             if(!ok) break;
01240             TT = pSubIndex->GetTokenType();     
01241             ok = (TT != TOKEN_EOF);
01242             if(!ok) break;
01243         }
01244     }
01245 
01246     // Current file position is deemed the start of the first line of data
01247     FirstLineOffset = (LibraryIndex) pSubIndex->tellIn();
01248 
01249     // Hit EOF somehow... This is bad
01250     if(TT == TOKEN_EOF)
01251         return(0);
01252 
01253     if (retok)
01254         return(Items);
01255 
01256     return(0);
01257 }
01258 
01259 
01260 
01261 /***********************************************************************************************
01262 
01263 >   BOOL Library::ScanRestOfFile(TCHAR *CachedIndex, INT32 Start, INT32 Finish, BOOL AddItems = TRUE)
01264 
01265     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
01266     Created:    22/4/95
01267 
01268     Inputs:     CachedIndex - points to the index file in memory
01269                 Start       - Offset to start of first index line
01270                 Finish      - Offset to end of file in memory
01271                 AddItems    - Set to FALSE if you don't want the items to be added to the gallery
01272 
01273     Returns:    TRUE if it succeeded, FALSE if not. 
01274                 If no items were found, it returns FALSE
01275 
01276     Purpose:    Scan the rest of the file (following the START), creating items
01277                 for each entry...
01278                 Also change ','s to 0's, so we can retrieve field strings more quickly later
01279                 on.
01280 
01281                 AddItems added so that recaching already created tree indexes wouldn't add new
01282                 items every time the gallery opens !
01283 
01284 ***********************************************************************************************/
01285 
01286 BOOL Library::ScanRestOfFile(TCHAR *CachedIndex, INT32 Start, INT32 Finish, BOOL AddItems)
01287 {
01288     if(CachedIndex == NULL)
01289     {
01290         ERROR3("Library::ScanRestOfFile - no cached index");
01291         return FALSE;
01292     }
01293 
01294     if(Start >= Finish)
01295     {
01296         ERROR3("Library::ScanRestOfFile - nothing to scan");
01297         return FALSE;
01298     }
01299 
01300     INT32 Offset = Start;
01301     INT32 NewItemOffset = 0;
01302     
01303     INT32 LineCount = 0;
01304     ItemCount = 0;
01305 
01306     TCHAR Ch = ' ';
01307     TCHAR NCh = ' ';
01308 
01309     // chars to look for
01310     const TCHAR CR = '\n';
01311     const TCHAR LF = '\r';
01312     const TCHAR REM = '#';
01313     const TCHAR SEP = ',';
01314     const TCHAR SPC = ' ';
01315 
01316 #ifdef _DEBUG
01317     // Count commas in FieldString
01318     INT32 CommaCount = 0;
01319     INT32 FieldCommaCount = 0;
01320     TCHAR *Buf = (TCHAR *)FieldString;
01321     INT32 Len = FieldString.Length();
01322     for(INT32 i = 0; i < Len; i++)
01323         if(Buf[i] == SEP)
01324             FieldCommaCount ++;
01325 #endif
01326 
01327     BOOL ok = TRUE;
01328 
01329     do {
01330         // Offset should now point to the start of a line
01331 
01332 #ifdef _DEBUG
01333         CommaCount=0;
01334 #endif
01335 
01336         Ch = CachedIndex[Offset];
01337         if((Ch == REM) || (Ch == CR) || (Ch == LF) || (Ch == SPC) || (Ch == SEP))
01338             NewItemOffset = 0;
01339         else
01340             NewItemOffset = Offset;
01341 
01342         // Scan until eol
01343         do {
01344             Ch = CachedIndex[Offset];
01345 
01346 #ifdef _DEBUG
01347             // Another separator to count
01348             if(Ch == SEP)
01349                 CommaCount ++;
01350 #endif
01351             
01352             // Zap separators into zeros
01353             if(Ch == SEP || Ch == LF || Ch == CR)
01354                 CachedIndex[Offset] = 0;
01355             
01356             Offset ++;          
01357 
01358         } while ( (Offset < Finish) && (Ch != CR) && (Ch != LF));
01359 
01360         /* FIX */
01361 #ifdef _DEBUG
01362         if(CommaCount != FieldCommaCount && CommaCount != 0)
01363         {
01364             String_256 WarnMsg;
01365             String_32 Line;
01366             
01367             // Bodge which might go wrong... Solves overflow problem...
01368             for(INT32 i=0; i<16; i++)
01369                 ((TCHAR *)Line)[i] = *(CachedIndex + NewItemOffset + (i * sizeof(TCHAR)));
01370             ((TCHAR *)Line)[i] = 0;
01371 
01372             BOOL DoCommaWarning = TRUE;
01373 
01374 #ifdef DONT_REPORT_KNOWN_CLIPART_PROBLEMS
01375             // Here are a couple of 'fixes' to stop the error3's in debug builds...
01376             if(NewItemOffset == 4205 && Start == 154 && Finish == 4271 && Offset == 4242 && CommaCount == 4 && FieldCommaCount == 5)
01377                 DoCommaWarning = FALSE; // Apple.xar fix
01378             if(NewItemOffset == 4243 && Start == 154 && Finish == 4271 && Offset == 4270 && CommaCount == 4 && FieldCommaCount == 5)
01379                 DoCommaWarning = FALSE; // Fish.xar fix
01380 #endif
01381             // Another separator to count
01382             if(DoCommaWarning)
01383             {
01384                 if(CommaCount > FieldCommaCount)    
01385                     wsprintf(WarnMsg, "Too many commas in line '%s' of '%s'", (TCHAR *)Line, (const TCHAR *)SubLibPath->GetPath());
01386                 else
01387                     wsprintf(WarnMsg, "Not enough commas in line '%s' of '%s'", (TCHAR *)Line, (const TCHAR *)SubLibPath->GetPath());
01388                 ERROR3(WarnMsg);
01389             }
01390         }
01391 #endif
01392         /* FIX */
01393 
01394         // Since we need access to the fields whilst adding the item (for sorting) we
01395         // add the item after fixing up the index line
01396         if(NewItemOffset != 0)
01397         {
01398             // Create a supergallery Display Item representing this library item, and add it
01399             // to our parent group
01400             if(AddItems)
01401             {
01402                 BOOL bIsNew = (m_lOldIndex != 0 && NewItemOffset >= m_lOldIndex) || (m_nModified == FOLDER_NEW);
01403                 ok = (ParentGallery->AddLibraryItem(ParentGroup, this, NewItemOffset, bIsNew) != NULL);
01404             }
01405 
01406             if(ok)
01407             {
01408                 ItemCount ++;
01409                 LineCount ++;
01410             }
01411         }
01412 
01413         NCh = CachedIndex[Offset];
01414 
01415         // Skip possibly double eol chars
01416         if ( ((Ch==LF) || (Ch==CR)) && ((NCh==LF) || (NCh==CR)) && (Offset < Finish) )
01417             Offset ++;  
01418 
01419     } while(Offset < Finish);
01420 
01421     return (ItemCount > 0);
01422 }
01423 
01424 
01425 /***********************************************************************************************
01426 
01427 >   BOOL Library::ScanRestOfFile(CCLexFile *pSubIndex)
01428 
01429     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
01430     Created:    18/2/95
01431 
01432     Inputs:     pSubIndex - points to a CCLexFile to be scanned. The file pointer on
01433                 entry is expected to be at the start of the index-file body.
01434 
01435     Returns:    TRUE if it succeeded, FALSE if not. 
01436                 If no items were found, it returns FALSE
01437 
01438     Purpose:    Scan the rest of the file (following the START), creating items
01439                 for each entry...
01440 
01441 ***********************************************************************************************/
01442 
01443 BOOL Library::ScanRestOfFile(CCLexFile *pSubIndex)
01444 {
01445     ERROR3IF(pSubIndex == NULL, "Library::ScanRestOfFile - NULL params are illegal");
01446 
01447     BOOL ok = TRUE;
01448     BOOL retok = TRUE;
01449 
01450     LexTokenType TT;
01451     UINT32 LineCount = 0;
01452     ItemCount = 0;
01453     LibraryIndex LineOffset = 0;
01454 
01455     // Current file position is deemed the start of the first line of data
01456     FirstLineOffset = (LibraryIndex) pSubIndex->tellIn();
01457 
01458     while(ok && retok)
01459     {
01460         // Remember line offset for the *start* of the line
01461         LineOffset = (LibraryIndex) pSubIndex->tellIn();
01462 
01463         if(!pSubIndex->GetToken()) break;
01464 
01465         // Keep reading tokens until we hit a normal one... (skips line ends and
01466         // comments for us - we could do this by skipping lines at a time, but there
01467         // are problems with comments...
01468         TT = pSubIndex->GetTokenType();     
01469         while (TT != TOKEN_NORMAL && ok)
01470         {
01471             // Remember line offset for the *start* of the line
01472             LineOffset = (LibraryIndex) pSubIndex->tellIn();
01473 
01474             ok = pSubIndex->GetToken();
01475             if(!ok) break;
01476             TT = pSubIndex->GetTokenType();     
01477             ok = (TT != TOKEN_EOF);
01478             if(!ok) break;
01479         }
01480         if(!ok) break;
01481 
01482         // Create a supergallery Display Item representing this library item, and add it
01483         // to our parent group
01484 
01485         ok = (ParentGallery->AddLibraryItem(ParentGroup, this, LineOffset) != NULL);
01486 
01487         if(ok) ItemCount ++;
01488         else break;
01489 
01490         // Search for EOF or EOL after reading a line
01491         TT = pSubIndex->GetTokenType();     
01492 
01493         while (TT != TOKEN_EOF && TT != TOKEN_EOL && TT != TOKEN_LINE && ok)
01494         {
01495             // Remember line offset for the *start* of the line
01496             LineOffset = (LibraryIndex) pSubIndex->tellIn();
01497 
01498             ok = pSubIndex->GetToken();
01499             if(!ok) break;
01500             TT = pSubIndex->GetTokenType();     
01501             ok = (TT != TOKEN_EOF);
01502             if(!ok) break;
01503         }
01504     }
01505 
01506     // Current file position is deemed the start of the first line of data
01507     LastLineOffset = (LibraryIndex) pSubIndex->tellIn();
01508 
01509     return (ItemCount > 0);
01510 }
01511 
01512 
01513 
01514 /***********************************************************************************************
01515 
01516 >   void Library::GetLibraryTitle(StringBase *ReturnedTitle)
01517 
01518     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
01519     Created:    24/2/95
01520 
01521     Outputs:    ReturnedTitle - will be filled in with the title (may NOT be NULL)
01522 
01523     Purpose:    To retrieve the title text for this library (this is the text
01524                 that a linked SGDisplayGroup will display in the gallery list
01525                 as in "Pictures of animals")
01526 
01527 ***********************************************************************************************/
01528 
01529 void Library::GetLibraryTitle(StringBase *ReturnedTitle)
01530 {
01531     ERROR3IF(ReturnedTitle == NULL, "Library::GetLIbraryTitle - NULL Params are illegal");
01532 
01533     if (Title == NULL)
01534         *ReturnedTitle = String_16(_R(IDS_LIBRARIES_UNAMED));
01535     else
01536         *ReturnedTitle = *Title;
01537 }
01538 
01539 
01540 
01541 /***********************************************************************************************
01542 
01543 >   BOOL Library::GetFilename(LibraryIndex Offset, StringBase *File, BOOL FullPath = TRUE)
01544 
01545     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
01546     Created:    18/2/95
01547 
01548     Inputs:     Offset      - the index identifying the item you require
01549                 FullPath    - If TRUE, return the full path of the file, otherwise just the filename
01550 
01551     Outputs:    File        - filled in path/file name
01552 
01553     Returns:    TRUE if it succeeded
01554 
01555     Purpose:    Return the path/filename for the indexed library item
01556 
01557     Notes:      File is now a stringbase for speed reasons. Constructing a full PathName was
01558                 found to be quite slow, and hindered sorting quite a bit. The FullPath param
01559                 is also included for this purpose.
01560 
01561 ***********************************************************************************************/
01562 
01563 BOOL Library::GetFilename(LibraryIndex Offset, StringBase *File, BOOL FullPath)
01564 {
01565     ERROR3IF(File == NULL, "Library::GetFilename - NULL params are illegal");
01566 
01567     if(!FullPath)
01568     {
01569         // Get filename from index file
01570         return (GetSingleField(Offset, 1, File));
01571     }
01572 
01573     String_256 Filename;
01574 
01575     // Get filename from index file
01576     if (!GetSingleField(Offset, 1, &Filename))
01577         return FALSE;
01578 
01579     // Path for normal files
01580     *File = SubLibPath->GetPath(TRUE);
01581     *File += Filename;
01582     
01583     return TRUE;
01584 }
01585 
01586 
01587 /***********************************************************************************************
01588 
01589 >   BOOL Library::GetFilename(LibraryIndex Offset, TCHAR **File)
01590 
01591     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
01592     Created:    3/5/95
01593 
01594     Inputs:     Offset - the index identifying the item you require
01595                 File - A pointer to a path name to be filled in (May NOT be NULL)
01596 
01597     Returns:    TRUE if it succeeded
01598 
01599     Purpose:    Return a pointer to the filename for the indexed library item
01600 
01601     Notes:      If we're using diskfiles this will return FALSE
01602 
01603 
01604 ***********************************************************************************************/
01605 
01606 BOOL Library::GetFilename(LibraryIndex Offset, TCHAR **File)
01607 {
01608     ERROR3IF(File == NULL, "Library::GetFilename - NULL params are illegal");
01609 
01610     // Get filename from index file
01611     return (GetSingleField(Offset, 1, File));
01612 }
01613 
01614 
01615 /***********************************************************************************************
01616 
01617 >   BOOL Library::GetTextname(LibraryIndex Offset, StringBase *Text)
01618 
01619     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
01620     Created:    18/2/95
01621 
01622     Inputs:     Offset - the index identifying the item you require
01623                 Text - A pointer to a string to recieve the text name (May NOT be NULL)
01624 
01625     Purpose:    Return the textual description for the indexed library item
01626 
01627 ***********************************************************************************************/
01628 
01629 BOOL Library::GetTextname(LibraryIndex Offset, StringBase *Text)
01630 {
01631     ERROR3IF(Text == NULL, "Library::GetTextname - NULL params are illegal");
01632     return(GetSingleField(Offset, 2, Text));
01633 }
01634 
01635 /***********************************************************************************************
01636 
01637 >   BOOL Library::GetTextname(LibraryIndex Offset, TCHAR **Text)
01638 
01639     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
01640     Created:    18/2/95
01641 
01642     Inputs:     Offset - the index identifying the item you require
01643     Outputs:    Text - A pointer to a string (May NOT be NULL)
01644 
01645     Purpose:    Return a pointer to the textual description for the indexed library item
01646 
01647 ***********************************************************************************************/
01648 
01649 BOOL Library::GetTextname(LibraryIndex Offset, TCHAR **Text)
01650 {
01651     ERROR3IF(Text == NULL, "Library::GetTextname - NULL params are illegal");
01652     return(GetSingleField(Offset, 2, Text));
01653 }
01654 
01655 
01656 
01657 /***********************************************************************************************
01658 
01659 >   UINT32 Library::GetID(LibraryIndex Offset)
01660 
01661     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
01662     Created:    18/2/95
01663 
01664     Inputs:     Offset - The library index identifying the item you want
01665 
01666     Purpose:    Return the ID for the indexed library item
01667                 Returns 0 if there was a problem (0 is an invalid ID)
01668 
01669 ***********************************************************************************************/
01670 
01671 UINT32 Library::GetID(LibraryIndex Offset)
01672 {
01673     String_8 Tmp;
01674     if (!GetSingleField(Offset, 3, &Tmp))
01675         return(0);
01676 
01677     return((UINT32) _ttoi((TCHAR *)Tmp));
01678 }
01679 
01680 
01681 /***********************************************************************************************
01682 
01683 >   BOOL Library::GetTitle(LibraryIndex Offset, StringBase *Title)
01684 
01685     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
01686     Created:    22/5/95
01687 
01688     Inputs:     Offset - the index identifying the item you require
01689     Outputs:    Title - A pointer to a path name to be filled in (May NOT be NULL)
01690 
01691     Returns:    TRUE if it succeeded
01692 
01693     Purpose:    Return the 'title' for the indexed library item (if there is one)
01694 
01695 ***********************************************************************************************/
01696 
01697 BOOL Library::GetTitle(LibraryIndex Offset, StringBase *Title)
01698 {
01699     ERROR3IF(Title == NULL, "Library::GetTitle - NULL params are illegal");
01700 
01701     String_64 Tmp(_R(IDS_LIBRARIES_INDEX_ITEM_TITLE));
01702     if(!GotField(&Tmp))
01703         return FALSE;
01704 
01705     // Get title from index file
01706     BOOL ok = GetSingleField(Offset, &Tmp, Title);
01707 
01708 //  BOOL ok = GetSingleField(Offset, 4, Title);
01709 
01710     // NULL titles are invalid - default to something else - probably filename
01711     if(Title->Length() == 0)
01712         ok = FALSE;
01713 
01714     return ok;
01715 }
01716 
01717 
01718 /***********************************************************************************************
01719 
01720 >   BOOL Library::GetTitle(LibraryIndex Offset, TCHAR **Title)
01721 
01722     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
01723     Created:    3/5/95
01724 
01725     Inputs:     Offset  - the index identifying the item you require
01726     Outputs:    Title   - ptr to title to return
01727 
01728     Returns:    TRUE if it succeeded
01729 
01730     Purpose:    Return a pointer to the title for the indexed library item
01731 
01732     Notes:      If we're using diskfiles this will return FALSE
01733 
01734 ***********************************************************************************************/
01735 
01736 BOOL Library::GetTitle(LibraryIndex Offset, TCHAR **Title)
01737 {
01738     ERROR3IF(Title == NULL, "Library::GetFilename - NULL params are illegal");
01739 
01740     String_64 Tmp(_R(IDS_LIBRARIES_INDEX_ITEM_TITLE));
01741     if(!GotField(&Tmp))
01742         return FALSE;
01743 
01744     // Get title from index file
01745     BOOL ok = GetSingleField(Offset, &Tmp, Title);
01746 //  BOOL ok = GetSingleField(Offset, 4, Title);
01747 
01748     // NULL titles are invalid - default to something else - probably filename
01749     if(camStrlen(*Title)  == 0)
01750         ok = FALSE;
01751 
01752     return ok;
01753 }
01754 
01755 /***********************************************************************************************
01756 
01757 >   BOOL Library::GetThumbnail(LibraryIndex Offset, SGThumbSize Size, BOOL Urgent,
01758                                 KernelBitmap **Thumbnail )
01759 
01760     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>; modified by Adrian 1/12/96 
01761     Created:    22/2/95
01762     Inputs:     Offset into index file
01763                 Size of thumbnail (Small, Medium, Large)
01764                 Urgent - set to true if we want the thumbnail NOW ! (if false, only returns thumbnail if in cache)
01765 
01766     Outputs:    Thumbnail - The value pointed to by Result will be filled in with
01767                 a pointer to a created thumbnail. This may be NULL if a thumb could
01768                 not be found/created (if Urgent == FALSE, then this will be NULL if the
01769                 thumb is not already cached in memory)
01770 
01771     Returns:    TRUE if it succeeds (though this may still return a NULL thumbnail ptr)
01772                 FALSE if it failed miserably
01773 
01774     Purpose:    Return a pointer to the thumbnail for the given library index.
01775 
01776 ***********************************************************************************************/
01777 
01778 BOOL Library::GetThumbnail(LibraryIndex Offset, SGThumbSize Size, BOOL Urgent,
01779                             KernelBitmap **Thumbnail)
01780 {
01781     if (Thumbnails == NULL)
01782         return FALSE;
01783 
01784     UINT32 ID = GetID(Offset);
01785     Thumbnails->SetSize(Size);
01786 
01787     // For ripping thumbnails out of art files, we need the name of the art file
01788     PathName ActualFile;
01789     PathName *pActualFile = &ActualFile;
01790     String_256 TheFile;
01791 
01792     if(!GetFilename(Offset, &TheFile, TRUE))
01793         pActualFile = NULL;
01794     else
01795         ActualFile.SetPathName(TheFile);
01796                                                                                                                  
01797     return(Thumbnails->GetThumbnail(ID, Urgent, Thumbnail, pActualFile));
01798 }
01799 
01800 
01801 
01802 /***********************************************************************************************
01803 
01804 >   void Library::KillAllThumbnails(void)
01805 
01806     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
01807     Created:    22/2/95
01808 
01809     Purpose:    Deletes all thumbnails from cache
01810 
01811 ***********************************************************************************************/
01812 
01813 void Library::KillAllThumbnails(void)
01814 {
01815     if (Thumbnails != NULL)
01816         Thumbnails->DeleteThumbnails();
01817 }                                 
01818 
01819 
01820 
01821 
01822 /***********************************************************************************************
01823 
01824 >   BOOL Library::LocalPath2URL(String_256* pLocalPath)
01825 
01826     Author:     Adrian_Stoicar (Xara Group Ltd) <camelotdev@xara.com>
01827     Created:    01/12/96
01828 
01829     Inputs:    a pointer to a String_256 containing local path to convert to a URL
01830 
01831     Outputs: the expected location of the file on our web site. The input string is overwritten
01832                  with this location, but only if the function succeeds. The input string will not be
01833                  modified in case of failure.
01834                 
01835 
01836     Returns: TRUE is successful, FALSE if failed
01837 
01838     Purpose:    converts a local path to a URL, using the base URL read from the library index file
01839                     The URL can be used to download the file 
01840 ***********************************************************************************************/
01841 
01842 BOOL Library::LocalPath2URL(String_256* pLocalPath)
01843 {
01844     // The local path is made up of:
01845     // 1) a root path which is usually the exe's directory
01846     // 2) a leaf relative path which is assumed to be identical on the local drive and our web site
01847     // The URL is obtained by appending this leaf path to the root URL, and
01848     // converting all backslashes to normal ones. The returned URL is always lower case.
01849 
01850     String_256 strLocalPath(*pLocalPath);
01851     String_256 strURL(_T("http://xara.xaraonline.com/XaraX2/Resources/"));
01852     if (strURL.Length() == 0) 
01853     {
01854         ERROR3("URL base string is empty");
01855         return FALSE; // we don't have a base url, so can't convert
01856     }
01857     String_256 strWebFilesDir(GetStringField(Type, _R(IDS_CACHEDIR)));
01858     strWebFilesDir += _T("\\");
01859     strLocalPath.toLower();
01860     strWebFilesDir.toLower();
01861     strURL += camStrstr((TCHAR*) strLocalPath, (TCHAR*) strWebFilesDir + String_256(_R(IDS_CACHEPATH)).Length());
01862     strURL.toLower();
01863     // Convert backslashes to normal (UNIX) ones
01864     TCHAR* pBackSlash = NULL;
01865     while (pBackSlash = camStrchr((TCHAR*) strURL, _T('\\')))
01866             *pBackSlash = _T('/');
01867     // Check if the URL is valid
01868     WCHAR  wchURL[INTERNET_MAX_PATH_LENGTH];
01869     MultiByteToWideChar(CP_ACP, 0,  (TCHAR*) strURL, -1, wchURL, INTERNET_MAX_PATH_LENGTH);
01870     BOOL bIsValid = (IsValidURL(NULL, wchURL, 0) == S_OK) ? TRUE : FALSE;
01871     if (bIsValid)
01872     {
01873         *pLocalPath = strURL;
01874         return TRUE;
01875     }
01876     else
01877     {
01878         ERROR3("Conversion resulted in an invalid URL");
01879         return FALSE;
01880     }
01881 }
01882 
01883 
01884 
01885 /***********************************************************************************************
01886 
01887 >   BOOL Library::GetSingleField(LibraryIndex Offset, UINT32 Count, StringBase *Field)
01888 
01889     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
01890     Created:    18/2/95
01891 
01892     Inputs:     Offset - The index identifying the library item to get the field for
01893                 Count - Identifies which field toi retrieve from the line of index
01894                 information for this item.
01895     
01896     Outputs:    Field will be filled in with the field contents.
01897 
01898     Returns:    FALSE if it fails; Field will contain a blank string ("")
01899 
01900     Purpose:    Return a single field for a given library item
01901                 Use this for extended info
01902 
01903 ***********************************************************************************************/
01904 
01905 BOOL Library::GetSingleField(LibraryIndex Offset, UINT32 Count, StringBase *Field)
01906 {
01907     ERROR3IF(Field == NULL, "Library::GetSingleField - NULL Params are illegal");
01908 
01909 #ifdef FIELDCACHE
01910     // We've got a hit in our field cache
01911     if(CacheGet(Offset, Count, Field))
01912         return TRUE;
01913 #endif
01914 
01915     // Extract the entry from the index file
01916     BOOL GotField = FALSE;
01917 
01918     // Check if we've got a cached version of the index
01919     if(CachedSubIndexBuf != NULL)
01920     {
01921         GotField = GetSingleFieldFromMemory(Offset, Count, Field);
01922     }
01923     
01924     // Memory file didn't have item, or not present... use a disk file
01925     if(!GotField)
01926     {
01927         GotField = GetSingleFieldFromDisk(Offset, Count, Field);
01928     }
01929 
01930     // If we got the field, whack it in the cache, otherwise return a blank
01931     if(!GotField)
01932         *Field = TEXT("");
01933 #ifdef FIELDCACHE
01934     else
01935     {
01936         // Clean the string up a bit
01937         LibraryFile::KillLeadingSpaces(Field);
01938         CachePut(Offset, Count, Field);
01939     }
01940 #endif
01941     
01942     return GotField;
01943 }
01944 
01945 
01946 /***********************************************************************************************
01947 
01948 >   BOOL Library::GetSingleField(LibraryIndex Offset, UINT32 Count, TCHAR **Field)
01949 
01950     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
01951     Created:    18/2/95
01952 
01953     Inputs:     Offset - The index identifying the library item to get the field for
01954                 Count - Identifies which field toi retrieve from the line of index
01955                 information for this item.
01956     
01957     Outputs:    Field will point to the field contents.
01958 
01959     Returns:    FALSE if it fails;
01960 
01961     Purpose:    Return a single field for a given library item
01962                 Use this for extended info
01963 
01964     Notes:      If using disk files we currently return false, this means you should always
01965                 use the string copying one above if this returns false, etc...
01966 
01967 ***********************************************************************************************/
01968 
01969 BOOL Library::GetSingleField(LibraryIndex Offset, UINT32 Count, TCHAR **Field)
01970 {
01971     ERROR3IF(Field == NULL, "Library::GetSingleField - NULL Params are illegal");
01972 
01973     // Extract the entry from the index file
01974     BOOL GotField = FALSE;
01975 
01976     // Check if we've got a cached version of the index
01977     if(CachedSubIndexBuf != NULL)
01978     {
01979         // This will call the TCHAR ** version, not the stringbase version
01980         GotField = GetSingleFieldFromMemory(Offset, Count, Field);
01981     }
01982     
01983     return GotField;
01984 }
01985 
01986 
01987 
01988 
01989 /***********************************************************************************************
01990 
01991 >   BOOL Library::GetSingleFieldFromMemory(LibraryIndex Offset, UINT32 Count, StringBase *Field)
01992 
01993     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
01994     Created:    22/4/95
01995 
01996     Inputs:     Offset - The index identifying the library item to get the field for
01997                 Count - Identifies which field toi retrieve from the line of index
01998                 information for this item.
01999     
02000     Outputs:    Field will be filled in with the field contents.
02001 
02002     Returns:    FALSE if it fails
02003 
02004     Purpose:    Return a single field for a given library item using the 0 padded, cached
02005                 index file in memory.
02006 
02007 ***********************************************************************************************/
02008 
02009 BOOL Library::GetSingleFieldFromMemory(LibraryIndex Offset, UINT32 Count, StringBase *Field)
02010 {
02011     ERROR3IF(Field == NULL, "Library::GetSingleField - NULL Params are illegal");
02012     ERROR3IF(Offset > CachedBufLength, "Library::GetSingleField - given out of range offset");
02013     ERROR3IF(CachedSubIndexBuf == NULL, "Library::GetSingleField - called with null index buffer");
02014 
02015 #if 0
02016     // Equivalent to a memfile seek
02017     TCHAR *Start = CachedSubIndexBuf + Offset;
02018     TCHAR *Finish = CachedSubIndexBuf + CachedBufLength;
02019 
02020     if(Count == 1)
02021     {
02022         *Field = Start;
02023         return TRUE;
02024     }
02025     else
02026     {
02027         // chars to look for
02028         const TCHAR SPC = ' ';
02029 
02030         TCHAR Ch = *Start;
02031         UINT32 FieldCount = 1;
02032 
02033         // scan through fields until we hit our baby
02034         while(Count > FieldCount && Start < Finish)
02035         {
02036             if(Ch == 0)
02037                 FieldCount ++;
02038             Start += sizeof(TCHAR);
02039             Ch = *Start;
02040         }
02041 
02042         if(Count == FieldCount)
02043         {
02044             // Quick, speedy kill leading spaces type thing
02045             Ch = *Start;
02046             while(Ch == SPC && Ch != 0 && Start < Finish)
02047             {
02048                 Start += sizeof(TCHAR);
02049                 Ch = *Start;
02050             }
02051 
02052             // COPY String into field (could pass back a pointer ?)     
02053             *Field = Start;
02054             return TRUE;
02055         }
02056         else
02057             return FALSE;
02058     }   
02059 
02060     return FALSE;
02061 #endif
02062 
02063     TCHAR *Fld;
02064     BOOL ok = GetSingleFieldFromMemory(Offset, Count, &Fld);
02065     *Field = Fld;
02066 
02067     return ok;
02068 }
02069 
02070 /***********************************************************************************************
02071 
02072 >   BOOL Library::GetSingleFieldFromMemory(LibraryIndex Offset, UINT32 Count, TCHAR **Field)
02073 
02074     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
02075     Created:    3/5/95
02076 
02077     Inputs:     Offset - The index identifying the library item to get the field for
02078                 Count - Identifies which field toi retrieve from the line of index
02079                 information for this item.
02080     
02081     Outputs:    Field will point to the field string in memory
02082 
02083     Returns:    FALSE if it fails
02084 
02085     Purpose:    Return a pointer to a single field for a given library item using the 0
02086                 padded, cached index file in memory.
02087 
02088 ***********************************************************************************************/
02089 
02090 BOOL Library::GetSingleFieldFromMemory(LibraryIndex Offset, UINT32 Count, TCHAR **Field)
02091 {
02092     ERROR3IF(Field == NULL, "Library::GetSingleField - NULL Params are illegal");
02093     ERROR3IF(Offset > CachedBufLength, "Library::GetSingleField - given out of range offset");
02094     ERROR3IF(CachedSubIndexBuf == NULL, "Library::GetSingleField - called with null index buffer");
02095 
02096     // Equivalent to a memfile seek
02097     TCHAR *Start = CachedSubIndexBuf + Offset;
02098     TCHAR *Finish = CachedSubIndexBuf + CachedBufLength;
02099 
02100     if(Count == 1)
02101     {
02102         *Field = Start;
02103         return TRUE;
02104     }
02105     else
02106     {
02107         // chars to look for
02108         const TCHAR SPC = ' ';
02109 
02110         TCHAR Ch = *Start;
02111         UINT32 FieldCount = 1;
02112 
02113         // scan through fields until we hit our baby
02114         while(Count > FieldCount && Start < Finish)
02115         {
02116             if(Ch == 0) FieldCount ++;
02117             Start += sizeof(TCHAR);
02118             Ch = *Start;
02119         }
02120 
02121         if(Count == FieldCount)
02122         {
02123             // Quick, speedy kill leading spaces type thing
02124             Ch = *Start;
02125             while(Ch == SPC && Ch != 0 && Start < Finish)
02126             {
02127                 Start += sizeof(TCHAR);
02128                 Ch = *Start;
02129             }
02130 
02131             // Pass back a pointer to the string data
02132             *Field = Start;
02133             return TRUE;
02134         }
02135         else
02136             return FALSE;
02137     }   
02138 
02139     return FALSE;
02140 }
02141  
02142 /***********************************************************************************************
02143 
02144 >   BOOL Library::GetSingleFieldFromDisk(LibraryIndex Offset, UINT32 Count, StringBase *Field)
02145 
02146     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
02147     Created:    22/4/95
02148 
02149     Inputs:     Offset - The index identifying the library item to get the field for
02150                 Count - Identifies which field toi retrieve from the line of index
02151                 information for this item.
02152     
02153     Outputs:    Field will be filled in with the field contents.
02154 
02155     Returns:    FALSE if it fails
02156 
02157     Purpose:    Return a single field for a given library item using a diskfile for the index
02158 
02159 ***********************************************************************************************/
02160 
02161 BOOL Library::GetSingleFieldFromDisk(LibraryIndex Offset, UINT32 Count, StringBase *Field)
02162 {
02163     ERROR3IF(Field == NULL, "Library::GetSingleField - NULL Params are illegal");
02164 
02165     BOOL ok = TRUE;
02166     BOOL OpenedOK = TRUE;
02167     CCLexFile *SubIndex = NULL;
02168 
02169     // If we've not got a cached version of the index, use a diskfile on the index itself
02170     SubIndex = new CCDiskFile;
02171 
02172     // Open the index file, seek to our position and rip out our token
02173     if(SubIndex != NULL)
02174         OpenedOK = ((CCDiskFile *)SubIndex)->open(*IndexFile, ios::in);
02175 
02176     if(SubIndex == NULL)
02177     {
02178         ERROR3("Library::Init Disk SubIndex not created properly");
02179         return FALSE;
02180     }
02181 
02182     if(!OpenedOK)
02183     {
02184         ERROR3("Library::Init Disk SubIndex not opened properly");
02185         delete SubIndex;
02186         return FALSE;
02187     }
02188     
02189     // Subindex seeking required
02190     if (!SubIndex->InitLexer(TRUE))
02191     {
02192         ERROR3("Library::GetSingleField InitLexer failed");
02193         if(SubIndex->isOpen())
02194             SubIndex->close();
02195         delete SubIndex;
02196         return FALSE;
02197     }
02198 
02199     SubIndex->SetWhitespace("");            // Setting this to blank lets us read non-"'d strings
02200     SubIndex->SetDelimiters(",");       // ,s delimit our fields
02201     SubIndex->SetCommentMarker('#');        // #'d lines are commented out
02202     SubIndex->SetStringDelimiters("");  // No string delimiters
02203 
02204     SubIndex->seekIn(Offset);
02205     
02206     String_256 Token;
02207     LexTokenType TT = TOKEN_EOL;
02208 
02209     LibraryIndex FOffset;
02210     ok = SubIndex->GetToken();
02211     TT = SubIndex->GetTokenType();      
02212 
02213     FOffset = (LibraryIndex) SubIndex->tellIn();
02214 
02215     if(FOffset != Offset)
02216         ERROR3("Lexer didn't seek properly");
02217 
02218     while(Offset > FOffset && ok && TT != EOF)
02219     {
02220         ok = SubIndex->GetToken();
02221         FOffset = (LibraryIndex) SubIndex->tellIn();
02222         TT = SubIndex->GetTokenType();      
02223         if (TT == TOKEN_EOF) ok = FALSE;
02224     }
02225 
02226     if(!ok)
02227     {
02228         ERROR3("Library::GetSingleField Line past end of file");
02229 //      if(CachedSubIndex == NULL)
02230 //      {
02231             if(SubIndex->isOpen())
02232                 SubIndex->close();
02233             delete SubIndex;
02234 //      }
02235         return FALSE;
02236     }
02237 
02238     // Get the first token in the line (since we did a seek, the first few
02239     // tries might return garbage...)
02240     while(ok && TT != TOKEN_NORMAL)
02241     {
02242         ok = SubIndex->GetToken();
02243 
02244         if (ok)
02245         {
02246             TT = SubIndex->GetTokenType();      
02247             if (TT == TOKEN_EOF)
02248                 ok = FALSE;
02249         }
02250     }
02251 
02252     if (ok)
02253     {
02254         UINT32 i = 1;
02255 
02256         // Keep reading tokens until we hit the one we want
02257         while(Count > i && ok)
02258         {
02259             Token = SubIndex->GetTokenBuf();
02260             LibraryFile::KillLeadingSpaces(&Token);
02261 
02262             if (Token == String_8(",") )
02263                 i++;                        // Found a comma, move to next field
02264         
02265             ok = SubIndex->GetToken();      // Get next token
02266         }
02267 
02268         // Hopefully the token buffer now contains our item
02269         if (ok)                        
02270         {
02271             Token = SubIndex->GetTokenBuf();
02272             LibraryFile::KillLeadingSpaces(&Token);
02273 
02274             if (Token == String_8(",") )
02275                 *Field = TEXT("");
02276             else
02277                 *Field = Token;
02278         }
02279     }
02280 
02281     // reclaim lexer-buffer memory
02282     SubIndex->DeinitLexer();    
02283 
02284     // and close the file...
02285     if(SubIndex->isOpen())
02286         SubIndex->close();
02287 
02288     // and reclaim the diskfile memory...
02289     delete SubIndex;
02290 
02291     return ok;
02292 }
02293 
02294 /***********************************************************************************************
02295 
02296 >   BOOL GetSingleField(LibraryIndex Offset, String_64 *FieldName, StringBase *Field);
02297 
02298     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
02299     Created:    28/3/95
02300 
02301     Inputs:     Offset      - The index identifying the library item to get the field for
02302                 FieldName   - Name of field we require (must be in field header)
02303     
02304     Outputs:    Field       - will be filled in with the field contents.
02305 
02306     Returns:    FALSE if it fails;
02307 
02308     Purpose:    Return a single field for a given library item and field description
02309                 Use this for extended info
02310 
02311     Notes:      The above code assumes that the first three fields are always:
02312                     Filename, Description, ID
02313 
02314                 We've now got 'Title' as a fourth, but only if it's in the field description...
02315         
02316                 After that we've got things like 'Key' and 'Size' which we check
02317                 the positions of using this string...
02318 
02319 ***********************************************************************************************/
02320 
02321 BOOL Library::GetSingleField(LibraryIndex Offset, String_64 *FieldName, StringBase *Field)
02322 {
02323     ERROR3IF(FieldName == NULL || Field == NULL, "Library::GetSingleField given nulls");
02324 
02325     if(!GotField(FieldName))
02326     {
02327         *Field = TEXT("");
02328         return FALSE;
02329     }
02330 
02331     INT32 Count = FindField(FieldName);
02332 
02333     return (Count > 0 && GetSingleField(Offset, Count, Field));
02334 }
02335 
02336 /***********************************************************************************************
02337 
02338 >   BOOL GetSingleField(LibraryIndex Offset, String_64 *FieldName, StringBase *Field);
02339 
02340     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
02341     Created:    28/3/95
02342 
02343     Inputs:     Offset      - The index identifying the library item to get the field for
02344                 FieldName   - Name of field we require (must be in field header)
02345     
02346     Outputs:    Field       - will be pointed to the field contents (if index cached).
02347 
02348     Returns:    FALSE if it fails;
02349 
02350     Purpose:    Get a pointer to a single field for a given library item and field description
02351                 using the extended info
02352 
02353     Notes:      The above code assumes that the first three fields are always:
02354                     Filename, Description, ID
02355         
02356                 After that we've got things like 'Key', 'Size', 'Title' which we check
02357                 the positions of using this string...
02358 
02359                 If the index isn't in memory we can't return the pointer !
02360 
02361 ***********************************************************************************************/
02362 
02363 BOOL Library::GetSingleField(LibraryIndex Offset, String_64 *FieldName, TCHAR **Field)
02364 {
02365     ERROR3IF(FieldName == NULL || Field == NULL, "Library::GetSingleField given nulls");
02366 
02367     if(!GotField(FieldName))
02368         return FALSE;
02369 
02370     INT32 Count = FindField(FieldName);
02371 
02372     return (Count > 0 && GetSingleField(Offset, Count, Field));
02373 }
02374 
02375 /***********************************************************************************************
02376 
02377 >   INT32 Library::FindField(String_64 *FieldName);
02378 
02379     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
02380     Created:    22/5/95
02381 
02382     Inputs:     FieldName   - Field to look for
02383     
02384     Returns:    Position of field - so for 'ID' we would return 3, etc...
02385 
02386     Purpose:    Works out the column for the given field string
02387 
02388 ***********************************************************************************************/
02389 
02390 INT32 Library::FindField(String_64 *FieldName)
02391 {
02392     ERROR3IF(FieldName == NULL, "Library::FindField given nulls");
02393 
02394     INT32 Pos = FieldString.Sub(*FieldName);
02395     
02396     if(Pos != -1)
02397     {
02398         // Find out which field it was
02399         String_256 Left;
02400         FieldString.Left(&Left, Pos);
02401         const TCHAR BrkChar = ',';
02402 
02403         // This bit could go in basestr...      
02404         INT32 Count = 0;
02405         TCHAR *Buf = (TCHAR *)Left;
02406         INT32 Len = Left.Length();
02407         for(INT32 i = 0; i < Len; i++)
02408             if(Buf[i] == BrkChar)
02409                 Count ++;
02410 
02411         // Number of commas + 1 is our field
02412         Count ++;
02413 
02414         return Count;
02415     }
02416 
02417     return 0;
02418 }
02419 
02420 
02421 /***********************************************************************************************
02422 
02423 >   BOOL Library::GotField(String_64 *FieldName);
02424 
02425     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
02426     Created:    22/5/95
02427 
02428     Inputs:     FieldName   - Field to look for
02429     
02430     Returns:    TRUE if the field string has the specified field...
02431 
02432     Purpose:    Check if a string is in the field description string...
02433 
02434 ***********************************************************************************************/
02435 
02436 BOOL Library::GotField(String_64 *FieldName)
02437 {
02438     return (FieldString.Sub(*FieldName) != -1);
02439 }
02440       
02441 /***********************************************************************************************
02442 
02443 >   BOOL Library::CacheInit(INT32 Entries)
02444 
02445     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
02446     Created:    14/4/95
02447 
02448     Inputs:     Entries - The maximum number of entries in the field cache  
02449     Outputs:    
02450     Returns:    FALSE if it fails;
02451 
02452     Purpose:    Initialises memory for a sub-index file field cache.
02453                 Currently we use a single entry wide hash table with the specified number
02454                 of buckets. Reading items from the cache is much quicker than from the
02455                 index file itself, be it in memory or not ! (Well, that's the theory)
02456 
02457 ***********************************************************************************************/
02458 
02459 BOOL Library::CacheInit(INT32 Entries)
02460 {
02461     if(Entries == 0)
02462         FieldCache = NULL;
02463     else
02464         if(FieldCache == NULL)
02465             FieldCache = (SGFieldCache *)CCMalloc(sizeof(SGFieldCache) * Entries);
02466         
02467     if(FieldCache == NULL)
02468     {
02469         FieldCacheEntries = 0;
02470         ERROR3("Library::CacheInit - Not enough memory for a field cache - reduce the Fields in the ini file");
02471         return FALSE;
02472     }
02473     else
02474     {
02475         FieldCacheEntries = Entries;
02476 
02477         SGFieldCache Dummy;
02478         Dummy.Offset = 0;
02479         Dummy.Count = 0;
02480         Dummy.Field = NULL;
02481 
02482         for(INT32 i=0; i<Entries; i++)
02483         {
02484             FieldCache[i] = Dummy;
02485         }
02486     }
02487     return TRUE;
02488 }
02489 
02490 
02491 /***********************************************************************************************
02492 
02493 >   BOOL Library::CacheKill(void)
02494 
02495     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
02496     Created:    14/4/95
02497 
02498     Inputs:
02499     Outputs:    
02500     Returns:    FALSE if it fails;
02501 
02502     Purpose:    Reclaims all the memory used by the field cache.
02503 
02504 ***********************************************************************************************/
02505 
02506 BOOL Library::CacheKill(void)
02507 {
02508     TRACEUSER( "Richard", _T("Cache Kill\n"));
02509 
02510     if(FieldCache != NULL)
02511     {
02512         for(INT32 i=0; i<FieldCacheEntries; i++)
02513         {
02514             if(FieldCache[i].Field != NULL)
02515             {
02516                 CCFree(FieldCache[i].Field);
02517                 FieldCache[i].Field = NULL;
02518             }
02519         }
02520         FieldCacheEntries = 0;
02521 
02522         CCFree(FieldCache);
02523         FieldCache = NULL;
02524     }
02525 
02526     return TRUE;
02527 }
02528 
02529 /***********************************************************************************************
02530 
02531 >   INT32 Library::CacheHashFunction(LibraryIndex Offset, UINT32 Count)
02532 
02533     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
02534     Created:    14/4/95
02535 
02536     Inputs:     Offset - this is the file offset of the start of the relevant line
02537                 Count - Field count
02538     Outputs:    
02539     Returns:    Index into the hash table
02540 
02541     Purpose:    Returns an index into the hash table for the given parameters.
02542                 The simpler, the quicker, but probably the less efficient.
02543 
02544     Notes:      I've had a play around with this function, and due to the random nature
02545                 of the index files, can't really improve on the below all that much. Since
02546                 the below is so quick, this is where it's been left.
02547 
02548 ***********************************************************************************************/
02549 
02550 INT32 Library::CacheHashFunction(LibraryIndex Offset, UINT32 Count)
02551 {
02552     return ((Count + Offset) % FieldCacheEntries);
02553 }
02554 
02555 /***********************************************************************************************
02556 
02557 >   BOOL Library::CachePut(LibraryIndex Offset, UINT32 Count, StringBase *Field)
02558 
02559     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
02560     Created:    14/4/95
02561 
02562     Inputs:     Offset - this is the file offset of the start of the relevant line
02563                 Count - Field count
02564                 Field - The field string to put in the cache
02565     Outputs:    
02566     Returns:    TRUE if we allocated the memory, etc...
02567 
02568     Purpose:    Adds an item into the cache for returning later on with CacheGet
02569 
02570 ***********************************************************************************************/
02571 
02572 BOOL Library::CachePut(LibraryIndex Offset, UINT32 Count, StringBase *Field)
02573 {
02574     TRACEUSER( "Richard", _T("Cache Put\n"));
02575 
02576     // Put the field in the field buffer / line cache, etc...
02577     if(FieldCache != NULL)
02578     {       
02579         SGFieldCache OurEntry;
02580         OurEntry.Offset = Offset;
02581         OurEntry.Count = Count;
02582         OurEntry.Field = (TCHAR *)CCMalloc((Field->Length()+1) * sizeof(TCHAR));
02583         if(OurEntry.Field == NULL)
02584         {
02585             ERROR3("Library::GetSingleField can't allocate enough string space in field buffer");
02586             return FALSE;
02587         }
02588         else
02589         {
02590             camStrcpy(OurEntry.Field, (TCHAR *)*Field);
02591         }
02592     
02593         SGFieldCache *plc = &FieldCache[CacheHashFunction(Offset, Count)];
02594         
02595         if(plc->Field != NULL)
02596         {
02597             CCFree(plc->Field);
02598             plc->Field = NULL;
02599             //TRACEUSER( "Richard", _T("Hash Clash at %d\n"), CacheHashFunction(Offset, Count));
02600         }
02601     
02602         *plc = OurEntry;
02603 
02604         return TRUE;
02605     }
02606     return FALSE;
02607 }
02608 
02609 /***********************************************************************************************
02610 
02611 >   BOOL Library::CacheGet(LibraryIndex Offset, UINT32 Count, StringBase *Field)
02612 
02613     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
02614     Created:    14/4/95
02615 
02616     Inputs:     Offset - this is the file offset of the start of the relevant line
02617                 Count - Field count
02618     Outputs:    Field - The resulting field
02619     Returns:    TRUE if the item was there
02620 
02621     Purpose:    Checks if an item is in the cache. If it is, return it.
02622 
02623 ***********************************************************************************************/
02624 
02625 BOOL Library::CacheGet(LibraryIndex Offset, UINT32 Count, StringBase *Field)
02626 {
02627 #if 0
02628     // Check the FieldCache occupancy
02629     if(FieldCache != NULL)
02630     {       
02631         INT32 Occupancy = 0;
02632         for(INT32 i=0; i<FieldCacheEntries; i++)
02633         {
02634             if(FieldCache[i].Field != NULL) Occupancy++;
02635         }
02636         TRACEUSER( "Richard", _T("Hash usage %d out of %d - %d%%\n"), Occupancy, FieldCacheEntries, (100 * Occupancy / FieldCacheEntries));
02637     }
02638 #endif
02639         
02640     // See if our entry is in the cache
02641     SGFieldCache OurEntry;
02642     if(FieldCache != NULL)
02643     {       
02644         OurEntry = FieldCache[CacheHashFunction(Offset, Count)];
02645     
02646         if(OurEntry.Offset == Offset && OurEntry.Count == Count && OurEntry.Field != NULL)
02647         {
02648             String_256 tmpstr(OurEntry.Field);
02649             *Field = tmpstr;
02650             return TRUE;
02651         }
02652     }
02653 
02654     //TRACEUSER( "Richard", _T("Field not in cache..."));
02655     
02656     return FALSE;
02657 }
02658 
02659 
02660 /***********************************************************************************************
02661 
02662 >   BOOL Library::SaveIndexInDisplayedOrder(PathName *IndexPathName, BOOL NewIDs);
02663 
02664     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
02665     Created:    3/5/95
02666 
02667     Inputs:     IndexPathName - path to output index file to
02668                 NewIDs - regenerate the IDs in numerical order
02669     Outputs:
02670     Returns:    FALSE if it fails; TRUE if we did it all ok
02671 
02672     Purpose:    Save out an index file in the order the group is displayed (possibly sorted !)
02673     Notes:      This is strictly a debug only function !
02674 
02675 ***********************************************************************************************/
02676 
02677 BOOL Library::SaveIndexInDisplayedOrder(PathName *IndexPathName, BOOL NewIDs)
02678 {
02679 #ifdef SAVEINDEX
02680     // Create index file
02681     CCDiskFile *IndexPath = new CCDiskFile(1024, TRUE, FALSE);
02682     ERROR2IF(IndexPath == NULL, FALSE, "Null index file allocated");
02683 
02684     if(!IndexPath->open(*IndexPathName, ios::out))
02685     {
02686         ERROR3("Can't create new index file");
02687         delete IndexPath;
02688         return FALSE;
02689     }
02690 
02691     // Write the header to the index file
02692     IndexPath->write(CachedSubIndexBuf, (UINT32)FirstLineOffset);
02693 
02694     // Loop through each item in the group as they're displayed and save each one out...
02695     BOOL ok = TRUE;
02696 
02697     // For the NewID stuff...
02698     INT32 Count = 0;
02699 
02700     SGDisplayNode *Item = ParentGroup;
02701 
02702     // Get the first item in the group...
02703     if(Item != NULL)
02704         Item = Item->GetChild();
02705 
02706     // Loop through all the group items
02707     while (Item != NULL)
02708     {
02709         if(Item->IsKindOf(CC_RUNTIME_CLASS(SGLibDisplayItem)))
02710         {
02711             Count++;
02712 
02713             SGLibDisplayItem *LibItem = (SGLibDisplayItem *) Item;
02714 
02715             LibraryIndex Offset = LibItem->GetDisplayedLibraryIndex();
02716             String_64 Field;
02717 
02718             TCHAR FieldStringBuffer[256];
02719             TCHAR *FieldStringDone = (TCHAR *)FieldStringBuffer;
02720             camStrcpy(FieldStringDone, (TCHAR *)FieldString);
02721 
02722             BOOL MoreFields = TRUE;
02723 
02724             // Rip out each field in turn
02725             while(MoreFields)
02726             {           
02727                 // find next comma in FieldStringDone and replace it with a 0
02728                 // If there are none then we assume that the end has come...
02729                 TCHAR *Comma = camStrchr(FieldStringDone, _T(','));
02730                 if(Comma != NULL)
02731                     *Comma = 0;
02732                 else
02733                     MoreFields = FALSE;
02734 
02735                 // kill leading spaces from FieldStringDone
02736                 while(FieldStringDone[0] == ' ')
02737                     FieldStringDone += sizeof(TCHAR);
02738 
02739                 // FieldStringDone now points to a field string... Get the data...
02740                 String_64 FieldStringToUse(FieldStringDone);
02741 
02742                 if(NewIDs && (FieldStringToUse == String_64(_R(IDS_LIBRARIES_INDEX_ITEM_ID))))
02743                     wsprintf(Field, "%d", Count);
02744                 else
02745                     ok = GetSingleField(Offset, &FieldStringToUse, &Field);
02746 
02747                 ERROR3IF(!ok, "Problems getting a field");
02748             
02749                 // Write the data into the new index file
02750                 IndexPath->write((TCHAR *)Field, (UINT32)Field.Length() * sizeof(TCHAR));
02751 
02752                 // Ternimate the data, if it's the last field, use a return...
02753                 if(Comma != NULL)
02754                 {
02755                     IndexPath->write((TCHAR *)",", sizeof(TCHAR) * 1);
02756                     FieldStringDone += ((camStrlen(FieldStringDone)+1) * sizeof(TCHAR));
02757                 }
02758                 else
02759                     IndexPath->write((TCHAR *)"\r\n", sizeof(TCHAR) * 2);       
02760             }
02761         }
02762         // If we've reached the end, this will be NULL
02763         Item = Item->GetNext();
02764     }
02765 
02766     // Close the index file and tidy up
02767     IndexPath->close();
02768     delete IndexPath;
02769 
02770     ERROR3IF(Count != ItemCount, "Wrong number of items in group -> bad !");
02771 
02772     return TRUE;
02773 #endif
02774     return FALSE;
02775 }
02776 
02777 
02778 /***********************************************************************************************
02779 
02780 >   static BOOL Library::InitLibPrefs(void);
02781 
02782     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
02783     Created:    3/4/95
02784 
02785     Inputs:     
02786     Outputs:        
02787     Returns:    FALSE if it fails; TRUE if we got our prefs from the ini file
02788 
02789     Purpose:    Initialises the preferences in the ini file and returns the values
02790                 of the entries if they're there already
02791 
02792     Notes:
02793 
02794 ***********************************************************************************************/
02795 
02796 BOOL Library::InitLibPrefs(void)
02797 {
02798     // Only do this once
02799     static BOOL AlreadyCalled = FALSE;
02800     if(AlreadyCalled) return FALSE;
02801     AlreadyCalled = TRUE;
02802 
02803 #ifndef EXCLUDE_GALS
02804     
02805     GetApplication()->DeclareSection(TEXT("Libraries"), 12);
02806 
02807     // The locations of the libraries (as found via browse or scan)
02808     GetApplication()->DeclarePref(TEXT("Libraries"), TEXT("ClipArt"), &LibClipartSGallery::ClipartPath);
02809     GetApplication()->DeclarePref(TEXT("Libraries"), TEXT("WebTheme"), &LibClipartSGallery::WebThemePath);
02810 
02811 #ifndef STANDALONE
02812 //WEBSTER-Martin-09/01/97   - Put back by Ranbir.
02813 //#ifndef WEBSTER
02814     GetApplication()->DeclarePref(TEXT("Libraries"), TEXT("Font"), &FontsSGallery::DefaultLibraryPath);
02815 //#endif //WEBSTER
02816     GetApplication()->DeclarePref(TEXT("Libraries"), TEXT("Texture"), &LibFillsSGallery::DefaultLibraryPath);
02817 #endif
02818 
02819     // Remember the last display modes used
02820     GetApplication()->DeclarePref(TEXT("Libraries"), TEXT("ClipartDisplayMode"), &LibClipartSGallery::DefaultDisplayMode, 0, 2);
02821 #ifndef STANDALONE
02822 //WEBSTER-Martin-09/01/97
02823 //#ifndef WEBSTER   - Put back by Ranbir.
02824     GetApplication()->DeclarePref(TEXT("Libraries"), TEXT("FontDisplayMode"), &FontsSGallery::DefaultDisplayMode, 0, 4);
02825 //#endif //WEBSTER
02826     GetApplication()->DeclarePref(TEXT("Libraries"), TEXT("FillDisplayMode"), &LibFillsSGallery::DefaultDisplayMode, 0, 2);
02827 #endif //WEBSTER
02828 
02829 #ifdef _DEBUG
02830     // Cache the library index files in memory, so index accesses require NO disk accesses, except for thumbnails
02831     GetApplication()->DeclarePref(TEXT("Libraries"), TEXT("CacheIndexFiles"), &Library::CacheIndexFile, 0, 1);
02832 #endif
02833 
02834     // Redraw the library galleries in two passes
02835     GetApplication()->DeclarePref(TEXT("Libraries"), TEXT("BackgroundRedraw"), &Library::BackgroundRedraw, 0, 1);
02836 
02837     // Number of thumbnails to cache in memory for EACH GROUP
02838     GetApplication()->DeclarePref(TEXT("Libraries"), TEXT("Thumbnails"), &SGThumbs::MaxThumbnails, 1, 100);
02839 
02840     // Number of fields to cache in the Field cache for EACH GROUP
02841     GetApplication()->DeclarePref(TEXT("Libraries"), TEXT("FieldCache"), &Library::MaxFieldCacheEntries, 1, 1000);
02842 
02843     // Rip info out of existing indexes when generating new ones
02844     GetApplication()->DeclarePref(TEXT("Libraries"), TEXT("UseOldIndexesWhenCreating"), &GenerateIndexFile::UseOldIndexes, 0, 1);
02845 
02846     // Rip info out of existing indexes when generating new ones
02847     GetApplication()->DeclarePref(TEXT("Libraries"), TEXT("UseDocCommentsWhenCreating"), &GenerateIndexFile::UseDocComments, 0, 1);
02848 
02849     // Rip info out of existing indexes when generating new ones
02850     GetApplication()->DeclarePref(TEXT("Libraries"), TEXT("AskAboutRemoving"), &LibraryGallery::AskAboutRemoving, 0, 1);
02851 
02852     // Enable 'remote' library indexes if target media is read-only...
02853     GetApplication()->DeclarePref(TEXT("Libraries"), TEXT("RemoteIndexes"), &Library::RemoteIndexes, 0, 1);
02854 
02855     // Location for 'remote' library indexes (if empty, use temp)...
02856     GetApplication()->DeclarePref(TEXT("Libraries"), TEXT("RemoteIndexLocation"), &Library::RemoteIndexLocation);
02857 
02858     // Should we make sounds if the index contains them ?
02859     GetApplication()->DeclarePref(TEXT("Libraries"), TEXT("Enhancements"), &LibClipartSGallery::DoSounds);
02860 
02861     // Should we use an explorer dialog on win95 if we can ?
02862     GetApplication()->DeclarePref(TEXT("Libraries"), TEXT("Explorer"), &SGLibOil::UseExplorerForAdd);
02863 
02864     // Enable 'quick indexes'
02865 #ifdef _DEBUG
02866     GetApplication()->DeclarePref(TEXT("Libraries"), TEXT("QuickIndexes"), &Library::QuickIndex, 0, 1);
02867 #endif
02868 
02869     // Should we just build the groups without items for speed ?
02870     GetApplication()->DeclarePref(TEXT("Libraries"), TEXT("Virtualising"), &SGLibGroup::LibraryVirtualisingEnabled, 0, 1);
02871 
02872 //WEBSTER-Martin-09/01/97
02873 //#ifndef WEBSTER
02874 #ifndef STANDALONE
02875     // Preferences for the fonts gallery
02876     GetApplication()->DeclareSection(TEXT("FontGallery"), 3);
02877 
02878     // Preview string used in the installed section
02879     GetApplication()->DeclarePref(TEXT("FontGallery"), TEXT("LargeInstalledDisplayString"), &FontsSGallery::LargeDisplayString);
02880 
02881     // Delete the corresponding TTF and FOT files in windows\system (or wherever) when deinstalling the font
02882     GetApplication()->DeclarePref(TEXT("FontGallery"), TEXT("DeleteFilesOnDeinstall"), &FontsSGallery::DeleteTTFandFOTfiles, 0, 1);
02883 
02884     // Enable or Disable ATM Alias in menus / galleries...
02885     GetApplication()->DeclarePref(TEXT("FontGallery"), TEXT("DisableATMAliases"), &ATMInstall::DisableATMAliases, 0, 1);
02886 #endif \\STANDALONE
02887 //#endif \\WEBSTER
02888 #endif
02889     return TRUE;
02890 }
02891 
02892 /***********************************************************************************************
02893 
02894 >   static BOOL Library::CacheLibPrefs(void);
02895 
02896     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
02897     Created:    12/12/97
02898     Returns:    FALSE if it fails; TRUE if we everything went ok
02899     Purpose:    Called during preference wiping to allow us to squirrel away any settings that
02900                 we desire before they are wiped. This is useful if we want to retain newly
02901                 installed preferences that the installer has deliberately put there! E.g the paths
02902                 to the clipart etc on the CD.
02903 
02904 ***********************************************************************************************/
02905 
02906 BOOL Library::CacheLibPrefs(void)
02907 {
02908     // Save away the current values stored in the preferences
02909     // Must read the values directly from the preferences as our preference variables will
02910     // not have been set up yet!
02911     Camelot.GetPrefDirect(TEXT("Libraries"), TEXT("ClipArt"),   &g_ClipartLibraryPath);
02912     Camelot.GetPrefDirect(TEXT("Libraries"), TEXT("WebTheme"),  &g_WebThemeLibraryPath);
02913     Camelot.GetPrefDirect(TEXT("Libraries"), TEXT("Font"),      &g_FontLibraryPath);
02914     Camelot.GetPrefDirect(TEXT("Libraries"), TEXT("Texture"),   &g_FillsLibraryPath);
02915 
02916     //g_ClipartLibraryPath  = LibClipartSGallery::DefaultLibraryPath;
02917     //g_FontLibraryPath     = FontsSGallery::DefaultLibraryPath;
02918     //g_FillsLibraryPath        = LibFillsSGallery::DefaultLibraryPath;
02919     
02920     return TRUE;
02921 }
02922 
02923 /***********************************************************************************************
02924 
02925 >   static BOOL Library::RestoreLibPrefs(void);
02926 
02927     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
02928     Created:    12/12/97
02929     Returns:    FALSE if it fails; TRUE if we everything went ok
02930     Purpose:    Called during preference wiping to allow us to squirrel away any settings that
02931                 we desire before they are wiped. This is useful if we want to retain newly
02932                 installed preferences that the installer has deliberately put there! E.g the paths
02933                 to the clipart etc on the CD.
02934 
02935 ***********************************************************************************************/
02936 
02937 BOOL Library::RestoreLibPrefs(void)
02938 {
02939     // Must save the values directly into the preferences as our preference variables will
02940     // not have been set up yet!
02941     const TCHAR * pClipPath = g_ClipartLibraryPath;
02942     const TCHAR * pWebPath = g_WebThemeLibraryPath;
02943     const TCHAR * pFontPath = g_FontLibraryPath;
02944     const TCHAR * pFillsPath = g_FillsLibraryPath;
02945     // Only put back the values if they contain something useful. Mustn't put back blank entires
02946     // otherwise the galleries will error about bad paths!
02947     if (!g_ClipartLibraryPath.IsEmpty())
02948         Camelot.SetPrefDirect(TEXT("Libraries"), TEXT("ClipArt"),   pClipPath);
02949     if (!g_WebThemeLibraryPath.IsEmpty())
02950         Camelot.SetPrefDirect(TEXT("Libraries"), TEXT("WebTheme"),  pWebPath);
02951     if (!g_FontLibraryPath.IsEmpty())
02952         Camelot.SetPrefDirect(TEXT("Libraries"), TEXT("Font"),      pFontPath);
02953     if (!g_FillsLibraryPath.IsEmpty())
02954         Camelot.SetPrefDirect(TEXT("Libraries"), TEXT("Texture"),   pFillsPath);
02955 
02956 //  LibClipartSGallery::DefaultLibraryPath  = g_ClipartLibraryPath;
02957 //  FontsSGallery::DefaultLibraryPath       = g_FontLibraryPath;
02958 //  LibFillsSGallery::DefaultLibraryPath    = g_FillsLibraryPath;
02959 
02960     return TRUE;
02961 }

Generated on Sat Nov 10 03:46:58 2007 for Camelot by  doxygen 1.4.4