| 2 | | Copyright (c) 2005 Lars Ivar Igesund, J Duncan, 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) 2005 Lars Ivar Igesund, J Duncan, 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. |
|---|
| 82 | | public this(LoaderRegistry registry, FileBuffer file){ |
|---|
| 83 | | this.registry = registry; |
|---|
| 84 | | load(file); |
|---|
| 85 | | } |
|---|
| 86 | | |
|---|
| 87 | | public void loadSymbolTable(char [] symtable, uint size){ |
|---|
| 88 | | // TODO: Do something sensible about this |
|---|
| 89 | | // I suppose it wouldn't be in the archive at all |
|---|
| 90 | | // unless some optimizing scheme could be devised. |
|---|
| 91 | | // larsivi 20060101 |
|---|
| 92 | | } |
|---|
| 93 | | |
|---|
| 94 | | public DynamicModule[] getModules(){ |
|---|
| 95 | | return this.modules; |
|---|
| 96 | | } |
|---|
| 97 | | |
|---|
| 98 | | private char[] getModuleName(char[] filename){ |
|---|
| 99 | | if(filename[0] == '/'){ |
|---|
| 100 | | uint offset = Atoi.parse(Text.trim(filename[1..$])); |
|---|
| 101 | | return stringtable[offset..Text.indexOf(stringtable[offset..$], "/")+offset]; |
|---|
| 102 | | } |
|---|
| 103 | | else{ |
|---|
| 104 | | return filename[0..Text.indexOf(filename, r"/")]; |
|---|
| 105 | | } |
|---|
| 106 | | } |
|---|
| 107 | | |
|---|
| 108 | | private void load(IBuffer buffer){ |
|---|
| 109 | | ArchiveReader reader = new ArchiveReader(buffer); |
|---|
| 110 | | |
|---|
| 111 | | // read the library signature |
|---|
| 112 | | int nAddress; |
|---|
| 113 | | char[] signature; |
|---|
| 114 | | reader.get(signature,ARCHID.length); |
|---|
| 115 | | |
|---|
| 116 | | if((signature.length != ARCHID.length) || (signature != ARCHID)){ |
|---|
| 117 | | throw new Exception("Invalid library signature."); |
|---|
| 118 | | } |
|---|
| | 82 | public this(LoaderRegistry registry, FileBuffer file){ |
|---|
| | 83 | this.registry = registry; |
|---|
| | 84 | load(file); |
|---|
| | 85 | } |
|---|
| | 86 | |
|---|
| | 87 | public void loadSymbolTable(char [] symtable, uint size){ |
|---|
| | 88 | debug debugLog("* Loading symbol table"); |
|---|
| | 89 | // TODO: Do something sensible about this |
|---|
| | 90 | // I suppose it wouldn't be in the archive at all |
|---|
| | 91 | // unless some optimizing scheme could be devised. |
|---|
| | 92 | // larsivi 20060101 |
|---|
| | 93 | } |
|---|
| | 94 | |
|---|
| | 95 | public DynamicModule[] getModules(){ |
|---|
| | 96 | return this.modules; |
|---|
| | 97 | } |
|---|
| | 98 | |
|---|
| | 99 | private char[] getModuleName(char[] filename){ |
|---|
| | 100 | if(filename[0] == '/'){ |
|---|
| | 101 | uint offset = Atoi.parse(Text.trim(filename[1..$])); |
|---|
| | 102 | return stringtable[offset..Text.indexOf(stringtable[offset..$], "/")+offset]; |
|---|
| | 103 | } |
|---|
| | 104 | else{ |
|---|
| | 105 | return filename[0..Text.indexOf(filename, r"/")]; |
|---|
| | 106 | } |
|---|
| | 107 | } |
|---|
| | 108 | |
|---|
| | 109 | private void load(IBuffer buffer){ |
|---|
| | 110 | ArchiveReader reader = new ArchiveReader(buffer); |
|---|
| | 111 | |
|---|
| | 112 | // read the library signature |
|---|
| | 113 | int nAddress; |
|---|
| | 114 | char[] signature; |
|---|
| | 115 | reader.get(signature,ARCHID.length); |
|---|
| | 116 | |
|---|
| | 117 | if((signature.length != ARCHID.length) || (signature != ARCHID)){ |
|---|
| | 118 | throw new Exception("Invalid library signature."); |
|---|
| | 119 | } |
|---|
| 120 | | // read the remaining records |
|---|
| 121 | | while(reader.hasMore){ |
|---|
| 122 | | void alignReader(){ |
|---|
| 123 | | if(reader.getPosition & 1){ |
|---|
| 124 | | debug debugLog("* padding data address"); |
|---|
| 125 | | ubyte dummy; |
|---|
| 126 | | reader.get(dummy); |
|---|
| 127 | | } |
|---|
| 128 | | } |
|---|
| 129 | | alignReader(); |
|---|
| 130 | | if(!reader.hasMore()) break; // re-alignment may cause EOF |
|---|
| 131 | | |
|---|
| 132 | | // read member header |
|---|
| 133 | | ArchiveHeader hdr; |
|---|
| 134 | | reader.get(hdr); // throws "illegal library file" |
|---|
| 135 | | //assert( hdr.ar_fmag == ARFMAG ); |
|---|
| 136 | | |
|---|
| 137 | | if( hdr.ar_fmag != ARFMAG ){ |
|---|
| 138 | | throw new DDLException("Invalid link member signature: %d\n",hdr.ar_fmag[1]); |
|---|
| 139 | | } |
|---|
| 140 | | |
|---|
| 141 | | char [] fName = Text.trim(hdr.ar_name); |
|---|
| 142 | | uint fSize = Atoi.parse(Text.trim(hdr.ar_size)); |
|---|
| 143 | | |
|---|
| 144 | | // read member data |
|---|
| 145 | | char[] memberData; |
|---|
| 146 | | reader.get(memberData,fSize); |
|---|
| 147 | | |
|---|
| 148 | | switch(fName){ |
|---|
| 149 | | case "/": |
|---|
| 150 | | // Need to check the next header |
|---|
| 151 | | // If it has the same name, it is a |
|---|
| 152 | | // PECOFF lib, otherwise it's an Ar-lib |
|---|
| 153 | | ArchiveHeader tmphdr; |
|---|
| 154 | | reader.get(tmphdr); |
|---|
| 155 | | |
|---|
| 156 | | if (Text.trim(tmphdr.ar_name) == "/") { |
|---|
| 157 | | // PECOFF archive |
|---|
| 158 | | fSize = Atoi.parse(Text.trim(tmphdr.ar_size)); |
|---|
| 159 | | reader.get(memberData,fSize); |
|---|
| 160 | | loadSymbolTable(memberData,fSize); |
|---|
| 161 | | } |
|---|
| 162 | | else { // Ar |
|---|
| 163 | | // Step back to previous pos |
|---|
| 164 | | |
|---|
| 165 | | // WORKAROUND: I have no idea |
|---|
| 166 | | // what happens here, if I use |
|---|
| 167 | | // the AH.sizeof directly in seek |
|---|
| 168 | | // it seems to use seekEnd |
|---|
| 169 | | // instead. larsivi 20060101 |
|---|
| 170 | | int len = ArchiveHeader.sizeof; |
|---|
| 171 | | reader.seek(-len); |
|---|
| 172 | | loadSymbolTable(memberData,fSize); |
|---|
| 173 | | } |
|---|
| 174 | | break; |
|---|
| 175 | | case "//": |
|---|
| 176 | | stringtable.length = fSize; |
|---|
| 177 | | assert (stringtable.length == memberData.length); |
|---|
| 178 | | stringtable = memberData; |
|---|
| 179 | | break; |
|---|
| 180 | | default: // The rest |
|---|
| 181 | | FileBuffer embeddedFile = new FileBuffer(getModuleName(fName),memberData); |
|---|
| 182 | | DynamicLibrary dl = this.registry.load(embeddedFile); |
|---|
| 183 | | addModules(dl.getModules()); |
|---|
| 184 | | break; |
|---|
| 185 | | } |
|---|
| 186 | | } |
|---|
| 187 | | } |
|---|
| 188 | | |
|---|
| 189 | | public ExportSymbol[] getExports(){ |
|---|
| 190 | | return exports.values; |
|---|
| 191 | | } |
|---|
| 192 | | |
|---|
| 193 | | public ExportSymbol getExport(char[] name){ |
|---|
| 194 | | if (name in exports){ |
|---|
| 195 | | return exports[name]; |
|---|
| 196 | | } |
|---|
| 197 | | else { |
|---|
| 198 | | return ExportSymbol.NONE; |
|---|
| 199 | | } |
|---|
| 200 | | } |
|---|
| 201 | | |
|---|
| 202 | | public char[] getType(){ |
|---|
| 203 | | return "Archive"; |
|---|
| 204 | | } |
|---|
| 205 | | |
|---|
| 206 | | public char[][char[]] getAttributes(){ |
|---|
| 207 | | return null; |
|---|
| 208 | | } |
|---|
| 209 | | |
|---|
| 210 | | //TODO: implement me |
|---|
| 211 | | public DynamicModule getModuleForExport(char[] name){ |
|---|
| 212 | | return null; |
|---|
| 213 | | } |
|---|
| 214 | | |
|---|
| 215 | | //TODO: implement me |
|---|
| 216 | | public ubyte[] getResource(char[] name){ |
|---|
| 217 | | return (ubyte[]).init; |
|---|
| 218 | | } |
|---|
| 219 | | |
|---|
| 220 | | private void addModules(DynamicModule[] modules){ |
|---|
| 221 | | if (!exportsready){ |
|---|
| 222 | | foreach(DynamicModule dm; modules){ |
|---|
| 223 | | foreach(ExportSymbol es; |
|---|
| 224 | | dm.getExports()){ |
|---|
| 225 | | exports[es.name] = es; |
|---|
| 226 | | } |
|---|
| 227 | | } |
|---|
| 228 | | } |
|---|
| 229 | | this.modules ~= modules; |
|---|
| 230 | | } |
|---|
| | 121 | // read the remaining records |
|---|
| | 122 | while(reader.hasMore){ |
|---|
| | 123 | |
|---|
| | 124 | void alignReader(){ |
|---|
| | 125 | if(reader.getPosition & 1){ |
|---|
| | 126 | debug debugLog("* padding data address"); |
|---|
| | 127 | ubyte dummy; |
|---|
| | 128 | reader.get(dummy); |
|---|
| | 129 | } |
|---|
| | 130 | } |
|---|
| | 131 | |
|---|
| | 132 | alignReader(); |
|---|
| | 133 | if(!reader.hasMore()) break; // re-alignment may cause EOF |
|---|
| | 134 | |
|---|
| | 135 | // read member header |
|---|
| | 136 | ArchiveHeader hdr; |
|---|
| | 137 | reader.get(hdr); // throws "illegal library file" |
|---|
| | 138 | //assert( hdr.ar_fmag == ARFMAG ); |
|---|
| | 139 | |
|---|
| | 140 | if( hdr.ar_fmag != ARFMAG ){ |
|---|
| | 141 | throw new DDLException("Invalid link member signature: %d\n",hdr.ar_fmag[1]); |
|---|
| | 142 | } |
|---|
| | 143 | |
|---|
| | 144 | char [] fName = Text.trim(hdr.ar_name); |
|---|
| | 145 | uint fSize = Atoi.parse(Text.trim(hdr.ar_size)); |
|---|
| | 146 | |
|---|
| | 147 | // read member data |
|---|
| | 148 | char[] memberData; |
|---|
| | 149 | reader.get(memberData,fSize); |
|---|
| | 150 | |
|---|
| | 151 | switch(fName){ |
|---|
| | 152 | case "/": |
|---|
| | 153 | // Need to check the next header |
|---|
| | 154 | // If it has the same name, it is a |
|---|
| | 155 | // PECOFF lib, otherwise it's an Ar-lib |
|---|
| | 156 | ArchiveHeader tmphdr; |
|---|
| | 157 | reader.get(tmphdr); |
|---|
| | 158 | |
|---|
| | 159 | if (Text.trim(tmphdr.ar_name) == "/") { |
|---|
| | 160 | // PECOFF archive |
|---|
| | 161 | fSize = Atoi.parse(Text.trim(tmphdr.ar_size)); |
|---|
| | 162 | reader.get(memberData,fSize); |
|---|
| | 163 | loadSymbolTable(memberData,fSize); |
|---|
| | 164 | } |
|---|
| | 165 | else { // Ar |
|---|
| | 166 | // Step back to previous pos |
|---|
| | 167 | |
|---|
| | 168 | // WORKAROUND: I have no idea |
|---|
| | 169 | // what happens here, if I use |
|---|
| | 170 | // the AH.sizeof directly in seek |
|---|
| | 171 | // it seems to use seekEnd |
|---|
| | 172 | // instead. larsivi 20060101 |
|---|
| | 173 | int len = ArchiveHeader.sizeof; |
|---|
| | 174 | reader.seek(reader.getPosition() - len); |
|---|
| | 175 | loadSymbolTable(memberData,fSize); |
|---|
| | 176 | } |
|---|
| | 177 | break; |
|---|
| | 178 | case "//": |
|---|
| | 179 | debug debugLog("* String table found in archive"); |
|---|
| | 180 | stringtable.length = fSize; |
|---|
| | 181 | assert (stringtable.length == memberData.length); |
|---|
| | 182 | stringtable = memberData; |
|---|
| | 183 | break; |
|---|
| | 184 | default: // The rest |
|---|
| | 185 | debug debugLog("* Loading module %s from archive", getModuleName(fName)); |
|---|
| | 186 | debug debugLog("* file starts with: ", memberData[0..4]); |
|---|
| | 187 | FileBuffer embeddedFile = new FileBuffer(getModuleName(fName),memberData); |
|---|
| | 188 | DynamicLibrary dl = this.registry.load(embeddedFile); |
|---|
| | 189 | addModules(dl.getModules()); |
|---|
| | 190 | break; |
|---|
| | 191 | } |
|---|
| | 192 | } |
|---|
| | 193 | } |
|---|
| | 194 | |
|---|
| | 195 | public ExportSymbol[] getExports(){ |
|---|
| | 196 | return exports.values; |
|---|
| | 197 | } |
|---|
| | 198 | |
|---|
| | 199 | public ExportSymbol getExport(char[] name){ |
|---|
| | 200 | if (name in exports){ |
|---|
| | 201 | return exports[name]; |
|---|
| | 202 | } |
|---|
| | 203 | else { |
|---|
| | 204 | return ExportSymbol.NONE; |
|---|
| | 205 | } |
|---|
| | 206 | } |
|---|
| | 207 | |
|---|
| | 208 | public char[] getType(){ |
|---|
| | 209 | return "Archive"; |
|---|
| | 210 | } |
|---|
| | 211 | |
|---|
| | 212 | public char[][char[]] getAttributes(){ |
|---|
| | 213 | return null; |
|---|
| | 214 | } |
|---|
| | 215 | |
|---|
| | 216 | //TODO: implement me |
|---|
| | 217 | public DynamicModule getModuleForExport(char[] name){ |
|---|
| | 218 | return null; |
|---|
| | 219 | } |
|---|
| | 220 | |
|---|
| | 221 | //TODO: implement me |
|---|
| | 222 | public ubyte[] getResource(char[] name){ |
|---|
| | 223 | return (ubyte[]).init; |
|---|
| | 224 | } |
|---|
| | 225 | |
|---|
| | 226 | private void addModules(DynamicModule[] modules){ |
|---|
| | 227 | if (!exportsready){ |
|---|
| | 228 | foreach(DynamicModule dm; modules){ |
|---|
| | 229 | foreach(ExportSymbol es; dm.getExports()){ |
|---|
| | 230 | exports[es.name] = es; |
|---|
| | 231 | } |
|---|
| | 232 | } |
|---|
| | 233 | } |
|---|
| | 234 | this.modules ~= modules; |
|---|
| | 235 | } |
|---|