| 2 | | Copyright (c) 2006 Eric Anderton |
|---|
| 3 | | |
|---|
| 4 | | Permission is hereby granted, free of charge, to any person |
|---|
| 5 | | obtaining a copy of this software and associated documentation |
|---|
| 6 | | files (the "Software"), to deal in the Software without |
|---|
| 7 | | restriction, including without limitation the rights to use, |
|---|
| 8 | | copy, modify, merge, publish, distribute, sublicense, and/or |
|---|
| 9 | | sell copies of the Software, and to permit persons to whom the |
|---|
| 10 | | Software is furnished to do so, subject to the following |
|---|
| 11 | | conditions: |
|---|
| 12 | | |
|---|
| 13 | | The above copyright notice and this permission notice shall be |
|---|
| 14 | | included in all copies or substantial portions of the Software. |
|---|
| 15 | | |
|---|
| 16 | | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|---|
| 17 | | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
|---|
| 18 | | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
|---|
| 19 | | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
|---|
| 20 | | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
|---|
| 21 | | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|---|
| 22 | | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
|---|
| 23 | | OTHER DEALINGS IN THE SOFTWARE. |
|---|
| | 2 | Copyright (c) 2006 Eric Anderton, Tomasz Stachowiak |
|---|
| | 3 | |
|---|
| | 4 | Permission is hereby granted, free of charge, to any person |
|---|
| | 5 | obtaining a copy of this software and associated documentation |
|---|
| | 6 | files (the "Software"), to deal in the Software without |
|---|
| | 7 | restriction, including without limitation the rights to use, |
|---|
| | 8 | copy, modify, merge, publish, distribute, sublicense, and/or |
|---|
| | 9 | sell copies of the Software, and to permit persons to whom the |
|---|
| | 10 | Software is furnished to do so, subject to the following |
|---|
| | 11 | conditions: |
|---|
| | 12 | |
|---|
| | 13 | The above copyright notice and this permission notice shall be |
|---|
| | 14 | included in all copies or substantial portions of the Software. |
|---|
| | 15 | |
|---|
| | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|---|
| | 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
|---|
| | 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
|---|
| | 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
|---|
| | 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
|---|
| | 21 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|---|
| | 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
|---|
| | 23 | OTHER DEALINGS IN THE SOFTWARE. |
|---|
| 46 | | LoaderRegistry loaderRegistry; |
|---|
| 47 | | DynamicLibrary[] rootLibraries; |
|---|
| 48 | | DynamicLibrary[char[]] cachedLibraries; // libraries by namespace |
|---|
| 49 | | Attributes attributes; |
|---|
| 50 | | FilePath root; |
|---|
| 51 | | |
|---|
| 52 | | debug protected void debugPathList(char[] prompt,FilePath[] list){ |
|---|
| 53 | | debugLog("%s (%d)\n",prompt,list.length); |
|---|
| 54 | | foreach(path; list){ |
|---|
| 55 | | debugLog(" %s\n",path.toUtf8()); |
|---|
| 56 | | } |
|---|
| 57 | | } |
|---|
| 58 | | |
|---|
| 59 | | protected FilePath[] getRootFiles(){ |
|---|
| 60 | | FilePath[] result = (new FileProxy(root)).toList(); |
|---|
| 61 | | if(result.length >= 2){ |
|---|
| 62 | | result = result[2..$]; //HACK: get rid of the '.' and '..' entries |
|---|
| 63 | | } |
|---|
| 64 | | else{ |
|---|
| 65 | | result.length = 0; |
|---|
| 66 | | } |
|---|
| 67 | | debug debugPathList("PathLibrary.getRootFiles",result); |
|---|
| 68 | | return result; |
|---|
| 69 | | } |
|---|
| 70 | | |
|---|
| 71 | | protected FilePath[] getFiles(char[] subDirectory){ |
|---|
| 72 | | FilePath[] result = (new FileProxy(root.toString ~ subDirectory)).toList(); |
|---|
| 73 | | if(result.length >= 2){ |
|---|
| 74 | | result = result[2..$]; //HACK: get rid of the '.' and '..' entries |
|---|
| 75 | | } |
|---|
| 76 | | else{ |
|---|
| 77 | | result.length = 0; |
|---|
| 78 | | } |
|---|
| 79 | | debug debugPathList("PathLibrary.getFiles",result); |
|---|
| 80 | | return result; |
|---|
| 81 | | } |
|---|
| 82 | | |
|---|
| 83 | | protected FilePath[] getAllFiles(){ |
|---|
| 84 | | FilePath[] result; |
|---|
| 85 | | FileScan scan = new FileScan(); |
|---|
| 86 | | |
|---|
| 87 | | bool filter(FilePath path){ |
|---|
| 88 | | return true; // don't filter at all |
|---|
| 89 | | } |
|---|
| 90 | | void handle(File file){ |
|---|
| 91 | | result ~= file.getPath(); |
|---|
| 92 | | } |
|---|
| 93 | | |
|---|
| 94 | | scan(root,&filter); |
|---|
| 95 | | scan.files(&handle); |
|---|
| 96 | | |
|---|
| 97 | | debug debugPathList("PathLibrary.getAllFiles",result); |
|---|
| 98 | | return result; |
|---|
| 99 | | } |
|---|
| 100 | | |
|---|
| 101 | | protected char[] convertPathToNamespace(char[] path){ |
|---|
| 102 | | char[] temp = Text.replace(path,'/','.'); |
|---|
| 103 | | return Text.replace(temp,'\\','.'); |
|---|
| 104 | | } |
|---|
| 105 | | |
|---|
| 106 | | protected char[] convertNamespaceToPath(char[] namespace){ |
|---|
| 107 | | int split = Text.rIndexOf(namespace,'.'); |
|---|
| 108 | | if(split == -1){ |
|---|
| 109 | | return ""; |
|---|
| 110 | | } |
|---|
| 111 | | // process everything up to the last '.' - this is the true namespace |
|---|
| 112 | | return Text.replace(namespace[0..split],'.','\\'); |
|---|
| 113 | | } |
|---|
| 114 | | |
|---|
| 115 | | protected char[] parseNamespace(char[] symbolName){ |
|---|
| 116 | | char[] dName = demangleSymbol(symbolName); |
|---|
| 117 | | uint split; |
|---|
| 118 | | |
|---|
| 119 | | // find where symbol ends |
|---|
| 120 | | for(split=0; split<dName.length; split++){ |
|---|
| 121 | | switch(dName[split]){ |
|---|
| 122 | | case '(': |
|---|
| 123 | | case ' ': |
|---|
| 124 | | case ';': |
|---|
| 125 | | break; |
|---|
| 126 | | default: |
|---|
| 127 | | } |
|---|
| 128 | | } |
|---|
| 129 | | return dName[0..split]; |
|---|
| 130 | | } |
|---|
| 131 | | |
|---|
| 132 | | public this(char[] rootPath,LoaderRegistry loaderRegistry){ |
|---|
| 133 | | this.root = new FilePath(rootPath); |
|---|
| 134 | | this.loaderRegistry = loaderRegistry; |
|---|
| 135 | | |
|---|
| 136 | | //pre-load all root libs |
|---|
| 137 | | foreach(FilePath filepath; getRootFiles()){ |
|---|
| 138 | | debug debugLog("[PathLibrary] Loading: %s",filepath.splice(root)); |
|---|
| 139 | | DynamicLibrary lib = loaderRegistry.load(filepath.splice(root)); |
|---|
| 140 | | if(lib){ |
|---|
| 141 | | rootLibraries ~= lib; |
|---|
| 142 | | } |
|---|
| 143 | | } |
|---|
| 144 | | |
|---|
| 145 | | attributes["PATH.path"] = root.toUtf8; |
|---|
| 146 | | } |
|---|
| 147 | | |
|---|
| 148 | | public ExportSymbolPtr getSymbol(char[] name){ |
|---|
| 149 | | DynamicModule mod = this.getModuleForSymbol(name); |
|---|
| 150 | | if(mod) return mod.getSymbol(name); |
|---|
| 151 | | return null; |
|---|
| 152 | | } |
|---|
| 153 | | |
|---|
| 154 | | public ExportSymbol[] getSymbols(){ |
|---|
| 155 | | ExportSymbol[] symbols; |
|---|
| 156 | | foreach(DynamicModule mod; getModules()){ |
|---|
| 157 | | symbols ~= mod.getSymbols(); |
|---|
| 158 | | } |
|---|
| 159 | | return symbols; |
|---|
| 160 | | } |
|---|
| 161 | | |
|---|
| 162 | | public DynamicModule[] getModules(){ |
|---|
| 163 | | DynamicModule[] result; |
|---|
| 164 | | |
|---|
| 165 | | //go through all the files in scope and load everything possible |
|---|
| 166 | | //NOTE: this ignores already loaded root libs |
|---|
| 167 | | foreach(FilePath libPath; getAllFiles()){ |
|---|
| 168 | | DynamicLibrary lib = loaderRegistry.load(libPath.toString); |
|---|
| 169 | | if(lib) result ~= lib.getModules(); |
|---|
| 170 | | } |
|---|
| 171 | | return result; |
|---|
| 172 | | } |
|---|
| 173 | | |
|---|
| 174 | | public char[] getType(){ |
|---|
| 175 | | return "PATH"; |
|---|
| 176 | | } |
|---|
| 177 | | |
|---|
| 178 | | public char[][char[]] getAttributes(){ |
|---|
| 179 | | return this.attributes; |
|---|
| 180 | | } |
|---|
| 181 | | |
|---|
| 182 | | public DynamicModule getModuleForSymbol(char[] name){ |
|---|
| 183 | | if(name.length > 2 && name[0..2] == "_D"){ |
|---|
| 184 | | char[] namespace = parseNamespace(name); |
|---|
| 185 | | |
|---|
| 186 | | // dig through the root libs |
|---|
| 187 | | foreach(DynamicLibrary lib; rootLibraries){ |
|---|
| 188 | | DynamicModule mod = lib.getModuleForSymbol(name); |
|---|
| 189 | | cachedLibraries[namespace] = lib; |
|---|
| 190 | | if(mod) return mod; |
|---|
| 191 | | } |
|---|
| 192 | | |
|---|
| 193 | | // attempt to search the cache |
|---|
| 194 | | DynamicLibrary* pLib = namespace in cachedLibraries; |
|---|
| 195 | | if(pLib) return pLib.getModuleForSymbol(name); |
|---|
| 196 | | |
|---|
| 197 | | // look for a path match |
|---|
| 198 | | char[] path = this.root.toString() ~ convertNamespaceToPath(namespace); |
|---|
| 199 | | if(path != ""){ |
|---|
| 200 | | //find first loadable library file that matches <root-path><path>/* and contains 'name' |
|---|
| 201 | | foreach(FilePath libPath; getFiles(path)){ |
|---|
| 202 | | DynamicLibrary lib = loaderRegistry.load(libPath.toString); |
|---|
| 203 | | if(lib) return lib.getModuleForSymbol(name); |
|---|
| 204 | | } |
|---|
| 205 | | } |
|---|
| 206 | | } |
|---|
| 207 | | // match a non-D symbol |
|---|
| 208 | | else{ |
|---|
| 209 | | // dig through the root libs |
|---|
| 210 | | foreach(DynamicLibrary lib; rootLibraries){ |
|---|
| 211 | | DynamicModule mod = lib.getModuleForSymbol(name); |
|---|
| 212 | | if(mod) return mod; |
|---|
| 213 | | } |
|---|
| 214 | | } |
|---|
| 215 | | //failed to find the module |
|---|
| 216 | | debug debugLog("PathLibrary.getModuleForSymbol - failed to find: %s",name); |
|---|
| 217 | | return null; |
|---|
| 218 | | } |
|---|
| 219 | | |
|---|
| 220 | | // expects resource in file-path format |
|---|
| 221 | | public ubyte[] getResource(char[] name){ |
|---|
| 222 | | FileConduit fc = new FileConduit(this.root.toString ~ name); |
|---|
| 223 | | ubyte[] data = new ubyte[fc.length]; |
|---|
| 224 | | fc.read(data); |
|---|
| 225 | | return data; |
|---|
| 226 | | } |
|---|
| | 52 | LoaderRegistry loaderRegistry; |
|---|
| | 53 | DynamicLibrary[] rootLibraries; |
|---|
| | 54 | DynamicLibrary[char[]] cachedLibraries; // libraries by namespace |
|---|
| | 55 | Attributes attributes; |
|---|
| | 56 | FilePath root; |
|---|
| | 57 | protected char[] delegate(char[])[] namespaceTranslators; |
|---|
| | 58 | |
|---|
| | 59 | void addNamespaceTranslator(char[] delegate(char[]) dg) { |
|---|
| | 60 | namespaceTranslators ~= dg; |
|---|
| | 61 | } |
|---|
| | 62 | |
|---|
| | 63 | |
|---|
| | 64 | debug protected void debugPathList(char[] prompt,FilePath[] list){ |
|---|
| | 65 | debugLog("%s (%d)\n",prompt,list.length); |
|---|
| | 66 | foreach(path; list){ |
|---|
| | 67 | debugLog(" %s\n",path.toUtf8()); |
|---|
| | 68 | } |
|---|
| | 69 | } |
|---|
| | 70 | |
|---|
| | 71 | protected FilePath[] getRootFiles(){ |
|---|
| | 72 | FilePath[] result = (new FileProxy(root)).toList(); |
|---|
| | 73 | if(result.length >= 2){ |
|---|
| | 74 | result = result[2..$]; //HACK: get rid of the '.' and '..' entries |
|---|
| | 75 | } |
|---|
| | 76 | else{ |
|---|
| | 77 | result.length = 0; |
|---|
| | 78 | } |
|---|
| | 79 | debug debugPathList("PathLibrary.getRootFiles",result); |
|---|
| | 80 | return result; |
|---|
| | 81 | } |
|---|
| | 82 | |
|---|
| | 83 | protected FilePath[] getFiles(char[] subDirectory){ |
|---|
| | 84 | FilePath[] result = (new FileProxy(root.toString ~ subDirectory)).toList(); |
|---|
| | 85 | if(result.length >= 2){ |
|---|
| | 86 | result = result[2..$]; //HACK: get rid of the '.' and '..' entries |
|---|
| | 87 | } |
|---|
| | 88 | else{ |
|---|
| | 89 | result.length = 0; |
|---|
| | 90 | } |
|---|
| | 91 | debug debugPathList("PathLibrary.getFiles",result); |
|---|
| | 92 | return result; |
|---|
| | 93 | } |
|---|
| | 94 | |
|---|
| | 95 | protected FilePath[] getAllFiles(){ |
|---|
| | 96 | FilePath[] result; |
|---|
| | 97 | FileScan scan = new FileScan(); |
|---|
| | 98 | |
|---|
| | 99 | bool filter(FilePath path){ |
|---|
| | 100 | return true; // don't filter at all |
|---|
| | 101 | } |
|---|
| | 102 | void handle(File file){ |
|---|
| | 103 | result ~= file.getPath(); |
|---|
| | 104 | } |
|---|
| | 105 | |
|---|
| | 106 | scan(root,&filter); |
|---|
| | 107 | scan.files(&handle); |
|---|
| | 108 | |
|---|
| | 109 | debug debugPathList("PathLibrary.getAllFiles",result); |
|---|
| | 110 | return result; |
|---|
| | 111 | } |
|---|
| | 112 | |
|---|
| | 113 | protected char[] convertPathToNamespace(char[] path){ |
|---|
| | 114 | char[] temp = Text.replace(path,'/','.'); |
|---|
| | 115 | return Text.replace(temp,'\\','.'); |
|---|
| | 116 | } |
|---|
| | 117 | |
|---|
| | 118 | protected char[] convertNamespaceToPath(char[] namespace){ |
|---|
| | 119 | int split = Text.rIndexOf(namespace,'.'); |
|---|
| | 120 | if(split == -1){ |
|---|
| | 121 | return ""; |
|---|
| | 122 | } |
|---|
| | 123 | // process everything up to the last '.' - this is the true namespace |
|---|
| | 124 | return Text.replace(namespace[0..split],'.','\\'); |
|---|
| | 125 | } |
|---|
| | 126 | |
|---|
| | 127 | |
|---|
| | 128 | private static bool dSymbolStripType(char[] s, inout char[] res) { |
|---|
| | 129 | static char[][] prefixes = [ |
|---|
| | 130 | "_Class", "__init_", "__vtbl_", "__arguments_", |
|---|
| | 131 | "__d", "_assert_", "_array_", "__modctor_", |
|---|
| | 132 | "__moddtor_", "__ModuleInfo_", "__nullext", |
|---|
| | 133 | "_Dmain", "_DWinMain", "_D" |
|---|
| | 134 | ]; |
|---|
| | 135 | |
|---|
| | 136 | foreach (char[] prefix; prefixes) { |
|---|
| | 137 | if (s.length > prefix.length && s[0 .. prefix.length] == prefix) { |
|---|
| | 138 | res = s[prefix.length .. length]; |
|---|
| | 139 | return true; |
|---|
| | 140 | } |
|---|
| | 141 | } |
|---|
| | 142 | |
|---|
| | 143 | return false; |
|---|
| | 144 | } |
|---|
| | 145 | |
|---|
| | 146 | |
|---|
| | 147 | private static char[] parseNamespace(char[] symbolName) { |
|---|
| | 148 | char[] raw; |
|---|
| | 149 | if (!dSymbolStripType(symbolName, raw) || !isdigit(raw[0])) { |
|---|
| | 150 | return symbolName; |
|---|
| | 151 | } |
|---|
| | 152 | |
|---|
| | 153 | char[] res; |
|---|
| | 154 | while (raw.length > 0 && isdigit(raw[0])) { |
|---|
| | 155 | int len = 0; |
|---|
| | 156 | while (raw.length > 0 && isdigit(raw[0])) { |
|---|
| | 157 | len *= 10; |
|---|
| | 158 | len += raw[0] - '0'; |
|---|
| | 159 | raw = raw[1..$]; |
|---|
| | 160 | } |
|---|
| | 161 | if (raw.length < len) { |
|---|
| | 162 | // invalid symbol ? |
|---|
| | 163 | return symbolName; |
|---|
| | 164 | } |
|---|
| | 165 | |
|---|
| | 166 | if (res.length) res ~= '.'; |
|---|
| | 167 | res ~= raw[0 .. len]; |
|---|
| | 168 | raw = raw[len .. $]; |
|---|
| | 169 | } |
|---|
| | 170 | |
|---|
| | 171 | return res; |
|---|
| | 172 | } |
|---|
| | 173 | |
|---|
| | 174 | |
|---|
| | 175 | private static char[] getParentNamespace(char[] name) { |
|---|
| | 176 | int i = name.rfind('.'); |
|---|
| | 177 | if (-1 == i) return null; |
|---|
| | 178 | else return name[0 .. i]; |
|---|
| | 179 | } |
|---|
| | 180 | |
|---|
| | 181 | |
|---|
| | 182 | unittest { |
|---|
| | 183 | static char[][2][] tests = [ |
|---|
| | 184 | ["printf", "printf"], |
|---|
| | 185 | ["_foo", "_foo"], |
|---|
| | 186 | ["_D88", "_D88"], |
|---|
| | 187 | ["_D4test3fooAa", "test.foo"], |
|---|
| | 188 | ["_D8demangle8demangleFAaZAa", "demangle.demangle"], |
|---|
| | 189 | ["_D6object6Object8opEqualsFC6ObjectZi", "object.Object.opEquals"], |
|---|
| | 190 | ["_D4test2dgDFiYd", "test.dg"], |
|---|
| | 191 | ["_D4test58__T9factorialVde67666666666666860140VG5aa5_68656c6c6fVPvnZ9factorialf", "test.__T9factorialVde67666666666666860140VG5aa5_68656c6c6fVPvnZ.factorial"], |
|---|
| | 192 | ["_D4test101__T9factorialVde67666666666666860140Vrc9a999999999999d9014000000000000000c00040VG5aa5_68656c6c6fVPvnZ9factorialf","test.__T9factorialVde67666666666666860140Vrc9a999999999999d9014000000000000000c00040VG5aa5_68656c6c6fVPvnZ.factorial"], |
|---|
| | 193 | ["_D4test34__T3barVG3uw3_616263VG3wd3_646566Z1xi", "test.__T3barVG3uw3_616263VG3wd3_646566Z.x"] |
|---|
| | 194 | ]; |
|---|
| | 195 | |
|---|
| | 196 | |
|---|
| | 197 | foreach (char[][2] t; tests) { |
|---|
| | 198 | assert (parseNamespace(t[0]) == t[1]); |
|---|
| | 199 | } |
|---|
| | 200 | |
|---|
| | 201 | assert(getParentNamespace("std.stdio") == "std"); |
|---|
| | 202 | assert(getParentNamespace("foo.bar.baz") == "foo.bar"); |
|---|
| | 203 | assert(getParentNamespace("blah") is null); |
|---|
| | 204 | } |
|---|
| | 205 | |
|---|
| | 206 | |
|---|
| | 207 | public this(char[] rootPath,LoaderRegistry loaderRegistry, bool preloadRootLibs = true){ |
|---|
| | 208 | this.root = new FilePath(rootPath); |
|---|
| | 209 | this.loaderRegistry = loaderRegistry; |
|---|
| | 210 | |
|---|
| | 211 | if (preloadRootLibs) { |
|---|
| | 212 | //pre-load all root libs |
|---|
| | 213 | foreach(FilePath filepath; getRootFiles()){ |
|---|
| | 214 | debug debugLog("[PathLibrary] Loading: %s",filepath.splice(root)); |
|---|
| | 215 | DynamicLibrary lib = loaderRegistry.load(filepath.splice(root)); |
|---|
| | 216 | if(lib){ |
|---|
| | 217 | rootLibraries ~= lib; |
|---|
| | 218 | } |
|---|
| | 219 | } |
|---|
| | 220 | } |
|---|
| | 221 | |
|---|
| | 222 | addNamespaceTranslator(&convertNamespaceToPath); |
|---|
| | 223 | |
|---|
| | 224 | attributes["PATH.path"] = root.toUtf8; |
|---|
| | 225 | } |
|---|
| | 226 | |
|---|
| | 227 | public ExportSymbolPtr getSymbol(char[] name){ |
|---|
| | 228 | DynamicModule mod = this.getModuleForSymbol(name); |
|---|
| | 229 | if(mod) return mod.getSymbol(name); |
|---|
| | 230 | return null; |
|---|
| | 231 | } |
|---|
| | 232 | |
|---|
| | 233 | public ExportSymbol[] getSymbols(){ |
|---|
| | 234 | ExportSymbol[] symbols; |
|---|
| | 235 | foreach(DynamicModule mod; getModules()){ |
|---|
| | 236 | symbols ~= mod.getSymbols(); |
|---|
| | 237 | } |
|---|
| | 238 | return symbols; |
|---|
| | 239 | } |
|---|
| | 240 | |
|---|
| | 241 | public DynamicModule[] getModules(){ |
|---|
| | 242 | DynamicModule[] result; |
|---|
| | 243 | |
|---|
| | 244 | //go through all the files in scope and load everything possible |
|---|
| | 245 | //NOTE: this ignores already loaded root libs |
|---|
| | 246 | foreach(FilePath libPath; getAllFiles()){ |
|---|
| | 247 | DynamicLibrary lib = loaderRegistry.load(libPath.toString); |
|---|
| | 248 | if(lib) result ~= lib.getModules(); |
|---|
| | 249 | } |
|---|
| | 250 | return result; |
|---|
| | 251 | } |
|---|
| | 252 | |
|---|
| | 253 | public char[] getType(){ |
|---|
| | 254 | return "PATH"; |
|---|
| | 255 | } |
|---|
| | 256 | |
|---|
| | 257 | public char[][char[]] getAttributes(){ |
|---|
| | 258 | return this.attributes; |
|---|
| | 259 | } |
|---|
| | 260 | |
|---|
| | 261 | public DynamicModule getModuleForSymbol(char[] name){ |
|---|
| | 262 | if(name.length > 2 && name[0..2] == "_D"){ |
|---|
| | 263 | for (char[] namespace = parseNamespace(name); namespace !is null; namespace = getParentNamespace(namespace)) { |
|---|
| | 264 | |
|---|
| | 265 | // dig through the root libs |
|---|
| | 266 | foreach(DynamicLibrary lib; rootLibraries){ |
|---|
| | 267 | DynamicModule mod = lib.getModuleForSymbol(name); |
|---|
| | 268 | cachedLibraries[namespace] = lib; |
|---|
| | 269 | if(mod) return mod; |
|---|
| | 270 | } |
|---|
| | 271 | |
|---|
| | 272 | // attempt to search the cache |
|---|
| | 273 | DynamicLibrary* pLib = namespace in cachedLibraries; |
|---|
| | 274 | if(pLib) return pLib.getModuleForSymbol(name); |
|---|
| | 275 | |
|---|
| | 276 | foreach (xlat; namespaceTranslators) { |
|---|
| | 277 | // look for a path match |
|---|
| | 278 | char[] path = joinPaths(this.root.toString(), xlat(namespace.dup)); |
|---|
| | 279 | if(path != ""){ |
|---|
| | 280 | if (fileExists(path) && isFile(path)) { |
|---|
| | 281 | DynamicLibrary lib = loaderRegistry.load(path); |
|---|
| | 282 | if(lib) { |
|---|
| | 283 | cachedLibraries[namespace] = lib; |
|---|
| | 284 | return lib.getModuleForSymbol(name); |
|---|
| | 285 | } |
|---|
| | 286 | } |
|---|
| | 287 | |
|---|
| | 288 | //find first loadable library file that matches <root-path><path>/* and contains 'name' |
|---|
| | 289 | foreach(FilePath libPath; getFiles(path)){ |
|---|
| | 290 | DynamicLibrary lib = loaderRegistry.load(libPath.toString); |
|---|
| | 291 | if(lib) { |
|---|
| | 292 | cachedLibraries[namespace] = lib; |
|---|
| | 293 | return lib.getModuleForSymbol(name); |
|---|
| | 294 | } |
|---|
| | 295 | } |
|---|
| | 296 | } |
|---|
| | 297 | } |
|---|
| | 298 | } |
|---|
| | 299 | } |
|---|
| | 300 | // match a non-D symbol |
|---|
| | 301 | else{ |
|---|
| | 302 | // dig through the root libs |
|---|
| | 303 | foreach(DynamicLibrary lib; rootLibraries){ |
|---|
| | 304 | DynamicModule mod = lib.getModuleForSymbol(name); |
|---|
| | 305 | if(mod) return mod; |
|---|
| | 306 | } |
|---|
| | 307 | } |
|---|
| | 308 | //failed to find the module |
|---|
| | 309 | debug debugLog("PathLibrary.getModuleForSymbol - failed to find: %s",name); |
|---|
| | 310 | return null; |
|---|
| | 311 | } |
|---|
| | 312 | |
|---|
| | 313 | // expects resource in file-path format |
|---|
| | 314 | public ubyte[] getResource(char[] name){ |
|---|
| | 315 | FileConduit fc = new FileConduit(this.root.toString ~ name); |
|---|
| | 316 | ubyte[] data = new ubyte[fc.length]; |
|---|
| | 317 | fc.read(data); |
|---|
| | 318 | return data; |
|---|
| | 319 | } |
|---|