#
# Unpacker for Dean Edward's p.a.c.k.e.r, a part of javascript beautifier
# by Einar Lielmanis <einar@jsbeautifier.org>
#
#     written by Stefano Sanfilippo <a.little.coder@gmail.com>
#     Updated to handle radix 33..61 properly  swan46 <eleonora45@gmx.net>
#     Updated to handle string begin and end properly swan46 <eleonora45@gmx.net>
#
# usage:
#
# if detect(some_string):
#     unpacked = unpack(some_string)
#

"""Unpacker for Dean Edward's p.a.c.k.e.r"""

import re
import string
from jsbeautifier.unpackers import UnpackingError

PRIORITY = 1

def detect(source):
    global beginstr
    global endstr
    beginstr = ''
    endstr = ''
    """Detects whether `source` is P.A.C.K.E.R. coded."""
    mystr = source.replace(' ', '').find('eval(function(p,a,c,k,e,')
    if(mystr > 0): 
       beginstr = source[:mystr]
    if(mystr != -1):
       """ Find endstr"""
       if(source.split("')))", 1)[0] == source):
          try:
             endstr = source.split("}))", 1)[1]
          except IndexError:
             endstr = ''
       else:
          endstr = source.split("')))", 1)[1]
    return ( mystr != -1 )

def unpack(source):
    """Unpacks P.A.C.K.E.R. packed js code."""
    payload, symtab, radix, count = _filterargs(source)

    if count != len(symtab):
        raise UnpackingError('Malformed p.a.c.k.e.r. symtab.')

    try:
        unbase = Unbaser(radix)
    except TypeError:
        raise UnpackingError('Unknown p.a.c.k.e.r. encoding.')

    def lookup(match):
        """Look up symbols in the synthetic symtab."""
        word  = match.group(0)
        return symtab[unbase(word)] or word

    source = re.sub(r'\b\w+\b', lookup, payload)
    return _replacestrings(source)

def _filterargs(source):
    """Juice from a source file the four args needed by decoder."""
    juicers = [ (r"}\('(.*)', *(\d+), *(\d+), *'(.*)'\.split\('\|'\), *(\d+), *(.*)\)\)"),
                (r"}\('(.*)', *(\d+), *(\d+), *'(.*)'\.split\('\|'\)"),
              ]
    for juicer in juicers:
        args = re.search(juicer, source, re.DOTALL)
        if args:
            a = args.groups()
            try:
                return a[0], a[3].split('|'), int(a[1]), int(a[2])
            except ValueError:
                raise UnpackingError('Corrupted p.a.c.k.e.r. data.')

    # could not find a satisfying regex
    raise UnpackingError('Could not make sense of p.a.c.k.e.r data (unexpected code structure)')



def _replacestrings(source):
    global beginstr
    global endstr
    """Strip string lookup table (list) and replace values in source."""
    match = re.search(r'var *(_\w+)\=\["(.*?)"\];', source, re.DOTALL)

    if match:
        varname, strings = match.groups()
        startpoint = len(match.group(0))
        lookup = strings.split('","')
        variable = '%s[%%d]' % varname
        for index, value in enumerate(lookup):
            source = source.replace(variable % index, '"%s"' % value)
        return source[startpoint:]
    return beginstr + source + endstr


class Unbaser(object):
    """Functor for a given base. Will efficiently convert
    strings to natural numbers."""
    ALPHABET  = {
        62 : '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
        95 : (' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ'
              '[\]^_`abcdefghijklmnopqrstuvwxyz{|}~')
    }

    def __init__(self, base):
        self.base = base

        # fill elements 37...61, if necessary
        if 36 < base < 62: 
            if not hasattr(self.ALPHABET, self.ALPHABET[62][:base]):
                      self.ALPHABET[base] =  self.ALPHABET[62][:base]
            #attrs = self.ALPHABET
            #print ', '.join("%s: %s" % item for item in attrs.items())
        # If base can be handled by int() builtin, let it do it for us
        if 2 <= base <= 36:
            self.unbase = lambda string: int(string, base)
        else:
            # Build conversion dictionary cache
            try:
                self.dictionary = dict((cipher, index) for
                    index, cipher in enumerate(self.ALPHABET[base]))
            except KeyError:
                raise TypeError('Unsupported base encoding.')

            self.unbase = self._dictunbaser

    def __call__(self, string):
        return self.unbase(string)

    def _dictunbaser(self, string):
        """Decodes a  value to an integer."""
        ret = 0
        for index, cipher in enumerate(string[::-1]):
            ret += (self.base ** index) * self.dictionary[cipher]
        return ret

@@ -184,167 +184,10 @@
 om%3E%0A
-#     Updated to handle radix 33..61 properly  swan46 %3Celeonora45@gmx.net%3E%0A#     Updated to handle string begin and end properly swan46 %3Celeonora45@gmx.net%3E%0A
 #%0A
+
 # us
@@ -394,16 +394,17 @@
 TY = 1%0A%0A
+%0A
 def dete
@@ -632,17 +632,16 @@
 tr %3E 0):
- 
 %0A       
@@ -950,17 +950,16 @@
 return (
- 
 mystr !=
@@ -965,12 +965,12 @@
 = -1
- 
 )%0A%0A
+%0A
 def 
@@ -1400,17 +1400,16 @@
    word 
- 
 = match.
@@ -1547,16 +1547,17 @@
 ource)%0A%0A
+%0A
 def _fil
@@ -2270,17 +2270,16 @@
 re)')%0A%0A%0A
-%0A
 def _rep
@@ -2977,17 +2977,16 @@
 LPHABET 
- 
 = %7B%0A    
@@ -2991,17 +2991,16 @@
       62
- 
 : '01234
@@ -3069,17 +3069,16 @@
       95
- 
 : (' !%22#
@@ -3324,17 +3324,16 @@
 se %3C 62:
- 
 %0A       
@@ -3437,17 +3437,16 @@
 %5Bbase%5D =
- 
  self.AL
@@ -4358,16 +4358,16 @@
 cipher%5D%0A
-
         
@@ -4377,8 +4377,9 @@
 urn ret%0A
+%0A

Update packer.py