docs: def tamper_file(filepath, mode='e', proba=0.03, block_proba=None, blocksize=65535, burst_length=None, header=None):
      """ Randomly tamper a file's content """
      if header and header > 0:
          blocksize = header
  
      tamper_count = 0 # total number of characters tampered in the file
      total_size = 0 # total buffer size, NOT necessarily the total file size (depends if you set header or not)
      with open(filepath, "r+b") as fh: # 'r+' allows to read AND overwrite characters. Else any other option won't allow both ('a+' read and append, 'w+' erases the file first then allow to read and write), and 'b' is just for binary because we can open any filetype.
          if proba >= 1: proba = 1.0/os.fstat(fh.fileno()).st_size * proba # normalizing probability if it's an integer (ie: the number of characters to flip on average)
          buf = fh.read(blocksize) # We process blocks by blocks because it's a lot faster (IO is still the slowest operation in any computing system)
          while len(buf) > 0:
              total_size += len(buf)
              if not block_proba or (random.random() < block_proba): # If block tampering is enabled, process only if this block is selected by probability
                  pos2tamper = []
                  burst_remain = 0 # if burst is enabled and corruption probability is triggered, then we will here store the remaining number of characters to corrupt (the length is uniformly sampled over the range specified in arguments)
                  # Create the list of bits to tamper (it's a lot more efficient to precompute the list of characters to corrupt, and then modify in the file the characters all at once)
                  for i in xrange(len(buf)):
                      if burst_remain > 0 or (random.random() < proba): # Corruption probability: corrupt only if below the bit-flip proba
                          pos2tamper.append(i) # keep this character's position in the to-be-corrupted list
                          if burst_remain > 0: # if we're already in a burst, we minus one and continue onto the next character
                              burst_remain -= 1
                          elif burst_length: # else we're not in a burst, we create one (triggered by corruption probability: as soon as one character triggers the corruption probability, then we do a burst)
                              burst_remain = random.randint(burst_length[0], burst_length[1]) - 1 # if burst is enabled, then we randomly (uniformly) pick a random length for the burst between the range specified, and since we already tampered one character, we minus 1
                  # If there's any character to tamper in the list, we tamper the string
                  if pos2tamper:
                      tamper_count = tamper_count + len(pos2tamper)
                      #print("Before: %s" % buf)
                      buf = bytearray(buf) # Strings in Python are immutable, thus we need to convert to a bytearray
                      for pos in pos2tamper:
                          if mode == 'e' or mode == 'erasure': # Erase the character (set a null byte)
                              buf[pos] = 0
                          elif mode == 'n' or mode == 'noise': # Noising the character (set a random ASCII character)
                              buf[pos] = random.randint(0,255)
                      #print("After: %s" % buf)
                      # Overwriting the string into the file
                      prevpos = fh.tell() # need to store and place back the seek cursor because after the write, if it's the end of the file, the next read may be buggy (getting characters that are not part of the file)
                      fh.seek(fh.tell()-len(buf)) # Move the cursor at the beginning of the string we just read
                      fh.write(buf) # Overwrite it
                      fh.seek(prevpos) # Restore the previous position after the string
              # If we only tamper the header, we stop here by setting the buffer to an empty string
              if header and header > 0:
                  buf = ''
              # Else we continue to the next data block
              else:
                  # Load the next characters from file
                  buf = fh.read(blocksize)
      return [tamper_count, total_size]