// This code is part of VDF GUIdance // Visit us @ http://www.vdf-guidance.com // e-Mail us @ info@vdf-guidance.com // VDF GUIdance is a mutual project of // Frank Vandervelpen - Vandervelpen Systems and // Wil van Antwerpen - Antwise Solutions // All software source code should be used <> without any warranty. // // // *** cFolderSet package *** // This package enables you to enumerate thru files and folders on a windows box. // It works with the windows API and creates a object oriented interface to work with // the data. // There is no userface attached anywhere, so that you can safely use this from both // VDF as well as WebApp // // Supported are: // - enumeration of a folder based on a searchpath // - renaming of files and folders in the search-criteria // // // Not supported for the moment: // - recursive folders // - Security info such as ACL and owners // - FileCreation // - non windows environments // // **WvA: November 17, 2001 // I would like to dedicate this code to a relative of mine that passed away earlier // this week. // Harry Stokkermans, God bless, hope you will find some peace now. // // Aug 28, 2006 // Changed destroy_object into destroy as reported by David Martinko // Removed insert of ":" character between parse_drive and parse_path // as reported by Hans van de Laar // Changed delete_data logic so that sending a delete_data also delete's // all fileproperty objects. // // Oct 23, 2006 // Added FilterSet logic and disable parentpath logic for use in webapp // // Dec 7, 2006 // Extended the filter logic for webapp and now added functionality for // supplying the filetypes that are allowed AND the filenames that are // allowed. This gives us some means to only show the files that are in // our database. // Use vWin32fh.pkg Use Parsefn.pkg Use set.pkg Enum_list // Constant File Properties Define CFP_LONG_FILENAME Define CFP_SHORT_FILENAME Define CFP_FILE_ATTRIBUTES Define CFP_FILE_SIZE // in bytes Define CFP_CREATION_DATETIME Define CFP_LASTACCESS_DATETIME Define CFP_LASTWRITE_DATETIME Define CFP_RECORDSIZE // Keep this field as the last one in your struct End_enum_list // Constant File Attributes Define CFA_READONLY for |CI$00000001 Define CFA_HIDDEN for |CI$00000002 Define CFA_SYSTEM for |CI$00000004 Define CFA_DIRECTORY for |CI$00000010 Define CFA_ARCHIVE for |CI$00000020 Define CFA_ENCRYPTED for |CI$00000040 Define CFA_NORMAL for |CI$00000080 Define CFA_TEMPORARY for |CI$00000100 Class cFileProperties Is A Array Procedure Construct_Object Forward Send Construct_Object Property Integer phoFolderSet 0 End_Procedure // Construct_Object End_Class // cFileProperties Class cFolderSet Is A Array Procedure Construct_Object Forward Send Construct_Object Property String psCurrentSearchPath "" // contains values such as "C:\*.s??" Property String psCurrentFolderName "" // This property will always end with a backslash, Ex. "C:\" Property String psFilterSet "" // If set then this defines the set of extensions that we allow to be used, example: "*.jpg;*.png" Property Integer piCurrentFile 0 Property Integer phoParentFolderSet 0 Property Boolean pbRecursive False // N.A. Set to true to retrieve all underlying folders Property Boolean pbObjectDestroyState False // Private, do not set Property Boolean pbEnableParentPaths False // To stop allowing the use of relative pathing in the URL "..\default.asp" Property Boolean pbClearFiltersOnRefresh False // Don't clear the active filters when refreshing Property Boolean pbRefreshActive False // PRIVATE Object oAcceptTypes is a Set End_Object Object oAcceptFiles is a Set End_Object End_Procedure // Construct_Object Procedure AddAcceptType String sType Move (Lowercase(trim(sType))) To sType Send Add_Element Of (oAcceptTypes(Self)) sType End_Procedure // AddAcceptType Procedure AddAcceptFile String sFileName Move (Lowercase(trim(sFileName))) To sFileName Send Add_Element Of (oAcceptFiles(Self)) sFileName End_Procedure // AddAcceptFile Function HasAcceptFilters Returns Boolean Integer iTypeCount Integer iFileCount Boolean bHasFilters Get Item_Count Of (oAcceptTypes(Self)) To iTypeCount Get Item_Count Of (oAcceptFiles(Self)) To iFileCount Move ((iTypeCount+iFileCount)>0) To bHasFilters Function_Return bHasFilters End_Function // HasAcceptFilters Procedure ClearAcceptFilters If (oAcceptTypes(Self)<>0) Begin // Using Alt-F4 to close the app seems to destroy the // kiddie objects first, which is why we test for the object // existence before sending delete towards it. Send Delete_Data Of (oAcceptTypes(Self)) Send Delete_Data Of (oAcceptFiles(Self)) End End_Procedure // ClearAcceptFilters Procedure Set LongFileName Integer iItem String sFileName Integer hoFileProps If (iItem < (Item_Count(Self))) Begin Get Value Item iItem To hoFileProps If (hoFileProps > Desktop) Begin Set Value Of hoFileProps Item CFP_LONG_FILENAME To sFileName End End End_Procedure // Set LongFileName Function LongFileName Integer iItem Returns String String sFileName Integer hoFileProps If (iItem < (Item_Count(Self))) Begin Get Value Item iItem To hoFileProps If (hoFileProps > Desktop) Begin Get Value Of hoFileProps Item CFP_LONG_FILENAME To sFileName End End Function_Return sFileName End_Function // LongFileName Procedure Set AlternateFileName Integer iItem String sFileName Integer hoFileProps If (iItem < (Item_Count(Self))) Begin Get Value Item iItem To hoFileProps If (hoFileProps > Desktop) Begin Set Value Of hoFileProps Item CFP_SHORT_FILENAME To sFileName End End End_Procedure // Set AlternateFileName Function AlternateFileName Integer iItem Returns String String sFileName Integer hoFileProps If (iItem < (Item_Count(Self))) Begin Get Value Item iItem To hoFileProps If (hoFileProps > Desktop) Begin Get Value Of hoFileProps Item CFP_SHORT_FILENAME To sFileName End End Function_Return sFileName End_Function // AlternateFileName // // Returns item number of the long filename if the filename // exists in the current buffer. // Returns -1 if nothing found. // Function FindLongFileName String sFileName returns integer Integer ndx retVal ArrMax String sLongFileName get item_count to ArrMax move -1 to retVal move 0 to ndx while (ndx < ArrMax AND retVal = -1) Get LongFileName Item ndx To sLongFileName If (Uppercase(sLongFileName) = Uppercase(sFileName)) move ndx to retVal Move (ndx + 1) to ndx Loop function_return retVal End_Function // FindLongFileName Procedure Set FileAttributes Integer iItem Dword dwFileAttributes Integer hoFileProps If (iItem < (Item_Count(Self))) Begin Get Value Item iItem To hoFileProps If (hoFileProps > Desktop) Begin Set Value Of hoFileProps Item CFP_FILE_ATTRIBUTES To dwFileAttributes End End End_Procedure // Set FileAttributes Function FileAttributes Integer iItem Returns Dword Dword dwFileAttributes Integer hoFileProps If (iItem < (Item_Count(Self))) Begin Get Value Item iItem To hoFileProps If (hoFileProps > Desktop) Begin Get Value Of hoFileProps Item CFP_FILE_ATTRIBUTES To dwFileAttributes End End Function_Return dwFileAttributes End_Function // FileAttributes Function IsAttributeReadOnly Integer iFile Returns Integer Dword dwFileAttributes Get FileAttributes Item iFile To dwFileAttributes Function_Return (dwFileAttributes iAnd CFA_READONLY) End_Function // IsAttributeReadOnly Function IsAttributeHidden Integer iFile Returns Integer Dword dwFileAttributes Get FileAttributes Item iFile To dwFileAttributes Function_Return (dwFileAttributes iAnd CFA_HIDDEN) End_Function // IsAttributeHidden Function IsAttributeSystem Integer iFile Returns Integer Dword dwFileAttributes Get FileAttributes Item iFile To dwFileAttributes Function_Return (dwFileAttributes iAnd CFA_SYSTEM) End_Function // IsAttributeSystem Function IsAttributeDirectory Integer iFile Returns Integer Dword dwFileAttributes Get FileAttributes Item iFile To dwFileAttributes Function_Return (dwFileAttributes iAnd CFA_DIRECTORY) End_Function // IsAttributeDirectory Function IsAttributeArchive Integer iFile Returns Integer Dword dwFileAttributes Get FileAttributes Item iFile To dwFileAttributes Function_Return (dwFileAttributes iAnd CFA_ARCHIVE) End_Function // IsAttributeArchive Function IsAttributeEncrypted Integer iFile Returns Integer Dword dwFileAttributes Get FileAttributes Item iFile To dwFileAttributes Function_Return (dwFileAttributes iAnd CFA_ENCRYPTED) End_Function // IsAttributeEncrypted Function IsAttributeNormal Integer iFile Returns Integer Dword dwFileAttributes Get FileAttributes Item iFile To dwFileAttributes Function_Return (dwFileAttributes iAnd CFA_NORMAL) End_Function // IsAttributeNormal Function IsAttributeTemporary Integer iFile Returns Integer Dword dwFileAttributes Get FileAttributes Item iFile To dwFileAttributes Function_Return (dwFileAttributes iAnd CFA_TEMPORARY) End_Function // IsAttributeTemporary // THis will return current attributes as a string much like the one you can see // in windows explorer, or when using the dos attrib command // We denominate the setting ot the attribute by returning its value Capitalized. // ADSHR = Archive Directory System Hidden Readonly all set. // adshr = None of the queried attributes are set. Function FileAttributeString Integer iFile Returns String Dword dwFileAttributes String sAttrib Get FileAttributes Item iFile To dwFileAttributes Move (if ( dwFileAttributes iAnd CFA_ARCHIVE , "A", "a")) To sAttrib Move (sAttrib+if ( dwFileAttributes iAnd CFA_DIRECTORY , "D", "d")) To sAttrib Move (sAttrib+if ( dwFileAttributes iAnd CFA_SYSTEM , "S", "s")) To sAttrib Move (sAttrib+if ( dwFileAttributes iAnd CFA_HIDDEN , "H", "h")) To sAttrib Move (sAttrib+if ( dwFileAttributes iAnd CFA_READONLY , "R", "r")) To sAttrib Function_Return sAttrib End_Function // FileAttributeString Procedure Set FileSizeBytes Integer iItem String sSize Integer hoFileProps If (iItem < (Item_Count(Self))) Begin Get Value Item iItem To hoFileProps If (hoFileProps > Desktop) Begin Set Value Of hoFileProps Item CFP_FILE_SIZE To sSize End End End_Procedure // Set FileSizeBytes Function FileSizeBytes Integer iItem Returns String String sSize Integer hoFileProps If (iItem < (Item_Count(Self))) Begin Get Value Item iItem To hoFileProps If (hoFileProps > Desktop) Begin Get Value Of hoFileProps Item CFP_FILE_SIZE To sSize End End Function_Return sSize End_Function // FileSizeBytes // Max filesize that we can return is 2,147,483,647 KB which seems large enough // for a single file for the next few years or so. Function FileSizekBytes Integer iItem Returns Integer String sSize Integer hoFileProps Integer iSize If (iItem < (Item_Count(Self))) Begin Get Value Item iItem To hoFileProps If (hoFileProps > Desktop) Begin Get Value Of hoFileProps Item CFP_FILE_SIZE To sSize Move (integer((sSize/1024.0)+0.5)) To iSize End End Function_Return iSize End_Function // FileSizekBytes Procedure Set CreationDateTime Integer iItem String sCreationDateTime Integer hoFileProps If (iItem < (Item_Count(Self))) Begin Get Value Item iItem To hoFileProps If (hoFileProps > Desktop) Begin Set Value Of hoFileProps Item CFP_CREATION_DATETIME To sCreationDateTime End End End_Procedure // Set CreationDateTime Function CreationDateTime Integer iItem Returns String String sCreationDateTime Integer hoFileProps If (iItem < (Item_Count(Self))) Begin Get Value Item iItem To hoFileProps If (hoFileProps > Desktop) Begin Get Value Of hoFileProps Item CFP_CREATION_DATETIME To sCreationDateTime End End Function_Return sCreationDateTime End_Function // CreationDateTime Procedure Set LastAccessDateTime Integer iItem String sLastAccessDateTime Integer hoFileProps If (iItem < (Item_Count(Self))) Begin Get Value Item iItem To hoFileProps If (hoFileProps > Desktop) Begin Set Value Of hoFileProps Item CFP_LASTACCESS_DATETIME To sLastAccessDateTime End End End_Procedure // Set LastAccessDateTime Function LastAccessDateTime Integer iItem Returns String String sLastAccessDateTime Integer hoFileProps If (iItem < (Item_Count(Self))) Begin Get Value Item iItem To hoFileProps If (hoFileProps > Desktop) Begin Get Value Of hoFileProps Item CFP_LASTACCESS_DATETIME To sLastAccessDateTime End End Function_Return sLastAccessDateTime End_Function // LastAccessDateTime Procedure Set LastWriteDateTime Integer iItem String sLastWriteDateTime Integer hoFileProps If (iItem < (Item_Count(Self))) Begin Get Value Item iItem To hoFileProps If (hoFileProps > Desktop) Begin Set Value Of hoFileProps Item CFP_LASTWRITE_DATETIME To sLastWriteDateTime End End End_Procedure // Set LastWriteDateTime Function LastWriteDateTime Integer iItem Returns String String sLastWriteDateTime Integer hoFileProps If (iItem < (Item_Count(Self))) Begin Get Value Item iItem To hoFileProps If (hoFileProps > Desktop) Begin Get Value Of hoFileProps Item CFP_LASTWRITE_DATETIME To sLastWriteDateTime End End Function_Return sLastWriteDateTime End_Function // LastWriteDateTime // Create a new file properties object // Function CreateFileObject Returns Handle Handle hoFileProperties Get Create (RefClass(cFileProperties)) to hoFileProperties Function_Return hoFileProperties End_Function // Adds a new slot for the file at the end in the buffer. // Returns the itemnumber of the file in the array if succesfull, // otherwise a value of -1 is returned. Function AddFile String sFileName Returns Integer Integer iRowCount hoFile Get Item_Count To iRowCount Get CreateFileObject To hoFile If (hoFile > Desktop) Begin Set Array_Value Item iRowCount To hoFile Set piCurrentFile To iRowCount Set LongFileName Item iRowCount To sFileName Set Name Of hoFile To (("oFileProps_")+sFileName) End Else Move -1 To iRowCount Function_Return iRowCount End_Function // AddFile // // This function is called if there are any filters set. // It checks the filename passed against the list of allowed // filetypes and filenames. // One can set filetypes, filenames or both to limit the output. // Function IsFileValid String sFileName Returns Boolean Integer iCount Integer iPos Boolean bIsValid String sExt String sFilterSet Move True To bIsValid Move (lowercase(sFileName)) To sFileName Get Item_Count Of (oAcceptTypes(Self)) To iCount If (iCount>0) Begin Get psFilterSet To sFilterSet Move (lowercase(sFilterSet)) To sFilterSet Get ParseFileExtension sFileName To sExt Move ("*."+trim(sExt)) To sExt // a bit of a lame filter.. If (Pos(sExt,sFilterSet)=0) Begin Move False To bIsValid End End If (bIsValid) Begin Get Item_Count Of (oAcceptFiles(Self)) To iCount If (iCount>0) Begin Get Find_Element Of (oAcceptFiles(Self)) To iPos If (iPos=-1) Begin // not found Move False To bIsValid End End End Function_Return bIsValid End_Function // IsFileValid // Read the folder at sSearchPath into the buffer // The searchpath may contain wildcard characters such as ? and * // If you want to list the contents of a folder // Procedure LoadBuffer String sSearchPath String sPath String sAlternateFileName sLongFileName sFileMask Integer hFindFile bIsFolder Integer iVoid iRetval iFile Boolean bHasFilters Boolean bEnableParentPaths Boolean bAddFile Dword dwFileAttributes Dword dwFileSizeHigh Dword dwFileSizeLow Dword dwLowDateTime Dword dwHighDateTime tvWin32FindData FindData Move (trim(sSearchPath)) To sSearchPath Get pbEnableParentPaths To bEnableParentPaths Get HasAcceptFilters To bHasFilters If (bEnableParentPaths=False) Begin Move (Replaces("..\",sSearchPath,"")) To sSearchPath End Get vFolderExists sSearchPath To bIsFolder If (bIsFolder) Begin // vFolderexists also supports wildcards, this is not what we Move (If( Pos("?",sSearchPath) <> 0,False,True)) To bIsFolder // expect for a true If (bIsFolder) Begin // folder, so we reset the status Move (If( Pos("*",sSearchPath) <> 0,False,True)) To bIsFolder End End If (bIsFolder) Begin Move (sysconf(SYSCONF_FILE_MASK)) To sFileMask // normally *.* Move (vFolderFormat(sSearchPath)) To sSearchPath Move (sSearchPath+sFileMask) To sSearchPath End Set psCurrentSearchPath To sSearchPath Move (Parse_Drive(sSearchPath)+Parse_Path(sSearchPath)) To sPath Move (vFolderFormat(sPath)) To sPath // psCurrentFolderName should always end with Move 1 To iRetval Set psCurrentFolderName To sPath // a directory separator (a backslash) Move 0 To FindData.nFileSizeLow Move (vWin32_FindFirstFile (AddressOf(sSearchPath), AddressOf(FindData))) To hFindFile If (hFindFile <> vINVALID_HANDLE_VALUE) Begin Repeat Move (UCharArrayToString(FindData.cFileName)) To sLongFileName Move FindData.dwFileAttributes To dwFileAttributes // Seen some really weird things when not getting rid of the zero's, zero's or not valid in a normal filename anyways, as an extra bonus this should speed things up as now it doesnt check 260 chars anymore Move (CString(sLongFileName)) To sLongFileName // We need to know if this is a folder a little later Move (dwFileAttributes iAnd CFA_DIRECTORY) To bIsFolder Move True To bAddFile // Assume we want to add this file into our array If (bEnableParentPaths=False And (sLongFileName="." Or sLongFileName="..")) Begin Move False To bAddFile End Else If (bIsFolder=False) Begin // A filter set has been defined, so check if the filename matches the filter. Get IsFileValid sLongFileName To bAddFile End If (bAddFile) Begin // It's a valid file start adding it to our array Get AddFile sLongFileName To iFile If (iFile <> -1) Begin Move (UCharArrayToString(FindData.cAlternateFileName)) To sAlternateFileName If (sAlternateFileName = "") Begin // Use GetShortPathName winAPI, short what? funk win9x it's a thing of the past End Set AlternateFileName Item iFile To sAlternateFileName // These are the file_attributes that can be matched with the above defines Set FileAttributes Item iFile To dwFileAttributes Move FindData.nFileSizeHigh To dwFileSizeHigh Move FindData.nFileSizeLow To dwFileSizeLow Set FileSizeBytes Item iFile To (String((dwFileSizeHigh * vMaxDword) + dwFileSizeLow)) Move FindData.ftCreationLowDateTime To dwLowDateTime Move FindData.ftCreationHighDateTime To dwHighDateTime Set CreationDateTime Item iFile To (vConvertFileDateTime (dwLowDateTime, dwHighDateTime)) Move FindData.ftLastAccessLowDateTime To dwLowDateTime Move FindData.ftLastAccessHighDateTime To dwHighDateTime Set LastAccessDateTime Item iFile To (vConvertFileDateTime (dwLowDateTime, dwHighDateTime)) Move FindData.ftLastWriteLowDateTime To dwLowDateTime Move FindData.ftLastWriteHighDateTime To dwHighDateTime Set LastWriteDateTime Item iFile To (vConvertFileDateTime (dwLowDateTime, dwHighDateTime)) End Else Begin Move False To iRetVal End End If (iRetVal<> False) Begin Move (vWin32_FindNextFile (hFindFile, AddressOf(FindData))) To iRetval End // If iRetval = false the function call fails but GetLastError // fails to tell me if this was because we do not find any files // anymore. // Actually the returnValue is vERROR_NO_MORE_FILES Until iRetval Eq dfFalse Move (vWin32_FindClose (hFindFile)) To ivoid End // hFindFile End_Procedure // LoadBuffer Procedure DeleteAllProperties Integer iCount iIndex Handle hoFileProperties hoFolderSet Get Item_Count To iCount For iIndex From 0 To (iCount-1) Get Value Item iIndex To hoFileProperties If (hoFileProperties <> 0 and (Object_ID(hoFileProperties)<>0)) Begin Get phoFolderSet of hoFileProperties To hoFolderSet If (hoFolderSet <> 0) Begin Send DeleteAllProperties To hoFolderSet End Send Delete_Data Of hoFileProperties Send Destroy Of hoFileProperties Set Value Item iIndex To 0 End Loop End_Procedure // DeleteAllProperties Procedure Delete_Data If (pbObjectDestroyState(Self)=False) Begin Send DeleteAllProperties If (pbRefreshActive(Self)=False Or pbClearFiltersOnRefresh(Self)) Begin Send ClearAcceptFilters End End Forward Send Delete_Data End_Procedure // Delete_Data Procedure destroy Send Delete_Data Set pbObjectDestroyState To True Forward Send destroy End_Procedure // destroy // Refreshes the contents of the current data in the folderset // This is a non-recursive operation. Procedure Refresh String sSearchPath Integer bRecursive Set pbRefreshActive To True Send Delete_Data Get psCurrentSearchPath To sSearchPath Send LoadBuffer sSearchPath Set pbRefreshActive To False End_Procedure // Refresh // This function will physically rename the file at slot iFile to its new filename sNewFileName // The Current folder will be refreshed immediately after this process completes // Returns a nonzero integer if the renaming process fails. Function RenameFileItem Integer iFile String sNewFileName Returns Integer String sOldFileName sFolderName Integer hoFileProps iRetVal If (iFile < (Item_Count(Self))) Begin Get Value Item iFile To hoFileProps If (hoFileProps > Desktop) Begin Get Value Of hoFileProps Item CFP_LONG_FILENAME To sOldFileName Get psCurrentFolderName To sFolderName Get vRenameFile (sFolderName+sOldFileName) (sFolderName+sNewFileName) To iRetVal If (iRetVal = 0) Begin Send Refresh End End End Else Begin Move 1 To iRetVal End Function_Return iRetVal End_Function // RenameFileItem // This function will physically delete the file at slot iFile. // The Current folder will be refreshed immediately after this process completes // Returns a nonzero integer if the Delete process fails. Function DeleteFileItem Integer iFile Returns Integer String sFileName sFolderName Integer hoFileProps iRetVal If (iFile < (Item_Count(Self))) Begin Get Value Item iFile To hoFileProps If (hoFileProps > Desktop) Begin Get Value Of hoFileProps Item CFP_LONG_FILENAME To sFileName Get psCurrentFolderName To sFolderName Get vDeleteFile (sFolderName+sFileName) To iRetVal If (iRetVal = 0) Begin Send Refresh End End End Else Begin Move 1 To iRetVal End Function_Return iRetVal End_Function // DeleteFileItem // This function will remove the file at slot iFile from the folder set buffer // This does not make any changes on disk. // // Returns a nonzero integer if the remove process fails. Function DeleteBufferItem Integer iFile Returns Integer String sFileName Integer hoFileProps iRetVal If (iFile < (Item_Count(Self))) Begin Get Value Item iFile To hoFileProps If (hoFileProps > Desktop and (Object_Id(hoFileProps)<>0)) Begin Send Delete_Data Of hoFileProps Send Destroy Of hoFileProps Send Delete_Item iFile End End Else Begin Move 1 To iRetVal End Function_Return iRetVal End_Function // DeleteBufferItem Procedure RemoveBufferFileByName String sFileName Integer iFile Integer iFail Get FindLongFileName sFileName To iFile If (iFile>=0) Begin Get DeleteBufferItem iFile To iFail End End_Procedure // RemoveBufferFileByName End_Class // cFolderSet Object oFileBrowser Is A cFolderSet End_Object // oFileBrowser