-- Rockstar File Utility -- Rockstar North -- 1/3/2005 -- by Greg Smith -- by Luke Openshaw -- Set of utility functions for dealing with files --filein "pipeline/util/string.ms" -- loaded on startup by startup.ms ---------------------------------------------------------------------------------------- -- These old function-names are now aliases of built-in Max functions: ---------------------------------------------------------------------------------------- global RsFileExists = DoesFileExist global RsRemovePath = FilenameFromPath global RsRemoveFile = GetFilenamePath ---------------------------------------------------------------------------------------- -- from a full path to a file return just the filename with no extension ---------------------------------------------------------------------------------------- fn RsRemovePathAndExtension path = ( local outVal = getFilenameFile path -- getFilenameFile only strips the last extension, it doesn't deal with piled-up extensions: return (filterString outVal ".")[1] ) ---------------------------------------------------------------------------------------- -- use & - reference for extension ---------------------------------------------------------------------------------------- fn RsRemoveExtension path extension: = ( local extParts = (filterString path ".") if unsupplied!=extension then *extension = extParts[2] return extParts[1] ) ---------------------------------------------------------------------------------------- -- find the last occurance of a character in a string ---------------------------------------------------------------------------------------- fn RsFindLast searched char = ( retidx = -1 for i = 1 to searched.count do ( if retidx == -1 then ( index = searched.count - (i - 1) if char == searched[index] then ( retidx = index ) ) ) retidx ) -------------------------------------------------------------- -- makes sure that a passed in string is a valid path -------------------------------------------------------------- fn RsMakeSafeSlashes pathin = ( pathout = "" if isKindOf pathin String do ( local c local prevSlash = False for i = 1 to pathin.count do ( c = pathin[i] if (c == "/") or (c == "\\") then ( if not prevSlash do ( pathout += "/" ) prevSlash = True ) else ( prevSlash = False pathout += c ) ) ) pathout ) -------------------------------------------------------------- -- makes sure that a passed in string is a valid path -------------------------------------------------------------- fn RsMakeBackSlashes pathin = ( pathout = "" if isKindOf pathin String do ( local c local prevSlash = False for i = 1 to pathin.count do ( c = pathin[i] if (c == "/") or (c == "\\") then ( if not prevSlash do ( pathout += "\\" ) prevSlash = True ) else ( prevSlash = False pathout += c ) ) ) pathout ) ---------------------------------------------------------------------------------------- -- takes the filename of the path, leaving just the directory that the file is in ---------------------------------------------------------------------------------------- fn RsRemoveFilename fullpath = ( RsMakeSafeSlashes (getFilenamePath fullpath) ) -------------------------------------------------------------- -- makes sure that a passed in string is a valid path -------------------------------------------------------------- fn RsMakeSafePath pathin = ( pathout = RsMakeSafeSlashes pathin if pathout[pathout.count] != "/" then ( pathout = pathout + "/" ) pathout ) ------------------------------------------------------------------------------------------------- -- check that all the paths exist for the passed in file path ------------------------------------------------------------------------------------------------- fn RsMakeSurePathExists filePath = ( local dirPath = "" if ( "" == ( getFilenameType filePath ) ) then dirPath = filePath else dirPath = (getFilenamePath filePath) makedir DirPath ) ------------------------------------------------------------------------------------------------- -- delete a directory and any files in contains ------------------------------------------------------------------------------------------------- fn RsDeleteDirectory dir = ( -- GunnarD found bug 697996, taking out fo now diruse = RsMakeSafeSlashes dir return rexDeleteDirectory diruse ) ------------------------------------------------------------------------------------------------- -- delete all the files of a certain type in a directory ------------------------------------------------------------------------------------------------- fn RsDeleteFiles wildcard = ( wildcard = RsMakeBackSlashes wildcard retval = true files = getfiles wildcard for file in files do ( if retval == true then ( if deletefile file == false then ( retval = false ) ) ) retval ) ------------------------------------------------------------------------------------------------- -- copy all files by wildcard to a target folder ------------------------------------------------------------------------------------------------- fn RsCopyFiles wildcard targetdir = ( retval = true files = getfiles wildcard for file in files do ( if retval == true then ( targetfile = filenameFromPath file if copyfile file (targetdir + "/" + targetfile) == false then ( retval = false ) ) ) retval ) ------------------------------------------------------------------------------------------------- -- returns true if a file exists and is readonly else false ------------------------------------------------------------------------------------------------- fn RsIsFileReadOnly file = ( if ( doesFileExist file ) then ( getfileattribute file #readOnly ) else false ) ------------------------------------------------------------------------------------------------- -- RsFindFilesRecursive -- Recursively find list of files under rootpath matching wildcard(s) -- (e.g. "*.ide" or #("*.tga", "*.jpg)) ------------------------------------------------------------------------------------------------- fn RsFindFilesRecursive rootpath wildcards foundFiles:#() = ( local foundFiles = #() if not isKindOf wildcards Array do ( wildcards = #(wildcards) ) for wildcard in wildcards do ( join foundFiles (getFiles (rootpath + "/" + wildcard)) ) -- Post process to have consistent file paths for i = 1 to foundFiles.count do ( foundFiles[i] = RsMakeSafeSlashes foundFiles[i] ) for subDir in getDirectories (rootpath + "/*") do ( join foundFiles (RsFindFilesRecursive subDir wildcards foundFiles:foundFiles) ) return foundFiles ) ------------------------------------------------------------------------------------------------- -- name: RsFileExist -- description: Check if a file exists ------------------------------------------------------------------------------------------------- global RsFileExist = doesFileExist ------------------------------------------------------------------------------------------------- -- RsFindDirsRec -- Do not call this externally, use RsFindDirsRecursive ------------------------------------------------------------------------------------------------- fn RsFindDirsRec dirpath dirList = ( dirs = getDirectories (dirpath + "*") join dirList dirs for dir in dirs do ( RsFindDirsRec dir dirList ) ) ------------------------------------------------------------------------------------------------- -- RsFindDirsRecursive -- Recursively find list of dirs under rootpath with the folder name pattern ------------------------------------------------------------------------------------------------- fn RsFindDirsRecursive rootpath pattern foundDirs:#() = ( matchedDirs = #() RsFindDirsRec rootpath foundDirs for dir in foundDirs do ( -- Checks for trailing slash too as that is included in getDirectories incase * is not -- on the end of the pattern passed in if ( matchPattern dir pattern:pattern or matchPattern dir pattern:(pattern + "\\") ) do ( appendIfUnique matchedDirs dir ) ) matchedDirs ) -- -- name: RsDirectoryWriteable -- desc: Check that a directory exists and is writeable -- fn RsDirectoryWriteable dir = ( -- Because RsConfigGetNetworkStreamDir() returns a path ending with a '/', this should check -- if the '/' is present and if so remove it. if (matchPattern dir pattern:"*/" == true) then ( dir = substring dir 1 (dir.count - 1) ) -- DHM 2/8/10 -- to be blunt "isDirectoryWriteable" doesn't work with our -- network paths at least. Lets try to write a test file; which is kind of nasty and could -- leave a temporary file behind; but its got the machine name so its relatively safe. -- isDirectoryWriteable dir try ( local filename = (dir + "\\3dsmax_writeable_" + sysInfo.computername + ".txt") local fp = openFile filename mode:"w" format "File created for RsDirectoryWriteable(). Delete if modified date is not now!" to:fp close fp deleteFile filename true ) catch ( false ) ) -- -- name: RsFileModDate -- desc: Return file modifier date/time as .Net DateTime object -- (for comparison) -- fn RsFileModDate filename = ( local fileClass = dotNetClass "System.IO.File" local md = fileClass.GetLastWriteTime( filename ) md ) -- -- name: RsFileCreateDate -- desc: Return file creation date/time as .Net DateTime object -- (for comparison) -- fn RsFileCreateDate filename = ( local fileClass = dotNetClass "System.IO.File" local md = fileClass.GetCreationTime( filename ) md ) -- Open-dialog to get multiple filenames at once: fn RSgetOpenFilenames caption:"Open" filename:"" types:"All Files (*.*)|*.*" default:1 = ( local openDialog = DotNetObject "System.Windows.Forms.OpenFileDialog" openDialog.multiSelect = true openDialog.title = caption local filePath = getFilenamePath filename if doesFileExist filePath do ( openDialog.initialDirectory = filePath ) -- MAXScript getOpenFilename uses trailing |; DotNet's OpenFileDialog filter does not. if (types[types.count] == "|") do (types = (substring types 1 (types.count - 1))) openDialog.filter = types openDialog.filterIndex = default local result = openDialog.ShowDialog() if (result.Equals result.OK) then openDialog.filenames else undefined ) -- Removes any empty directories under path dirPath fn RsRemoveEmptyFolders dirPath = ( HiddenDOSCommand ("for /f \"usebackq delims=\" %d in (`\"dir \"" + (RsMakeBackSlashes dirPath) + "\" /ad/b/s | sort /R\"`) do rd \"%d\"") ) -- Returns hash of dirPath's file-times, allowing for easy change-tracking: fn RsPathTimeHash dirPath = ( local dirFilenames = RsFindFilesRecursive dirPath #("*.*") local fileTimes = for filename in dirFilenames collect (getFileModDate filename) getHashValue fileTimes 1 )