/** Provides classes for working with files and folders. */ import Location /** A file or folder. */ class Container extends @container, Top { /** * Gets the absolute, canonical path of this container, using forward slashes * as path separator. * * The path starts with a _root prefix_ followed by zero or more _path * segments_ separated by forward slashes. * * The root prefix is of one of the following forms: * * 1. A single forward slash `/` (Unix-style) * 2. An upper-case drive letter followed by a colon and a forward slash, * such as `C:/` (Windows-style) * 3. Two forward slashes, a computer name, and then another forward slash, * such as `//FileServer/` (UNC-style) * * Path segments are never empty (that is, absolute paths never contain two * contiguous slashes, except as part of a UNC-style root prefix). Also, path * segments never contain forward slashes, and no path segment is of the * form `.` (one dot) or `..` (two dots). * * Note that an absolute path never ends with a forward slash, except if it is * a bare root prefix, that is, the path has no path segments. A container * whose absolute path has no segments is always a `Folder`, not a `File`. */ abstract string getAbsolutePath(); /** * Gets a URL representing the location of this container. * * For more information see [Providing URLs](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/#providing-urls). */ abstract string getURL(); /** * Gets the relative path of this file or folder from the root folder of the * analyzed source location. The relative path of the root folder itself is * the empty string. * * This has no result if the container is outside the source root, that is, * if the root folder is not a reflexive, transitive parent of this container. */ string getRelativePath() { exists(string absPath, string pref | absPath = this.getAbsolutePath() and sourceLocationPrefix(pref) | absPath = pref and result = "" or absPath = pref.regexpReplaceAll("/$", "") + "/" + result and not result.matches("/%") ) } /** * Gets the base name of this container including extension, that is, the last * segment of its absolute path, or the empty string if it has no segments. * * Here are some examples of absolute paths and the corresponding base names * (surrounded with quotes to avoid ambiguity): * * * * * * * * * *
Absolute pathBase name
"/tmp/tst.java""tst.java"
"C:/Program Files (x86)""Program Files (x86)"
"/"""
"C:/"""
"D:/"""
"//FileServer/"""
*/ string getBaseName() { result = this.getAbsolutePath().regexpCapture(".*/(([^/]*?)(?:\\.([^.]*))?)", 1) } /** * Gets the extension of this container, that is, the suffix of its base name * after the last dot character, if any. * * In particular, * * - if the name does not include a dot, there is no extension, so this * predicate has no result; * - if the name ends in a dot, the extension is the empty string; * - if the name contains multiple dots, the extension follows the last dot. * * Here are some examples of absolute paths and the corresponding extensions * (surrounded with quotes to avoid ambiguity): * * * * * * * * *
Absolute pathExtension
"/tmp/tst.java""java"
"/tmp/.classpath""classpath"
"/bin/bash"not defined
"/tmp/tst2."""
"/tmp/x.tar.gz""gz"
*/ string getExtension() { result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(\\.([^.]*))?", 3) } /** * Gets the stem of this container, that is, the prefix of its base name up to * (but not including) the last dot character if there is one, or the entire * base name if there is not. * * Here are some examples of absolute paths and the corresponding stems * (surrounded with quotes to avoid ambiguity): * * * * * * * * *
Absolute pathStem
"/tmp/tst.java""tst"
"/tmp/.classpath"""
"/bin/bash""bash"
"/tmp/tst2.""tst2"
"/tmp/x.tar.gz""x.tar"
*/ string getStem() { result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(?:\\.([^.]*))?", 1) } /** Gets the parent container of this file or folder, if any. */ Container getParentContainer() { containerparent(result, this) } /** Gets a file or sub-folder in this container. */ Container getAChildContainer() { this = result.getParentContainer() } /** Gets a file in this container. */ File getAFile() { result = this.getAChildContainer() } /** Gets the file in this container that has the given `baseName`, if any. */ File getFile(string baseName) { result = this.getAFile() and result.getBaseName() = baseName } /** Gets a sub-folder in this container. */ Folder getAFolder() { result = this.getAChildContainer() } /** Gets the sub-folder in this container that has the given `baseName`, if any. */ Folder getFolder(string baseName) { result = this.getAFolder() and result.getBaseName() = baseName } /** * Gets a textual representation of this container. * * The default implementation gets the absolute path to the container, but subclasses may override * to provide a different result. To get the absolute path of any `Container`, call * `Container.getAbsolutePath()` directly. */ override string toString() { result = this.getAbsolutePath() } } /** A folder. */ class Folder extends Container, @folder { override string getAbsolutePath() { folders(this, result) } /** Gets the URL of this folder. */ override string getURL() { result = "folder://" + this.getAbsolutePath() } override string getAPrimaryQlClass() { result = "Folder" } } /** * A file. * * Note that `File` extends `Container` as it may be a `jar` file. */ class File extends Container, @file { override string getAbsolutePath() { files(this, result) } /** Gets the URL of this file. */ override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" } override string getAPrimaryQlClass() { result = "File" } } /** * A Java archive file with a ".jar" extension. */ class JarFile extends File { JarFile() { this.getExtension() = "jar" } /** * Gets the main attribute with the specified `key` * from this JAR file's manifest. */ string getManifestMainAttribute(string key) { jarManifestMain(this, key, result) } /** * Gets the "Specification-Version" main attribute * from this JAR file's manifest. */ string getSpecificationVersion() { result = this.getManifestMainAttribute("Specification-Version") } /** * Gets the "Implementation-Version" main attribute * from this JAR file's manifest. */ string getImplementationVersion() { result = this.getManifestMainAttribute("Implementation-Version") } /** * Gets the per-entry attribute for the specified `entry` and `key` * from this JAR file's manifest. */ string getManifestEntryAttribute(string entry, string key) { jarManifestEntries(this, entry, key, result) } override string getAPrimaryQlClass() { result = "JarFile" } }