#!/usr/bin/env python
from XmlMutatorMin import XmlMutatorMin
# Default settings (production mode)
__mutator__ = None
__seed__ = "RANDOM"
__log__ = False
__log_file__ = "wrapper.log"
# AFL functions
def log(text):
    """
          Logger
    """
    global __seed__
    global __log__
    global __log_file__
    if __log__:
        with open(__log_file__, "a") as logf:
            logf.write("[%s] %s\n" % (__seed__, text))
def init(seed):
    """
          Called once when AFL starts up. Seed is used to identify the AFL instance in log files
    """
    global __mutator__
    global __seed__
    # Get the seed
    __seed__ = seed
    # Create a global mutation class
    try:
	__mutator__ = XmlMutatorMin(__seed__, verbose=__log__)
        log("init(): Mutator created")
    except RuntimeError as e:
        log("init(): Can't create mutator: %s" % e.message)
def fuzz(buf, add_buf):
    """
          Called for each fuzzing iteration.
    """
    global __mutator__ 
    # Do we have a working mutator object?
    if __mutator__ is None:
        log("fuzz(): Can't fuzz, no mutator available")
        return buf
    # Try to use the AFL buffer
    via_buffer = True
    # Interpret the AFL buffer (an array of bytes) as a string
    if via_buffer:
        try:
            buf_str = str(buf)
            log("fuzz(): AFL buffer converted to a string")
        except:
            via_buffer = False
            log("fuzz(): Can't convert AFL buffer to a string")
    # Load XML from the AFL string
    if via_buffer:
        try:
            __mutator__.init_from_string(buf_str)
            log("fuzz(): Mutator successfully initialized with AFL buffer (%d bytes)" % len(buf_str))
        except:
            via_buffer = False
            log("fuzz(): Can't initialize mutator with AFL buffer")
    # If init from AFL buffer wasn't succesful
    if not via_buffer:
         log("fuzz(): Returning unmodified AFL buffer")
         return buf
    # Sucessful initialization -> mutate
    try:
        __mutator__.mutate(max=5)
        log("fuzz(): Input mutated")
    except:
        log("fuzz(): Can't mutate input => returning buf")
        return buf
            
    # Convert mutated data to a array of bytes
    try:
        data = bytearray(__mutator__.save_to_string())
        log("fuzz(): Mutated data converted as bytes")
    except:
        log("fuzz(): Can't convert mutated data to bytes => returning buf")
        return buf
    # Everything went fine, returning mutated content
    log("fuzz(): Returning %d bytes" % len(data))
    return data
# Main (for debug)
if __name__ == '__main__':
    __log__ = True
    __log_file__ = "/dev/stdout"
    __seed__ = "RANDOM"
    init(__seed__)
    in_1 = bytearray("ffffzzzzzzzzzzzz")
    in_2 = bytearray("")
    out = fuzz(in_1, in_2)
    print(out)