sgindgen.cpp

Go to the documentation of this file.
00001 // $Id: sgindgen.cpp 1361 2006-06-25 16:43:38Z 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 // Gallery index generation classes
00099 
00100 /*
00101 */
00102 
00103 #include "camtypes.h"
00104 #include "sgindgen.h"
00105 
00106 /*#include "ccfile.h"
00107 //#include "pathname.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00108 //#include "thumb.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00109 #include "sgliboil.h"
00110 //#include "richard.h"
00111 #include "progress.h"
00112 //#include "resource.h"
00113 //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00114 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00115 #ifndef WEBSTER
00116 #include "extfilts.h"
00117 #include "imglib.h"
00118 #include "img_err.h"
00119 #endif  //WEBSTER
00120 //#include "accures.h"
00121 //#include "oilfltrs.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00122 //#include "resource.h"
00123 #include "sgscanf.h"
00124 //#include "simon.h"        // for _R(IDS_CONTINUE)
00125 //#include "sgscan.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00126 //#include "richard2.h"
00127 //#include "camfiltr.h" // BaseCamelotFilter - new version 2 native/web filter - in camtypes.h [AUTOMATICALLY REMOVED]
00128 //#include "cxfdefs.h"      // CXF_IDWORD1, signature of new file format - in camtypes.h [AUTOMATICALLY REMOVED]
00129 
00130 #include "bmpexdoc.h"
00131 #include "bmpfiltr.h"
00132 #include "prvwflt.h"
00133 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00134 */
00135 
00136 extern BOOL MakeShortPath(LPTSTR lpszPath, size_t cchMaxLen);
00137 
00138 DECLARE_SOURCE("$Revision: 1361 $");
00139 
00140 CC_IMPLEMENT_DYNCREATE(GenerateIndexFile, CCObject)
00141 CC_IMPLEMENT_DYNCREATE(IndGenFileBuffer, CCObject)
00142 
00143 PORTNOTE("other", "Removed most of sgindgen.cpp" )
00144 #ifndef EXCLUDE_FROM_XARALX
00145 
00146 #define new CAM_DEBUG_NEW
00147 
00148 // Static initialisation
00149 
00150 // Preference setting saying whether thumbnail generation is required   
00151 #ifdef _DEBUG
00152 #ifdef _BATCHING
00153 BOOL GenerateIndexFile::CreateFontIndexes = TRUE;
00154 #else
00155 BOOL GenerateIndexFile::CreateFontIndexes = FALSE;
00156 #endif
00157 #else
00158 BOOL GenerateIndexFile::CreateFontIndexes = FALSE;
00159 #endif
00160 
00161 // Use old indexes and doc comments for index generation
00162 BOOL GenerateIndexFile::UseOldIndexes = TRUE;
00163 BOOL GenerateIndexFile::UseDocComments = TRUE;
00164 
00165 // Use automatic index update technology ?
00166 BOOL GenerateIndexFile::UseAutomaticUpdate = FALSE;
00167 
00168 // define this to add filenames without their extensions as default descriptions
00169 //#define FILENAME_AS_DEFAULT_DESCRIPTION
00170 
00171 // Display warnings unless told not to
00172 static BOOL QuietThumbnail = FALSE;
00173 
00174 // Keep doing index until told not to
00175 static BOOL StopIndGen = FALSE;
00176 
00177 static FilePos LastFoundItemInIndex = 0;
00178 
00179 // Tmp disk file for index ripping
00180 //CCDiskFile *TmpDiskFile = NULL;
00181 
00182 #endif
00183 
00184 /***********************************************************************************************
00185 
00186 >   GenerateIndexFile::GenerateIndexFile()
00187 
00188     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
00189     Created:    27/05/95
00190 
00191     Inputs:     
00192     Outputs:
00193     Returns:
00194 
00195     Purpose:    Variable initalising constructor
00196     Notes:
00197 
00198 ***********************************************************************************************/
00199 
00200 GenerateIndexFile::GenerateIndexFile()
00201 {
00202     LibType = SGLib_Blank;
00203     DoThumbnails = FALSE;
00204     Author = _T("");
00205     IndexFile = NULL;
00206     IndexCountOff = 0;
00207     hSearch = NULL;
00208     ID = 0;
00209     TotalFiles = 0;
00210     TmpIndexFile = NULL;
00211     OldIndexStart = 0;
00212     OldIndexDescriptionField = OldIndexKeywordField = OldIndexTitleField = 0;
00213     OldIndexOK = FALSE;
00214     OldIndexDescription = "";
00215 //  TmpDiskFile = NULL;
00216 }
00217 
00218 #if 0
00219 
00220 /***********************************************************************************************
00221 
00222 >   BOOL GenerateIndexFile::CloseSearchHandle(void);
00223 
00224     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
00225     Created:    09/04/95
00226 
00227     Inputs:     
00228     Outputs:
00229     Returns:    TRUE if things went ok.
00230 
00231     Purpose:    Close the search handle
00232     Notes:
00233 
00234 ***********************************************************************************************/
00235 
00236 BOOL GenerateIndexFile::CloseSearchHandle(void)
00237 {
00238     // Close the search handle
00239     if(hSearch != NULL) {
00240         if (!FindClose(hSearch)) {
00241             ERROR3("Couldn't close search handle.");
00242             return FALSE;
00243         }
00244         else
00245         {
00246             hSearch = NULL;
00247         }
00248     }
00249     return TRUE;
00250 }
00251     
00252 /***********************************************************************************************
00253 
00254 >   BOOL GenerateIndexFile::CloseIndexFileHandle(void);
00255 
00256     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
00257     Created:    09/04/95
00258 
00259     Inputs:     
00260     Outputs:
00261     Returns:    TRUE if things went ok.
00262 
00263     Purpose:    Close the file handle
00264     Notes:
00265 
00266 ***********************************************************************************************/
00267 
00268 BOOL GenerateIndexFile::CloseIndexFileHandle(void)
00269 {
00270     if(IndexFile != NULL)
00271     {
00272         IndexFile->close();
00273         delete IndexFile;
00274         IndexFile = NULL;
00275     }
00276     return TRUE;
00277 }
00278 
00279 
00280 /***********************************************************************************************
00281 
00282 >   static BOOL GenerateIndexFile::IsDirectoryReadOnly(PathName *Directory);
00283 
00284     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
00285     Created:    07/04/95
00286 
00287     Inputs:     Directory   - location of directory we're interested in (without trailing \)
00288     Outputs:
00289     Returns:    TRUE if things the specified directory is read only
00290 
00291     Purpose:    See Returns...
00292     Notes:
00293 
00294 ***********************************************************************************************/
00295 
00296 BOOL GenerateIndexFile::IsDirectoryReadOnly(PathName *Directory)
00297 {
00298     ERROR3IF(Directory == NULL, "GenerateIndexFile::IsDirectoryReadOnly given a NULL dir");
00299 
00300     String_256 ROPathStr(Directory->GetPath(TRUE));
00301     ROPathStr += TEXT("XaraInf");               // Read only check - not displayed, etc...
00302     PathName ROPath(ROPathStr);
00303     Error::ClearError();
00304 
00305     CCDiskFile ROFile(1024, FALSE, TRUE);
00306     BOOL ReadOnly = TRUE;
00307     BOOL CreatedFile = FALSE;
00308 
00309     // Exceptions here mean the directory is RO (or there was some other problem)
00310     TRY
00311     {
00312         CreatedFile = ROFile.open(ROPath, ios::out);
00313     }
00314         
00315     CATCH(CFileException, e)
00316     {
00317         // The directory with the files in is READ ONLY...
00318         ReadOnly = TRUE;
00319         Error::ClearError();
00320     }
00321     END_CATCH
00322 
00323     // Make sure that the files are closed and the memory is reclaimed properly...
00324     if (ROFile.isOpen())
00325         ROFile.close();
00326 
00327     if(CreatedFile)
00328     {
00329         SGLibOil::FileDelete(&ROPath);
00330         return FALSE;
00331     }
00332 
00333     return TRUE;
00334 }
00335 
00336 /***********************************************************************************************
00337 
00338 >   static BOOL GenerateIndexFile::CheckForRemote(PathName *FilesDirectory, String_256 *RemoteDirectory);
00339 
00340     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
00341     Created:    07/04/95
00342 
00343     Inputs:     FilesDirectory  - location of directory with files in, on read only media
00344     Outputs:    RemoteDirectory - location of existing indexed remote directory
00345     Returns:    TRUE if we found a remote index directory
00346 
00347     Purpose:    Given a directory on a CD (for example), check whether we've already done
00348                 a remote index for it or not... And return its location.
00349     Notes:
00350 
00351 ***********************************************************************************************/
00352 
00353 BOOL GenerateIndexFile::CheckForRemote(PathName *FilesDirectory, String_256 *RemoteDirectory)
00354 {
00355     ERROR3IF(FilesDirectory == NULL || RemoteDirectory == NULL, "GenerateIndexFile::CheckForRemote given NULL args");
00356 
00357     *RemoteDirectory = Library::RemoteIndexLocation;
00358     BOOL UseTmp = FALSE;
00359 
00360     if(RemoteDirectory->Length()==0)
00361         UseTmp = TRUE;
00362     else
00363     {
00364         PathName RemLocPath(*RemoteDirectory);
00365         if(!RemLocPath.IsValid() || !SGLibOil::FileExists(&RemLocPath) || IsDirectoryReadOnly(&RemLocPath))
00366             UseTmp = TRUE;
00367     }
00368 
00369     if(UseTmp)
00370     {
00371         TCHAR *OSTMP = _tgetenv("TEMP");
00372         if(OSTMP == NULL)
00373         {
00374             //PathName RemLocPath(*RemoteDirectory);
00375 
00376             // Check the specified remote directory isn't read only
00377             //if(IsDirectoryReadOnly(&RemLocPath) || RemLocPath)
00378             //{
00379             *RemoteDirectory = TEXT("");
00380             return FALSE;
00381             //}
00382         }
00383 
00384         camStrcpy((TCHAR *)*RemoteDirectory, OSTMP);
00385     }
00386 
00387     String_256 TmpDir(FilesDirectory->GetFileName(FALSE));
00388     String_256 FPath(FilesDirectory->GetPath());
00389 
00390     if(SGLibOil::IsRootDirectory(&FPath))
00391     {
00392 /*      String_256 Test("\\\\deepfried\\chicken");
00393         GiveMeAValidDirectoryName(&Test, &TmpDir);
00394         ERROR3_PF(("%s -> %s", (TCHAR *)Test, (TCHAR *)TmpDir));
00395 
00396         Test = "a:\\";
00397         GiveMeAValidDirectoryName(&Test, &TmpDir);
00398         ERROR3_PF(("%s -> %s", (TCHAR *)Test, (TCHAR *)TmpDir));
00399 
00400         Test = "\\fred\\fish";
00401         GiveMeAValidDirectoryName(&Test, &TmpDir);
00402         ERROR3_PF(("%s -> %s", (TCHAR *)Test, (TCHAR *)TmpDir));
00403 
00404         Test = "\\\\fred\\fish";
00405         GiveMeAValidDirectoryName(&Test, &TmpDir);
00406         ERROR3_PF(("%s -> %s", (TCHAR *)Test, (TCHAR *)TmpDir));
00407 
00408         Test = "\\\\fred\\fish\\fosh";
00409         GiveMeAValidDirectoryName(&Test, &TmpDir);
00410         ERROR3_PF(("%s -> %s", (TCHAR *)Test, (TCHAR *)TmpDir));
00411 
00412         Test = "x\\\\fred\\fish\\fosh";
00413         GiveMeAValidDirectoryName(&Test, &TmpDir);
00414         ERROR3_PF(("%s -> %s", (TCHAR *)Test, (TCHAR *)TmpDir));
00415 
00416         Test = "\\\\wibble";
00417         GiveMeAValidDirectoryName(&Test, &TmpDir);
00418         ERROR3_PF(("%s -> %s", (TCHAR *)Test, (TCHAR *)TmpDir));
00419 
00420         Test = "\\\\wibble\\";
00421         GiveMeAValidDirectoryName(&Test, &TmpDir);
00422         ERROR3_PF(("%s -> %s", (TCHAR *)Test, (TCHAR *)TmpDir));
00423 
00424         Test = "\\\\wibble\\\\";
00425         GiveMeAValidDirectoryName(&Test, &TmpDir);
00426         ERROR3_PF(("%s -> %s", (TCHAR *)Test, (TCHAR *)TmpDir));
00427 
00428         Test = "\\\\wibble\\ ";
00429         GiveMeAValidDirectoryName(&Test, &TmpDir);
00430         ERROR3_PF(("%s -> %s", (TCHAR *)Test, (TCHAR *)TmpDir));*/
00431 
00432         if(!GiveMeAValidDirectoryName(&FPath, &TmpDir))
00433             return FALSE;
00434     }
00435 
00436     // Well, we could do it, but it's a little nasty using temp\xarainfo aot temp\something\xarainfo
00437     if(TmpDir.Length() == 0)
00438         return FALSE;
00439 
00440     SGLibOil::AppendSlashIfNotPresent(RemoteDirectory);
00441     *RemoteDirectory += TmpDir;
00442 
00443     PathName RemLocPath(*RemoteDirectory);
00444     if(RemLocPath.IsValid() && SGLibOil::FileExists(&RemLocPath) && !IsDirectoryReadOnly(&RemLocPath))
00445         return TRUE;
00446     else
00447         return FALSE;
00448 }
00449 
00450 
00451 /***********************************************************************************************
00452 
00453 >   static BOOL GenerateIndexFile::GiveMeAValidDirectoryName(String_256 *Input, String_256 *Output)
00454 
00455     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
00456     Created:    20/02/96
00457 
00458     Inputs:     Input   - String of random characters -> "\\deepthought\fishcake", "a:\", "hg23~';e#y", etc
00459     Outputs:    Output  - String which could be used as a directory name -> "deepthou", "a", "hg23ey"
00460     Returns:    TRUE if things went ok, FALSE if no valid chars were found...
00461 
00462     Purpose:    Given a random string, construct a valid directory name from the string. This is
00463                 smashing if we want a directory name from a root directory, etc...
00464 
00465 ***********************************************************************************************/
00466 
00467 BOOL GenerateIndexFile::GiveMeAValidDirectoryName(String_256 *Input, String_256 *Output)
00468 {
00469     ERROR3IF(Input == NULL || Output == NULL, "GenerateIndexFile::GiveMeAValidDirectoryName given NULL params");
00470 
00471     if(Input == NULL || Output == NULL)
00472         return FALSE;
00473 
00474     INT32 Length = Input->Length();
00475     Output->Empty();
00476     INT32 StartIndex = 0;
00477 
00478     if(Input->Sub(String_8("\\\\")) == 0 && Input->CountChar('\\') > 2)
00479     {
00480         String_256 Tmp;
00481         Input->Right(&Tmp, Length - 2);
00482 
00483         // Tmp now holds string minus the \\ at the start, so we can get an index to the third \ in the string
00484         StartIndex = Tmp.Sub(String_8("\\")) + 2;
00485 
00486         if((Length - StartIndex) < 2)
00487             StartIndex = 0;
00488     }
00489 
00490     for(INT32 i = StartIndex; i <= Length; i++)
00491     {
00492         if(Output->Length() < 8)
00493         {
00494             if(iswalnum((*Input)[i])) // != '\\' && (*Input)[i] != ':')
00495                 *Output += TEXT((*Input)[i]); 
00496         }
00497     }
00498 
00499     if(Output->Length() > 0)
00500         return TRUE;
00501 
00502     return FALSE;
00503 }
00504 
00505 /***********************************************************************************************
00506 
00507 >   BOOL GenerateIndexFile::RemoteIndexSetup(PathName *FilesPath);
00508 
00509     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
00510     Created:    07/04/95
00511 
00512     Inputs:     
00513     Outputs:
00514     Returns:    TRUE if things went ok and we're using a remote index.
00515 
00516     Purpose:    Check with the user that it's ok to use a remote index, and find a sensible
00517                 location to put it.
00518     Notes:
00519 
00520 ***********************************************************************************************/
00521 
00522 BOOL GenerateIndexFile::RemoteIndexSetup(PathName *FilesPath)
00523 {
00524     ERROR3IF(FilesPath == NULL, "GenerateIndexFile::RemoteIndexSetup passed a null path");
00525 
00526     IndexIsRemote = FALSE;
00527     RemoteLocationOfIndex = "";
00528     RemoteLocationOfFiles = "";
00529 
00530     if(!Library::RemoteIndexes)
00531         return FALSE;
00532 
00533     BOOL Existing = CheckForRemote(FilesPath, &RemoteLocationOfIndex);
00534 
00535     if(RemoteLocationOfIndex.Length() == 0)
00536         return FALSE;
00537 
00538     // Only report this if the user hasn't already found the index for us...
00539     if(!SGLibOil::FileExists(&Index))
00540     {
00541         // "The chosen folder appears to be read only. Would you like to use '#1%s' for the index and thumbnail data? etc..."
00542         String_256 Msg;
00543         String_256 SmallLocation;
00544         RemoteLocationOfIndex.Left(&SmallLocation, 100);
00545         Msg.MakeMsg(_R(IDS_LIBRARY_CREATE_REMOTE), (TCHAR *)SmallLocation);
00546         Error::SetError(0, Msg, 0);
00547         INT32 ButtonPressed = InformWarning(0, _R(IDS_CREATE), _R(IDS_CANCEL));
00548         Error::ClearError();
00549 
00550         if(ButtonPressed != 1)
00551             return FALSE;
00552     }
00553 
00554     // Pathname for the index file -> c:\clipart\jobby\xarainfo
00555     PathName TmpPath(RemoteLocationOfIndex);
00556 
00557     if(!SGLibOil::FileExists(&TmpPath))
00558     {
00559         // Create the Xarainfo\.. directory
00560         if (!CreateDirectory((TCHAR *)RemoteLocationOfIndex, NULL))
00561         {
00562             DWORD err = GetLastError();     
00563             ERROR3("Can't create Tmp Index directory");
00564             return FALSE;
00565         }
00566     }
00567 
00568     IndexIsRemote = TRUE;
00569     SGLibOil::AppendSlashIfNotPresent(&RemoteLocationOfIndex);
00570     /*if(RemoteLocationOfIndex[RemoteLocationOfIndex.Length()-1] != '\\')
00571         RemoteLocationOfIndex += TEXT("\\");*/
00572     RemoteLocationOfIndex += String_16(_R(IDS_LIBRARIES_XARAINFO_DIRNAME));
00573     RemoteLocationOfFiles = FilesPath->GetPath(FALSE);
00574 
00575     return TRUE;
00576 }
00577 
00578 
00579 /***********************************************************************************************
00580 
00581 >   BOOL GenerateIndexFile::CreateIndexFile(void);
00582 
00583     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
00584     Created:    09/04/95
00585 
00586     Inputs:     
00587     Outputs:
00588     Returns:    TRUE if things went ok.
00589 
00590     Purpose:    Create the index file and keywords file then add headers to them                                                       
00591     Notes:
00592 
00593 ***********************************************************************************************/
00594 
00595 BOOL GenerateIndexFile::CreateIndexFile(void)
00596 {
00597     if(!GenerateIndexFile::CreateFontIndexes && LibType == SGLib_Font)
00598         return FALSE;
00599 
00600     String_256 XIPathStr;
00601 
00602     // Check that we have write access to the directory in question...
00603     if(IsDirectoryReadOnly(&LibPath))
00604     {
00605         // The directory with the files in is READ ONLY...
00606         Error::ClearError();
00607 
00608         if(RemoteIndexSetup(&LibPath))
00609         {
00610             XIPathStr = RemoteLocationOfIndex;
00611             IndexIsRemote = TRUE;
00612 
00613             String_256 NewIndex(RemoteLocationOfIndex);
00614             SGLibOil::AppendSlashIfNotPresent(&NewIndex);
00615             /*if(NewIndex[NewIndex.Length()-1] != '\\')
00616                 NewIndex += TEXT("\\");*/
00617             NewIndex += Index.GetFileName(TRUE);
00618 
00619             Index = NewIndex;
00620         }
00621         else
00622         {
00623             // Can't find a sensible temp directory, or remote indexes aren't enabled...
00624             // Tell the user that their media is read only...
00625             InformWarning(_R(IDS_READONLY_MEDIA), _R(IDS_OK));
00626             XIPathStr = LibPath.GetPath(TRUE);
00627             XIPathStr += String_16(_R(IDS_LIBRARIES_XARAINFO_DIRNAME));
00628             IndexIsRemote = FALSE;
00629         }
00630     }
00631     else
00632     {
00633         XIPathStr = LibPath.GetPath(TRUE);
00634         XIPathStr += String_16(_R(IDS_LIBRARIES_XARAINFO_DIRNAME));
00635         IndexIsRemote = FALSE;
00636     }
00637 
00638     /***********************************************************************************/
00639 
00640     // Pathname for the index file -> c:\clipart\jobby\xarainfo
00641     PathName XIPath(XIPathStr);
00642 
00643     if(!SGLibOil::FileExists(&XIPath))
00644     {
00645         // Create the Xarainfo directory
00646         if (!CreateDirectory((TCHAR *)XIPathStr, NULL))
00647         {
00648             DWORD err = GetLastError();     
00649             ERROR3("Can't create XaraInfo directory");
00650             return FALSE;
00651         }
00652     }
00653 
00654     // This should only be true if we've succesfully found an old index, scanned its header
00655     // and copied it to and index.bak file
00656     OldIndexOK = FALSE;
00657 
00658     // If there's already an index file there, make a backup...
00659     if(SGLibOil::FileExists(&Index) && GenerateIndexFile::UseOldIndexes)
00660     {
00661         TmpIndexFile = new PathName(Index); /*(String_256)"C:\\Xaraclip.BAK");*/
00662         if(TmpIndexFile != NULL)
00663         {
00664             TmpIndexFile->SetType("BAK");
00665             SGLibOil::FileCopy(&Index, TmpIndexFile);
00666 
00667             OldIndexOK = PrePassIndex(TmpIndexFile, &OldIndexStart, &OldIndexDescriptionField,
00668                             &OldIndexKeywordField, &OldIndexTitleField, &OldIndexDescription);
00669         }
00670     }
00671 
00672     IndexFile = new CCDiskFile(1024, TRUE, FALSE);
00673     if(IndexFile == NULL)
00674     {
00675         ERROR3("Null index file allocated");
00676         return FALSE;
00677     }
00678 
00679     if(!IndexFile->open(Index, ios::out))
00680     {
00681         TRACEUSER( "Richard", _T("Can't open index file"));
00682         delete IndexFile;
00683         IndexFile = NULL;
00684         return FALSE;
00685     }
00686 
00687     return TRUE;
00688 }
00689 
00690 /***********************************************************************************************
00691 
00692 >   BOOL GenerateIndexFile::DoIndexHeader(void);
00693 
00694     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
00695     Created:    09/04/95
00696 
00697     Inputs:     
00698     Outputs:
00699     Returns:    TRUE if things went ok.
00700 
00701     Purpose:    Add all the header data to an index file
00702     Notes:
00703 
00704 ***********************************************************************************************/
00705 
00706 BOOL GenerateIndexFile::DoIndexHeader(void)
00707 {
00708     String_256 Line(_R(IDS_LIBRARIES_INDEX_FILE_FOR));
00709     Line += LibPath.GetFileName();
00710     Line += TEXT("\r\n");
00711     AddLineToIndex(&Line);
00712 
00713 //  _stprintf(Line, "#\r\n# Entry count:\r\n");
00714 //  AddLineToIndex(&Line);
00715 
00716     IndexCountOff = IndexFile->tell();
00717 
00718     ID = 0;
00719     wsprintf(Line, "%05d", TotalFiles);
00720     Line += TEXT("\r\n");
00721     AddLineToIndex(&Line);
00722 
00723 //  _stprintf(Line, "# Synonym file:\r\nSynonyms.txt\r\n");
00724     Line = _R(IDS_LIBRARIES_SYNONYM_FILENAME);
00725     Line += TEXT("\r\n");
00726     AddLineToIndex(&Line);
00727 
00728 //  _stprintf(Line, "# Thumbnail sizes (Small, Medium, Large):\r\n");
00729 //  AddLineToIndex(&Line);
00730 
00731     // Fonts have weird thumbnail sizes
00732     if(LibType == SGLib_Font)
00733         Line = TEXT("28,16, 160,12, 180,26\r\n");
00734     else
00735         Line = TEXT("45,45, 130,64, 130,130\r\n");
00736 
00737 //      _stprintf(Line, "32,32, 64,64, 128,128\r\n");
00738 
00739     AddLineToIndex(&Line);
00740     
00741     // "Filename, Description, ID, Title, Key, Size\r\n"
00742     Line = String_16(_R(IDS_LIBRARIES_INDEX_ITEM_FILENAME));
00743     Line += TEXT(", ");
00744     Line += String_16(_R(IDS_LIBRARIES_INDEX_ITEM_DESC));
00745     Line += TEXT(", ");
00746     Line += String_16(_R(IDS_LIBRARIES_INDEX_ITEM_ID));
00747     Line += TEXT(", ");
00748     Line += String_16(_R(IDS_LIBRARIES_INDEX_ITEM_TITLE));
00749     Line += TEXT(", ");
00750     Line += String_16(_R(IDS_LIBRARIES_INDEX_ITEM_KEY));
00751     Line += TEXT(", ");
00752     Line += String_16(_R(IDS_LIBRARIES_INDEX_ITEM_SIZE));
00753     Line += TEXT("\r\n");
00754     AddLineToIndex(&Line);
00755 
00756     String_256 Description;
00757     if(OldIndexDescription.Length() == 0 || !GenerateIndexFile::UseOldIndexes)
00758     {
00759         String_256 TmpPath(LibPath.GetPath());
00760         LibraryFile::TidyUpSubPath(&TmpPath);
00761         TmpPath.Left(&Description, 60);
00762     }
00763     else
00764         Description = OldIndexDescription;  
00765 
00766     Line = TEXT("#");
00767     Line += String_16(_R(IDS_LIBRARIES_INDEX_DESCRITION)); // "#DESCRIPTION:"
00768     Line += TEXT(" ") + Description;
00769     Line += TEXT("\r\n");
00770     AddLineToIndex(&Line);
00771 
00772     if(IndexIsRemote)
00773     {
00774         Line = _R(IDS_LIBRARIES_INDEX_FILES);
00775         Line += TEXT(" ") + RemoteLocationOfFiles;
00776         Line += TEXT("\r\n");
00777         AddLineToIndex(&Line);
00778     }
00779 
00780     Line = _R(IDS_LIBRARIES_INDEX_START);
00781     Line += TEXT("\r\n");
00782     AddLineToIndex(&Line);
00783 
00784     return TRUE;
00785 }
00786 
00787 /***********************************************************************************************
00788 
00789 >   BOOL GenerateIndexFile::AddToSubLibrary(void);
00790 
00791     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
00792     Created:    09/04/95
00793 
00794     Inputs:     
00795     Outputs:
00796     Returns:    TRUE if things went ok.
00797 
00798     Purpose:    This little baby scans a directory for all the files we're expecting and adds
00799                 sensible dummy entries into the Index file...
00800     Notes:
00801 
00802 ***********************************************************************************************/
00803 
00804 BOOL GenerateIndexFile::AddToSubLibrary(void)
00805 {
00806     BOOL Problems = FALSE;
00807     INT32 Count = FileNameBuffer.ItemCount();
00808     INT32 i = 0;
00809 
00810     while(i < Count)
00811     {
00812         TCHAR *Item = FileNameBuffer.GetItem(i);
00813         i++;
00814 
00815         if(Item != NULL)
00816         {
00817             PathName FileToAdd(Item);
00818 
00819             if(!AddFile(&FileToAdd))
00820             {
00821                 ERROR3("Problems adding file to index or keyword file - or ESC pressed");
00822                 Problems = TRUE;
00823                 i = Count;
00824             }
00825         }
00826     }
00827 
00828     return !Problems;
00829 }
00830 
00831 /***********************************************************************************************
00832 
00833 >   INT32 GenerateIndexFile::CountValidFiles(void);
00834 
00835     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
00836     Created:    24/04/95
00837 
00838     Inputs:     
00839     Outputs:
00840     Returns:    Number of files that have 'add to index' potential for this type of library
00841 
00842     Purpose:    Counts what it returns
00843     Notes:
00844 
00845 ***********************************************************************************************/
00846 
00847 INT32 GenerateIndexFile::CountValidFiles(void)
00848 {
00849     // Progress bar for generation status
00850     String_64 Status(_R(IDS_LIBRARY_CREATION_SCANNING));
00851     BeginSlowJob(-1, FALSE, &Status);
00852 
00853     INT32 Count = 0;
00854     BOOL Counting = TRUE;
00855     BOOL Creating = FALSE;
00856     INT32 Pass = 0;
00857     BOOL ok = TRUE;
00858 
00859     String_256 FileSearch((const TCHAR *)LibPath.GetPath(TRUE));    
00860     FileSearch += TEXT("*.*");
00861 
00862     WIN32_FIND_DATA FileData;
00863     BOOL fFinished;
00864 
00865     // We go through the below code twice.
00866     // The first time we just count the number of files, so we know how big to make the
00867     // array for the second pass...
00868     do
00869     {
00870         Pass ++;
00871         Counting = (Pass == 1);
00872         Creating = (Pass == 2);
00873 
00874         fFinished = FALSE;
00875         hSearch = 0;
00876 
00877         // Start searching for files
00878         hSearch = FindFirstFile(FileSearch, &FileData);
00879         if (hSearch == INVALID_HANDLE_VALUE)
00880         {
00881             ERROR3("No valid files found in this directory");
00882             fFinished = TRUE;
00883         }
00884 
00885         while (!fFinished)
00886         {
00887             // Add full pathname to file
00888             String_256 FileToAddStr((const TCHAR *)LibPath.GetPath(TRUE));
00889             FileToAddStr += (TCHAR *)FileData.cFileName;
00890 
00891             // Only use normal files - not directories, hidden files, etc...
00892             DWORD FileAttributes = GetFileAttributes(FileToAddStr);
00893 
00894             if( ((FileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
00895                 (FileAttributes & FILE_ATTRIBUTE_HIDDEN) ||
00896                 (FileAttributes & FILE_ATTRIBUTE_SYSTEM)) == 0)
00897             {
00898                 PathName FileToAdd(FileToAddStr);
00899 
00900                 // Check if the file is addable to the index
00901                 if(IsFileType(&FileToAdd, LibType))
00902                 {
00903                     // First or second pass (first == counting files, second == adding files)
00904                     if(Counting)
00905                         Count ++;
00906 
00907                     // Second pass, allocate memory for string and add it into the buffer
00908                     if(Creating)
00909                         FileNameBuffer.AddItem((TCHAR *)FileToAddStr);
00910                 }
00911             }
00912         
00913             // Find the next file
00914             if (!FindNextFile(hSearch, &FileData))
00915                 fFinished = TRUE;
00916         }
00917 
00918         // Close the search handle
00919         if(!CloseSearchHandle())
00920             ERROR3("Couldn't close search handle.");
00921 
00922         if(Count != 0 && Counting)
00923         {
00924             ok = FileNameBuffer.Init(Count);
00925         }
00926 
00927         if(Count != 0 && Creating)
00928         {
00929             ok = FileNameBuffer.Sort();
00930         }
00931 
00932 
00933     } while(Count != 0 && Pass < 2 && ok);
00934 
00935     EndSlowJob();
00936     return Count;
00937 }
00938 
00939 #endif
00940 
00941 /***********************************************************************************************
00942 
00943 >   IndGenFileBuffer::IndGenFileBuffer()
00944 
00945     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
00946     Created:    15/05/95
00947 
00948     Inputs:
00949     Outputs:
00950     Returns:
00951 
00952     Purpose:    Constructor
00953     Notes:      Since MSDOS seems happy returning filenames of files in a directory in a
00954                 completely random fashion, we need to have some way of storing all the ones
00955                 it returns us and sorting them alphabetically, so we can generate index files
00956                 in a nice alphabetical order.
00957 
00958                 The data structure used below is basically an array of TCHAR *'s pointed to
00959                 by Buffer. These TCHAR *'s are CCMalloced and given variable length C style
00960                 strings by AddItem. The destructor handles the memory tidying up.
00961 
00962 ***********************************************************************************************/
00963 
00964 IndGenFileBuffer::IndGenFileBuffer()
00965 {
00966     Buffer = NULL;
00967     Items = 0;
00968     Position = 0;
00969 }
00970 
00971 /***********************************************************************************************
00972 
00973 >   IndGenFileBuffer::~IndGenFileBuffer()
00974 
00975     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
00976     Created:    15/05/95
00977 
00978     Inputs:
00979     Outputs:
00980     Returns:
00981 
00982     Purpose:    Destructor - frees all the memory
00983     Notes:
00984 
00985 ***********************************************************************************************/
00986 
00987 IndGenFileBuffer::~IndGenFileBuffer()
00988 {   
00989     if(Buffer != NULL)
00990     {
00991         for(INT32 i = 0; i<Items; i++)
00992         {
00993             if(Buffer[i] != NULL)
00994                 CCFree(Buffer[i]);
00995         }
00996 
00997         CCFree(Buffer);
00998         Buffer = NULL;
00999     }
01000 }
01001 
01002 #if 0
01003 
01004 /***********************************************************************************************
01005 
01006 >   BOOL IndGenFileBuffer::Init(INT32 Count)
01007 
01008     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
01009     Created:    15/05/95
01010 
01011     Inputs:     Count   - Number of files we're going to be adding
01012     Outputs:
01013     Returns:    TRUE if things went ok.
01014 
01015     Purpose:    Initialise the FileName Buffer system with a given number of entries
01016     Notes:
01017 
01018 ***********************************************************************************************/
01019 
01020 BOOL IndGenFileBuffer::Init(INT32 Count)
01021 {
01022     ERROR3IF(Buffer != NULL, "IndGenFileBuffer::Init called twice for same object");
01023 
01024     Items = Count;
01025     Buffer = (TCHAR **)CCMalloc(sizeof(TCHAR *) * Count);
01026 
01027     if(Buffer == NULL)
01028     {
01029         ERROR3("IndGenFileBuffer::Init failed to allocate buffer memory");
01030         Items = 0;
01031         return FALSE;
01032     }
01033 
01034     for(INT32 i = 0; i<Items; i++)
01035     {
01036         Buffer[i] = NULL;
01037     }   
01038 
01039     return TRUE;
01040 }
01041 
01042 /***********************************************************************************************
01043 
01044 >   BOOL IndGenFileBuffer::AddItem(INT32 Count)
01045 
01046     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
01047     Created:    15/05/95
01048 
01049     Inputs:     String  - pointer to null terminated string of TCHARS which we want to add
01050     Outputs:
01051     Returns:    TRUE if things went ok.
01052 
01053     Purpose:    Add a filename to the FileName buffer
01054     Notes:
01055 
01056 ***********************************************************************************************/
01057 
01058 BOOL IndGenFileBuffer::AddItem(TCHAR *String)
01059 {
01060     ERROR3IF(Items == 0, "IndGenFileBuffer::AddItem called without initialising first");
01061 
01062     if(Position >= Items)
01063     {
01064         ERROR3("IndGenFileBuffer::AddItem called too many times");
01065         return FALSE;
01066     }
01067 
01068     BOOL ok = FALSE;
01069 
01070     Buffer[Position] = (TCHAR *)CCMalloc((camStrlen(String) + 1) * sizeof(TCHAR));
01071     if(Buffer[Position] != NULL)
01072     {
01073         camStrcpy(Buffer[Position], String);
01074         ok = TRUE;
01075     }
01076 
01077     Position++;
01078 
01079     return ok;
01080 }
01081 
01082 /***********************************************************************************************
01083 
01084 >   BOOL IndGenFileBuffer::Sort(void)
01085 
01086     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
01087     Created:    15/05/95
01088 
01089     Inputs:
01090     Outputs:    
01091     Returns:    TRUE if the buffer was sorted ok
01092 
01093     Purpose:    Sort the strings pointed to by the buffer alphabetically
01094     Notes:
01095 
01096 ***********************************************************************************************/
01097 
01098 BOOL IndGenFileBuffer::Sort(void)
01099 {
01100     qsort(Buffer, Items, sizeof(TCHAR *), IndGenFileBuffer::SortComparator);
01101 
01102     return FALSE;
01103 }
01104 
01105 /********************************************************************************************
01106 
01107 >   static INT32 __cdecl IndGenFileBuffer::SortComparator(const void *Item1, const void *Item2)
01108 
01109     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
01110     Created:    15/5/95
01111 
01112     Inputs:     Item1, Item2 - the strings to be compared
01113 
01114     Returns:    a negative, zero, or positive result of comparing the strings
01115 
01116     Purpose:    'qsort' comparator function, used when sorting the file name buffer
01117 
01118     Notes:
01119 
01120 ********************************************************************************************/
01121 
01122 INT32 __cdecl IndGenFileBuffer::SortComparator(const void *Item1, const void *Item2)
01123 {
01124     if(Item1 == NULL || Item2 == NULL)
01125     {
01126         ERROR3("IndGenFileBuffer::SortComparator given null params");
01127         return 0;
01128     }
01129 
01130     TCHAR *String1 = *((TCHAR **)Item1);
01131     TCHAR *String2 = *((TCHAR **)Item2);
01132 
01133     // Sort by name - case insensitive - 'FRED' and 'fred' are equal...
01134     INT32 Value = CompareString(LOCALE_USER_DEFAULT,
01135         (NORM_IGNORECASE | NORM_IGNOREKANATYPE | NORM_IGNOREWIDTH),
01136         String1, -1, String2, -1);  // multi-locale supported compare routine
01137     Value -= 2;
01138 
01139     return(Value);
01140 }
01141 
01142 /***********************************************************************************************
01143 
01144 >   TCHAR *IndGenFileBuffer::GetItem(INT32 Count)
01145 
01146     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
01147     Created:    15/05/95
01148 
01149     Inputs:     Count   - position of item in buffer
01150     Outputs:    
01151     Returns:    Pointer to the string at offset 'Count'
01152 
01153     Purpose:    Return pointer to item at index 'Count'
01154     Notes:      This can return NULL, and will if the item hasn't been allocated properly...
01155 
01156 ***********************************************************************************************/
01157 
01158 TCHAR *IndGenFileBuffer::GetItem(INT32 Count)
01159 {
01160     ERROR3IF(Count > Position, "IndGenFileBuffer::GetItem given an index which hasn't been added yet");
01161 
01162     return Buffer[Count];
01163 }
01164 
01165 /***********************************************************************************************
01166 
01167 >   BOOL GenerateIndexFile::FixSubLibraryNumber(void);
01168 
01169     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
01170     Created:    09/04/95
01171 
01172     Inputs:
01173     Outputs:
01174     Returns:    TRUE if things went ok.
01175 
01176     Purpose:    Poke the count field with the correct value
01177     Notes:
01178 
01179 ***********************************************************************************************/
01180 
01181 BOOL GenerateIndexFile::FixSubLibraryNumber(void)
01182 {
01183     if(IndexFile && IndexCountOff)
01184     {
01185         IndexFile->seek(IndexCountOff);
01186         String_256 Line;
01187         wsprintf(Line, "%05d", ID);
01188         AddLineToIndex(&Line);
01189     }
01190     else
01191         return FALSE;
01192 
01193     return TRUE;
01194 }
01195 
01196 
01197 /***********************************************************************************************
01198 
01199 >   BOOL GenerateIndexFile::AddFile(PathName *FileName);
01200 
01201     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
01202     Created:    09/04/95
01203 
01204     Inputs:     FileName - name of file to add to index
01205     Outputs:
01206     Returns:    TRUE if things went ok.
01207 
01208     Purpose:    Add a file to the index
01209     Notes:
01210 
01211 ***********************************************************************************************/
01212 
01213 BOOL GenerateIndexFile::AddFile(PathName *FileName)
01214 {
01215     // Update progress bar & Line count
01216     if(!ContinueSlowJob(ID))
01217         return FALSE;
01218     ID++;
01219 
01220     TRACEUSER( "Richard", _T("Adding %s - ID %d to Index file\n"), (const TCHAR *)FileName->GetPath(), ID);
01221 
01222     // Get the file's size
01223     INT32 Size = (DWORD)SGLibOil::FileSize(FileName);
01224 
01225     // Default filename - force to lower case
01226     String_256 FName(FileName->GetFileName(TRUE));
01227     FName.toLower();
01228 
01229     // And capitalise the first character
01230     TCHAR First = camToupper(((TCHAR *)FName)[0]);
01231     ((TCHAR *)FName)[0] = First;
01232 
01233     // Default description - lowercase filename without file extension
01234     String_256 Description;
01235 
01236 #ifdef FILENAME_AS_DEFAULT_DESCRIPTION
01237     Description = FileName->GetFileName(FALSE);
01238     Description.toLower();
01239 
01240     // And capitalise the first character
01241     First = camToupper(((TCHAR *)Description)[0]);
01242     ((TCHAR *)Description)[0] = First;
01243 #endif
01244 
01245     // Default keywords - none
01246     String_256 Keywords("");
01247 
01248     // Default title - none
01249     String_256 Title("");
01250 
01251     BOOL FoundProperDescription = FALSE;
01252     
01253     // If it's a ttf font, rip out the name from the file
01254     if(LibType == SGLib_Font) {
01255 
01256         String_8 Ending(".");
01257         Ending += FileName->GetType();
01258         Ending.toLower();
01259         Ending += ";";
01260 
01261         if(Ending.Sub((String_8)".ttf;") != -1)
01262         {
01263             String_256 MenuName;
01264             if(RipTrueTypeNameFromFile(FileName, &MenuName))
01265             {
01266                 Description = MenuName;
01267                 FoundProperDescription = TRUE;
01268             }
01269         }
01270 
01271         if(Ending.Sub((String_8)".pfb;") != -1)
01272         {
01273             String_256 MenuName;
01274             BOOL Bold = FALSE;
01275             BOOL Italic = FALSE;
01276             if(RipATMNameFromFile(FileName, &MenuName, &Bold, &Italic))
01277             {
01278                 // Since this is going in the index, it would be silly to have a comma now wouldn't it ?
01279                 if(Bold || Italic) MenuName += ";";
01280                 if(Bold) MenuName += String_16(_R(IDS_FONTS_CAPITAL_BOLD));
01281                 if(Italic) MenuName += String_16(_R(IDS_FONTS_CAPITAL_ITALIC));
01282 
01283                 Description = MenuName;
01284                 FoundProperDescription = TRUE;
01285             }
01286         }
01287     }
01288 
01289     // If it's an art / eps file, rip out the comment block
01290     // NB: The function checks to see if it can handle the file type, no need to do it here...
01291     // We could also rip authors and keywords out possibly in the future...
01292     if((LibType == SGLib_ClipArt || LibType == SGLib_ClipArt_WebThemes) && !FoundProperDescription && GenerateIndexFile::UseDocComments)
01293     {
01294         String_256 OldDesc(Description);
01295         String_256 OldKeywords(Keywords);
01296         String_256 OldTitle(Title);
01297         if(RipDescriptionFromFile(FileName, &OldDesc, &OldKeywords, &OldTitle))
01298         {
01299             Description = OldDesc;
01300             Keywords = OldKeywords;
01301             Title = OldTitle;
01302             FoundProperDescription = TRUE;
01303         }
01304     }
01305 
01306     // If we haven't found a name yet, scan the tmp copy of the old index (if there was one)
01307     // Also get any old keywords found in the index for the item
01308     if(TmpIndexFile != NULL)
01309     {
01310 /*  if(!FoundProperDescription && TmpIndexFile != NULL && OldIndexOK && GenerateIndexFile::UseOldIndexes)
01311     { */ 
01312         String_256 OldDesc(Description);
01313         String_256 OldKeywords(Keywords);
01314         String_256 OldTitle(Title);
01315 
01316 /*      if(((LastFoundItemInIndex - 128) >      OldIndexStart) && RipDescriptionFromIndex(TmpIndexFile, FileName, LastFoundItemInIndex - 128, 
01317                 OldIndexDescriptionField, OldIndexKeywordField, OldIndexTitleField,
01318                 &OldDesc, &OldKeywords, &OldTitle))
01319         {
01320             Description = OldDesc;
01321             Keywords = OldKeywords;
01322             Title = OldTitle;
01323             FoundProperDescription = TRUE;
01324         }
01325         else
01326         {*/
01327             String_256 FN;
01328             FN = FileName->GetFileName();
01329     
01330             if(RipDescriptionFromIndex(TmpIndexFile, FileName, OldIndexStart, 
01331                     OldIndexDescriptionField, OldIndexKeywordField, OldIndexTitleField,
01332                     &OldDesc, &OldKeywords, &OldTitle))
01333             {
01334                 Description = OldDesc;
01335                 Keywords = OldKeywords;
01336                 Title = OldTitle;
01337                 FoundProperDescription = TRUE;
01338 
01339                 if(Description == Title)
01340                     Description = (String_256)"";
01341 
01342             }
01343             else
01344             {
01345 #ifdef _BATCHING
01346                 // If the entry for a .xar file isn't found in the index, check for a .art with
01347                 // the same name, and use that if found...
01348                 String_8 Ending(FileName->GetType());
01349                 Ending.toLower();
01350                 if(Ending.Sub((String_8)"xar") != -1)
01351                 {
01352                     PathName NewFileName(*FileName);
01353                     NewFileName.SetType("ART");
01354                 
01355                     if(RipDescriptionFromIndex(TmpIndexFile, &NewFileName, OldIndexStart, 
01356                             OldIndexDescriptionField, OldIndexKeywordField, OldIndexTitleField,
01357                             &OldDesc, &OldKeywords, &OldTitle))
01358                     {
01359                         Description = OldDesc;
01360                         Keywords = OldKeywords;
01361                         Title = OldTitle;
01362                         FoundProperDescription = TRUE;
01363 
01364                         if(Description == Title)
01365                             Description = (String_256)"";
01366                     }
01367                 }
01368 #endif
01369                 //ERROR3("Couldn't find title\keywords for '%s'", (TCHAR *)FN);
01370             }
01371     //  }
01372 /*      if(Keywords.Length() == 0)
01373         {
01374             String_256 WarnMsg;
01375             _stprintf(WarnMsg, "Couldn't find keywords for '%s'", (TCHAR *)FN);
01376             ERROR3(WarnMsg);
01377         }*/
01378     }
01379 
01380 
01381 
01382     // Matt 04/01/2001 - Removing the filename shortening for clipart /web themes gallery index creation code...
01383     // When it shortens a filename to the 8.3 format, the file can no longer be found as it was left with the original INT32 name
01384     // The comment below appears unfounded, 'CreateProcess' is not called within Xara... Also, checked (with Derek's help!) for instances of
01385     // ShellExecute(), thread spawning calls and system calls which may use the INT32 filename incorrectly - couldn't find any...
01386     /*
01387 
01388   //String_256 ShortPath(FName);
01389     String_256 ShortPath(FileName->GetPath());
01390 
01391     // Make the path into its "short form", ie. 8.3 MS-DOS compatible.  This is necessary
01392     // as Windows NT doesn't like paths with spaces, even though it allows them (eg.
01393     // CreateProcess will fail when parsing the image path / command line).
01394 #ifdef _DEBUG
01395     ERROR3IF(!MakeShortPath((TCHAR *)ShortPath, _MAX_PATH), "MakeShortPath failed in SGIndGen");
01396 #else
01397     MakeShortPath((TCHAR *)ShortPath, _MAX_PATH);
01398 #endif
01399 
01400 
01401     // Get a filename from a full path string...
01402     PathName SrtPath(ShortPath);
01403     ShortPath = SrtPath.GetFileName(TRUE);
01404 
01405     // If we're using a short filename for the filename, and haven't got a title yet,
01406     // use the full filename as the title 
01407     if(Title.Length() == 0)
01408     {
01409         String_256 ShortPathU(ShortPath);
01410         String_256 LongPathU(FName);
01411         ShortPathU.toUpper();
01412         LongPathU.toUpper();
01413 
01414         if(ShortPathU != LongPathU)
01415         {
01416             Title = FName;
01417         }
01418     }
01419 */
01420 
01421     // Just so we don't get any spurious commas...
01422     if(Description.Length() != 0)
01423         ReplaceCharacters(&Description, ',', ';');
01424 
01425     if(Title.Length() != 0)
01426         ReplaceCharacters(&Title, ',', ';');
01427 
01428     if(Keywords.Length() != 0)
01429         ReplaceCharacters(&Keywords, ',', ';');
01430     
01431     String_256 Line;
01432     wsprintf(Line, "%s, %s, %d, %s, %s, %d\r\n", (TCHAR *)/*ShortPath*/FName, (TCHAR *)Description,
01433                                         ID, (TCHAR *)Title, (TCHAR *)Keywords, Size/*, (TCHAR *)Author*/);
01434     AddLineToIndex(&Line);
01435 
01436     if( DoThumbnails )
01437         CreateThumbnails(FileName, TRUE);
01438 
01439     if(StopIndGen)
01440         return FALSE;
01441 
01442     return TRUE;
01443 }
01444 
01445 /***********************************************************************************************
01446 
01447 >   static BOOL GenerateIndexFile::IsFileType(PathName *FileName, const SGLibType Type);
01448 
01449     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
01450     Created:    09/04/95
01451 
01452     Inputs:     FileName - filename and path of file
01453                 Type - type of library
01454     Outputs:
01455     Returns:    TRUE or FALSE
01456 
01457     Purpose:    Return true if a file should be associated with the index
01458     Notes:
01459 
01460 ***********************************************************************************************/
01461 
01462 BOOL GenerateIndexFile::IsFileType(PathName *FileName, const SGLibType Type)
01463 {
01464 
01465     String_8 Ending(".");
01466     Ending += FileName->GetType();
01467     Ending.toLower();
01468     Ending += ";";
01469 
01470     // Ending now has the format '.art;' or whatever
01471 
01472     switch(Type) {
01473         case SGLib_Font:
01474             // Include straight truetype fonts
01475             if(Ending.Sub((String_8)".ttf;") != -1) return TRUE;
01476             
01477             // Also include ATM fonts, but check all the required files are present first
01478             if(Ending.Sub((String_8)".pfb;") != -1)
01479             {   
01480                 PathName TmpFile(*FileName);
01481                 TmpFile.SetType((String_8)"pfm");
01482                 BOOL PFM = SGLibOil::FileExists(&TmpFile);
01483                 TmpFile.SetType((String_8)"afm");
01484                 BOOL AFM = SGLibOil::FileExists(&TmpFile);
01485                 if(PFM && AFM)
01486                     return TRUE;
01487             }
01488             break;
01489 
01490         case SGLib_ClipArt:
01491         case SGLib_ClipArt_WebThemes:
01492             {
01493                 // Speed optimisation for native files
01494                 if( (Ending.Sub((String_8)".art;") != -1)
01495                     || (Ending.Sub((String_8)".xar;") != -1)
01496                     || (Ending.Sub((String_8)".cxn;") != -1)
01497                     || (Ending.Sub((String_8)".cxw;") != -1)
01498                     || (Ending.Sub((String_8)".web;") != -1) )
01499                     return TRUE;
01500 
01501                 // Whizz through all the filters checking if the given file has a standard filter extension
01502                 Filter *pFilter = Filter::GetFirst();
01503 
01504                 while (pFilter != NULL)
01505                 {
01506                     FilterFlags Flags = pFilter->GetFlags();
01507 
01508                     if ( Flags.CanImport && Flags.ShowFilter )
01509                     {
01510                         // Get the filter string... and compare it with the ending                      
01511                         // Note this has the format 'xara studio document|*.art;*.eps'
01512                         // Adding a ';' to the end means we can check an ending of the form '.art;' with the
01513                         // line and it won't return matches for stuff like 'o' files...
01514                         String_256 FilterString(pFilter->pOILFilter->ConstructFilterString());
01515                         FilterString.toLower();
01516                         FilterString += ";";
01517 
01518                         if(FilterString.Sub(Ending) != -1)
01519                             return TRUE;
01520                     }
01521 
01522                     // Try the next filter
01523                     pFilter = Filter::GetNext(pFilter);
01524                 }
01525 
01526                 // This causes random problems later on !
01527                 /*  PathName TmpPath(*FileName);
01528                     INT32 f = AccusoftFilters::GetTypeOfFile(TmpPath);          
01529                     if (f > -1 )
01530                         return TRUE;
01531                 */
01532 
01533             }
01534             break;
01535 
01536         case SGLib_Texture:
01537         case SGLib_Bitmap:
01538             {
01539                 Filter *pFilter = Filter::GetFirst();
01540                 while (pFilter != NULL)
01541                 {
01542                     FilterFlags Flags = pFilter->GetFlags();
01543 
01544                     if ( Flags.CanImport && Flags.ShowFilter && pFilter->IS_KIND_OF(BitmapFilter))
01545                     {
01546                         // Get the filter string... and compare it with the ending                      
01547                         // Note this has the format 'xara studio document|*.art;*.eps'
01548                         // Adding a ';' to the end means we can check an ending of the form '.art;' with the
01549                         // line and it won't return matches for stuff like 'o' files...
01550                         String_256 FilterString(pFilter->pOILFilter->ConstructFilterString());
01551                         FilterString.toLower();
01552                         FilterString += ";";
01553 
01554                         if(FilterString.Sub(Ending) != -1)
01555                             return TRUE;
01556                     }
01557 
01558                     // Try the next filter
01559                     pFilter = Filter::GetNext(pFilter);
01560                 }
01561             }
01562             break;
01563 
01564         case SGLib_Blank:
01565             return TRUE;
01566 
01567         case SGLib_Fractal:
01568         case SGLib_Colour:
01569         default:
01570             break;
01571     }
01572 
01573     return FALSE;
01574 }
01575 
01576 /***********************************************************************************************
01577 
01578 >   INT8 GenerateIndexFile::GetShort(FILE *fp);
01579 
01580     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
01581     Created:    09/04/95
01582 
01583     Inputs:     Pointer to file location
01584     Outputs:
01585     Returns:    16bit value
01586 
01587     Purpose:    Get a 16bit value from the file
01588     Notes:
01589 
01590 ***********************************************************************************************/
01591 
01592 INT8 GenerateIndexFile::GetShort(FILE *fp)
01593 {
01594     INT8 ret;
01595     ret = (_gettc(fp) << 8);
01596     ret += _gettc(fp);
01597     return ret;
01598 }
01599 
01600 /***********************************************************************************************
01601 
01602 >   INT8 GenerateIndexFile::GetFixed(FILE *fp);
01603 
01604     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
01605     Created:    09/04/95
01606 
01607     Inputs:     File pointer for file
01608     Outputs:
01609     Returns:    The short
01610 
01611     Purpose:    Return the integer part of a 16.16 fixed only
01612     Notes:
01613 
01614 ***********************************************************************************************/
01615 
01616 INT8 GenerateIndexFile::GetFixed(FILE *fp)
01617 {
01618     INT8 ret;
01619     ret = (_gettc(fp) << 8);
01620     ret += _gettc(fp);
01621     _gettc(fp);
01622     _gettc(fp);
01623     return ret;
01624 }
01625 
01626 /***********************************************************************************************
01627 
01628 >   INT32 GenerateIndexFile::GetLONG(FILE *fp);
01629 
01630     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
01631     Created:    09/04/95
01632 
01633     Inputs:     A file pointer
01634     Outputs:
01635     Returns:    The 32bit INT32 value
01636 
01637     Purpose:    Return a full 32 bit number from a file
01638     Notes:
01639 
01640 ***********************************************************************************************/
01641 
01642 INT32 GenerateIndexFile::GetLONG(FILE *fp)
01643 {
01644     INT32 ret;
01645     ret = (_gettc(fp) << 24);
01646     ret |= (_gettc(fp) << 16);
01647     ret |= (_gettc(fp) << 8);
01648     ret |= (_gettc(fp));
01649     return ret;
01650 }       
01651 
01652 
01653 /***********************************************************************************************
01654 
01655 >   BOOL GenerateIndexFile::RipTrueTypeNameFromFile(PathName *FileName, String_256 *RetName);
01656 
01657     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
01658     Created:    09/04/95
01659 
01660     Inputs:     FileName - filename and path of ttf file
01661                 RetName - returns the truetype name, as found in the file
01662     Outputs:
01663     Returns:    TRUE if things went ok.
01664 
01665     Purpose:    Rip out the full typeface name from a font file
01666 
01667     Notes:      This is a bit of a desperate hack, and I'm not totally sure it will work
01668                 with all flavours of TTF file. However, it's worked on all the ones I've
01669                 tried it with.
01670 
01671                 As an aside... There's a call 'GetTypeFaceNameFromTTF(FileName, Name, 64)'
01672                 documented in MSDN as in the MS setup suite. Indeed it even appears in the
01673                 header file, but it seems to be missing from their DLL. If this ever reappears
01674                 somewhere, probably best to replace the code below with a proper call !
01675 
01676 ***********************************************************************************************/
01677 
01678 BOOL GenerateIndexFile::RipTrueTypeNameFromFile(PathName *FileName, String_256 *RetName)
01679 {
01680 #ifdef _DEBUG
01681 
01682     if(FileName == NULL || RetName == NULL)
01683     {
01684         ERROR3("GenerateIndexFile::RipTrueTypeNameFromFile given null params - bad !");
01685         return FALSE;
01686     }
01687 
01688     BOOL ok=TRUE;
01689     BOOL found = FALSE;
01690         
01691     FILE *file = NULL;
01692                            
01693     file = _tfopen((const TCHAR *)FileName->GetPath(), "rb");
01694     if(file) {
01695 
01696         /**********************/
01697 
01698         INT8 version =  GetFixed(file);
01699         UINT8 NumTables = GetShort(file);
01700 
01701         GetShort(file);
01702         GetShort(file);
01703         GetShort(file);  
01704 
01705         /**********************/
01706 
01707         TCHAR tag[8] = "";
01708         static INT32 checksum = 0;
01709         static INT32 Noffset = 0;
01710         static INT32 length = 0;
01711 
01712         static INT32 NameOffset = 0;
01713         
01714         INT32 i;
01715                      
01716         for(i=1; i<=NumTables; i++) {
01717 
01718             //fread(tag, sizeof(char), 4, file);
01719 
01720             tag[0]      = _gettc(file);
01721             tag[1]      = _gettc(file);
01722             tag[2]      = _gettc(file);
01723             tag[3]      = _gettc(file);
01724             tag[4]      = 0;
01725             
01726             checksum    = GetLONG(file);
01727             Noffset     = GetLONG(file);
01728             length      = GetLONG(file);
01729 
01730             if(feof(file)) {
01731                 DWORD Z = GetLastError();
01732                 ERROR3("eof returned in ttf file");
01733             }
01734 
01735             // name
01736             if(!(camStrcmp(tag,"name"))) {
01737                 NameOffset = Noffset;
01738             } 
01739             
01740         }
01741 
01742         /**********************/
01743 
01744         // OK, so we've looked through all the tags, now decode the name block
01745         if(NameOffset != 0) {
01746 
01747             if(fseek(file, NameOffset, SEEK_SET)) {
01748                 ERROR3("Can't find TTF name table");
01749                 fclose(file);
01750                 return FALSE;
01751             }
01752 
01753             UINT8 FormatSelect = GetShort(file);
01754             UINT8 NumRecords   = GetShort(file);
01755             UINT8 StringStore  = GetShort(file);
01756 
01757             UINT8 PlatformID;
01758             UINT8 PlatformSpecID;
01759             UINT8 LangID;
01760             UINT8 NameID;
01761             UINT8 StrLen;
01762             UINT8 StrOff;
01763 
01764             UINT8 family_strlen = 0;
01765             UINT8 family_stroff = 0;
01766 
01767             for(i=1; i<=NumRecords; i++) {
01768                     
01769                 PlatformID      = GetShort(file);
01770                 PlatformSpecID  = GetShort(file);
01771                 LangID          = GetShort(file);
01772                 NameID          = GetShort(file);
01773                 StrLen          = GetShort(file);
01774                 StrOff          = GetShort(file);
01775 
01776                 // Currently we only bother with the Macintosh name, as it's in ASCII not UNICODE !
01777                 if(NameID == 4 && PlatformID == 1) {
01778 
01779                 //  printf("We've got a family name\n");
01780 
01781                     family_strlen = StrLen;
01782                     family_stroff = StrOff;
01783                 
01784                     fpos_t pos;
01785 
01786                     fgetpos(file, &pos);
01787                     if(fseek(file, family_stroff + StringStore + NameOffset, SEEK_SET)) {
01788                     
01789                         ERROR3("String in name table past end of file in TTF file.");
01790                     
01791                     } else { 
01792 
01793                         if(family_strlen >= 255) family_strlen = 255-1;
01794 
01795                         TCHAR Name[255];
01796 
01797                         // Get typeface name from file - +1 for the terminator...
01798                         _fgetts(Name, family_strlen+1, file);
01799                         found = TRUE;
01800 
01801                         camStrcpy((TCHAR *)*RetName, Name);
01802                 
01803                         TRACEUSER( "Richard", _T("Font name = %s\n"), Name);
01804                         TRACEUSER( "Richard", _T("PlatID %d, SpecID %d, LangID %d\n"), PlatformID, PlatformSpecID, LangID);
01805                     }
01806                     fsetpos(file, &pos);                         
01807                 }
01808             }
01809 
01810             if(!found)
01811                 ERROR3("Can't find TTF family name");
01812 
01813         }
01814 
01815         /**********************/
01816 
01817         fclose(file);
01818     }
01819                    
01820     return found;
01821 
01822 #endif
01823 
01824     return TRUE;
01825 }
01826 
01827 /***********************************************************************************************
01828 
01829 >   BOOL GenerateIndexFile::RipATMNameFromFile(PathName *FileName, String_256 *RetName, BOOL *Bold, BOOL *Italic);
01830 
01831     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
01832     Created:    07/10/95
01833 
01834     Inputs:     FileName    - filename and path of pfm/pfb files
01835     Outputs:    RetName     - returns the typeface name, as should be displayed in menus...
01836                 Bold        - true if the file is bold
01837                 Italic      - true if the file is italic
01838     Returns:    TRUE if things went ok.
01839 
01840     Purpose:    Rip out the ATM name to display in a menu for a given set of pfb/pfm files. Also
01841                 aquire the bold / italic status of the files...
01842 
01843     Notes:      As with the TTF function, this is a bit of a desperate hack, and I'm not totally
01844                 sure it will work with all flavours of ATM file. However, it's worked on all the
01845                 ones I've tried it with.
01846 
01847 ***********************************************************************************************/
01848 
01849 BOOL GenerateIndexFile::RipATMNameFromFile(PathName *FileName, String_256 *RetName, BOOL *Bold, BOOL *Italic)
01850 {
01851 #ifdef _DEBUG
01852 
01853     ERROR3IF(FileName == NULL || RetName == NULL || Bold == NULL || Italic == NULL, "Null params given to ATM ripper");
01854 
01855     // The basic idea behind doing this is to scan the pfm file for 'PostScript<0>', use the next
01856     // bit as the menu name, then check the last bit for flags...
01857     //          PostScript<0>Aldine401 BT<0>Aldine401BT-BoldA<0>
01858 
01859     BOOL ok = TRUE;
01860 
01861     *RetName = TEXT("");
01862     *Bold = FALSE;
01863     *Italic = FALSE;
01864 
01865     PathName PFMPath(*FileName);
01866     PFMPath.SetType((String_8)"PFM");
01867 
01868     if(!SGLibOil::FileExists(&PFMPath))
01869     {
01870         ERROR3("Can't find PFM file");
01871         return FALSE;
01872     }
01873 
01874     CCDiskFile PFMFile(1024, FALSE, TRUE);
01875 
01876     TRY
01877     {
01878         // Open the xxx.pfm file
01879         ok = PFMFile.open(PFMPath, ios::in | ios::nocreate | ios::binary);
01880     }   
01881             
01882     CATCH(CFileException, e)
01883     {
01884         Error::ClearError();
01885         return FALSE;
01886     }
01887     END_CATCH
01888 
01889     FilePos Position = 100; //199;
01890     BOOL FoundPostScript = FALSE;
01891     PFMFile.seekIn(Position);
01892         
01893     TRY
01894     {
01895         // Keep looping through the file until we hit the end...
01896         while(!PFMFile.eof() && !FoundPostScript)
01897         {
01898 
01899             DWORD Buffer[256];
01900             memset(Buffer, 0, 256 * 4);
01901             PFMFile.seekIn(Position);
01902 
01903             if(!FoundPostScript)
01904             {
01905                 PFMFile.read((void *)Buffer, 11);
01906 
01907                 if(!camStrcmp(((TCHAR *)Buffer) , "PostScript"))    // Debug
01908                 {
01909 //                  ERROR3("Found postscript");
01910                     FoundPostScript = TRUE;
01911                     
01912                     TCHAR Typeface[256];
01913                     INT32 Count = 0;
01914 
01915                     do {
01916                         PFMFile.read((void *)Buffer, 1);
01917                         Typeface[Count] = ((TCHAR *)Buffer)[0];
01918                     } while(Typeface[Count++] != 0 && !PFMFile.eof());
01919 
01920                     TCHAR Styles[256];
01921                     Count = 0;
01922 
01923                     do {
01924                         PFMFile.read((void *)Buffer, 1);
01925                         Styles[Count] = ((TCHAR *)Buffer)[0];
01926                     } while(Styles[Count++] != 0 && !PFMFile.eof());
01927 
01928                     String_256 StyleStr;
01929                     StyleStr = (TCHAR *)Styles;
01930 
01931                     // ALL BELOW STRINGS ARE DEBUG ONLY...
01932 
01933                     // Major bodge here... If light, but medium, then we're bold... Erm... got that ? No ? Me neither !
01934                     if(StyleStr.Sub((String_8)"-Medium") != -1)
01935                     {
01936                         String_256 TypeString(Typeface);
01937                         if(TypeString.Sub((String_8)"Lt") != -1)
01938                             *Bold = TRUE;
01939                     }
01940 
01941                     if( StyleStr.Sub((String_8)"-Bold") != -1
01942                         || StyleStr.Sub((String_8)"-Semi") != -1
01943                         || StyleStr.Sub((String_8)"-Black") != -1
01944                         || StyleStr.Sub((String_8)"-Demi") != -1
01945                         || StyleStr.Sub((String_8)"-Heavy") != -1)
01946                         *Bold = TRUE;
01947 
01948                     // Some names seem to get truncated randomly if BOLDITALIC...
01949                     if( StyleStr.Sub((String_8)"Ital") != -1
01950                         || StyleStr.Sub((String_8)"BoldIt") != -1
01951                         || StyleStr.Sub((String_8)"DemiIt") != -1
01952                         || StyleStr.Sub((String_8)"SemiIt") != -1
01953                         || StyleStr.Sub((String_8)"HeavyIt") != -1
01954                         || StyleStr.Sub((String_8)"BlackIt") != -1)
01955                         *Italic = TRUE;
01956 
01957                     StyleStr = (TCHAR *)Typeface;
01958                     *RetName = StyleStr;
01959 
01960                     // Now hack out the rest
01961                 }
01962             }
01963 
01964             Position ++;
01965         }
01966     }
01967 
01968     // See if there was a file io error
01969     CATCH(CFileException, e)
01970     {
01971         // Something rather unhelpful has taken place, or we've reached the end of the file......
01972         ok = FALSE;
01973 
01974         // remove any errors
01975         Error::ClearError();
01976     }
01977     END_CATCH
01978 
01979     // Make sure that the files are closed and the memory is reclaimed properly...
01980     TRY
01981     {
01982         if (PFMFile.isOpen())
01983             PFMFile.close();
01984     }
01985     CATCH(CFileException, e)
01986     {
01987         // Failed to close the files - not much we can do about it really
01988         Error::ClearError();
01989     }
01990     END_CATCH
01991 
01992 
01993 #endif
01994 
01995     return TRUE;
01996 }
01997 
01998 /***********************************************************************************************
01999 
02000 >   static BOOL GenerateIndexFile::PreCreateThumbnail(PathName *InFile);
02001 
02002     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
02003     Created:    06/09/96
02004 
02005     Inputs:     InFile  - Input path and filename
02006     Outputs:
02007     Returns:    TRUE if we can generate a thumbnail without exploding.
02008 
02009     Purpose:    This will check that creating the thumbnail won't cause us to go BANG !
02010         
02011                 Currently if you give Accusoft a 32BPP thumbnail, all hell breaks loose on win95
02012 
02013 ***********************************************************************************************/
02014 
02015 BOOL GenerateIndexFile::PreCreateThumbnail(PathName *InFile)
02016 {
02017     if(InFile == NULL)
02018         return FALSE;
02019 
02020     String_8 Ending(InFile->GetType());
02021     Ending.toLower();
02022 
02023     // Check for nonstandard bmp bpps
02024     if(Ending.Sub((String_8)"bmp") != -1)
02025     {
02026         BOOL NiceHappyBpp = FALSE;
02027 
02028         FILE *pFile = fopen((const TCHAR *)InFile->GetPath(), "rb");
02029         if(pFile)
02030         {
02031             INT32 b = fgetc(pFile);
02032             INT32 m = fgetc(pFile);
02033 
02034             // Check file header really is a bmp file
02035             if(b == 'B' && m == 'M')
02036             {
02037                 DWORD BppOffset = sizeof(BITMAPFILEHEADER) + 4 + 4 + 4 + 2;
02038                 
02039                 if(!fseek(pFile, BppOffset, SEEK_SET))
02040                 {
02041                     INT32 bpp = fgetc(pFile);
02042                     bpp += (fgetc(pFile) << 8);
02043 
02044                     // These are the formats Accusoft support...
02045                     if(bpp == 1 || bpp == 4 || bpp == 8 || bpp == 24)
02046                         NiceHappyBpp = TRUE;
02047                 }
02048             }
02049             fclose(pFile);
02050         }
02051         return NiceHappyBpp;
02052     }
02053 
02054     return TRUE;
02055 }
02056 
02057 
02058 /***********************************************************************************************
02059 
02060 >   BOOL GenerateIndexFile::CreateThumbnail(PathName *InFile, PathName *OutFile, UINT8 XSize, UINT8 YSize);
02061 
02062     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
02063     Created:    09/04/95
02064 
02065     Inputs:     InFile  - Input path and filename
02066                 OutFile - Output path and filename
02067                 XSize   - Width of rectangle to scale image to
02068                 YSize   - Height of rectangle to scale image to
02069     Outputs:
02070     Returns:    TRUE if things went ok.
02071 
02072     Purpose:    Given an input filename and output filename, generate a thumbnail to fit in the
02073                 rectangle described.
02074                 
02075     Notes:      Aspect ratio is maintained, and the output thumbnail is guaranteed not to exeed the
02076                 dimensions given...
02077 
02078 ***********************************************************************************************/
02079 
02080 BOOL GenerateIndexFile::CreateThumbnail(PathName *InFile, PathName *OutFile, UINT8 XSize, UINT8 YSize)
02081 {
02082     // We can't generate font thumbnails yet
02083     if(LibType == SGLib_Font)
02084         return FALSE;
02085 
02086     // Now you're just being silly...
02087     if(XSize == 0 || YSize == 0)
02088         return FALSE;
02089 
02090     // Pre explosion check
02091     if(!PreCreateThumbnail(InFile))
02092         return FALSE;
02093 
02094 //#ifdef WEBSTER
02095 
02096     // create a disk file
02097     CCDiskFile TempDiskFile(1024, FALSE, TRUE);
02098     
02099     // open it for reading
02100     BOOL ok = TempDiskFile.open(*InFile, ios::in | ios::binary);
02101 
02102     // Make sure we have a generic filter!
02103     GenericFilter *pGenericFilter = Filter::GetGenericFilter();
02104     if (ok) ok = (pGenericFilter != NULL);
02105     if (ok)
02106     {
02107         // import the file into a kernel bitmap
02108 
02109         // remember the file size
02110         UINT32 FileSize = TempDiskFile.Size();
02111 
02112         // find the best filter for the import
02113         Filter *pImportFilter = pGenericFilter->GetBestFilter(&TempDiskFile);
02114     
02115         if (pImportFilter == NULL) 
02116             return FALSE;  // no filter capable of importing the file
02117         
02118         // Find the png thumbnail filter for export
02119         Filter *pFilter = Filter::GetFirst();
02120         while (pFilter != NULL)
02121         {
02122             if (IS_A(pFilter,ThumbnailFilterPNG))
02123                 // This is the filter!
02124                 break;
02125 
02126             // Try the next filter
02127             pFilter = Filter::GetNext(pFilter);
02128         }
02129 
02130         if (pFilter == NULL)
02131             return FALSE;  // filter not found
02132 
02133         // get the bitmap filter
02134         ThumbnailFilterPNG *pPNGFilter = (ThumbnailFilterPNG *)pFilter;
02135         
02136         INT32 PixelSize = 72000 / 96;   // Size of output pixel in millipoints
02137 
02138         // remember the preview size
02139         INT32 OldPreviewSize = PreviewFilter::PreviewBitmapSize;
02140         
02141         // Set the Preview to be just over an inch accross
02142         PreviewFilter::PreviewBitmapSize = (XSize > YSize ? XSize : YSize) * PixelSize;
02143 
02144         // remember the current and the selected documents
02145         Document *pOldCurrent = Document::GetCurrent();
02146         Document *pOldSelected = Document::GetSelected();
02147         
02148         // create a new document, needed for the bitmap import
02149         Document *pDoc = new Document(TRUE);
02150         if (pDoc == NULL)
02151             ok = FALSE;
02152         else
02153         {
02154             pDoc->Init(0);
02155 
02156             // create an operation (for the export)
02157             SelOperation *pOp = new SelOperation;
02158             if (pOp == NULL)
02159                 ok = FALSE;
02160             else
02161             {
02162                 // set our document as selected
02163                 Document::SetSelectedViewAndSpread(pDoc, NULL, pDoc->FindFirstSpread());
02164 
02165                 if (pImportFilter->IS_KIND_OF(BaseBitmapFilter))
02166                 {
02167                     KernelBitmap *pKernelBitmap = NULL;
02168 
02169                     // bitmap filter, so simply import the bitmap
02170                     ok = pImportFilter->ImportBitmap(&TempDiskFile, &pKernelBitmap);
02171 
02172                     // close the file 
02173                     if (TempDiskFile.isOpen())
02174                         TempDiskFile.close();
02175 
02176                     //create a new bitmap export document
02177                     BitmapExportDocument *pBmpDoc = new BitmapExportDocument();
02178                     if (pBmpDoc != NULL)
02179                     {
02180                         // set the bitmap size
02181                         DocRect RectToExport;
02182                         RectToExport.lo.x = 0;
02183                         RectToExport.lo.y = 0;
02184                         RectToExport.hi.x = XSize * PixelSize;
02185                         RectToExport.hi.y = YSize * PixelSize;
02186 
02187                         // pass the bitmap to the document
02188                         pBmpDoc->Init(pKernelBitmap, RectToExport);
02189 
02190                         if (ok) ok = pPNGFilter->DoExport(pOp, &TempDiskFile, OutFile, pBmpDoc, TRUE);
02191 
02192                         // get rid of the document
02193                         delete pBmpDoc;
02194                     }
02195                     else
02196                         ok = FALSE;
02197 
02198                     // get rid of the bitmap
02199         //          if (pKernelBitmap != NULL)
02200         //              delete pKernelBitmap;
02201                 }
02202                 else
02203                 {
02204                     // web/xar file, so try to import the file
02205 
02206                     // remember the current view
02207                     View *pOldView = View::GetCurrent();
02208 
02209                     // create a new view 
02210                     DocView *pView = new DocView(pDoc);
02211                     if (pView && pView->Init())
02212                     {
02213                         // set the view as current (the import function requires a current view)
02214                         pView->SetCurrent();
02215 
02216                         // import the file into the document
02217                         ok = pImportFilter->DoImport(pOp,&TempDiskFile,pDoc);
02218 
02219                         delete pView;
02220                     }
02221 
02222                     // restore the last view
02223                     if (pOldView != NULL)
02224                         pOldView->SetCurrent();
02225                     else
02226                         View::SetNoCurrent();
02227 
02228                     // close the file 
02229                     if (TempDiskFile.isOpen())
02230                         TempDiskFile.close();
02231 
02232                     // export the document into the OutFile
02233                     if (ok) ok = pPNGFilter->DoExport(pOp, &TempDiskFile, OutFile, pDoc, TRUE);
02234                 }
02235 
02236                 // delete the created operation
02237                 delete pOp;
02238             }
02239 
02240             // restore the previous current document ...
02241             if (pOldCurrent != NULL)
02242                 pOldCurrent->SetCurrent();
02243             else
02244                 Document::SetNoCurrent();
02245 
02246             //... and the selected one together with its view and spread
02247             if (pOldSelected != NULL)
02248                 Document::SetSelectedViewAndSpread(pOldSelected);
02249             else
02250                 Document::SetNoSelectedViewAndSpread();
02251 
02252             // delete our document
02253             delete pDoc;
02254             pDoc = NULL;
02255         }
02256 
02257         // Set the Preview back to its default setting
02258         PreviewFilter::PreviewBitmapSize = OldPreviewSize;
02259     }
02260 
02261     // close the file 
02262     if (TempDiskFile.isOpen())
02263         TempDiskFile.close();
02264 //  return FALSE;
02265 
02266 
02267 //#else //WEBSTER
02268 
02269 #if FALSE
02270 
02271     // Check Accusoft dll is loaded...
02272     static WarnAboutAccusoft = TRUE;
02273     if (AccusoftFilters::GetVersionNumber() <= 0)
02274     {
02275 #ifdef _DEBUG
02276         if(WarnAboutAccusoft)
02277         {
02278             // tell the user there was a problem, and give them a skip button so we don't
02279             // whinge in the future...
02280             String_256 Msg("Accusoft DLL not found, can't generate thumbnails"); // debug only
02281             Error::SetError(0, Msg, 0);
02282             INT32 ButtonPressed = InformWarning(0, _R(IDS_SKIP), _R(IDS_SILENT));
02283             Error::ClearError();
02284 
02285             if(ButtonPressed == 2)
02286                 WarnAboutAccusoft = FALSE;
02287         }
02288 #endif
02289         return FALSE;
02290     }
02291 
02292     TRACEUSER( "Richard", _T("About to do %s (%d)"), (const TCHAR *)InFile->GetPath(), SGLibOil::FileSize(InFile));
02293 
02294     BOOL ok = FALSE;
02295 
02296     // Read the header info from the input file
02297     void *Fish = CCMalloc(sizeof(BITMAPINFOHEADER) + 256 * 4);
02298     BITMAPINFOHEADER *header = (BITMAPINFOHEADER *)Fish;
02299     
02300     char FileWithPath[256];
02301     camStrcpy(FileWithPath, (const TCHAR *)InFile->GetPath());
02302     
02303     INT32 z = AccusoftFilters::pfnIMGLOW_get_fileinfo(FileWithPath, header);
02304     if(z<0)
02305     {   
02306 #ifdef _DEBUG
02307         // This is only really a 'can't get the thumbnail for this file' error...
02308         if(!QuietThumbnail)
02309         {
02310             String_256 Msg;
02311             wsprintf(Msg, "GenIdxFl::CreateThumbnail GetFileInfo - '%s' (0x%x '", (const TCHAR *)InFile->GetPath(), z);
02312             String_256 bodge(_R(IDE_ACCUSOFT_ERROR) - z);
02313             Msg += bodge;
02314             Msg += TEXT("')");
02315             ERROR3(Msg);
02316         }
02317 #endif
02318         CCFree(Fish);
02319     }
02320     else
02321     {
02322         // Using the header info, work out what dimensions the output bmp needs to be
02323         INT32 BmpX = 0;
02324         INT32 BmpY = 0;
02325 
02326         BmpX = header->biWidth;
02327         BmpY = header->biHeight;
02328 
02329         CCFree(Fish);
02330 
02331         double XScale = (double)BmpX / (double)XSize;
02332         double YScale = (double)BmpY / (double)YSize;
02333 
02334         double Scale = (double)1;
02335         if(XScale > YScale)
02336             Scale = XScale;
02337         else
02338             Scale = YScale;
02339         if(Scale <= (double)0)
02340             Scale = (double)0.1;
02341 
02342         XScale = (double)BmpX / (double)Scale;
02343         YScale = (double)BmpY / (double)Scale;
02344 
02345         INT32 Xscale = (INT32)XScale;
02346         INT32 Yscale = (INT32)YScale;
02347 
02348         // Set the output size
02349         INT32 x = AccusoftFilters::pfnIMGLOW_set_decompsize(Xscale, Yscale);
02350         if(x<0)
02351         {
02352 #ifdef _DEBUG
02353             String_256 Msg;
02354             _stprintf(Msg, "GenIdxFl::CreateThumbnail SetDecompSize - '%s' (0x%x '", (const TCHAR *)InFile->GetPath(), x);
02355             String_256 bodge(_R(IDE_ACCUSOFT_ERROR) - x);
02356             Msg += bodge;
02357             Msg += TEXT("')");
02358             ERROR3(Msg);
02359 #endif
02360         }
02361         else
02362         {
02363             // Decompress the actual bitmap
02364             INT32 imghandle = AccusoftFilters::pfnIMG_decompress_bitmap(FileWithPath);
02365             if(imghandle<0)
02366             {
02367 #ifdef _DEBUG
02368                 String_256 Msg;
02369                 _stprintf(Msg, "GenIdxFl::CreateThumbnail DecompBitmap - '%s' (0x%x '", (const TCHAR *)InFile->GetPath(), imghandle);
02370                 String_256 bodge(_R(IDE_ACCUSOFT_ERROR) - imghandle);
02371                 Msg += bodge;
02372                 Msg += TEXT("')");
02373                 ERROR3(Msg);
02374 #endif
02375             } else {    
02376         
02377                 TCHAR OutFileAndPath[256];
02378                 camStrcpy(OutFileAndPath, (const TCHAR *)OutFile->GetPath());
02379 
02380                 // Save the newly decompressed / scaled bitmap
02381                 INT32 Problem = AccusoftFilters::pfnIMG_save_bitmap(imghandle, OutFileAndPath, BMP_UNCOMPRESSED);
02382 
02383                 if(Problem == 0)
02384                 {
02385                     // We loaded, scaled and saved ok...
02386                     ok = TRUE;                  
02387                 }
02388                 else
02389                 {
02390 #ifdef _DEBUG
02391                     String_256 Msg;
02392                     _stprintf(Msg, "GenIdxFl::CreateThumbnail SaveBitmap - '%s' (0x%x '", (const TCHAR *)InFile->GetPath(), Problem);
02393                     String_256 bodge(_R(IDE_ACCUSOFT_ERROR) - Problem);
02394                     Msg += bodge;
02395                     Msg += TEXT("')");
02396                     ERROR3(Msg);
02397 #endif
02398                 }
02399             }
02400         }
02401     }
02402 
02403 
02404 #endif  // FALSE
02405 
02406     // Problems...
02407     if(!ok)
02408     {
02409         if(!QuietThumbnail)
02410         {
02411             // tell the user there was a problem
02412             String_256 Msg;
02413             Msg.MakeMsg(_R(IDS_LIBRARY_THUMBNAIL_PROBLEMS), (const TCHAR *)InFile->GetFileName(TRUE));
02414             Error::SetError(0, Msg, 0);
02415             INT32 ButtonPressed = InformWarning(0, _R(IDS_OK), _R(IDS_SILENT), _R(IDS_STOP), NULL);
02416             Error::ClearError();
02417 
02418             if(ButtonPressed == 2)
02419                 QuietThumbnail = TRUE;
02420 
02421             if(ButtonPressed == 3)
02422                 StopIndGen = TRUE;
02423         }
02424 
02425         // If there was a problem, delete the resulting mess -> seems to like creating 0 length files, etc...
02426         SGLibOil::FileDelete(OutFile);
02427     }
02428 
02429 //  // Possibly reset the dll properly...
02430 //  INT32 x = AccusoftFilters::pfnIMGLOW_set_decompsize(0, 0);
02431 
02432     return ok;
02433 
02434 //#endif    //WEBSTER
02435 }
02436 
02437 /***********************************************************************************************
02438 
02439 >   BOOL GenerateIndexFile::CreateThumbnails(PathName *FileName, BOOL NewSystem = TRUE);
02440 
02441     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
02442     Created:    09/04/95
02443 
02444     Inputs:     FileName  - file to get thumbnail of
02445                 NewSystem - set to TRUE and we'll just generate 1 (large) thumbnail with the same
02446                             name as the file itself (but in the XI dir and with a .bmp ext).
02447     Outputs:
02448     Returns:    TRUE if we want to carry on after this file...
02449     
02450     Purpose:    Create the thumbnail(s) for the specified file
02451     Notes:      OldSystem == generate three bitmaps for the file - Small, Medium and Large
02452                                                                  - filenames == A00002L.bmp, etc
02453                 NewSystem == generate one (large) bitmap for the file - same filename as file
02454 
02455                 (With the NewSystem) we also check if the thumbnail has already been generated
02456                 and save ourselves a bit (well, quite a lot) of time if this is the case.
02457 
02458     SeeAlso:    GenerateIndexFile::CreateThumbnail
02459 
02460 ***********************************************************************************************/
02461 
02462 BOOL GenerateIndexFile::CreateThumbnails(PathName *FileName, BOOL NewSystem)
02463 {
02464     if(FileName == NULL)
02465     {
02466         ERROR3("GenerateIndexFile::CreateThumbnails given a null filename - bad");
02467         return FALSE;
02468     }
02469 
02470     if(LibType == SGLib_Font || LibType == SGLib_Colour)
02471     {
02472         // ERROR3("Thumbnail cannot be generated for this library.");
02473         return FALSE;
02474     }
02475 
02476     // Don't generate thumbnails for certain files...
02477     String_8 Ending;
02478     Ending = FileName->GetType();
02479     Ending.toLower();
02480 
02481     // These are the new native and web formats, these may change to be different
02482     // file extensions
02483     if(Ending == (String_8)"cxn")
02484         return TRUE;
02485     // Web files may not have preview bitmaps but below we use Accusoft to generate a preview bitmap
02486     if(Ending == (String_8)"cxw")
02487         return TRUE;
02488     if((Ending == (String_8)"web") || (Ending == (String_8)"xar"))
02489     {
02490         // Don't error, just set exceptions...
02491         CCDiskFile File(1024, FALSE, TRUE);
02492 
02493         BOOL ok;
02494 
02495         // Open file and check if it exists at the same time
02496         TRY
02497         {
02498             ok = File.open(*FileName, ios::in | ios::binary | ios::nocreate);
02499         }       
02500         CATCH( CFileException, e)
02501         {
02502             ok = FALSE;
02503             Error::ClearError();
02504         }
02505         END_CATCH
02506 
02507         // First check that the file is what we think it is.
02508         BOOL IsNewFormat = FALSE;
02509         UINT32 FilterId = FILTERID_NONE;
02510 
02511         // In the process it will position the file at the start of the preview bitmap image
02512         // and get the image type
02513         if (ok)
02514         {
02515             // This method looks for a preview image at the start of the file, and returns
02516             // the format of that image in FilterId.
02517             if (BaseCamelotFilter::SkipToPreviewBitmap(&File, &IsNewFormat, &FilterId))
02518             {
02519                 if (FilterId != FILTERID_NONE)
02520                     return TRUE;
02521             }
02522 
02523             // If the above test failed, then we're not dealing with a CX2/XaraX file.
02524             // We now need to see whether it's a CX1.1 file, ie binary EPS with TIFF header.
02525             else
02526             {
02527                 GenericFilter* pGenericFilter = Filter::GetGenericFilter();
02528                 if (pGenericFilter != NULL)
02529                 {
02530                     File.seek(0);
02531                     Filter* pOldXarFilter = pGenericFilter->GetBestFilter(&File);
02532                     if (pOldXarFilter != NULL &&
02533                         pOldXarFilter->FilterID == FILTERID_NATIVE_EPS)
02534                         return TRUE;
02535                 }
02536             }
02537         }
02538     }
02539     if(Ending == (String_8)"art")
02540         return TRUE;
02541     if(Ending == (String_8)"cdr")
02542         return TRUE;
02543     if(Ending == (String_8)"cdt")
02544         return TRUE;
02545     if(Ending == (String_8)"cdx")
02546         return TRUE;
02547     if(Ending == (String_8)"cmx")
02548         return TRUE;
02549     if(Ending == (String_8)"eps")
02550         return TRUE;
02551 //  if(Ending == (String_8)"ai")
02552 //      return TRUE;
02553     if(Ending == (String_8)"wmf")
02554         return TRUE;
02555     if(Ending == (String_8)"pcd")
02556         return TRUE;
02557 
02558 
02559     BOOL okl = TRUE, okm = TRUE, oks = TRUE;
02560     PathName InFile(*FileName);
02561     PathName OutFile;
02562 
02563     // Defaults
02564     TCHAR LibraryTypeCharacter = 'A';
02565     UINT8 XsizeL = 128, YsizeL = 128;
02566     UINT8 XsizeM = 128,  YsizeM = 64;
02567     UINT8 XsizeS = 45,  YsizeS = 45;
02568 
02569     String_256 OutFileStr;
02570 
02571     if(NewSystem)
02572     {
02573         if(IndexIsRemote)
02574         {
02575             // Use the temp directory, or whereever the index is...
02576             OutFileStr = RemoteLocationOfIndex;
02577             SGLibOil::AppendSlashIfNotPresent(&OutFileStr);
02578             /*if(OutFileStr[OutFileStr.Length()-1] != '\\')
02579                 OutFileStr += TEXT("\\");*/
02580         }
02581         else
02582         {
02583             // Use the subdirectory of the files themselves
02584             OutFileStr = LibPath.GetPath(TRUE);
02585             OutFileStr += String_16(_R(IDS_LIBRARIES_XARAINFO_DIRNAME));
02586             OutFileStr += TEXT("\\");
02587         }
02588 
02589         OutFileStr += FileName->GetFileName(FALSE);
02590 //#ifdef WEBSTER
02591         // webster uses png 
02592         OutFileStr += TEXT(".png");
02593 //#else
02594 //      OutFileStr += TEXT(".bmp");
02595 //#endif
02596         OutFile.SetPathName(OutFileStr);
02597         if((SGLibOil::FileExists(&OutFile)) && (SGLibOil::FileSize(&OutFile) >= 0) )
02598         {
02599             // Thumbnail already exists and not 0-length
02600             UINT32 InModified = SGLibOil::FileModified(&InFile);
02601             UINT32 OutModified = SGLibOil::FileModified(&OutFile);
02602 
02603             // Don't bother updating the thumbnail if it's got a later timestamp than the
02604             // file itself...
02605             if(InModified <= OutModified)
02606                 return TRUE;
02607         }
02608 
02609         // Create a thumbnail for 'InFile'
02610         return (CreateThumbnail(&InFile, &OutFile, XsizeL, YsizeL));
02611     }
02612     else
02613     {
02614         switch(LibType)
02615         {
02616             // Fills, Texture, same thing...
02617             case SGLib_Texture:
02618                 LibraryTypeCharacter = 'T';
02619                 break;
02620 
02621             // Clipart and bitmaps live in the same gallery
02622             case SGLib_ClipArt:
02623             case SGLib_ClipArt_WebThemes:
02624             case SGLib_Bitmap:
02625                 LibraryTypeCharacter = 'A';
02626                 break;
02627 
02628             // Font previews are a completely different shape to the rest
02629             case SGLib_Font:
02630                 LibraryTypeCharacter = 'F';
02631                 XsizeL = 180;
02632                 YsizeL = 26;
02633                 XsizeM = 160;
02634                 YsizeM = 12;
02635                 XsizeS = 28;
02636                 YsizeS = 32;
02637                 break;
02638         }
02639 
02640         String_256 Dir(LibPath.GetPath(TRUE));      // Directory + \Xarainfo\                 .
02641         Dir += String_16(_R(IDS_LIBRARIES_XARAINFO_DIRNAME));
02642         Dir += TEXT("\\");
02643 
02644         // Go ahead and create all three thumbnails for the file...
02645         _stprintf(OutFileStr, "%s%C%05dL.bmp", (TCHAR *)Dir, LibraryTypeCharacter, ID);
02646         OutFile.SetPathName(OutFileStr);
02647         okl = CreateThumbnail(&InFile, &OutFile, XsizeL, YsizeL);
02648 
02649         _stprintf(OutFileStr, "%s%C%05dM.bmp", (TCHAR *)Dir, LibraryTypeCharacter, ID);
02650         OutFile.SetPathName(OutFileStr);
02651         okm = CreateThumbnail(&InFile, &OutFile, XsizeM, YsizeM);
02652     
02653         _stprintf(OutFileStr, "%s%C%05dS.bmp", (TCHAR *)Dir, LibraryTypeCharacter, ID);
02654         OutFile.SetPathName(OutFileStr);
02655         oks = CreateThumbnail(&InFile, &OutFile, XsizeS, YsizeS);
02656 
02657         return (okl && okm && oks);
02658     }
02659     return FALSE;                                           
02660 }
02661 
02662 /***********************************************************************************************
02663 
02664 >   BOOL GenerateIndexFile::RipDescriptionFromFile(PathName *FileName, String_256 *Text, 
02665             String_256 *Keywords = NULL, String_256 *Title = NULL)
02666 
02667     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
02668     Created:    10/05/95
02669 
02670     Inputs:     Filename - Filename of file
02671     Outputs:    Text - textual description to use for the file in the index
02672                 Keywords
02673                 Title
02674 
02675     Returns:    TRUE if we found a description for the file
02676 
02677     Purpose:    Try and work out a description and keywords given a file.
02678                 Currently we only check ART/EPS files and CDR files.
02679 
02680 ***********************************************************************************************/
02681 
02682 BOOL GenerateIndexFile::RipDescriptionFromFile(PathName *FileName, String_256 *Text, String_256 *Keywords, String_256 *Title)
02683 {
02684     ERROR3IF(FileName == NULL, "GenerateIndexFile::RipDescriptionFromIndex given null filename");
02685     ERROR3IF(Text == NULL, "GenerateIndexFile::RipDescriptionFromIndex given null text");
02686 
02687     String_256 Type(FileName->GetType());
02688     Type.toLower();
02689 
02690 
02691 #ifdef _BATCHING  
02692     if( (Type.Sub((String_8)"xar") != -1) || (Type.Sub((String_8)"art") != -1) )
02693     {
02694         PathName TmpPath(*FileName);
02695         TmpPath.SetType("CDR");
02696         if(SGLibOil::FileExists(&TmpPath))
02697         {
02698             return RipDescriptionFromCDRFile(&TmpPath, Text, Keywords, Title);
02699         }
02700     }
02701 #endif
02702 
02703 //#if NEW_NATIVE_FILTER // New native filters, only available to those who need them at present
02704     // Rip the indexing strings from the version 2 native/web format files
02705     if( (Type.Sub((String_8)"cxn") != -1) || (Type.Sub((String_8)"cxw") != -1) || (Type.Sub((String_8)"web") != -1) )
02706     {
02707         return RipDescriptionFromNativeV2File(FileName, Text, Keywords, Title);
02708     }
02709 //#endif
02710 
02711     if( (Type.Sub((String_8)"xar") != -1) || (Type.Sub((String_8)"art") != -1) || (Type.Sub((String_8)"eps") != -1) )
02712     {
02713         // Now that we have had the decision to make .cxns become .xars, we must check to see if its a
02714         // new native file before doing the EPS parsing. This will have the added side effect of hiding 
02715         // the binary file from the EPS parser, which seems to toast memory if this is not done!
02716         BOOL IsNewNativeFile = FALSE;
02717         BOOL ok = RipDescriptionFromNativeV2File(FileName, Text, Keywords, Title, &IsNewNativeFile); 
02718         // If we found it was a new native file then return the result to the caller
02719         if (IsNewNativeFile)
02720             return ok;
02721 
02722         // Otherwise, assume it is old format and so let the EPS parser have a go at ripping out
02723         // the comments.
02724         return RipDescriptionFromEPSFile(FileName, Text, Keywords, Title);
02725     }
02726 
02727 #ifdef _BATCHING
02728     if( (Type.Sub((String_8)"cdr") != -1) )
02729     {
02730         return RipDescriptionFromCDRFile(FileName, Text, Keywords, Title);
02731     }
02732 #endif
02733 
02734     return FALSE;
02735 }
02736 
02737 /***********************************************************************************************
02738 
02739 >   BOOL GenerateIndexFile::RipDescriptionFromCDRFile(PathName *FileName, String_256 *Text, 
02740             String_256 *Keywords = NULL, String_256 *Title = NULL)
02741 
02742     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
02743     Created:    10/05/95
02744 
02745     Inputs:     Filename - Filename of file
02746     Outputs:    Text - textual description to use for the file in the index
02747                 Keywords
02748                 Title
02749 
02750     Returns:    TRUE if we found a description for the file
02751 
02752     Purpose:    Try and work out a description and keywords given a cdr 5 file
02753 
02754     Notes:      There might be problems if the preview bitmaps are ever changed to be something
02755                 other than tiffs, at the moment we check the first four bytes of the file to see
02756                 if it's a tiff file and jump over the tiffity bit if it is...
02757 
02758                 CDR files seem to contain the text "INFOIKEY" near the start, then four 0's then a bunch
02759                 of ';' separated keywords (with spaces)...
02760 
02761 
02762 ***********************************************************************************************/
02763 
02764 BOOL GenerateIndexFile::RipDescriptionFromCDRFile(PathName *FileName, String_256 *Text, String_256 *Keywords, String_256 *Title)
02765 {
02766 #ifdef _BATCHING   
02767 
02768 //  ERROR3IF(FileName == NULL || RetName == NULL || Bold == NULL || Italic == NULL, "Null params given to ATM ripper");
02769 
02770     BOOL ok = TRUE;
02771 
02772     PathName CDRPath(*FileName);
02773 
02774     if(!SGLibOil::FileExists(&CDRPath))
02775     {
02776         ERROR3("Can't find CDR file");
02777         return FALSE;
02778     }
02779 
02780     CCDiskFile CDRFile(1024, FALSE, TRUE);
02781 
02782     TRY
02783     {
02784         // Open the xxx.cdr file
02785         ok = CDRFile.open(CDRPath, ios::in | ios::nocreate | ios::binary);
02786     }   
02787             
02788     CATCH(CFileException, e)
02789     {
02790         Error::ClearError();
02791         return FALSE;
02792     }
02793     END_CATCH
02794 
02795     FilePos Position = 0x400; //199;
02796     BOOL FoundInfoIKey = FALSE;
02797     CDRFile.seekIn(Position);
02798         
02799     TRY
02800     {
02801         // Keep looping through the file until we hit the end...
02802         while(!CDRFile.eof() && !FoundInfoIKey)
02803         {
02804             DWORD Buffer[256];
02805             memset(Buffer, 0, 256 * 4);
02806             CDRFile.seekIn(Position);
02807 
02808             if(!FoundInfoIKey)
02809             {
02810                 CDRFile.read((void *)Buffer, 8);
02811 
02812                 // Debug
02813                 if(!camStrcmp(((TCHAR *)Buffer) , "INFOIKEY"))
02814                 {
02815                     FoundInfoIKey = TRUE;
02816                     
02817                     // Loop past the four '0's (possibly strings in some files ?)
02818                     INT32 Count = 3;
02819                     while(Count > 0 && !CDRFile.eof())
02820                     {
02821                         CDRFile.read((void *)Buffer, 1);
02822                         if(((TCHAR *)Buffer)[0] == 0)
02823                             Count --;
02824                     };
02825 
02826                     TCHAR Keys[256];
02827                     Count = -1;
02828 
02829                     do {
02830                         //Count ++;
02831                         CDRFile.read((void *)((char *)Keys + (++Count)), 1);
02832                         //Keys[Count] = ((TCHAR *)Buffer)[0];
02833                         //if(Keys[Count] == ',' || Keys[Count] == ' ')
02834                         //  Keys[Count] = ';';
02835                     } while(Keys[Count] != 0 && !CDRFile.eof() && Count < 255);
02836 
02837                     *Keywords = (String_256)Keys;
02838 
02839                     // Some chap at corel decided to stick loads of spaces in some of
02840                     // the clipart groups (space and graphics...)
02841                     // This will rip trailing spaces off...
02842                     if(Keywords->Sub((String_8)"   ") != -1)
02843                     {
02844                         String_256 Tmp(*Keywords);
02845                         Tmp.Left(Keywords, Tmp.Sub((String_8)"   "));                   
02846                     }
02847 
02848                     // Make the last keyword a title
02849                     String_256 Tmp(*Keywords);
02850                     String_256 Tmp2;
02851                     INT32 Offset = Tmp.Sub((String_8)";");              
02852                     while(Offset != -1 && Tmp.Length()>0)
02853                     {
02854                         Tmp2 = Tmp;
02855                         Tmp2.Right(&Tmp, ((Tmp2.Length() - Offset) - 1));
02856                         Offset = Tmp.Sub((String_8)";");
02857                     }
02858                     *Title = Tmp;           
02859 
02860                     ReplaceCharacters(Title, ',', ' ');
02861 
02862                     ReplaceCharacters(Keywords, ';', '|');
02863                     ReplaceCharacters(Keywords, ',', '|');
02864                     ReplaceCharacters(Keywords, ' ', '|');
02865 
02866                     CDRFile.close();
02867                     return TRUE;
02868                 }
02869             }
02870             Position ++;
02871         }
02872     }
02873 
02874     // See if there was a file io error
02875     CATCH(CFileException, e)
02876     {
02877         // Something rather unhelpful has taken place, or we've reached the end of the file......
02878         ok = FALSE;
02879 
02880         // remove any errors
02881         Error::ClearError();
02882     }
02883     END_CATCH
02884 
02885     // Make sure that the files are closed and the memory is reclaimed properly...
02886     TRY
02887     {
02888         if (CDRFile.isOpen())
02889             CDRFile.close();
02890     }
02891     CATCH(CFileException, e)
02892     {
02893         // Failed to close the files - not much we can do about it really
02894         Error::ClearError();
02895     }
02896     END_CATCH
02897 
02898 
02899 #endif
02900 
02901     return FALSE;
02902 }
02903 
02904 /***********************************************************************************************
02905 
02906 >   BOOL GenerateIndexFile::RipDescriptionFromEPSFile(PathName *FileName, String_256 *Text, 
02907             String_256 *Keywords = NULL, String_256 *Title = NULL)
02908 
02909     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
02910     Created:    10/05/95
02911 
02912     Inputs:     Filename - Filename of file
02913     Outputs:    Text - textual description to use for the file in the index
02914                 Keywords
02915                 Title
02916 
02917     Returns:    TRUE if we found a description for the file
02918 
02919     Purpose:    Try and work out a description given an art file (using comments in file)
02920                 This might work for the various eps files knocking about too, so it gives them
02921                 a chance.
02922 
02923     Notes:      There might be problems if the preview bitmaps are ever changed to be something
02924                 other than tiffs, at the moment we check the first four bytes of the file to see
02925                 if it's a tiff file and jump over the tiffity bit if it is...
02926 
02927 ***********************************************************************************************/
02928 
02929 BOOL GenerateIndexFile::RipDescriptionFromEPSFile(PathName *FileName, String_256 *Text, String_256 *Keywords, String_256 *Title)
02930 {
02931     CCDiskFile *EPSDiskFile = new CCDiskFile(1024, TRUE, FALSE);
02932     if (EPSDiskFile == NULL)
02933     {
02934         ERROR3("Problems allocating CCDiskFile");
02935         return FALSE;
02936     }
02937 
02938     if (!EPSDiskFile->InitLexer(TRUE))
02939     {
02940         ERROR3("Problems with InitLexer");
02941         delete EPSDiskFile;
02942         return FALSE;
02943     }
02944 
02945     if (!EPSDiskFile->open(*FileName, ios::in))
02946     {
02947         ERROR3("Can't open ART/EPS file");
02948         EPSDiskFile->DeinitLexer();
02949         delete EPSDiskFile;
02950         return FALSE;
02951     }
02952 
02953     // ART (+ XStudio EPS) files optionally contain document comments near their start.
02954     // The basic format of these in the file is:
02955     //
02956     // <tiff file and random general info>
02957     // %%DocumentInfo
02958     // %%+p .....
02959     // %%+c This is the document comment. If it's a large comment then it
02960     // %%+c will overwrap two lines like this.^
02961     // %%+c Uphats signify returns in the info... We don't take any notice
02962     // %%+c of the lines after the uphat...
02963     // %%+v
02964     // %%NextSection
02965     //
02966     // Since we don't have much room to display INT32 descriptions in the gallery we only currently
02967     // use the first line of comments in the code below.
02968 
02969     String_256 TokenBuffer("");
02970     LexTokenType TokType = TOKEN_LINE;
02971 
02972     BOOL FoundDocumentInfo = FALSE;
02973     BOOL FoundDescription  = FALSE;
02974     BOOL FileHasNoComments = FALSE;
02975     BOOL UpHat = FALSE;
02976 
02977     // OK, we will have to check for a preview bmp and skip to the Postscript if there is one
02978     // read the first 4 bytes and see if they match the magic PostScript word
02979     char Buf[4];
02980         
02981     // clear the buffer
02982     memset(Buf, 0, 4);
02983 
02984     // read the bytes in
02985     EPSDiskFile->read(Buf, 4);
02986 
02987     UINT32* pUINT32 = (UINT32*)Buf;
02988     // see if its a match
02989     if ((Buf[0]=='\xC5') && (Buf[1]=='\xD0') && (Buf[2]=='\xD3') && (Buf[3]=='\xC6'))
02990     {
02991         // Yes, this is a binary EPS file that has a TIFF attached, so find the EPS
02992         FilePos StartOfEPS = 0;
02993         EPSDiskFile->read(&StartOfEPS, 4);
02994         TRACEUSER( "Richard", _T("EPS Starts at %ld\n"), StartOfEPS);
02995     
02996         // Seek to the start of the EPS ready for the importer to read it.
02997         EPSDiskFile->seekIn(StartOfEPS, ios::beg);
02998     }
02999     else if (pUINT32[0] == CXF_IDWORD1)
03000     {
03001         // the first eight bytes are our magic identifier for the new native/web file format
03002         TRACEUSER( "Neville", _T(".xar file in new format\n"));
03003         return FALSE;
03004     }
03005     else
03006     {
03007         // Nope, this must be any ordinary EPS file, so go back to the start of the file
03008         EPSDiskFile->seekIn(0, ios::beg);
03009         // +++++ WARNING +++++
03010         // Uses to cope with eps files without a preview bitmap in them but this is very bad news these
03011         // days. If we have .xar files which are really .cxn i.e. the new native format then we will start
03012         // lexing in a binary file. This is bad!!!!! Memory is toast is the more than likely outcome!
03013         // The check for new format files above should stop this but left in this warning just in case
03014         // somebody tries it with a different binary .xar file.
03015         // Neville 9/8/96
03016         TRACE( _T(".xar file without binary TIFF header! Dangerous! Assume no indexing data\n"));
03017         //return FALSE;
03018     }
03019 
03020     BOOL TimeToFinish = FALSE;
03021 
03022     // Make sure that the flags have priority over the GetLineToken call as if you find the %%Compression
03023     // line then reading the next line without turning compression on could prove to be slightly fatal
03024     // in that the EPS parser might try walking into the compressed region due to the buffering that it
03025     // does. If it does hit the %%Compression token then next time round the loop TimeToFinish will be
03026     // set and so use this to sop very quickly.
03027     while(!TimeToFinish && !FileHasNoComments && EPSDiskFile->GetLineToken() && TokType != TOKEN_EOF)
03028     {
03029         TokType = EPSDiskFile->GetTokenType();
03030         if(TokType == TOKEN_LINE)
03031         {
03032             TokenBuffer = EPSDiskFile->GetTokenBuf();
03033 
03034             if(FoundDocumentInfo)
03035             {
03036                 // We've reached the end of the section - finish looping...
03037                 if(TokenBuffer.Sub((String_8)"%%+") == -1)
03038                 {                   
03039                     FileHasNoComments = !FoundDescription;
03040                     TimeToFinish = TRUE;
03041                 }
03042 
03043                 // Check if this line holds our comment...
03044                 if(TokenBuffer.Sub((String_8)"%%+c ") == 0)
03045                 {
03046                     // Our string looks like: %%+c This bit of text here is a comment
03047                     // Guess which bit we need...
03048                     String_256 TheDesc( ((TCHAR *)TokenBuffer) + 5 );
03049                     String_256 TheDescU(TheDesc);       
03050                     TheDescU.toUpper();
03051 
03052                     // Unfortunately, fields are limited to 64 bytes (since lines shouldn't be over 256 bytes)
03053                     // If our description beats back these boundaries we give it a good beating forward...
03054                     // Maybe if life was easy then this wouldn't be a problem. Maybe if we had String_1024s this
03055                     // wouldn't be a problem, ah well...
03056                     if(TheDesc.Length() > 64)
03057                     {
03058                         TokenBuffer.Mid(&TheDesc, 5, 64);
03059                     }
03060                     else
03061                     {
03062                         // Check if we've got an uphat on our string (and strip it off if so...)
03063                         if(TheDesc.Sub((String_8)"^") != -1)
03064                         {
03065                             TokenBuffer.Mid(&TheDesc, 5, TheDesc.Sub((String_8)"^"));
03066                             UpHat = TRUE;
03067                         }
03068                     }
03069 
03070                     if(Keywords && TheDescU.Sub(String_16(_R(IDS_LIBRARIES_RIP_XAR_KEYWORDS))) == 0)
03071                     {
03072                         // this line is a keyword entry...
03073 
03074                         INT32 exclude = 4;
03075 
03076                         // strip leading spaces
03077                         while ( (((TCHAR *)TheDesc)[exclude] == ' ') && (exclude < TheDesc.Length()))
03078                             exclude ++;
03079 
03080                         TheDesc.Right(Keywords, TheDesc.Length() - exclude);
03081 
03082                         ReplaceCharacters(Keywords, ',', '|');
03083                     }
03084                     else
03085                     {
03086                         if(Title && TheDescU.Sub(String_16(_R(IDS_LIBRARIES_RIP_XAR_TITLE))) == 0)
03087                         {
03088                             // this line is a title entry...
03089                             INT32 exclude = 6;
03090 
03091                             // strip leading spaces
03092                             while ( (((TCHAR *)TheDesc)[exclude] == ' ') && (exclude < TheDesc.Length()))
03093                                 exclude ++;
03094 
03095                             TheDesc.Right(Title, TheDesc.Length() - exclude);
03096 
03097                             ReplaceCharacters(Title, ',', '|');
03098                         }
03099                         else
03100                         {
03101                             // default the line to be a description - only if it was the first
03102                             if(!FoundDescription)
03103                             {
03104                                 ReplaceCharacters(&TheDesc, ',', '|');
03105                                 *Text = TheDesc;
03106                             }
03107                         }
03108                     }
03109 
03110                     FoundDescription = TRUE;
03111                 }
03112             }
03113             else
03114             {
03115                 // Convert line to upper case for case insensitive match
03116                 String_256 TokenBufferU(TokenBuffer);
03117                 TokenBufferU.toUpper();
03118 
03119                 // Check line for start of document info section
03120                 if(TokenBufferU.Sub((String_16)"%%DOCUMENTINFO") == 0)
03121                 {
03122                     FoundDocumentInfo = TRUE;
03123                 }
03124     
03125                 // Check to see if we've overshot, and are wasting time...
03126                 if( (TokenBufferU.Sub((String_16)"%%AWCOLOURTABLE") == 0)
03127                     || (TokenBufferU.Sub((String_16)"%%COMPRESSION") == 0)
03128                     || (TokenBuffer.Sub((String_8)"%") != 0) )
03129                 {
03130                     FileHasNoComments = TRUE;
03131                     TimeToFinish = TRUE;
03132                 }
03133             }
03134         }
03135     }
03136     
03137     // reclaim lexer-buffer memory
03138     EPSDiskFile->DeinitLexer();
03139 
03140     if(EPSDiskFile->isOpen())
03141         EPSDiskFile->close();
03142 
03143     delete EPSDiskFile;
03144 
03145     return FoundDescription;
03146 }
03147 
03148 /***********************************************************************************************
03149 
03150 >   BOOL GenerateIndexFile::RipDescriptionFromNativeV2File(PathName *FileName, String_256 *Text, 
03151             String_256 *Keywords = NULL, String_256 *Title = NULL, BOOL *FileIsNewNative = NULL)
03152 
03153     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
03154     Created:    05/08/96
03155 
03156     Inputs:     Filename - Filename of file
03157     Outputs:    Text - textual description to use for the file in the index
03158                 Keywords
03159                 Title
03160 
03161     Returns:    TRUE if we found a description for the file
03162 
03163     Purpose:    Try and work out a description given a new version 2 format native, cxn, file
03164                 (using a document comment record stored in the file). This is not stored in
03165                 Web format files as this is meant to be the compact form of the file. 
03166                 This might work for the various eps files knocking about too, so it gives them
03167                 a chance.
03168 
03169 ***********************************************************************************************/
03170 
03171 BOOL GenerateIndexFile::RipDescriptionFromNativeV2File(PathName *FileName,
03172                                                        String_256 *Text, String_256 *Keywords, String_256 *Title,
03173                                                        BOOL *FileIsNewNative)
03174 {
03175     CCDiskFile *NativeDiskFile = new CCDiskFile(1024, TRUE, FALSE);
03176     if (NativeDiskFile == NULL)
03177     {
03178         ERROR3("Problems allocating CCDiskFile");
03179         return FALSE;
03180     }
03181 
03182     if (!NativeDiskFile->open(*FileName, ios::in))
03183     {
03184         ERROR3("Can't open CXN/CXW file");
03185         delete NativeDiskFile;
03186         return FALSE;
03187     }
03188 
03189     BOOL FoundDescription  = FALSE;
03190 
03191     // Ask the base camelot filter to rip out the document comment from the file, returns FALSE
03192     // if not a version 2 native or web file or the comment has not been found. Only returns TRUE
03193     // if a document comment has succesfully been found.
03194     // May not be found as only saved if there text has been entered into the document information
03195     // field.
03196     String_256 DocumentComment;
03197     BOOL IsNewNativeFile = FALSE;
03198     BOOL ok = BaseCamelotFilter::SkipToIndexInformation(NativeDiskFile, &DocumentComment, &IsNewNativeFile);
03199     // Return whether it was a new native/web file to the caller
03200     if (FileIsNewNative)
03201         *FileIsNewNative = IsNewNativeFile;
03202     if (!ok)
03203     {
03204         if(NativeDiskFile->isOpen())
03205             NativeDiskFile->close();
03206 
03207         delete NativeDiskFile;
03208         return FALSE;
03209     }
03210 
03211     // We should now have a document comment in DocumentComment.
03212     // If its emptry then there is no point in trying to rip the comments out
03213     if (!DocumentComment.IsEmpty())
03214     {
03215         // Rip the data we require from the comment.
03216         // We need to read a line at a time from the string and check if it starts with one of our
03217         // standard indexing strings. The first line, if it doesn't start with a standard indexing
03218         // string can be considered as a description string
03219 
03220         const TCHAR LineEnd = TEXT('\n');
03221         INT32 pos = 0;
03222         INT32 LastPos = 0;
03223         String_256 TheDesc;
03224         String_256 TheDescU;
03225         BOOL TimeToEnd = FALSE;
03226         while (pos >= 0 && !TimeToEnd)
03227         {
03228             // This will return -1 if not found or the position in the string of the line end
03229             pos = DocumentComment.FindNextChar(LineEnd, pos);
03230             // If a line end is not found then try parsing the entire string
03231             // We need to do this on the last pass as otherwise the last line in the string will
03232             // not be looked at
03233             if (pos == -1)
03234             {
03235                 // One passed the end of the string as the pos - LastPos - 1 will then be correct
03236                 pos = DocumentComment.Length() + 1;
03237                 // Make sure we only do this once
03238                 TimeToEnd = TRUE;
03239             }   
03240 
03241             // See if it is a blank line, if so then skip it
03242             if ((pos >= 0) && (pos - LastPos <= 1))
03243             {
03244                 // shift onto after the found line end character
03245                 pos += 1;
03246                 // remember this as the last search position
03247                 LastPos = pos;
03248             }
03249             else if ((pos >= 0) && (pos - LastPos > 1))
03250             {
03251                 // Get the line that we have just found, make sure we don't include the line end
03252                 // as otherwise is screws up the text line in the index file
03253                 DocumentComment.Mid(&TheDesc, LastPos , pos - LastPos - 1);
03254                 // shift onto after the found line end character
03255                 pos += 1;
03256                 // remember this as the last search position
03257                 LastPos = pos;
03258 
03259                 // Get an upper case version of the string, ready to do do our comparing on
03260                 TheDescU = TheDesc;
03261                 TheDescU.toUpper();
03262                 // check for KEY:
03263                 if(Keywords && TheDescU.Sub(String_16(_R(IDS_LIBRARIES_RIP_XAR_KEYWORDS))) == 0)
03264                 {
03265                     // this line is a keyword entry...
03266 
03267                     INT32 exclude = 4; // Length of KEY: 
03268 
03269                     // strip leading spaces
03270                     while ( (((TCHAR *)TheDesc)[exclude] == ' ') && (exclude < TheDesc.Length()))
03271                         exclude ++;
03272 
03273                     TheDesc.Right(Keywords, TheDesc.Length() - exclude);
03274 
03275                     ReplaceCharacters(Keywords, ',', '|');
03276                 }
03277                 else
03278                 {
03279                     // Check for TITLE
03280                     if(Title && TheDescU.Sub(String_16(_R(IDS_LIBRARIES_RIP_XAR_TITLE))) == 0)
03281                     {
03282                         // this line is a title entry...
03283                         INT32 exclude = 6; // Length of TITLE: 
03284 
03285                         // strip leading spaces
03286                         while ( (((TCHAR *)TheDesc)[exclude] == ' ') && (exclude < TheDesc.Length()))
03287                             exclude ++;
03288 
03289                         TheDesc.Right(Title, TheDesc.Length() - exclude);
03290 
03291                         ReplaceCharacters(Title, ',', '|');
03292                     }
03293                     else
03294                     {
03295                         // default the line to be a description - only if it was the first
03296                         if(!FoundDescription)
03297                         {
03298                             ReplaceCharacters(&TheDesc, ',', '|');
03299                             *Text = TheDesc;
03300                         }
03301                     }
03302                 }
03303 
03304                 // Flag we have found a comment
03305                 FoundDescription = TRUE;
03306             }
03307         }
03308     }
03309 
03310     if(NativeDiskFile->isOpen())
03311         NativeDiskFile->close();
03312 
03313     delete NativeDiskFile;
03314 
03315     return FoundDescription;
03316 }
03317 
03318 #endif
03319 
03320 /***********************************************************************************************
03321 
03322 >   static BOOL GenerateIndexFile::ReplaceCharacters(StringBase *Source, TCHAR Search, TCHAR Replace)
03323 
03324     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
03325     Created:    25/05/95
03326 
03327     Inputs:     Source      - Source string
03328                 Search      - Character to search for
03329                 Replace     - Character to replace found 'search' characters with
03330     Outputs:    Updates the buffer in 'Source'
03331     Returns:    TRUE if it all worked...
03332 
03333     Purpose:    To find and replace specific characters in a string
03334 
03335 ***********************************************************************************************/
03336 
03337 BOOL GenerateIndexFile::ReplaceCharacters(StringBase *Source, TCHAR Search, TCHAR Replace)
03338 {
03339     ERROR3IF(Source == NULL, "GenerateIndexFile::ReplaceCharacters - source == null");
03340 
03341     INT32 Len = Source->Length();
03342     if (Len == 0)
03343         return FALSE;
03344 
03345 #ifdef _DEBUG
03346     INT32 Count = 0;
03347 #endif
03348 
03349     TCHAR *Buf = (TCHAR *)*Source;
03350     for(INT32 i = 0; i < Len; i++)
03351     {
03352         if(*Buf == Search)
03353         {
03354             *Buf = Replace;
03355 #ifdef _DEBUG
03356             Count ++;
03357 #endif
03358         }
03359         Buf ++;
03360     }
03361 
03362 #ifdef _DEBUG
03363     TRACEUSER("Richard", _T("%d %c chars found in %s and replaced with %c\n"), Count, Search, (TCHAR *)*Source, Replace);
03364 #endif
03365     return TRUE;
03366 }
03367 
03368 #if 0
03369 
03370 /***********************************************************************************************
03371 
03372 >   static INT32 GenerateIndexFile::CountCommas(StringBase *Source, StringBase &SearchFor)
03373 
03374     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
03375     Created:    25/05/95
03376 
03377     Inputs:     Source      - Source string with ,'s in
03378                 SearchFor   - Substring to search for in source string
03379     Outputs:
03380     Returns:    Count of commas to the left of 'searchfor' in 'source'
03381 
03382     Purpose:    To count the commas towards the left of a substring in a source string.
03383         
03384                 For example, passing it:
03385                 
03386                 "This, is, a string" and "stri" would return 2
03387 
03388 ***********************************************************************************************/
03389 
03390 INT32 GenerateIndexFile::CountCommas(StringBase *Source, StringBase &SearchFor)
03391 {
03392     ERROR3IF(Source == NULL, "GenerateIndexFile::CountCommas - source == null");
03393 
03394     INT32 Len = Source->Length();
03395     if(Len == 0)
03396         return 0;
03397 
03398     INT32 Count = 0;
03399     INT32 Pos = Source->Sub(SearchFor);
03400 
03401     if(Pos != -1)
03402     {
03403         // Find out which field it was
03404         String_256 Left;
03405         Source->Left(&Left, Pos);
03406         Len = Left.Length();
03407 
03408         // This bit could go in basestr...      
03409         TCHAR *Buf = (TCHAR *)Left;
03410         for(INT32 i = 0; i < Len; i++)
03411             if(*(Buf++) == ',')
03412                 Count ++;
03413     }
03414     return Count;
03415 }
03416 
03417 
03418 /***********************************************************************************************
03419 
03420 >   static BOOL GenerateIndexFile::GetToken(StringBase *Source, INT32 Count, String_256 *Result)
03421 
03422     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
03423     Created:    25/05/95
03424 
03425     Inputs:     Source      - Source string
03426                 Count       - Number of commas to skip in source string
03427     Outputs:    Result      - Resulting token found in string (with leading and trailing
03428                               spaces stripped)
03429     Returns:    TRUE if things went ok
03430 
03431     Purpose:    To return the space stripped token Count commas into the given string
03432 
03433 ***********************************************************************************************/
03434 
03435 BOOL GenerateIndexFile::GetToken(StringBase *Source, INT32 Count, String_256 *Result)
03436 {
03437     ERROR3IF(Source == NULL, "GenerateIndexFile::GetToken - source == null");
03438 
03439     TCHAR *Comma = NULL;
03440     
03441     if(Count == 0)
03442     {
03443         Comma = ((TCHAR *)*Source);
03444     }
03445     else
03446     {
03447         Comma = camStrchr((TCHAR *)*Source, _T(','));
03448 
03449         if(Count > 2)
03450         {
03451             for(INT32 i = Count - 1; i > 0; i--)
03452             {
03453                 Comma = camStrchr(Comma + 1, _T(','));
03454                 
03455                 // Couldn't find token in string - not enough commas
03456                 if(Comma == NULL)
03457                     return FALSE;       
03458             }
03459         }
03460     }
03461 
03462     INT32 first = (Comma - (TCHAR *)*Source) + 1;   
03463     INT32 second = 0;
03464     if(camStrchr(Comma + 1, _T(',')))
03465         second = (camStrchr(Comma + 1, _T(',')) - (TCHAR *)*Source);
03466     else
03467         second = camStrlen((TCHAR *)*Source);
03468 
03469     // strip leading spaces
03470     while ( (((TCHAR *)*Source)[first] == ' ') && (first < Source->Length()))
03471         first ++;
03472 
03473     // strip trailing spaces
03474     if(second > 0)
03475         while ( (((TCHAR *)*Source)[second-1] == ' ') && (second > first))
03476             second --;
03477 
03478     // Looks like we've got a valid string
03479     if(first != 0 && second != 0 && first < second)
03480     {
03481         Source->Mid(Result, first, second - first);
03482         return TRUE;
03483     }
03484 
03485     // Couldn't find token in string        
03486     return FALSE;
03487 }
03488 
03489 
03490 /***********************************************************************************************
03491 
03492 >   BOOL GenerateIndexFile::PrePassIndex(PathName *IndexFile, FilePos *Start,
03493         INT32 *DescriptionField, INT32 *KeywordField, INT32 *TitleField, String_256 *Description)
03494 
03495     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
03496     Created:    27/05/95
03497 
03498     Inputs:     IndexFile           - Filename of index file to scan
03499     Outputs:    Start               - File offset to 'START' text
03500                 DescriptionField    - Number of commas to left of 'description' field
03501                 KeywordField        - Number of commas to left of 'keyword' field
03502                 TitleField          - Number of commas to left of 'title' field
03503                 Description         - Description for group in gallery
03504 
03505     Returns:    TRUE if the index file looks ok to use
03506     
03507     Purpose:    Scan the old index header and return useful information
03508 
03509 ***********************************************************************************************/
03510 
03511 BOOL GenerateIndexFile::PrePassIndex(PathName *IndexFile, FilePos *Start,
03512         INT32 *DescriptionField, INT32 *KeywordField, INT32 *TitleField, String_256 *Description)
03513 {
03514     ERROR3IF(IndexFile == NULL, "GenerateIndexFile::PrePassIndex given null index");
03515 
03516     CCDiskFile *TmpDiskFile = new CCDiskFile(1024, TRUE, FALSE);
03517     if (TmpDiskFile == NULL)
03518     {
03519         ERROR3("Null index file allocated");
03520         return FALSE;
03521     }
03522 
03523     if (!TmpDiskFile->InitLexer(TRUE))
03524     {
03525         ERROR3("Problems with InitLexer");
03526         delete TmpDiskFile;
03527         TmpDiskFile = NULL;
03528         return FALSE;
03529     }
03530 
03531     if (!TmpDiskFile->open(*IndexFile, ios::in))
03532     {
03533         ERROR3("Can't open index file for pre pass");
03534         TmpDiskFile->DeinitLexer();
03535         delete TmpDiskFile;
03536         TmpDiskFile = NULL;
03537         return FALSE;
03538     }
03539 
03540     LexTokenType TokType = TOKEN_LINE;
03541     BOOL FoundFieldTitles = FALSE;
03542     BOOL FoundStart = FALSE;
03543 
03544     // Loop through header ripping the interesting stuff out
03545     while(TmpDiskFile->GetLineToken() && TokType != TOKEN_EOF && !FoundStart)
03546     {
03547         TokType = TmpDiskFile->GetTokenType();
03548         if(TokType == TOKEN_LINE || TokType == TOKEN_COMMENT)
03549         {
03550             String_256 TokenBufferU(TmpDiskFile->GetTokenBuf());
03551             TokenBufferU.toUpper();
03552 
03553             String_16 FilenameStr(_R(IDS_LIBRARIES_INDEX_ITEM_FILENAME));
03554             String_16 DescStr(_R(IDS_LIBRARIES_INDEX_ITEM_DESC));
03555             FilenameStr.toUpper();
03556             DescStr.toUpper();
03557 
03558             // Rip out the field positions from the field description line in the header
03559             if(TokType == TOKEN_LINE && !FoundFieldTitles && TokenBufferU.Sub(FilenameStr) == 0 && TokenBufferU.Sub(DescStr) > 0)
03560             {
03561                 if(DescriptionField)
03562                 {
03563                     String_16 Str(_R(IDS_LIBRARIES_INDEX_ITEM_DESC));
03564                     Str.toUpper();
03565                     *DescriptionField = CountCommas(&TokenBufferU, Str);
03566                 }
03567 
03568                 if(KeywordField)
03569                 {
03570                     String_16 Str(_R(IDS_LIBRARIES_INDEX_ITEM_KEY));
03571                     Str.toUpper();
03572                     *KeywordField = CountCommas(&TokenBufferU, Str);
03573                 }
03574                 
03575                 if(TitleField)
03576                 {
03577                     String_16 Str(_R(IDS_LIBRARIES_INDEX_ITEM_TITLE));
03578                     Str.toUpper();
03579                     *TitleField = CountCommas(&TokenBufferU, Str);
03580                 }
03581 
03582                 FoundFieldTitles = TRUE;
03583             }
03584             else if(TokType == TOKEN_LINE && TokenBufferU.Sub(String_16(_R(IDS_LIBRARIES_INDEX_START))) == 0)
03585             {
03586                 // We've found 'START', finish looping and return the results
03587                 if(Start)
03588                     *Start = TmpDiskFile->tellIn();
03589 
03590                 FoundStart = TRUE;
03591             }
03592             else
03593             {
03594                 // Check for the group description line. This could be in comment
03595                 // form: #DESC... or just normal form DESC... at the start of a line
03596                 INT32 Offset = TokenBufferU.Sub(String_16(_R(IDS_LIBRARIES_INDEX_DESCRITION)));
03597 
03598                 if(Description && Offset > -1 && Offset < 2)
03599                 {
03600                     String_256 TokenBuffer(TmpDiskFile->GetTokenBuf());
03601                     TokenBuffer.Right(Description, TokenBuffer.Length() - (12 + Offset));               
03602                     LibraryFile::KillLeadingSpaces(Description);
03603                 }
03604             }
03605         }
03606     }
03607     
03608     // reclaim lexer-buffer memory
03609     TmpDiskFile->DeinitLexer();
03610 
03611     if(TmpDiskFile->isOpen())
03612         TmpDiskFile->close();
03613 
03614     delete TmpDiskFile;
03615 
03616     return (FoundFieldTitles && FoundStart);
03617 }
03618 
03619 /***********************************************************************************************
03620 
03621 >   BOOL GenerateIndexFile::RipDescriptionFromIndex(PathName *IndexFile, PathName *FileName,
03622                     FilePos Start, INT32 DescriptionField, INT32 KeywordField, INT32 TitleField,
03623                     String_256 *Text, String_256 *Keywords = NULL, String_256 *Title = NULL)
03624     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
03625     Created:    10/05/95
03626 
03627     Inputs:     IndexFile           - Filename of index file to scan
03628                 FileName            - Filename of file to look for in index file
03629                 Start               - Offset from start of file to start scanning from
03630                 DescriptionField    - Number of commas to left of description field
03631                 KeywordField        - Number of commas to left of keyword field
03632                 TitleField          - Number of commas to left of title field
03633 
03634     Outputs:    Text                - Textual description to use for the file in the index
03635                 Keywords            - Keywords associated with the file in the index
03636                 Title               - Alternative title to display instead of filename in certain modes
03637 
03638     Returns:    TRUE if we found a description for the file
03639 
03640     Purpose:    Scan an old index file looking for the description of the given filename
03641 
03642     Notes:      PreScan does most of the parameter work for use...
03643 
03644 ***********************************************************************************************/
03645 
03646 BOOL GenerateIndexFile::RipDescriptionFromIndex(PathName *IndexFile, PathName *FileName,
03647                     FilePos Start, INT32 DescriptionField, INT32 KeywordField, INT32 TitleField,
03648                     String_256 *Text, String_256 *Keywords, String_256 *Title)
03649 {
03650     ERROR3IF(IndexFile == NULL, "GenerateIndexFile::RipDescriptionFromIndex given null index");
03651     ERROR3IF(FileName == NULL, "GenerateIndexFile::RipDescriptionFromIndex given null filename");
03652     ERROR3IF(Text == NULL, "GenerateIndexFile::RipDescriptionFromIndex given null text");
03653 
03654     if(IndexFile == NULL || FileName == NULL || Text == NULL)
03655         return FALSE;
03656 
03657     // We must always have 'filename' and 'description' as the first two...
03658     if(KeywordField < 2 || TitleField < 2 || (DescriptionField == TitleField))
03659         return FALSE;
03660 
03661     CCDiskFile *TmpDiskFile = new CCDiskFile(1024, TRUE, FALSE);
03662     if (TmpDiskFile == NULL)
03663     {
03664         ERROR3("Null index file allocated");
03665         return FALSE;
03666     }
03667 
03668     if (!TmpDiskFile->InitLexer(TRUE))
03669     {
03670         ERROR3("Problems with InitLexer");
03671         delete TmpDiskFile;
03672         return FALSE;
03673     }
03674 
03675     if (!TmpDiskFile->open(*IndexFile, ios::in))
03676     {
03677         ERROR3("Can't open backup index file");
03678         TmpDiskFile->DeinitLexer();
03679         delete TmpDiskFile;
03680         return FALSE;
03681     }
03682 
03683     // Jump over possibly useless lines..
03684     TmpDiskFile->seekIn(Start);
03685 
03686     String_256 TokenBuffer;
03687     LexTokenType TokType = TOKEN_LINE;
03688     BOOL FoundDescription = FALSE;
03689     String_256 TheFile(FileName->GetFileName());
03690     //String_256 ShortPath(TheFile);
03691     String_256 ShortPath(FileName->GetPath());
03692     TheFile.toUpper();
03693 
03694     // Make the path into its "short form", ie. 8.3 MS-DOS compatible.  This is necessary
03695     // as Windows NT doesn't like paths with spaces, even though it allows them (eg.
03696     // CreateProcess will fail when parsing the image path / command line).
03697 #ifdef _DEBUG
03698     ERROR3IF(!MakeShortPath((TCHAR *)ShortPath, _MAX_PATH), "MakeShortPath failed in SGIndGen");
03699 #else
03700     MakeShortPath((TCHAR *)ShortPath, _MAX_PATH);
03701 #endif
03702 
03703     // Get a filename from a full path string...
03704     PathName SrtPath(ShortPath);
03705     ShortPath = SrtPath.GetFileName(TRUE);
03706 
03707 
03708     while(TmpDiskFile->GetLineToken() && TokType != TOKEN_EOF && !FoundDescription)
03709     {
03710         TokType = TmpDiskFile->GetTokenType();
03711         if(TokType == TOKEN_LINE)
03712         {
03713             TokenBuffer = TmpDiskFile->GetTokenBuf();
03714             String_256 TokenBufferU(TokenBuffer);
03715             TokenBufferU.toUpper();
03716 
03717             // Check both uppercase versions for sub...
03718             // Note the filename is assumed to be the first field in each line, and the
03719             // description the second...
03720             if(TokenBufferU.Sub(TheFile) == 0 || TokenBufferU.Sub(ShortPath) == 0)
03721             {
03722                 TRACEUSER( "Richard", _T("Matched %s\n"), (TCHAR *)TheFile);
03723 
03724                 // Rip out the Description
03725                 // -----------------------
03726         
03727                 if(GetToken(&TokenBuffer, DescriptionField, Text))
03728                 {
03729                     FoundDescription = TRUE;
03730                     TRACEUSER( "Richard", _T("Description - '%s'\n"), (TCHAR *)*Text);
03731                 }
03732 
03733                 if(Title && TitleField != 0)
03734                 {
03735                     // Rip out the Title
03736                     // -----------------
03737 
03738                     if(GetToken(&TokenBuffer, TitleField, Title))
03739                     {
03740                         FoundDescription = TRUE;
03741                         TRACEUSER( "Richard", _T("Title - '%s'\n"), (TCHAR *)*Title);
03742                     }
03743                 }
03744 
03745                 if(Keywords && KeywordField != 0)
03746                 {
03747 
03748                     // Rip out the Keywords
03749                     // --------------------
03750 
03751                     if(GetToken(&TokenBuffer, KeywordField, Keywords))
03752                     {
03753                         FoundDescription = TRUE;
03754                         TRACEUSER( "Richard", _T("Keywords - '%s'\n"), (TCHAR *)*Keywords);
03755                     }
03756                 }
03757             }
03758         }
03759     }
03760 
03761 
03762 /*  if(FoundDescription)
03763     {
03764         LastFoundItemInIndex = TmpDiskFile->tell();
03765     }*/
03766     
03767     // reclaim lexer-buffer memory
03768     TmpDiskFile->DeinitLexer();
03769 
03770     if(TmpDiskFile->isOpen())
03771         TmpDiskFile->close();
03772 
03773     delete TmpDiskFile;
03774 
03775     // If no title present in index, but there was a description, or keywords, and the
03776     // file is an art file, use the art filename as the title...
03777     if(Title->Length() == 0 && FoundDescription)
03778     {
03779         String_256 Type(FileName->GetType());
03780         Type.toLower();
03781         if( (Type.Sub((String_8)"art") == 0) || (Type.Sub((String_8)"xar") == 0))
03782         {
03783             *Title = FileName->GetFileName(FALSE);
03784 
03785             // Default filename - force to lower case
03786             Title->toLower();
03787 
03788             // And capitalise the first character
03789             TCHAR First = camToupper(((TCHAR *)*Title)[0]);
03790             ((TCHAR *)*Title)[0] = First;
03791         }
03792     }
03793 
03794     return FoundDescription;
03795 }
03796 
03797 
03798 /***********************************************************************************************
03799 
03800 >   BOOL GenerateIndexFile::AddLineToIndex(String_256 *Text);
03801 
03802     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
03803     Created:    09/04/95
03804 
03805     Inputs:     Text - the text to add
03806     Outputs:
03807     Returns:    TRUE if things went ok.
03808 
03809     Purpose:    Adds the given text to the index file
03810     Notes:
03811 
03812 ***********************************************************************************************/
03813 
03814 BOOL GenerateIndexFile::AddLineToIndex(String_256 *Text)
03815 {
03816     if(IndexFile == NULL)
03817     {
03818         ERROR3("GenerateIndexFile::AddLineToIndex called with NULL index file");
03819         return FALSE;
03820     }
03821 
03822     if(Text == NULL)
03823     {
03824         ERROR3("GenerateIndexFile::AddLineToIndex called with NULL text ptr");
03825         return FALSE;
03826     }
03827 
03828     IndexFile->write(*Text, (UINT32)Text->Length());
03829 
03830     return TRUE;
03831 }
03832 
03833 /***********************************************************************************************
03834 
03835 >   BOOL GenerateIndexFile::CheckExistingIndexForRemoteness(PathName *IndexFile, PathName *FilesPath);
03836 
03837     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
03838     Created:    07/04/95
03839 
03840     Inputs:     IndexFile       - location and name of the index file to check
03841     Outputs:    FilesPath       - ptr to path of files in library to alter
03842     Returns:    TRUE if there's an index, and it's remote
03843 
03844     Purpose:    Check an index file to see if it's remote... If it is, return the remote location
03845                 to the caller...
03846     Notes:
03847 
03848 ***********************************************************************************************/
03849 
03850 BOOL GenerateIndexFile::CheckExistingIndexForRemoteness(PathName *IndexFile, PathName *FilesPath)
03851 {
03852     ERROR3IF(IndexFile == NULL || FilesPath == NULL, "GenerateIndexFile::CheckExistingIndexForRemoteness given null params");
03853     if(IndexFile == NULL || FilesPath == NULL)
03854         return FALSE;
03855 
03856     if(!SGLibOil::FileExists(IndexFile))
03857         return FALSE;
03858 
03859     CCDiskFile *TmpDiskFile = new CCDiskFile(1024, FALSE, TRUE);
03860     if (TmpDiskFile == NULL)
03861     {
03862         ERROR3("Null index file allocated");
03863         return FALSE;
03864     }
03865 
03866     if (!TmpDiskFile->InitLexer(TRUE))
03867     {
03868         ERROR3("Problems with InitLexer");
03869         delete TmpDiskFile;
03870         TmpDiskFile = NULL;
03871         return FALSE;
03872     }
03873 
03874     TRY
03875     {
03876         if (!TmpDiskFile->open(*IndexFile, ios::in))
03877         {
03878             ERROR3("Can't open index file for pre pass");
03879             TmpDiskFile->DeinitLexer();
03880             delete TmpDiskFile;
03881             TmpDiskFile = NULL;
03882             return FALSE;
03883         }
03884     }
03885 
03886     CATCH(CFileException, e)
03887     {
03888         // Some sort of problem with the open thingie...
03889         Error::ClearError();
03890         return FALSE;
03891     }
03892     END_CATCH
03893 
03894     LexTokenType TokType = TOKEN_LINE;
03895     String_256 RemotePath;
03896     BOOL FoundRemotePath = FALSE;
03897     BOOL FinishLooping = FALSE;
03898 
03899     // Loop through header ripping the interesting stuff out
03900     while(TmpDiskFile->GetLineToken() && TokType != TOKEN_EOF && !FinishLooping)
03901     {
03902         TokType = TmpDiskFile->GetTokenType();
03903         if(TokType == TOKEN_LINE || TokType == TOKEN_COMMENT)
03904         {
03905             String_256 TokenBufferU(TmpDiskFile->GetTokenBuf());
03906             TokenBufferU.toUpper();
03907 
03908             if(TokType == TOKEN_LINE && TokenBufferU.Sub(String_16(_R(IDS_LIBRARIES_INDEX_START))) == 0)
03909                 FinishLooping = TRUE;
03910             else
03911             {
03912                 // Check for the remote files line.
03913                 INT32 Offset = TokenBufferU.Sub(String_16(_R(IDS_LIBRARIES_INDEX_FILES)));
03914                 if(Offset == 0)
03915                 {
03916                     String_256 TokenBuffer(TmpDiskFile->GetTokenBuf());
03917                     TokenBuffer.Right(&RemotePath, TokenBuffer.Length() - (6 + Offset));                
03918                     LibraryFile::KillLeadingSpaces(&RemotePath);
03919                     FinishLooping = TRUE;
03920                     FoundRemotePath = TRUE;
03921                     FilesPath->SetPathName(RemotePath);
03922                 }
03923             }
03924         }
03925     }
03926     
03927     // reclaim lexer-buffer memory
03928     TmpDiskFile->DeinitLexer();
03929 
03930     if(TmpDiskFile->isOpen())
03931         TmpDiskFile->close();
03932 
03933     delete TmpDiskFile;
03934 
03935     return (FoundRemotePath);
03936 }
03937 
03938 
03939 
03940 /***********************************************************************************************
03941 
03942 >   BOOL GenerateIndexFile::Generate(PathName *IFile, PathName *LibDirPath, String_64 *Author
03943                                 SGLibType Type, BOOL Thumbnails);
03944 
03945     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
03946     Created:    9/4/95
03947 
03948     Inputs:     IFile - Full path of index file to generate - C:\testlib\animals\xarainfo\xaraclip.txt
03949                 LibDirPath - Full path of sublibrary - C:\testlib\animals
03950                 Author - Default origin of these files
03951                 Type - Type of library index required 
03952                 Thumbnails - Generate thumbnails if we can ?
03953     Outputs:
03954     Returns:    TRUE if things went ok.
03955 
03956     Purpose:    Generates a dummy index file for a directory of say .art files.
03957 
03958 ***********************************************************************************************/
03959 
03960 BOOL GenerateIndexFile::Generate(PathName *IFile, PathName *LibDirPath, String_64 *Auth,
03961                                  SGLibType Type, BOOL Thumbnails)
03962 {
03963 /*  String_256 IF(IFile->GetPath());
03964     String_256 LDP(LibDirPath->GetPath());
03965     ERROR3_PF(("Generate called with '%s' and '%s'", (TCHAR *)IF, (TCHAR *)LDP));*/
03966     
03967     if(IFile == NULL || LibDirPath == NULL)
03968     {
03969         ERROR3("GenerateIndexFile::Generate null params are bad");
03970         return FALSE;
03971     }
03972 
03973     if(SGLibOil::FileExists(IFile) && IsDirectoryReadOnly(LibDirPath))
03974     {
03975         ERROR3("Chosen directory is read only and already has an index... (We shouldn't really get here...)");
03976         return FALSE;
03977     }
03978 
03979     // Check if there's an existing index, and if so, check if it's a remote one...
03980     IndexIsRemote = CheckExistingIndexForRemoteness(IFile, LibDirPath);
03981 
03982     Index = *IFile;
03983     LibPath = *LibDirPath;
03984     LibType = Type;
03985     DoThumbnails = Thumbnails;
03986 
03987 #ifdef _DEBUG
03988     String_256 ChecksumDir(LibPath.GetPath());
03989     UINT32 Checksum = GetDirectoryChecksum(&ChecksumDir, Type);
03990     //ERROR3_PF(("Checksum for '%s' = %d", (TCHAR *)ChecksumDir, Checksum));
03991 #endif
03992 
03993     if(Auth != NULL)
03994         Author = *Auth;
03995     else
03996         Author = "";
03997 
03998     // DiskFile for index
03999     IndexFile = NULL;
04000 
04001     // Offset into index for the 'Number of files' data
04002     IndexCountOff = 0;
04003 
04004     // Search handle for directory scan     
04005     hSearch = NULL;
04006 
04007     // ID of current item and number of items in file
04008     ID = 0;
04009 
04010     // If we're overwriting an old index file, copy the old file to a tmp file and
04011     // use this variable to access it...
04012     TmpIndexFile = NULL;
04013 
04014     // Remote index stuff...
04015     IndexIsRemote = FALSE;
04016     RemoteLocationOfIndex = "";
04017     RemoteLocationOfFiles = "";
04018 
04019     BOOL ok = FALSE;
04020 
04021     // Display warnings unless told not to
04022     QuietThumbnail = FALSE;
04023 
04024     // Keep doing index until told not to
04025     StopIndGen = FALSE;
04026 
04027     // Total number of files that will be added to the index
04028     TotalFiles = CountValidFiles();
04029 
04030     if(TotalFiles == 0)
04031     {
04032         // "Can't find any files to add to index in specified folder";
04033         INT32 ButtonPressed = InformWarning(_R(IDS_LIBRARY_NO_FILES), _R(IDS_OK), NULL);
04034         Error::ClearError();
04035         ok = FALSE;
04036     }
04037     else
04038     {
04039         // Progress bar for generation status
04040         String_64 *Status = new String_64(_R(IDS_LIBRARY_GENERATING_INDEX));
04041         BeginSlowJob(TotalFiles, FALSE, Status);
04042 
04043         // Create the index file and keywords file then add headers to them                                                    
04044         if(CreateIndexFile())
04045         {
04046             // Add all the header data to an index file
04047             if(DoIndexHeader())
04048             {
04049                 // scan the directory for files and add them to the index and keyword files
04050                 ok = AddToSubLibrary();
04051 
04052                 // add in the number of IDs in the file
04053                 if(!FixSubLibraryNumber())
04054                     ok = FALSE;
04055             }
04056         }
04057     
04058         // Close the search handle
04059         CloseSearchHandle();
04060     
04061         // Close the file handle
04062         CloseIndexFileHandle();
04063 
04064         // If we created a temp index file, delete it
04065         if(TmpIndexFile != NULL)
04066         {
04067             SGLibOil::FileDelete(TmpIndexFile);
04068             delete TmpIndexFile;
04069             TmpIndexFile = NULL;
04070         }
04071 
04072         if(Status != NULL)
04073         {
04074             delete Status;
04075             Status = NULL;
04076         }
04077 
04078         EndSlowJob();
04079     }
04080 
04081     if(!ok)
04082     {
04083         TRACEUSER( "Richard", _T("All finished and hunky-dorey...\n"));
04084     }
04085 
04086     // Sort the index location out for the 'add' code...
04087     if(IndexIsRemote)
04088         *IFile = Index;
04089 
04090     // Just in case some stupid pathname problem occured...
04091     Error::ClearError();
04092 
04093     return ok;
04094 }
04095 
04096 
04097 /***********************************************************************************************
04098 
04099 >   static UINT32 GenerateIndexFile::GetDirectoryChecksum(String_256 *Directory, SGLibType Type = SGLib_Blank)
04100 
04101     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
04102     Created:    30/8/95
04103 
04104     Inputs:     Directory   - Path of directory to calculate check on
04105                 Type        - Type of library we require the checksum for (SGLib_Blank will include all
04106                                 the files in the directory, whereas SGLib_Texture will only include
04107                                 bitmapped images...)
04108     Outputs:
04109     Returns:    Checksum of files in directory
04110 
04111     Purpose:    Generates a dummy index file for a directory of say .art files.
04112 
04113 ***********************************************************************************************/
04114 
04115 UINT32 GenerateIndexFile::GetDirectoryChecksum(String_256 *Directory, SGLibType Type)
04116 {
04117     UINT32 Checksum = 0;
04118 
04119     if(GenerateIndexFile::UseAutomaticUpdate)
04120     {
04121         // Progress bar for checksum
04122         String_64 Status(_R(IDS_LIBRARIES_CALCULATING_CHECKSUM));
04123         BeginSlowJob(-1, FALSE, &Status);
04124 
04125         WIN32_FIND_DATA FileData;
04126         BOOL fFinished = FALSE;
04127         HANDLE hSearch = 0;
04128 
04129         String_256 FileSearch(*Directory);
04130         SGLibOil::AppendSlashIfNotPresent(&FileSearch);
04131         /*if(FileSearch[FileSearch.Length()-1] != '\\')
04132             FileSearch += TEXT("\\");*/
04133         FileSearch += TEXT("*.*");
04134 
04135         // Start searching for files
04136         hSearch = FindFirstFile(FileSearch, &FileData);
04137         if (hSearch == INVALID_HANDLE_VALUE)
04138         {
04139             ERROR3("No valid files found in this directory");
04140             fFinished = TRUE;
04141         }
04142 
04143         // Loop through those files...
04144         while (!fFinished)
04145         {
04146             // Add full pathname to file
04147             String_256 FileToAddStr(*Directory);
04148             SGLibOil::AppendSlashIfNotPresent(&FileToAddStr);
04149             /*if(FileToAddStr[FileToAddStr.Length()-1] != '\\')
04150                 FileToAddStr += TEXT("\\");*/
04151             FileToAddStr += (TCHAR *)FileData.cFileName;
04152 
04153             // Only use normal files - not directories, hidden files, etc...
04154             DWORD FileAttributes = GetFileAttributes(FileToAddStr);
04155 
04156             if( ((FileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
04157                 (FileAttributes & FILE_ATTRIBUTE_HIDDEN) ||
04158                 (FileAttributes & FILE_ATTRIBUTE_SYSTEM)) == 0)
04159             {
04160                 PathName FileToAdd(FileToAddStr);
04161 
04162                 // Check if the file is addable to the index
04163                 if(IsFileType(&FileToAdd, Type))
04164                 {
04165                     UINT32 Modified = SGLibOil::FileModified(&FileToAdd);
04166                     INT32 Size = SGLibOil::FileSize(&FileToAdd);
04167 
04168                     Checksum ++;
04169                     Checksum += Modified;
04170                     Checksum += Size;
04171                 }
04172             }
04173     
04174             // Find the next file
04175             if (!FindNextFile(hSearch, &FileData))
04176                 fFinished = TRUE;
04177         }
04178 
04179         // Close the search handle
04180         if(hSearch != NULL)
04181             if (!FindClose(hSearch))
04182                 ERROR3("Couldn't close search handle.");
04183         hSearch = NULL;
04184 
04185         EndSlowJob();
04186     }
04187 
04188     return Checksum;
04189 }
04190 
04191 #endif

Generated on Sat Nov 10 03:48:55 2007 for Camelot by  doxygen 1.4.4