Exemplo n.º 1
0
def CorrectExtension(filename):
    """since we don't trust the addon sites, we have to check the type of archive and correct the extension if necessary"""
    tracer.debug("CorrectExtension")
    
    newfilename = filename
    extn        = os.path.splitext(filename)[1].replace('.', '') # leaves only the extension, no leading dot
    
    # only test needed, for now, is to see if a zip really is a rar
    if extn.lower() == "zip":
        try:
            header = open(filename, "rb").read(3)
            if header == "Rar":
                WurmCommon.outWarning(_("%(filename)s is really a RAR file - renaming") % {'filename': filename})
                newfilename = filename[:-3] + "rar"
                try:
                    os.remove(newfilename)
                except:
                    pass # don't fail at this point
                try:
                    os.rename(filename, newfilename)
                except Exception, details:
                    raise Exception, "Error renaming %s to %s: %s" % (filename, newfilename, str(details))
                
                extn = "rar"
                WurmCommon.outDebug("^^^^ renamed to %s" % (newfilename))
        except Exception, details:
            raise Exception, "Could not check %s: %s" % (filename, str(details))
Exemplo n.º 2
0
 def IsFileRequired(filename, filemap):
     """Determines if the file is required"""
     tracer.log(WurmCommon.DEBUG5, "Archive - IsFileRequired")
     
     global ignorepaths, allowedfiles
     
     reignorepaths = [re.compile(x, re.I) for x in ignorepaths]
     
     if not filemap.has_key(filename):
         # File already filtered away in the mapping stage
         return False
     
     ignore = False
     for r in reignorepaths:
             if r.search(filename):
                 WurmCommon.outWarning(_("Ignoring path %(filename)s") % {'filename': filename})
                 ignore = True
     
     if ignore:
         return False
     
     ext = os.path.splitext(filename)[1].replace('.', '') # leaves only the extension, no leading dot
     if not ext.lower() in allowedfiles and not "SkinMe" in filename and not "README" in filename: # don't skip Skinner SkinMe !mkdir or README files
         WurmCommon.outWarning(_("Skipping forbidden file %(filename)s") % {'filename': filename})
         return False
     
     return True
Exemplo n.º 3
0
def PlainUnzip(zfilename, target):
    """ Just unzips a zipfile to target - currently only used by the auto-updater """
    tracer.debug("PlainUnzip")
    
    zfile = ZipFile(zfilename, "r")
    
    for n in zfile.namelist():
        if n[-1:] == '/': # is a directory
            try:
                os.makedirs(os.path.join(target, n))
            except:
                pass # path already exists
        else:
            orign = n
            ext   = os.path.splitext(n)[1].replace('.', '') # leaves only the extension, no leading dot
            mode  = "wb" #default to binary
            if ext.lower() in textfiles and not int(WurmCommon.getGlobalSetting(":PreserveNewline")):
                mode = "wt"
            
            filename = os.path.join(target, n)
            dirpath = os.path.dirname(filename)
            # Create additional directories - this is due to ambiguities in the ZIP file structure
            if dirpath and not os.path.exists(dirpath):
                os.makedirs(dirpath)
            
            try:
                f = open(filename, mode)
                f.write(zfile.read(orign))
                f.close()
            except Exception, details:
                WurmCommon.outWarning(_("Could not extract file %(filename)s") % {'filename': n}) # Accept that some files can't be extracted, in case of read-only custom files
                WurmCommon.outDebug("^^^ - %s" % (str(details)))
Exemplo n.º 4
0
 def ExtractFiles(self, filelist=None, target=None):
     """
     Extracts the specified files to target dir (if target is None, it uses the unpack dir) without preserving directory structure
     Returns a map 'filename given in filelist' -> 'filename on disk'
     """
     tracer.debug("7ZipArchive - ExtractFiles")
     
     if not filelist:
         filelist = self.namelist
     if not target:
         target = WurmCommon.directories["unpack"]
     
     fmap = {}
     
     szf = SevenZip.SevenZipFile(self.filename)
     
     for fl in filelist:
         if fl: # Ignore missing entries
             (dirname, fname) = os.path.split(fl)
             tfname = os.path.join(target, fname)
             szf.extract(fname, tfname)
             fmap[fl] = tfname
             WurmCommon.outDebug("Extracted %s from %s" % (fname, os.path.split(self.filename)[1]))
     
     szf = None
     
     return fmap
Exemplo n.º 5
0
 def ExtractFiles(self, filelist=None, target=None):
     """
     Extracts the specified files to target dir (if target is None, it uses the unpack dir) without preserving directory structure
     Returns a map 'filename given in filelist' -> 'filename on disk'
     """
     tracer.debug("RaRArchive - ExtractFiles")
     
     if not filelist:
         filelist = self.namelist
     if not target:
         target = WurmCommon.directories["unpack"]
     
     fmap = {}
     
     rf = RarFile.RarFile(self.filename)
     
     for fl in filelist:
         if fl: # Ignore missing entries
            (path, fname) = os.path.split(fl)
            ext = os.path.splitext(fl)[1].replace('.', '') # leaves only the extension, no leading dot
            if len(ext) > 0: # must check size, since directories may appear as files in the RAR
                rf.extract(fl, target, opts="-ep")
                fmap[fl] = os.path.join(target, fname)
                WurmCommon.outDebug("Extracted %s from %s") % (fl, target)
     
     rf = None
     
     return fmap
Exemplo n.º 6
0
 def OnCancel(self, event):
     """"""
     tracer.debug("WurmAddonInstallDlg - OnCancel")
     
     self.toInstall = []
     WurmCommon.outMessage(_("Install list cleaned"))
     self.Close()
Exemplo n.º 7
0
 def ExtractFiles(self, filelist=None, target=None):
     """
     Extracts the specified files to target dir (if target is None, it uses the unpack dir) without preserving directory structure
     Returns a map 'filename given in filelist' -> 'filename on disk'
     """
     tracer.debug("ZipArchive - ExtractFiles: %s, %s" % (str(filelist), target))
     
     if not filelist:
         filelist = self.namelist
     if not target:
         target = WurmCommon.directories["unpack"]
     
     fmap = {}
     
     f = ZipFile(self.filename, "r")
     
     for fl in filelist:
         if fl: # Ignore missing entries
             (dirname, fname) = os.path.split(fl)
             ext  = os.path.splitext(fl)[1].replace('.', '') # leaves only the extension, no leading dot
             mode = "wb" #default to binary
             if ext.lower() in textfiles and not int(WurmCommon.getGlobalSetting(":PreserveNewline")):
                 mode = "wt"
             
             tfname = os.path.join(target, fname)
             tf     = open(tfname, mode)
             tf.write(f.read(fl))
             tf.close()
             fmap[fl] = tfname
             WurmCommon.outDebug("Extracted %s from %s to %s" % (fname, os.path.split(self.filename)[1], tfname))
     
     f.close()
     
     return fmap
Exemplo n.º 8
0
def GetTemplate(sitetype):
    """ Prompt the user to choose an OtherSite/Child Template to use for the current Addon """
    tracer.debug("GetTemplate: [%s]" % sitetype)
    
    if sitetype == "OtherSite":
        table = WurmCommon.ostKeys
    else:
        table = WurmCommon.childtKeys
    
    WurmCommon.outDebug("%s keys: %s" % (sitetype, str(table)))
    
    selection = None
    title = '%s Templates' % sitetype
    # display dialog and process choice
    try:
        try:
            dlg = wx.SingleChoiceDialog(None, 'Choose a Template to use or Cancel for the default one', title, table)
            # The user pressed the "OK" button in the dialog
            if dlg.ShowModal() == wx.ID_OK:
                selection = dlg.GetStringSelection()
                WurmCommon.outDebug('Template selected: %s' % selection)
        except Exception, details:
            logger.exception("Error getting %s template: %s" % (sitetype, str(details)))
    finally:
        dlg.Destroy()
    
    return selection
Exemplo n.º 9
0
 def Unpack(self, target=None):
     """Extract the files from the Git Clone directory to the path specified in the mapping dictionary"""
     tracer.debug("GitArchive - Unpack")
     
     totalfiles = float(len(self.namelist)) # float to force non-integer division
     countfiles = 0
     
     for n in self.namelist:
         # report progress
         countfiles += 1
         if totalfiles > 1:
             WurmCommon.outProgressPercent(_("Copying from Git Clone dir"), countfiles/totalfiles)
         
         if not self.IsFileRequired(n, self.filemap):
             continue
         
         filename = self.filemap[n] # this is the filename on disk
         
         # create directories if they don't exist
         dirpath = os.path.dirname(filename)
         if dirpath and not os.path.exists(dirpath):
             os.makedirs(dirpath)
         
         # prepend the Git Clone directory to the source filename
         exportdirfile = os.path.join(self.exportdir, n)
         shutil.copy(exportdirfile, filename)
     
     WurmCommon.resetProgress()
Exemplo n.º 10
0
 def updateAddonList(addonname, addons):
     """ Update the AddonList with related Addon info """
     tracer.debug("Archive - updateAddonList")
     
     # Make sure "never before seen addons" have an entry in the list (they'll be set as [Related] to the main addon)
     if WurmCommon.addonlist.has_key(addonname) and len(addons) > 1:
         for a in addons:
             if not WurmCommon.addonlist.has_key(a) or WurmCommon.addonlist.getAtype(a) == '[Unknown]':
                 WurmCommon.addonlist.add(a, siteid=addonname, atype="[Related]")
                 WurmCommon.outDebug("Addon %s set as [Related] to %s" % (a, addonname))
Exemplo n.º 11
0
def WoWInstallAddon(filename, addonname, isChild=False):
    """ Install an Addon. Handles Zip & RaR archives and installation from a Subversion Repository"""
    tracer.debug("WoWInstallAddon: %s, %s, %s" % (filename, addonname, isChild))
    
    if threading.currentThread().getName() != "MainThread":
        WurmCommon.wurmlock["WurmUnpack"].acquire()
    
    (filename, extn) = CorrectExtension(filename)
    
    try:
        try:
            if extn.lower() == "zip":
                addonarchive = ZipArchive(filename, addonname)
            elif extn.lower() == "rar" and os.name == 'nt':
                if SevenZip and SevenZip.isAvailable():
                    addonarchive = SevenZipArchive(filename, addonname)
                else:
                    raise Exception, "Can't extract .rar files; please install 7-Zip (http://www.7-zip.org/) to enable RAR support (specifically, 7z.exe is needed, either in default installation location, on the path, or in the WUU directory)"
            elif extn.lower() == "rar":
                addonarchive = RaRArchive(filename, addonname)
            elif extn.lower() == "svn":
                addonarchive = SVNArchive(filename, addonname)
            elif extn.lower() == "git":
                addonarchive = GitArchive(filename, addonname)
            elif extn.lower() == "7z":
                addonarchive = SevenZipArchive(filename, addonname)
            else:
                raise Exception, "Unknown or unsupported archive type \"%s\"" % (extn)
            
            # Get the Archive file contents
            addonarchive.GetFilelist()
            
            # Map the Archive filenames to the Addon directory structure
            (addonarchive.filemap, addonarchive.addons) = MapFilenames(addonname, addonarchive.namelist, isChild=isChild)
            
            # Clean & Backup Addon directory
            addonarchive.CleanAndBackup(addonarchive.addons)
            
            # Make sure "never before seen addons" have an entry in the list
            addonarchive.updateAddonList(addonname, addonarchive.addons)
            
            # Unpack the archive file
            addonarchive.Unpack(target=WurmCommon.directories["addons"])
        
        except Exception, details:
            WurmCommon.outError("Installation of %s failed: %s" % (addonname, str(details)))
            raise
    finally:
        if threading.currentThread().getName() != "MainThread":
            WurmCommon.wurmlock["WurmUnpack"].release()
    
    return True
Exemplo n.º 12
0
 def Unpack(self, target=None):
     """Extract the files in the archive to the path specified in the mapping dictionary"""
     tracer.debug("7ZipArchive - Unpack")
     
     totalfiles = float(len(self.namelist)) # float to force non-integer division
     countfiles = 0
     
     rf = SevenZip.SevenZipFile(self.filename)
     
     for n in self.namelist:
         # report progress
         countfiles += 1
         if totalfiles > 1:
             WurmCommon.outProgressPercent(_("Unpacking RAR file"), countfiles/totalfiles)
         
         if not self.IsFileRequired(n, self.filemap):
             continue
         
         ext = os.path.splitext(n)[1].replace('.', '') # leaves only the extension, no leading dot
         if len(ext) == 0: # no extension, probably a directory, so ignore it
             WurmCommon.outWarning(_("Skipping probable directory %(filename)s") % {'filename': n})
             continue
         
         (path, filename) = os.path.split(n)
         if len(filename) > 0: # must check size, since directories may appear as files in the RAR
             try:
                 rf.extract(n, os.path.join(target, self.addonname))
             except SevenZip.SevenZipException, details:
                 WurmCommon.outError(_("Could not extract file %(filename)s") % {'filename': filename} + ":" + str(details))
                 continue
             WurmCommon.outMessage(_("Successfully Extracted %(filename)s to %(dirname)s") % {'filename': filename, 'dirname': os.path.join(target, self.addonname)})
Exemplo n.º 13
0
 def Unpack(self, target=None):
     """Extract the files in the RaR Archive to the path specified in the mapping dictionary"""
     tracer.debug("RaRArchive - Unpack")
     
     totalfiles = float(len(self.namelist)) # float to force non-integer division
     countfiles = 0
     
     rf = RarFile.RarFile(self.filename)
     
     for n in self.namelist:
         # report progress
         countfiles += 1
         if totalfiles > 1:
             WurmCommon.outProgressPercent(_("Unpacking RAR file"), countfiles/totalfiles)
         
         if not self.IsFileRequired(n, self.filemap):
             continue
         
         ext = os.path.splitext(n)[1].replace('.', '') # leaves only the extension, no leading dot
         if len(ext) == 0: # no extension, probably a directory, so ignore it
             WurmCommon.outWarning(_("Skipping probable directory %(filename)s") % {'filename': n})
             continue
         
         (path, filename) = os.path.split(n)
         if len(filename) > 0: # must check size, since directories may appear as files in the RAR
             rf.extract(n, target)
             WurmCommon.outDebug("Successfully extracted %(file)s to %(dir)s" % {'file': n, 'dir': target})
     
     rf = None
     WurmCommon.resetProgress()
Exemplo n.º 14
0
 def Unpack(self, target=None):
     """Extract the files in the RaR Archive to the path specified in the mapping dictionary"""
     tracer.debug("WinRaRArchive - Unpack")
     
     global textfiles
     
     totalfiles = float(len(self.namelist)) # float to force non-integer division
     countfiles = 0
     
     rfile = RarFile(self.filename)
     
     for rf in rfile.iterfiles():
         # report progress
         countfiles += 1
         if totalfiles > 1:
             WurmCommon.outProgressPercent(_("Unpacking RAR file"), countfiles/totalfiles)
         
         n = rf.filename
         
         if not self.IsFileRequired(n, self.filemap):
             continue
         
         if n[-1:] == '/': # is a directory
             try:
                 os.makedirs(os.path.join(target, n))
             except:
                 pass # path already exists
         else:
             ext   = os.path.splitext(n)[1].replace('.', '') # leaves only the extension, no leading dot
             mode  = "wb" # default to binary
             rmode = "rb" # UnRAR needs to have read mode specified, too
             if ext.lower() in textfiles and not int(WurmCommon.getGlobalSetting(":PreserveNewline")):
                 mode  = "wt"
                 rmode = "rt"
             
             filename = os.path.join(target, n)
             dirpath  = os.path.dirname(filename)
             # Create additional directories - this is due to ambiguities in the file structure
             if dirpath and not os.path.exists(dirpath):
                 os.makedirs(dirpath)
             
             if rf.size > 0: # must check size, since directories may appear as files in the RAR
                 try:
                     f = open(os.path.join(target, n), mode)
                     f.write(rf.open(rmode).read())
                     f.close()
                 except Exception, details:
                     WurmCommon.outWarning(_("Could not extract file %(filename)s") % {'filename': n}) # Accept that some files can't be extracted, in case of read-only custom files
                     WurmCommon.outDebug("^^^ - %s %s" % (str(Exception), str(details)))
                 WurmCommon.outDebug("Successfully Extracted %s to %s" % (n, dirpath))
Exemplo n.º 15
0
def GetSite():
    """ Prompt the user to choose a Site to change to for the selected Addon(s) """
    tracer.debug("GetSite")
    
    selection = None
    # display dialog and process choice
    try:
        try:
            dlg = wx.SingleChoiceDialog(None, 'Choose a Site to change to', 'Sites', asKeys)
            # The user pressed the "OK" button in the dialog
            if dlg.ShowModal() == wx.ID_OK:
                selection = dlg.GetStringSelection()
                WurmCommon.outDebug('Site selected: %s' % selection)
        except Exception, details:
            logger.exception("Error getting Site: %s" % str(details))
    finally:
        dlg.Destroy()
    
    return selection
Exemplo n.º 16
0
def GetSavedVarsDelete(savedvarslist):
    """ Prompt the user for which (if any) SavedVariables they want to delete """
    tracer.debug("GetSavedVarsDelete")
    
    selection = []
    title = 'Delete SavedVariables'
    
    try:
        try:
            dlg = wx.MultiChoiceDialog(None, 'Select one or more SavedVariables to delete', title, savedvarslist)
            if dlg.ShowModal() == wx.ID_OK:
                sel = dlg.GetSelections()
                selection = [savedvarslist[x] for x in sel]
                WurmCommon.outDebug("Selected %d items: %s" % (len(selection), ", ".join(selection)))
        except Exception, details:
            logger.exception("Error getting SV selection: %s" % (str(details),))
    finally:
        dlg.Destroy()
    
    return selection
Exemplo n.º 17
0
 def CleanAndBackup(addons):
     """Clean the Addons directories if required and Backup the previous version"""
     tracer.debug("Archive - CleanAndBackup")
     
     if int(WurmCommon.getGlobalSetting(":CleanExtract")):
         # Get all related addons
         toRelate = []
         for a in addons:
             r = WurmCommon.findAllRelated(a)
             if r:
                 toRelate += r
         
         if toRelate:
             total, failed = WurmCommon.DeleteAddons(toRelate, cleansettings=True)
         
         total, failed = WurmCommon.DeleteAddons(addons)
         WurmCommon.outStatus(_("%(stot)d of %(tot)d Addon(s) cleaned successfully") % {'stot': total - failed, 'tot': total})
     else:
         try:
             WurmCommon.BackupAddons(addons) # this won't do anything if no backupdir is set
         except:
             pass # not a critical error
Exemplo n.º 18
0
 def Unpack(self, target=None):
     """Extract the files in the Zip Archive to the path specified in the mapping dictionary"""
     tracer.debug("ZipArchive - Unpack")
     
     global textfiles
     
     totalfiles = float(len(self.namelist)) # float to force non-integer division
     countfiles = 0
     
     zfile = ZipFile(self.filename, "r")
     
     for n in self.namelist:
         # report progress
         countfiles += 1
         if totalfiles > 1:
             WurmCommon.outProgressPercent(_("Unpacking ZIP file"), countfiles/totalfiles)
         
         if not self.IsFileRequired(n, self.filemap):
             continue
         
         filename = self.filemap[n] # this is the filename on disk
         
         if n[-1:] == '/': # is a directory
             continue
         else:
             ext  = os.path.splitext(n)[1].replace('.', '') # leaves only the extension, no leading dot
             mode = "wb" # default to binary
             if ext.lower() in textfiles and not int(WurmCommon.getGlobalSetting(":PreserveNewline")):
                 mode = "wt" # ZipFile needs explicit text mode for text files (unless disabled in WUU)
             
             dirpath = os.path.dirname(filename)
             # Create additional WurmCommon.directories - this is due to ambiguities in the file structure
             if dirpath and not os.path.exists(dirpath):
                 os.makedirs(dirpath)
             
             try:
                 f = open(filename, mode)
                 f.write(zfile.read(n))
                 f.close()
             except Exception, details:
                 WurmCommon.outWarning(_("Could not extract file %(filename)s") % {'filename': n}) # Accept that some files can't be extracted, in case of read-only custom files
                 WurmCommon.outDebug("^^^ - %s" % (str(details)))
             WurmCommon.outDebug("Successfully Extracted %s to %s" % (n, dirpath))
Exemplo n.º 19
0
 def OnCloseWindow(self, event):
     """"""
     tracer.debug("WurmAddonInstallDlg - OnCloseWindow")
     
     global installlist
     
     if len(self.toInstall) > 0:
         msg = wx.MessageDialog(self, _("Download and install %(num)d Addons?") % {'num': len(self.toInstall)}, _("Close Install Addon(s)"), style=wx.YES_NO|wx.ICON_QUESTION)
         answer = msg.ShowModal()
         msg.Destroy()
         if answer == wx.ID_YES:
             for a in self.toInstall:
                 (frn, lon, sid, adt, spf) = self.addonlist.getAll(a)
                 spf['install'] = True
                 WurmCommon.addonlist.add(a, fname=frn, lname=lon, siteid=sid, atype=adt, flags=spf)
             WurmCommon.outStatus(_("%(num)d Addons queued for Installation, please wait...") % {'num': len(self.toInstall)})
         else:
             self.toInstall = []
     
     installlist = self.toInstall
     
     # end the dialog
     self.EndModal(wx.ID_OK)
Exemplo n.º 20
0
def MapFilenames(addonname, filelist, addonsonly=False, isChild=False):
    """ Makes a mapping filename_in_archive -> filename_on_disk, to place files where they belong.
    Returns a tuple: ({file_archive -> file_disk}, list_of_addons)
    if addonsonly is set, the return value is just list_of_addons.
    Don't assume the return value will stay a 2-tuple - multiple return flags might be added (like telling if an addon has special placements of files)
    """
    tracer.debug("MapFilenames: %s, %s" % (addonname, filelist))
    # WurmCommon.outDebug("MapFilenames: %s, %s" % (addonname, filelist))
    
    wowtoplevelfolders = ["fonts", "interface"] #case insensitve - only allowed folders for addons to put files in
    ignorefolders = ["__MACOSX", "FrameXML", ".svn", ".git"] # folders to ignore
    
    aalibs = ["Babylonian", "Configator", "DebugLib", "TipHelper"] # Auc-Advanced Libraries
    
    ia_re = "^" + interfaceaddonsre
    reia  = re.compile(ia_re, re.I)
    
    # Some flags we use to avoid double checks
    simple   = False # shortcut for simple addons
    intadd   = False # true if all files are in Interface\AddOns\AddonDir\
    # used to indicate whether we found a version directory
    isverdir = False
    verdir   = ""
    # Internal Lists and dictionaries
    addons   = []
    filemap  = {}
    prepaths = {} # stores the directory containing the addons not intuitively placed
    
    # First, find all the separate addons (every addon will have a .toc file with the same name as its directory)
    # Also, this checks to see if the zip is on the format AddonDir\*.* directly, to skip all the advanced checks
    
    for n in filelist:
        # Skip files with unparseable names
        try:
            n.decode()
        except:
            continue
        
        (path, ext)           = os.path.splitext(n)
        (directory, filename) = os.path.split(path)
        dirlist               = directory.split(os.sep)
        
        # Ignore certain directories
        ignoredir = False
        for dirname in ignorefolders:
            if dirname in directory:
                ignoredir = True
                break
        if ignoredir:
            continue
        
        # Ignore nopatch files and just directory entries
        if filename == "nopatch" or len(filename) == 0:
            continue
        
        # Ignore sub Library .toc files (prevents them from being installed separately)
        if (filename[:3] == "Lib" or "Library" in filename) and ext == ".toc" and filename != directory:
            continue
            
        if filename == "AceGUI-3.0-SharedMediaWidgets" and ext == ".toc" and filename != directory:
            continue
        
        # ignore Auc-Advanced Libraries
        if filename in aalibs and ext == ".toc" and filename != directory:
            continue
        
        # Ignore entries that are already set as Ignore/Dummy
        for entry in [ directory, filename, dirlist[0] ]:
            if entry in WurmCommon.addonlist:
                if WurmCommon.addonlist.getAtype(entry) in ("[Ignore]", "[Dummy]"):
                    continue
         
        # no addon directory supplied so use the addonname as the directory name instead
        if directory == "":
            filemapping = os.path.join(WurmCommon.directories["addons"],  addonname, n)
        else:
            # default to assume paths are "good"
            filemapping = os.path.join(WurmCommon.directories["addons"], n)
        
        # Check to see if the filelist contains a version directory entry
        # e.g. "KLHThreatMeter19.17d/"
        path = Archive._splitPath(directory)
        if len(path) > 1:
            # if the sub directory matches the beginning of its parent directory then its
            # parent directory is probably a version directory and should be removed
            if path[1] in path[0][:len(path[1])] and len(path[1]) < len(path[0]):
                # remove the version directory from the front of the namelist entry
                # and store it as the new file mapping
                filemapping = os.path.join(WurmCommon.directories["addons"], n[len(path[0])+1:])
                # remove the version directory from the front of the directory
                directory  = directory[len(path[0])+1:]
                isverdir = True
                verdir = "%s/" % (path[0])
        
        # store the file mapping in the dictionary
        filemap[n] = filemapping
        
        if ext.lower() == ".toc":
            addons.append(filename)
            if directory.lower() == filename.lower(): # if the ENTIRE path containing the file, and the file, are equal, this is a "simple ZIP" - this might not be true 100% of the time
                # If the directory name has a different capitalization to the filename then use the directory name instead, this handles BtmScan/btmScan
                if directory != filename:
                    del addons[-1]
                    addons.append(directory)
                simple = True
            else:
                if reia.search(directory):
                    filemap[n] = os.path.join(WurmCommon.directories["wow"], n) # remap the filename
                    intadd = True # path starts with Interface\AddOns
                elif directory != '':
                    intadd = False # we have to check it more thoroughly if just a single path is missing the Interface\AddOns part, unless it has no path at all
                
                # Store the path removing Interface/Addons from it if present
                if intadd:
                    (prepath, addondir) = os.path.split(directory[17:])
                else:
                    (prepath, addondir) = os.path.split(directory)
                if len(prepath) > 0:
                    prepaths[filename] = prepath
    
    logger.log(WurmCommon.DEBUG5, "prepaths: %s" % str(prepaths))
    
    # Cull the addon list a bit - remove contained addons
    for addon in prepaths:
        if prepaths[addon] in addons or prepaths[addon][:len(addonname)] in addons :
            try:
                del addons[addons.index(addon)] # remove the addon from the list
            except:
                pass # not critical if it isn't removed
    
    # remove the version directory entry from the file mapping dictionary
    if isverdir:
        try:
            del filemap[verdir]
        except:
            WurmCommon.outError("Unable to delete the version directory entry: %s" % verdir)
    
    # Used to simplify finding the addons in a zip
    if addonsonly:
        return addons
    
    if simple: # shortcut it here
        return (filemap, addons)
    
    # Ok, not a simple file, then we check for case 2: Interface\AddOns\AddonDir\*.*
    if intadd:
        # fixing all paths
        for n in filemap:
            if reia.search(n):
                filemap[n] = os.path.join(WurmCommon.directories["wow"], n) # remap the filename, using WoW dir as base instead of AddOns
        
        return (filemap, addons)
    
    # Right, the two simple cases are ruled out :(
    # ClearFont has everything in "[WoW folder]\Fonts" and "[WoW folder]\Interface\AddOns", so next test is to see if any of the "allowed target dirs" for unzip are in the paths (I've added "Fonts" and "Interface" to the list)
    # Tested with a range of addons, but not guaranteed to work with everyone
    
    for n in filelist:
        # Skip files with unparseable names
        try:
            n.decode()
        except:
            continue
        
        (path, filename)    = os.path.split(n)
        (mainpath, lastdir) = os.path.split(path)
        
        if lastdir in addons or (lastdir == addonname and isChild): # this is a plain addon directory
            filemap[n] = os.path.join(WurmCommon.directories["addons"], lastdir, filename)
            continue
        
        # test if this is a subdir of addon dir
        pathfound = False
        for a in addons:
            pathfound = False
            if a in mainpath: # yes, it is
                offset = path.find(a) # need to find how much to strip off the beginning of path
                filemap[n] = os.path.join(WurmCommon.directories["addons"], path[offset:], filename)
                pathfound = True
                break
        if pathfound:
            continue
        
        if lastdir.lower() in wowtoplevelfolders:
            filemap[n] = os.path.join(WurmCommon.directories["wow"], lastdir, filename)
            continue
        
        # no addon directory supplied so use the addonname as the directory name instead
        if lastdir.lower() == "addons" or lastdir == "":
            filemap[n] = os.path.join(WurmCommon.directories["addons"], addonname, filename)
            continue
        elif mainpath == "":
            filemap[n] = os.path.join(WurmCommon.directories["addons"],  addonname, lastdir, filename)
            continue
        
        # If this is a Child Addon then ignore the fact that the file cannot be placed because it hasn't got a TOC file
        if not isChild:
            del filemap[n] # just remove files that can't be placed
            WurmCommon.outWarning(_("Don't know where to place file %(filename)s") % {'filename': n})
    
    return (filemap, addons)