public function process_chunk($data) {

        $path = $data['path'];

        // expand the MOD paths so that they contain the module name
        if ($path === '/MOODLE_BACKUP/COURSE/MODULES/MOD') {
            $this->currentmod = strtoupper($data['tags']['MODTYPE']);
            $path = '/MOODLE_BACKUP/COURSE/MODULES/MOD/' . $this->currentmod;

        } else if (strpos($path, '/MOODLE_BACKUP/COURSE/MODULES/MOD') === 0) {
            $path = str_replace('/MOODLE_BACKUP/COURSE/MODULES/MOD', '/MOODLE_BACKUP/COURSE/MODULES/MOD/' . $this->currentmod, $path);
        }

        // expand the BLOCK paths so that they contain the module name
        if ($path === '/MOODLE_BACKUP/COURSE/BLOCKS/BLOCK') {
            $this->currentblock = strtoupper($data['tags']['NAME']);
            $path = '/MOODLE_BACKUP/COURSE/BLOCKS/BLOCK/' . $this->currentblock;

        } else if (strpos($path, '/MOODLE_BACKUP/COURSE/BLOCKS/BLOCK') === 0) {
            $path = str_replace('/MOODLE_BACKUP/COURSE/BLOCKS/BLOCK', '/MOODLE_BACKUP/COURSE/BLOCKS/BLOCK/' . $this->currentblock, $path);
        }

        if ($path !== $data['path']) {
            if (!array_key_exists($path, $this->pathelements)) {
                // no handler registered for the transformed MOD or BLOCK path
                $this->log('no handler attached', backup::LOG_WARNING, $path);
                return;

            } else {
                // pretend as if the original $data contained the tranformed path
                $data['path'] = $path;
            }
        }

        if (!array_key_exists($data['path'], $this->pathelements)) {
            // path added to the processor without the handler
            throw new convert_exception('missing_path_handler', $data['path']);
        }

        $element  = $this->pathelements[$data['path']];
        $object   = $element->get_processing_object();
        $method   = $element->get_processing_method();
        $returned = null; // data returned by the processing method, if any

        if (empty($object)) {
            throw new convert_exception('missing_processing_object', null, $data['path']);
        }

        // release the lock if we aren't anymore within children of it
        if (!is_null($this->pathlock) and strpos($data['path'], $this->pathlock) === false) {
            $this->pathlock = null;
        }

        // if the path is not locked, apply the element's recipes and dispatch
        // the cooked tags to the processing method
        if (is_null($this->pathlock)) {
            $rawdatatags  = $data['tags'];
            $data['tags'] = $element->apply_recipes($data['tags']);

            // if the processing method exists, give it a chance to modify data
            if (method_exists($object, $method)) {
                $returned = $object->$method($data['tags'], $rawdatatags);
            }
        }

        // if the dispatched method returned SKIP_ALL_CHILDREN, remember the current path
        // and lock it so that its children are not dispatched
        if ($returned === self::SKIP_ALL_CHILDREN) {
            // check we haven't any previous lock
            if (!is_null($this->pathlock)) {
                throw new convert_exception('already_locked_path', $data['path']);
            }
            // set the lock - nothing below the current path will be dispatched
            $this->pathlock = $data['path'] . '/';

        // if the method has returned any info, set element data to it
        } else if (!is_null($returned)) {
            $element->set_tags($returned);

        // use just the cooked parsed data otherwise
        } else {
            $element->set_tags($data['tags']);
        }
    }