diff --git a/typo3/sysext/core/Documentation/Changelog/master/Breaking-45899-SplitClassImportExportIntoClassesImportAndExport.rst b/typo3/sysext/core/Documentation/Changelog/master/Breaking-45899-SplitClassImportExportIntoClassesImportAndExport.rst
new file mode 100644
index 0000000000000000000000000000000000000000..5a9c5eb964ab9705046fd1784779d134906be2e1
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/master/Breaking-45899-SplitClassImportExportIntoClassesImportAndExport.rst
@@ -0,0 +1,26 @@
+==========================================================================
+Breaking: #45899 - Split class ImportExport into classes Import and Export
+==========================================================================
+
+Description
+===========
+
+Class TYPO3\CMS\Impexp\ImportExport (typo3/sysext/impexp/Classes/ImportExport.php) is split into a class dedicated for import and another one for export.
+
+
+Impact
+======
+
+Using and extending the class is not possible any more.
+
+
+Affected Installations
+======================
+
+Those which use the class and its methods directly or extend the class.
+
+
+Migration
+=========
+
+Use or extend one or both of the new classes (TYPO3\CMS\Impexp\Import and TYPO3\CMS\Impexp\Export).
\ No newline at end of file
diff --git a/typo3/sysext/impexp/Classes/Controller/ImportExportController.php b/typo3/sysext/impexp/Classes/Controller/ImportExportController.php
index 68537c78f9e341a6eaf4299923d62a4babdebca9..96c96982824be1c485f70ff7bc830af227ff496e 100644
--- a/typo3/sysext/impexp/Classes/Controller/ImportExportController.php
+++ b/typo3/sysext/impexp/Classes/Controller/ImportExportController.php
@@ -36,7 +36,8 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
 use TYPO3\CMS\Core\Utility\PathUtility;
 use TYPO3\CMS\Impexp\Domain\Repository\PresetRepository;
-use TYPO3\CMS\Impexp\ImportExport;
+use TYPO3\CMS\Impexp\Export;
+use TYPO3\CMS\Impexp\Import;
 use TYPO3\CMS\Impexp\View\ExportPageTreeView;
 use TYPO3\CMS\Lang\LanguageService;
 
@@ -58,12 +59,12 @@ class ImportExportController extends BaseScriptClass
     public $pageinfo;
 
     /**
-     * @var ImportExport
+     * @var Export
      */
     protected $export;
 
     /**
-     * @var ImportExport
+     * @var Import
      */
     protected $import;
 
@@ -312,8 +313,8 @@ class ImportExportController extends BaseScriptClass
         // Saving/Loading/Deleting presets:
         $this->presetRepository->processPresets($inData);
         // Create export object and configure it:
-        $this->export = GeneralUtility::makeInstance(ImportExport::class);
-        $this->export->init(0, 'export');
+        $this->export = GeneralUtility::makeInstance(Export::class);
+        $this->export->init(0);
         $this->export->setCharset($this->lang->charSet);
         $this->export->maxFileSize = $inData['maxFileSize'] * 1024;
         $this->export->excludeMap = (array)$inData['exclude'];
@@ -989,9 +990,9 @@ class ImportExportController extends BaseScriptClass
             if ($inData['new_import']) {
                 unset($inData['import_mode']);
             }
-            /** @var $import ImportExport */
-            $import = GeneralUtility::makeInstance(ImportExport::class);
-            $import->init(0, 'import');
+            /** @var $import Import */
+            $import = GeneralUtility::makeInstance(Import::class);
+            $import->init();
             $import->update = $inData['do_update'];
             $import->import_mode = $inData['import_mode'];
             $import->enableLogging = $inData['enableLogging'];
diff --git a/typo3/sysext/impexp/Classes/Export.php b/typo3/sysext/impexp/Classes/Export.php
new file mode 100644
index 0000000000000000000000000000000000000000..d25e826f7d53c0a684dde2bd682cab7668e370d4
--- /dev/null
+++ b/typo3/sysext/impexp/Classes/Export.php
@@ -0,0 +1,1144 @@
+<?php
+namespace TYPO3\CMS\Impexp;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Database\ReferenceIndex;
+use TYPO3\CMS\Core\Exception;
+use TYPO3\CMS\Core\Html\HtmlParser;
+use TYPO3\CMS\Core\Resource\File;
+use TYPO3\CMS\Core\Resource\ResourceFactory;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\PathUtility;
+
+/**
+ * EXAMPLE for using the impexp-class for exporting stuff:
+ *
+ * Create and initialize:
+ * $this->export = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Impexp\ImportExport::class);
+ * $this->export->init();
+ * Set which tables relations we will allow:
+ * $this->export->relOnlyTables[]="tt_news";	// exclusively includes. See comment in the class
+ *
+ * Adding records:
+ * $this->export->export_addRecord("pages", $this->pageinfo);
+ * $this->export->export_addRecord("pages", \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord("pages", 38));
+ * $this->export->export_addRecord("pages", \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord("pages", 39));
+ * $this->export->export_addRecord("tt_content", \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord("tt_content", 12));
+ * $this->export->export_addRecord("tt_content", \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord("tt_content", 74));
+ * $this->export->export_addRecord("sys_template", \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord("sys_template", 20));
+ *
+ * Adding all the relations (recursively in 5 levels so relations has THEIR relations registered as well)
+ * for($a=0;$a<5;$a++) {
+ * $addR = $this->export->export_addDBRelations($a);
+ * if (empty($addR)) break;
+ * }
+ *
+ * Finally load all the files.
+ * $this->export->export_addFilesFromRelations();	// MUST be after the DBrelations are set so that file from ALL added records are included!
+ *
+ * Write export
+ * $out = $this->export->compileMemoryToFileContent();
+ */
+
+/**
+ * T3D file Export library (TYPO3 Record Document)
+ */
+class Export extends ImportExport
+{
+    /**
+     * 1MB max file size
+     *
+     * @var int
+     */
+    public $maxFileSize = 1000000;
+
+    /**
+     * 1MB max record size
+     *
+     * @var int
+     */
+    public $maxRecordSize = 1000000;
+
+    /**
+     * 10MB max export size
+     *
+     * @var int
+     */
+    public $maxExportSize = 10000000;
+
+    /**
+     * Set  by user: If set, compression in t3d files is disabled
+     *
+     * @var bool
+     */
+    public $dontCompress = false;
+
+    /**
+     * If set, HTML file resources are included.
+     *
+     * @var bool
+     */
+    public $includeExtFileResources = false;
+
+    /**
+     * Files with external media (HTML/css style references inside)
+     *
+     * @var string
+     */
+    public $extFileResourceExtensions = 'html,htm,css';
+
+    /**
+     * Keys are [recordname], values are an array of fields to be included
+     * in the export
+     *
+     * @var array
+     */
+    protected $recordTypesIncludeFields = array();
+
+    /**
+     * Default array of fields to be included in the export
+     *
+     * @var array
+     */
+    protected $defaultRecordIncludeFields = array('uid', 'pid');
+
+    /**
+     * @var bool
+     */
+    protected $saveFilesOutsideExportFile = false;
+
+    /**
+     * @var NULL|string
+     */
+    protected $temporaryFilesPathForExport = null;
+
+    /**************************
+     * Initialize
+     *************************/
+
+    /**
+     * Init the object
+     *
+     * @param bool $dontCompress If set, compression of t3d files is disabled
+     * @return void
+     */
+    public function init($dontCompress = false)
+    {
+        parent::init();
+        $this->dontCompress = $dontCompress;
+        $this->mode = 'export';
+    }
+
+    /**************************
+     * Export / Init + Meta Data
+     *************************/
+
+    /**
+     * Set header basics
+     *
+     * @return void
+     */
+    public function setHeaderBasics()
+    {
+        // Initializing:
+        if (is_array($this->softrefCfg)) {
+            foreach ($this->softrefCfg as $key => $value) {
+                if (!strlen($value['mode'])) {
+                    unset($this->softrefCfg[$key]);
+                }
+            }
+        }
+        // Setting in header memory:
+        // Version of file format
+        $this->dat['header']['XMLversion'] = '1.0';
+        // Initialize meta data array (to put it in top of file)
+        $this->dat['header']['meta'] = array();
+        // Add list of tables to consider static
+        $this->dat['header']['relStaticTables'] = $this->relStaticTables;
+        // The list of excluded records
+        $this->dat['header']['excludeMap'] = $this->excludeMap;
+        // Soft Reference mode for elements
+        $this->dat['header']['softrefCfg'] = $this->softrefCfg;
+        // List of extensions the import depends on.
+        $this->dat['header']['extensionDependencies'] = $this->extensionDependencies;
+    }
+
+    /**
+     * Set charset
+     *
+     * @param string $charset Charset for the content in the export. During import the character set will be converted if the target system uses another charset.
+     * @return void
+     */
+    public function setCharset($charset)
+    {
+        $this->dat['header']['charset'] = $charset;
+    }
+
+    /**
+     * Sets meta data
+     *
+     * @param string $title Title of the export
+     * @param string $description Description of the export
+     * @param string $notes Notes about the contents
+     * @param string $packager_username Backend Username of the packager (the guy making the export)
+     * @param string $packager_name Real name of the packager
+     * @param string $packager_email Email of the packager
+     * @return void
+     */
+    public function setMetaData($title, $description, $notes, $packager_username, $packager_name, $packager_email)
+    {
+        $this->dat['header']['meta'] = array(
+            'title' => $title,
+            'description' => $description,
+            'notes' => $notes,
+            'packager_username' => $packager_username,
+            'packager_name' => $packager_name,
+            'packager_email' => $packager_email,
+            'TYPO3_version' => TYPO3_version,
+            'created' => strftime('%A %e. %B %Y', $GLOBALS['EXEC_TIME'])
+        );
+    }
+
+    /**
+     * Option to enable having the files not included in the export file.
+     * The files are saved to a temporary folder instead.
+     *
+     * @param bool $saveFilesOutsideExportFile
+     * @see getTemporaryFilesPathForExport()
+     */
+    public function setSaveFilesOutsideExportFile($saveFilesOutsideExportFile)
+    {
+        $this->saveFilesOutsideExportFile = $saveFilesOutsideExportFile;
+    }
+
+    /**
+     * Sets a thumbnail image to the exported file
+     *
+     * @param string $imgFilepath Filename reference, gif, jpg, png. Absolute path.
+     * @return void
+     */
+    public function addThumbnail($imgFilepath)
+    {
+        if (@is_file($imgFilepath)) {
+            $imgInfo = @getimagesize($imgFilepath);
+            if (is_array($imgInfo)) {
+                $fileContent = GeneralUtility::getUrl($imgFilepath);
+                $this->dat['header']['thumbnail'] = array(
+                    'imgInfo' => $imgInfo,
+                    'content' => $fileContent,
+                    'filesize' => strlen($fileContent),
+                    'filemtime' => filemtime($imgFilepath),
+                    'filename' => PathUtility::basename($imgFilepath)
+                );
+            }
+        }
+    }
+
+    /**************************
+     * Export / Init Page tree
+     *************************/
+
+    /**
+     * Sets the page-tree array in the export header and returns the array in a flattened version
+     *
+     * @param array $idH Hierarchy of ids, the page tree: array([uid] => array("uid" => [uid], "subrow" => array(.....)), [uid] => ....)
+     * @return array The hierarchical page tree converted to a one-dimensional list of pages
+     */
+    public function setPageTree($idH)
+    {
+        $this->dat['header']['pagetree'] = $this->unsetExcludedSections($idH);
+        return $this->flatInversePageTree($this->dat['header']['pagetree']);
+    }
+
+    /**
+     * Removes entries in the page tree which are found in ->excludeMap[]
+     *
+     * @param array $idH Page uid hierarchy
+     * @return array Modified input array
+     * @access private
+     * @see setPageTree()
+     */
+    public function unsetExcludedSections($idH)
+    {
+        if (is_array($idH)) {
+            foreach ($idH as $k => $v) {
+                if ($this->excludeMap['pages:' . $idH[$k]['uid']]) {
+                    unset($idH[$k]);
+                } elseif (is_array($idH[$k]['subrow'])) {
+                    $idH[$k]['subrow'] = $this->unsetExcludedSections($idH[$k]['subrow']);
+                }
+            }
+        }
+        return $idH;
+    }
+
+    /**************************
+     * Export
+     *************************/
+
+    /**
+     * Sets the fields of record types to be included in the export
+     *
+     * @param array $recordTypesIncludeFields Keys are [recordname], values are an array of fields to be included in the export
+     * @throws Exception if an array value is not type of array
+     * @return void
+     */
+    public function setRecordTypesIncludeFields(array $recordTypesIncludeFields)
+    {
+        foreach ($recordTypesIncludeFields as $table => $fields) {
+            if (!is_array($fields)) {
+                throw new Exception('The include fields for record type ' . htmlspecialchars($table) . ' are not defined by an array.', 1391440658);
+            }
+            $this->setRecordTypeIncludeFields($table, $fields);
+        }
+    }
+
+    /**
+     * Sets the fields of a record type to be included in the export
+     *
+     * @param string $table The record type
+     * @param array $fields The fields to be included
+     * @return void
+     */
+    public function setRecordTypeIncludeFields($table, array $fields)
+    {
+        $this->recordTypesIncludeFields[$table] = $fields;
+    }
+
+    /**
+     * Adds the record $row from $table.
+     * No checking for relations done here. Pure data.
+     *
+     * @param string $table Table name
+     * @param array $row Record row.
+     * @param int $relationLevel (Internal) if the record is added as a relation, this is set to the "level" it was on.
+     * @return void
+     */
+    public function export_addRecord($table, $row, $relationLevel = 0)
+    {
+        BackendUtility::workspaceOL($table, $row);
+        if ((string)$table !== '' && is_array($row) && $row['uid'] > 0 && !$this->excludeMap[$table . ':' . $row['uid']]) {
+            if ($this->checkPID($table === 'pages' ? $row['uid'] : $row['pid'])) {
+                if (!isset($this->dat['records'][$table . ':' . $row['uid']])) {
+                    // Prepare header info:
+                    $row = $this->filterRecordFields($table, $row);
+                    $headerInfo = array();
+                    $headerInfo['uid'] = $row['uid'];
+                    $headerInfo['pid'] = $row['pid'];
+                    $headerInfo['title'] = GeneralUtility::fixed_lgd_cs(BackendUtility::getRecordTitle($table, $row), 40);
+                    $headerInfo['size'] = strlen(serialize($row));
+                    if ($relationLevel) {
+                        $headerInfo['relationLevel'] = $relationLevel;
+                    }
+                    // If record content is not too large in size, set the header content and add the rest:
+                    if ($headerInfo['size'] < $this->maxRecordSize) {
+                        // Set the header summary:
+                        $this->dat['header']['records'][$table][$row['uid']] = $headerInfo;
+                        // Create entry in the PID lookup:
+                        $this->dat['header']['pid_lookup'][$row['pid']][$table][$row['uid']] = 1;
+                        // Initialize reference index object:
+                        $refIndexObj = GeneralUtility::makeInstance(ReferenceIndex::class);
+                        // Yes to workspace overlays for exporting....
+                        $refIndexObj->WSOL = true;
+                        $relations = $refIndexObj->getRelations($table, $row);
+                        $relations = $this->fixFileIDsInRelations($relations);
+                        $relations = $this->removeSoftrefsHavingTheSameDatabaseRelation($relations);
+                        // Data:
+                        $this->dat['records'][$table . ':' . $row['uid']] = array();
+                        $this->dat['records'][$table . ':' . $row['uid']]['data'] = $row;
+                        $this->dat['records'][$table . ':' . $row['uid']]['rels'] = $relations;
+                        // Add information about the relations in the record in the header:
+                        $this->dat['header']['records'][$table][$row['uid']]['rels'] = $this->flatDBrels($this->dat['records'][$table . ':' . $row['uid']]['rels']);
+                        // Add information about the softrefs to header:
+                        $this->dat['header']['records'][$table][$row['uid']]['softrefs'] = $this->flatSoftRefs($this->dat['records'][$table . ':' . $row['uid']]['rels']);
+                    } else {
+                        $this->error('Record ' . $table . ':' . $row['uid'] . ' was larger than maxRecordSize (' . GeneralUtility::formatSize($this->maxRecordSize) . ')');
+                    }
+                } else {
+                    $this->error('Record ' . $table . ':' . $row['uid'] . ' already added.');
+                }
+            } else {
+                $this->error('Record ' . $table . ':' . $row['uid'] . ' was outside your DB mounts!');
+            }
+        }
+    }
+
+    /**
+     * This changes the file reference ID from a hash based on the absolute file path
+     * (coming from ReferenceIndex) to a hash based on the relative file path.
+     *
+     * @param array $relations
+     * @return array
+     */
+    protected function fixFileIDsInRelations(array $relations)
+    {
+        foreach ($relations as $field => $relation) {
+            if (isset($relation['type']) && $relation['type'] === 'file') {
+                foreach ($relation['newValueFiles'] as $key => $fileRelationData) {
+                    $absoluteFilePath = $fileRelationData['ID_absFile'];
+                    if (GeneralUtility::isFirstPartOfStr($absoluteFilePath, PATH_site)) {
+                        $relatedFilePath = PathUtility::stripPathSitePrefix($absoluteFilePath);
+                        $relations[$field]['newValueFiles'][$key]['ID'] = md5($relatedFilePath);
+                    }
+                }
+            }
+            if ($relation['type'] === 'flex') {
+                if (is_array($relation['flexFormRels']['file'])) {
+                    foreach ($relation['flexFormRels']['file'] as $key => $subList) {
+                        foreach ($subList as $subKey => $fileRelationData) {
+                            $absoluteFilePath = $fileRelationData['ID_absFile'];
+                            if (GeneralUtility::isFirstPartOfStr($absoluteFilePath, PATH_site)) {
+                                $relatedFilePath = PathUtility::stripPathSitePrefix($absoluteFilePath);
+                                $relations[$field]['flexFormRels']['file'][$key][$subKey]['ID'] = md5($relatedFilePath);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return $relations;
+    }
+
+    /**
+     * Relations could contain db relations to sys_file records. Some configuration combinations of TCA and
+     * SoftReferenceIndex create also softref relation entries for the identical file. This results
+     * in double included files, one in array "files" and one in array "file_fal".
+     * This function checks the relations for this double inclusions and removes the redundant softref relation.
+     *
+     * @param array $relations
+     * @return array
+     */
+    protected function removeSoftrefsHavingTheSameDatabaseRelation($relations)
+    {
+        $fixedRelations = array();
+        foreach ($relations as $field => $relation) {
+            $newRelation = $relation;
+            if (isset($newRelation['type']) && $newRelation['type'] === 'db') {
+                foreach ($newRelation['itemArray'] as $key => $dbRelationData) {
+                    if ($dbRelationData['table'] === 'sys_file') {
+                        if (isset($newRelation['softrefs']['keys']['typolink'])) {
+                            foreach ($newRelation['softrefs']['keys']['typolink'] as $softrefKey => $softRefData) {
+                                if ($softRefData['subst']['type'] === 'file') {
+                                    $file = ResourceFactory::getInstance()->retrieveFileOrFolderObject($softRefData['subst']['relFileName']);
+                                    if ($file instanceof File) {
+                                        if ($file->getUid() == $dbRelationData['id']) {
+                                            unset($newRelation['softrefs']['keys']['typolink'][$softrefKey]);
+                                        }
+                                    }
+                                }
+                            }
+                            if (empty($newRelation['softrefs']['keys']['typolink'])) {
+                                unset($newRelation['softrefs']);
+                            }
+                        }
+                    }
+                }
+            }
+            $fixedRelations[$field] = $newRelation;
+        }
+        return $fixedRelations;
+    }
+
+    /**
+     * This analyses the existing added records, finds all database relations to records and adds these records to the export file.
+     * This function can be called repeatedly until it returns an empty array.
+     * In principle it should not allow to infinite recursivity, but you better set a limit...
+     * Call this BEFORE the ext_addFilesFromRelations (so files from added relations are also included of course)
+     *
+     * @param int $relationLevel Recursion level
+     * @return array overview of relations found and added: Keys [table]:[uid], values array with table and id
+     * @see export_addFilesFromRelations()
+     */
+    public function export_addDBRelations($relationLevel = 0)
+    {
+        // Traverse all "rels" registered for "records"
+        if (!is_array($this->dat['records'])) {
+            $this->error('There were no records available.');
+            return array();
+        }
+        $addR = array();
+        foreach ($this->dat['records'] as $k => $value) {
+            if (!is_array($this->dat['records'][$k])) {
+                continue;
+            }
+            foreach ($this->dat['records'][$k]['rels'] as $fieldname => $vR) {
+                // For all DB types of relations:
+                if ($vR['type'] == 'db') {
+                    foreach ($vR['itemArray'] as $fI) {
+                        $this->export_addDBRelations_registerRelation($fI, $addR);
+                    }
+                }
+                // For all flex/db types of relations:
+                if ($vR['type'] == 'flex') {
+                    // DB relations in flex form fields:
+                    if (is_array($vR['flexFormRels']['db'])) {
+                        foreach ($vR['flexFormRels']['db'] as $subList) {
+                            foreach ($subList as $fI) {
+                                $this->export_addDBRelations_registerRelation($fI, $addR);
+                            }
+                        }
+                    }
+                    // DB oriented soft references in flex form fields:
+                    if (is_array($vR['flexFormRels']['softrefs'])) {
+                        foreach ($vR['flexFormRels']['softrefs'] as $subList) {
+                            foreach ($subList['keys'] as $spKey => $elements) {
+                                foreach ($elements as $el) {
+                                    if ($el['subst']['type'] === 'db' && $this->includeSoftref($el['subst']['tokenID'])) {
+                                        list($tempTable, $tempUid) = explode(':', $el['subst']['recordRef']);
+                                        $fI = array(
+                                            'table' => $tempTable,
+                                            'id' => $tempUid
+                                        );
+                                        $this->export_addDBRelations_registerRelation($fI, $addR, $el['subst']['tokenID']);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+                // In any case, if there are soft refs:
+                if (is_array($vR['softrefs']['keys'])) {
+                    foreach ($vR['softrefs']['keys'] as $spKey => $elements) {
+                        foreach ($elements as $el) {
+                            if ($el['subst']['type'] === 'db' && $this->includeSoftref($el['subst']['tokenID'])) {
+                                list($tempTable, $tempUid) = explode(':', $el['subst']['recordRef']);
+                                $fI = array(
+                                    'table' => $tempTable,
+                                    'id' => $tempUid
+                                );
+                                $this->export_addDBRelations_registerRelation($fI, $addR, $el['subst']['tokenID']);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        // Now, if there were new records to add, do so:
+        if (!empty($addR)) {
+            foreach ($addR as $fI) {
+                // Get and set record:
+                $row = BackendUtility::getRecord($fI['table'], $fI['id']);
+                if (is_array($row)) {
+                    $this->export_addRecord($fI['table'], $row, $relationLevel + 1);
+                }
+                // Set status message
+                // Relation pointers always larger than zero except certain "select" types with
+                // negative values pointing to uids - but that is not supported here.
+                if ($fI['id'] > 0) {
+                    $rId = $fI['table'] . ':' . $fI['id'];
+                    if (!isset($this->dat['records'][$rId])) {
+                        $this->dat['records'][$rId] = 'NOT_FOUND';
+                        $this->error('Relation record ' . $rId . ' was not found!');
+                    }
+                }
+            }
+        }
+        // Return overview of relations found and added
+        return $addR;
+    }
+
+    /**
+     * Helper function for export_addDBRelations()
+     *
+     * @param array $fI Array with table/id keys to add
+     * @param array $addR Add array, passed by reference to be modified
+     * @param string $tokenID Softref Token ID, if applicable.
+     * @return void
+     * @see export_addDBRelations()
+     */
+    public function export_addDBRelations_registerRelation($fI, &$addR, $tokenID = '')
+    {
+        $rId = $fI['table'] . ':' . $fI['id'];
+        if (
+            isset($GLOBALS['TCA'][$fI['table']]) && !$this->isTableStatic($fI['table']) && !$this->isExcluded($fI['table'], $fI['id'])
+            && (!$tokenID || $this->includeSoftref($tokenID)) && $this->inclRelation($fI['table'])
+        ) {
+            if (!isset($this->dat['records'][$rId])) {
+                // Set this record to be included since it is not already.
+                $addR[$rId] = $fI;
+            }
+        }
+    }
+
+    /**
+     * This adds all files in relations.
+     * Call this method AFTER adding all records including relations.
+     *
+     * @return void
+     * @see export_addDBRelations()
+     */
+    public function export_addFilesFromRelations()
+    {
+        // Traverse all "rels" registered for "records"
+        if (!is_array($this->dat['records'])) {
+            $this->error('There were no records available.');
+            return;
+        }
+        foreach ($this->dat['records'] as $k => $value) {
+            if (!isset($this->dat['records'][$k]['rels']) || !is_array($this->dat['records'][$k]['rels'])) {
+                continue;
+            }
+            foreach ($this->dat['records'][$k]['rels'] as $fieldname => $vR) {
+                // For all file type relations:
+                if ($vR['type'] == 'file') {
+                    foreach ($vR['newValueFiles'] as $key => $fI) {
+                        $this->export_addFile($fI, $k, $fieldname);
+                        // Remove the absolute reference to the file so it doesn't expose absolute paths from source server:
+                        unset($this->dat['records'][$k]['rels'][$fieldname]['newValueFiles'][$key]['ID_absFile']);
+                    }
+                }
+                // For all flex type relations:
+                if ($vR['type'] == 'flex') {
+                    if (is_array($vR['flexFormRels']['file'])) {
+                        foreach ($vR['flexFormRels']['file'] as $key => $subList) {
+                            foreach ($subList as $subKey => $fI) {
+                                $this->export_addFile($fI, $k, $fieldname);
+                                // Remove the absolute reference to the file so it doesn't expose absolute paths from source server:
+                                unset($this->dat['records'][$k]['rels'][$fieldname]['flexFormRels']['file'][$key][$subKey]['ID_absFile']);
+                            }
+                        }
+                    }
+                    // DB oriented soft references in flex form fields:
+                    if (is_array($vR['flexFormRels']['softrefs'])) {
+                        foreach ($vR['flexFormRels']['softrefs'] as $key => $subList) {
+                            foreach ($subList['keys'] as $spKey => $elements) {
+                                foreach ($elements as $subKey => $el) {
+                                    if ($el['subst']['type'] === 'file' && $this->includeSoftref($el['subst']['tokenID'])) {
+                                        // Create abs path and ID for file:
+                                        $ID_absFile = GeneralUtility::getFileAbsFileName(PATH_site . $el['subst']['relFileName']);
+                                        $ID = md5($el['subst']['relFileName']);
+                                        if ($ID_absFile) {
+                                            if (!$this->dat['files'][$ID]) {
+                                                $fI = array(
+                                                    'filename' => PathUtility::basename($ID_absFile),
+                                                    'ID_absFile' => $ID_absFile,
+                                                    'ID' => $ID,
+                                                    'relFileName' => $el['subst']['relFileName']
+                                                );
+                                                $this->export_addFile($fI, '_SOFTREF_');
+                                            }
+                                            $this->dat['records'][$k]['rels'][$fieldname]['flexFormRels']['softrefs'][$key]['keys'][$spKey][$subKey]['file_ID'] = $ID;
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+                // In any case, if there are soft refs:
+                if (is_array($vR['softrefs']['keys'])) {
+                    foreach ($vR['softrefs']['keys'] as $spKey => $elements) {
+                        foreach ($elements as $subKey => $el) {
+                            if ($el['subst']['type'] === 'file' && $this->includeSoftref($el['subst']['tokenID'])) {
+                                // Create abs path and ID for file:
+                                $ID_absFile = GeneralUtility::getFileAbsFileName(PATH_site . $el['subst']['relFileName']);
+                                $ID = md5($el['subst']['relFileName']);
+                                if ($ID_absFile) {
+                                    if (!$this->dat['files'][$ID]) {
+                                        $fI = array(
+                                            'filename' => PathUtility::basename($ID_absFile),
+                                            'ID_absFile' => $ID_absFile,
+                                            'ID' => $ID,
+                                            'relFileName' => $el['subst']['relFileName']
+                                        );
+                                        $this->export_addFile($fI, '_SOFTREF_');
+                                    }
+                                    $this->dat['records'][$k]['rels'][$fieldname]['softrefs']['keys'][$spKey][$subKey]['file_ID'] = $ID;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * This adds all files from sys_file records
+     *
+     * @return void
+     */
+    public function export_addFilesFromSysFilesRecords()
+    {
+        if (!isset($this->dat['header']['records']['sys_file']) || !is_array($this->dat['header']['records']['sys_file'])) {
+            return;
+        }
+        foreach ($this->dat['header']['records']['sys_file'] as $sysFileUid => $_) {
+            $recordData = $this->dat['records']['sys_file:' . $sysFileUid]['data'];
+            $file = ResourceFactory::getInstance()->createFileObject($recordData);
+            $this->export_addSysFile($file);
+        }
+    }
+
+    /**
+     * Adds a files content from a sys file record to the export memory
+     *
+     * @param File $file
+     * @return void
+     */
+    public function export_addSysFile(File $file)
+    {
+        if ($file->getProperty('size') >= $this->maxFileSize) {
+            $this->error('File ' . $file->getPublicUrl() . ' was larger (' . GeneralUtility::formatSize($file->getProperty('size')) . ') than the maxFileSize (' . GeneralUtility::formatSize($this->maxFileSize) . ')! Skipping.');
+            return;
+        }
+        $fileContent = '';
+        try {
+            if (!$this->saveFilesOutsideExportFile) {
+                $fileContent = $file->getContents();
+            } else {
+                $file->checkActionPermission('read');
+            }
+        } catch (\Exception $e) {
+            $this->error('Error when trying to add file ' . $file->getCombinedIdentifier() . ': ' . $e->getMessage());
+            return;
+        }
+        $fileUid = $file->getUid();
+        $fileInfo = $file->getStorage()->getFileInfo($file);
+        // we sadly have to cast it to string here, because the size property is also returning a string
+        $fileSize = (string)$fileInfo['size'];
+        if ($fileSize !== $file->getProperty('size')) {
+            $this->error('File size of ' . $file->getCombinedIdentifier() . ' is not up-to-date in index! File added with current size.');
+            $this->dat['records']['sys_file:' . $fileUid]['data']['size'] = $fileSize;
+        }
+        $fileSha1 = $file->getStorage()->hashFile($file, 'sha1');
+        if ($fileSha1 !== $file->getProperty('sha1')) {
+            $this->error('File sha1 hash of ' . $file->getCombinedIdentifier() . ' is not up-to-date in index! File added on current sha1.');
+            $this->dat['records']['sys_file:' . $fileUid]['data']['sha1'] = $fileSha1;
+        }
+
+        $fileRec = array();
+        $fileRec['filesize'] = $fileSize;
+        $fileRec['filename'] = $file->getProperty('name');
+        $fileRec['filemtime'] = $file->getProperty('modification_date');
+
+        // build unique id based on the storage and the file identifier
+        $fileId = md5($file->getStorage()->getUid() . ':' . $file->getProperty('identifier_hash'));
+
+        // Setting this data in the header
+        $this->dat['header']['files_fal'][$fileId] = $fileRec;
+
+        if (!$this->saveFilesOutsideExportFile) {
+            // ... and finally add the heavy stuff:
+            $fileRec['content'] = $fileContent;
+        } else {
+            GeneralUtility::upload_copy_move($file->getForLocalProcessing(false), $this->getTemporaryFilesPathForExport() . $file->getProperty('sha1'));
+        }
+        $fileRec['content_sha1'] = $fileSha1;
+
+        $this->dat['files_fal'][$fileId] = $fileRec;
+    }
+
+    /**
+     * Adds a files content to the export memory
+     *
+     * @param array $fI File information with three keys: "filename" = filename without path, "ID_absFile" = absolute filepath to the file (including the filename), "ID" = md5 hash of "ID_absFile". "relFileName" is optional for files attached to records, but mandatory for soft referenced files (since the relFileName determines where such a file should be stored!)
+     * @param string $recordRef If the file is related to a record, this is the id on the form [table]:[id]. Information purposes only.
+     * @param string $fieldname If the file is related to a record, this is the field name it was related to. Information purposes only.
+     * @return void
+     */
+    public function export_addFile($fI, $recordRef = '', $fieldname = '')
+    {
+        if (!@is_file($fI['ID_absFile'])) {
+            $this->error($fI['ID_absFile'] . ' was not a file! Skipping.');
+            return;
+        }
+        if (filesize($fI['ID_absFile']) >= $this->maxFileSize) {
+            $this->error($fI['ID_absFile'] . ' was larger (' . GeneralUtility::formatSize(filesize($fI['ID_absFile'])) . ') than the maxFileSize (' . GeneralUtility::formatSize($this->maxFileSize) . ')! Skipping.');
+            return;
+        }
+        $fileInfo = stat($fI['ID_absFile']);
+        $fileRec = array();
+        $fileRec['filesize'] = $fileInfo['size'];
+        $fileRec['filename'] = PathUtility::basename($fI['ID_absFile']);
+        $fileRec['filemtime'] = $fileInfo['mtime'];
+        //for internal type file_reference
+        $fileRec['relFileRef'] = PathUtility::stripPathSitePrefix($fI['ID_absFile']);
+        if ($recordRef) {
+            $fileRec['record_ref'] = $recordRef . '/' . $fieldname;
+        }
+        if ($fI['relFileName']) {
+            $fileRec['relFileName'] = $fI['relFileName'];
+        }
+        // Setting this data in the header
+        $this->dat['header']['files'][$fI['ID']] = $fileRec;
+        // ... and for the recordlisting, why not let us know WHICH relations there was...
+        if ($recordRef && $recordRef !== '_SOFTREF_') {
+            $refParts = explode(':', $recordRef, 2);
+            if (!is_array($this->dat['header']['records'][$refParts[0]][$refParts[1]]['filerefs'])) {
+                $this->dat['header']['records'][$refParts[0]][$refParts[1]]['filerefs'] = array();
+            }
+            $this->dat['header']['records'][$refParts[0]][$refParts[1]]['filerefs'][] = $fI['ID'];
+        }
+        $fileMd5 = md5_file($fI['ID_absFile']);
+        if (!$this->saveFilesOutsideExportFile) {
+            // ... and finally add the heavy stuff:
+            $fileRec['content'] = GeneralUtility::getUrl($fI['ID_absFile']);
+        } else {
+            GeneralUtility::upload_copy_move($fI['ID_absFile'], $this->getTemporaryFilesPathForExport() . $fileMd5);
+        }
+        $fileRec['content_md5'] = $fileMd5;
+        $this->dat['files'][$fI['ID']] = $fileRec;
+        // For soft references, do further processing:
+        if ($recordRef === '_SOFTREF_') {
+            // RTE files?
+            if ($RTEoriginal = $this->getRTEoriginalFilename(PathUtility::basename($fI['ID_absFile']))) {
+                $RTEoriginal_absPath = PathUtility::dirname($fI['ID_absFile']) . '/' . $RTEoriginal;
+                if (@is_file($RTEoriginal_absPath)) {
+                    $RTEoriginal_ID = md5($RTEoriginal_absPath);
+                    $fileInfo = stat($RTEoriginal_absPath);
+                    $fileRec = array();
+                    $fileRec['filesize'] = $fileInfo['size'];
+                    $fileRec['filename'] = PathUtility::basename($RTEoriginal_absPath);
+                    $fileRec['filemtime'] = $fileInfo['mtime'];
+                    $fileRec['record_ref'] = '_RTE_COPY_ID:' . $fI['ID'];
+                    $this->dat['header']['files'][$fI['ID']]['RTE_ORIG_ID'] = $RTEoriginal_ID;
+                    // Setting this data in the header
+                    $this->dat['header']['files'][$RTEoriginal_ID] = $fileRec;
+                    $fileMd5 = md5_file($RTEoriginal_absPath);
+                    if (!$this->saveFilesOutsideExportFile) {
+                        // ... and finally add the heavy stuff:
+                        $fileRec['content'] = GeneralUtility::getUrl($RTEoriginal_absPath);
+                    } else {
+                        GeneralUtility::upload_copy_move($RTEoriginal_absPath, $this->getTemporaryFilesPathForExport() . $fileMd5);
+                    }
+                    $fileRec['content_md5'] = $fileMd5;
+                    $this->dat['files'][$RTEoriginal_ID] = $fileRec;
+                } else {
+                    $this->error('RTE original file "' . PathUtility::stripPathSitePrefix($RTEoriginal_absPath) . '" was not found!');
+                }
+            }
+            // Files with external media?
+            // This is only done with files grabbed by a softreference parser since it is deemed improbable that hard-referenced files should undergo this treatment.
+            $html_fI = pathinfo(PathUtility::basename($fI['ID_absFile']));
+            if ($this->includeExtFileResources && GeneralUtility::inList($this->extFileResourceExtensions, strtolower($html_fI['extension']))) {
+                $uniquePrefix = '###' . md5($GLOBALS['EXEC_TIME']) . '###';
+                if (strtolower($html_fI['extension']) === 'css') {
+                    $prefixedMedias = explode($uniquePrefix, preg_replace('/(url[[:space:]]*\\([[:space:]]*["\']?)([^"\')]*)(["\']?[[:space:]]*\\))/i', '\\1' . $uniquePrefix . '\\2' . $uniquePrefix . '\\3', $fileRec['content']));
+                } else {
+                    // html, htm:
+                    $htmlParser = GeneralUtility::makeInstance(HtmlParser::class);
+                    $prefixedMedias = explode($uniquePrefix, $htmlParser->prefixResourcePath($uniquePrefix, $fileRec['content'], array(), $uniquePrefix));
+                }
+                $htmlResourceCaptured = false;
+                foreach ($prefixedMedias as $k => $v) {
+                    if ($k % 2) {
+                        $EXTres_absPath = GeneralUtility::resolveBackPath(PathUtility::dirname($fI['ID_absFile']) . '/' . $v);
+                        $EXTres_absPath = GeneralUtility::getFileAbsFileName($EXTres_absPath);
+                        if ($EXTres_absPath && GeneralUtility::isFirstPartOfStr($EXTres_absPath, PATH_site . $this->fileadminFolderName . '/') && @is_file($EXTres_absPath)) {
+                            $htmlResourceCaptured = true;
+                            $EXTres_ID = md5($EXTres_absPath);
+                            $this->dat['header']['files'][$fI['ID']]['EXT_RES_ID'][] = $EXTres_ID;
+                            $prefixedMedias[$k] = '{EXT_RES_ID:' . $EXTres_ID . '}';
+                            // Add file to memory if it is not set already:
+                            if (!isset($this->dat['header']['files'][$EXTres_ID])) {
+                                $fileInfo = stat($EXTres_absPath);
+                                $fileRec = array();
+                                $fileRec['filesize'] = $fileInfo['size'];
+                                $fileRec['filename'] = PathUtility::basename($EXTres_absPath);
+                                $fileRec['filemtime'] = $fileInfo['mtime'];
+                                $fileRec['record_ref'] = '_EXT_PARENT_:' . $fI['ID'];
+                                // Media relative to the HTML file.
+                                $fileRec['parentRelFileName'] = $v;
+                                // Setting this data in the header
+                                $this->dat['header']['files'][$EXTres_ID] = $fileRec;
+                                // ... and finally add the heavy stuff:
+                                $fileRec['content'] = GeneralUtility::getUrl($EXTres_absPath);
+                                $fileRec['content_md5'] = md5($fileRec['content']);
+                                $this->dat['files'][$EXTres_ID] = $fileRec;
+                            }
+                        }
+                    }
+                }
+                if ($htmlResourceCaptured) {
+                    $this->dat['files'][$fI['ID']]['tokenizedContent'] = implode('', $prefixedMedias);
+                }
+            }
+        }
+    }
+
+    /**
+     * If saveFilesOutsideExportFile is enabled, this function returns the path
+     * where the files referenced in the export are copied to.
+     *
+     * @return string
+     * @throws \RuntimeException
+     * @see setSaveFilesOutsideExportFile()
+     */
+    public function getTemporaryFilesPathForExport()
+    {
+        if (!$this->saveFilesOutsideExportFile) {
+            throw new \RuntimeException('You need to set saveFilesOutsideExportFile to TRUE before you want to get the temporary files path for export.', 1401205213);
+        }
+        if ($this->temporaryFilesPathForExport === null) {
+            $temporaryFolderName = $this->getTemporaryFolderName();
+            $this->temporaryFilesPathForExport = $temporaryFolderName . '/';
+        }
+        return $this->temporaryFilesPathForExport;
+    }
+
+    /**
+     * DB relations flattend to 1-dim array.
+     * The list will be unique, no table/uid combination will appear twice.
+     *
+     * @param array $dbrels 2-dim Array of database relations organized by table key
+     * @return array 1-dim array where entries are table:uid and keys are array with table/id
+     */
+    public function flatDBrels($dbrels)
+    {
+        $list = array();
+        foreach ($dbrels as $dat) {
+            if ($dat['type'] == 'db') {
+                foreach ($dat['itemArray'] as $i) {
+                    $list[$i['table'] . ':' . $i['id']] = $i;
+                }
+            }
+            if ($dat['type'] == 'flex' && is_array($dat['flexFormRels']['db'])) {
+                foreach ($dat['flexFormRels']['db'] as $subList) {
+                    foreach ($subList as $i) {
+                        $list[$i['table'] . ':' . $i['id']] = $i;
+                    }
+                }
+            }
+        }
+        return $list;
+    }
+
+    /**
+     * Soft References flattend to 1-dim array.
+     *
+     * @param array $dbrels 2-dim Array of database relations organized by table key
+     * @return array 1-dim array where entries are arrays with properties of the soft link found and keys are a unique combination of field, spKey, structure path if applicable and token ID
+     */
+    public function flatSoftRefs($dbrels)
+    {
+        $list = array();
+        foreach ($dbrels as $field => $dat) {
+            if (is_array($dat['softrefs']['keys'])) {
+                foreach ($dat['softrefs']['keys'] as $spKey => $elements) {
+                    if (is_array($elements)) {
+                        foreach ($elements as $subKey => $el) {
+                            $lKey = $field . ':' . $spKey . ':' . $subKey;
+                            $list[$lKey] = array_merge(array('field' => $field, 'spKey' => $spKey), $el);
+                            // Add file_ID key to header - slightly "risky" way of doing this because if the calculation
+                            // changes for the same value in $this->records[...] this will not work anymore!
+                            if ($el['subst'] && $el['subst']['relFileName']) {
+                                $list[$lKey]['file_ID'] = md5(PATH_site . $el['subst']['relFileName']);
+                            }
+                        }
+                    }
+                }
+            }
+            if ($dat['type'] == 'flex' && is_array($dat['flexFormRels']['softrefs'])) {
+                foreach ($dat['flexFormRels']['softrefs'] as $structurePath => $subSoftrefs) {
+                    if (is_array($subSoftrefs['keys'])) {
+                        foreach ($subSoftrefs['keys'] as $spKey => $elements) {
+                            foreach ($elements as $subKey => $el) {
+                                $lKey = $field . ':' . $structurePath . ':' . $spKey . ':' . $subKey;
+                                $list[$lKey] = array_merge(array('field' => $field, 'spKey' => $spKey, 'structurePath' => $structurePath), $el);
+                                // Add file_ID key to header - slightly "risky" way of doing this because if the calculation
+                                // changes for the same value in $this->records[...] this will not work anymore!
+                                if ($el['subst'] && $el['subst']['relFileName']) {
+                                    $list[$lKey]['file_ID'] = md5(PATH_site . $el['subst']['relFileName']);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return $list;
+    }
+
+    /**
+     * If include fields for a specific record type are set, the data
+     * are filtered out with fields are not included in the fields.
+     *
+     * @param string $table The record type to be filtered
+     * @param array $row The data to be filtered
+     * @return array The filtered record row
+     */
+    protected function filterRecordFields($table, array $row)
+    {
+        if (isset($this->recordTypesIncludeFields[$table])) {
+            $includeFields = array_unique(array_merge(
+                $this->recordTypesIncludeFields[$table],
+                $this->defaultRecordIncludeFields
+            ));
+            $newRow = array();
+            foreach ($row as $key => $value) {
+                if (in_array($key, $includeFields)) {
+                    $newRow[$key] = $value;
+                }
+            }
+        } else {
+            $newRow = $row;
+        }
+        return $newRow;
+    }
+
+    /**************************
+     * File Output
+     *************************/
+
+    /**
+     * This compiles and returns the data content for an exported file
+     *
+     * @param string $type Type of output; "xml" gives xml, otherwise serialized array, possibly compressed.
+     * @return string The output file stream
+     */
+    public function compileMemoryToFileContent($type = '')
+    {
+        if ($type == 'xml') {
+            $out = $this->createXML();
+        } else {
+            $compress = $this->doOutputCompress();
+            $out = '';
+            // adding header:
+            $out .= $this->addFilePart(serialize($this->dat['header']), $compress);
+            // adding records:
+            $out .= $this->addFilePart(serialize($this->dat['records']), $compress);
+            // adding files:
+            $out .= $this->addFilePart(serialize($this->dat['files']), $compress);
+            // adding files_fal:
+            $out .= $this->addFilePart(serialize($this->dat['files_fal']), $compress);
+        }
+        return $out;
+    }
+
+    /**
+     * Creates XML string from input array
+     *
+     * @return string XML content
+     */
+    public function createXML()
+    {
+        // Options:
+        $options = array(
+            'alt_options' => array(
+                '/header' => array(
+                    'disableTypeAttrib' => true,
+                    'clearStackPath' => true,
+                    'parentTagMap' => array(
+                        'files' => 'file',
+                        'files_fal' => 'file',
+                        'records' => 'table',
+                        'table' => 'rec',
+                        'rec:rels' => 'relations',
+                        'relations' => 'element',
+                        'filerefs' => 'file',
+                        'pid_lookup' => 'page_contents',
+                        'header:relStaticTables' => 'static_tables',
+                        'static_tables' => 'tablename',
+                        'excludeMap' => 'item',
+                        'softrefCfg' => 'softrefExportMode',
+                        'extensionDependencies' => 'extkey',
+                        'softrefs' => 'softref_element'
+                    ),
+                    'alt_options' => array(
+                        '/pagetree' => array(
+                            'disableTypeAttrib' => true,
+                            'useIndexTagForNum' => 'node',
+                            'parentTagMap' => array(
+                                'node:subrow' => 'node'
+                            )
+                        ),
+                        '/pid_lookup/page_contents' => array(
+                            'disableTypeAttrib' => true,
+                            'parentTagMap' => array(
+                                'page_contents' => 'table'
+                            ),
+                            'grandParentTagMap' => array(
+                                'page_contents/table' => 'item'
+                            )
+                        )
+                    )
+                ),
+                '/records' => array(
+                    'disableTypeAttrib' => true,
+                    'parentTagMap' => array(
+                        'records' => 'tablerow',
+                        'tablerow:data' => 'fieldlist',
+                        'tablerow:rels' => 'related',
+                        'related' => 'field',
+                        'field:itemArray' => 'relations',
+                        'field:newValueFiles' => 'filerefs',
+                        'field:flexFormRels' => 'flexform',
+                        'relations' => 'element',
+                        'filerefs' => 'file',
+                        'flexform:db' => 'db_relations',
+                        'flexform:file' => 'file_relations',
+                        'flexform:softrefs' => 'softref_relations',
+                        'softref_relations' => 'structurePath',
+                        'db_relations' => 'path',
+                        'file_relations' => 'path',
+                        'path' => 'element',
+                        'keys' => 'softref_key',
+                        'softref_key' => 'softref_element'
+                    ),
+                    'alt_options' => array(
+                        '/records/tablerow/fieldlist' => array(
+                            'useIndexTagForAssoc' => 'field'
+                        )
+                    )
+                ),
+                '/files' => array(
+                    'disableTypeAttrib' => true,
+                    'parentTagMap' => array(
+                        'files' => 'file'
+                    )
+                ),
+                '/files_fal' => array(
+                    'disableTypeAttrib' => true,
+                    'parentTagMap' => array(
+                        'files_fal' => 'file'
+                    )
+                )
+            )
+        );
+        // Creating XML file from $outputArray:
+        $charset = $this->dat['header']['charset'] ?: 'utf-8';
+        $XML = '<?xml version="1.0" encoding="' . $charset . '" standalone="yes" ?>' . LF;
+        $XML .= GeneralUtility::array2xml($this->dat, '', 0, 'T3RecordDocument', 0, $options);
+        return $XML;
+    }
+
+    /**
+     * Returns TRUE if the output should be compressed.
+     *
+     * @return bool TRUE if compression is possible AND requested.
+     */
+    public function doOutputCompress()
+    {
+        return $this->compress && !$this->dontCompress;
+    }
+
+    /**
+     * Returns a content part for a filename being build.
+     *
+     * @param array $data Data to store in part
+     * @param bool $compress Compress file?
+     * @return string Content stream.
+     */
+    public function addFilePart($data, $compress = false)
+    {
+        if ($compress) {
+            $data = gzcompress($data);
+        }
+        return md5($data) . ':' . ($compress ? '1' : '0') . ':' . str_pad(strlen($data), 10, '0', STR_PAD_LEFT) . ':' . $data . ':';
+    }
+}
diff --git a/typo3/sysext/impexp/Classes/Import.php b/typo3/sysext/impexp/Classes/Import.php
new file mode 100644
index 0000000000000000000000000000000000000000..a1a39a3d714ce75f3f3759cf05c1ef7dadf4e196
--- /dev/null
+++ b/typo3/sysext/impexp/Classes/Import.php
@@ -0,0 +1,2071 @@
+<?php
+namespace TYPO3\CMS\Impexp;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\DataHandling\DataHandler;
+use TYPO3\CMS\Core\Exception;
+use TYPO3\CMS\Core\Resource\DuplicationBehavior;
+use TYPO3\CMS\Core\Resource\File;
+use TYPO3\CMS\Core\Resource\FileInterface;
+use TYPO3\CMS\Core\Resource\ResourceFactory;
+use TYPO3\CMS\Core\Resource\StorageRepository;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\MathUtility;
+use TYPO3\CMS\Core\Utility\PathUtility;
+use TYPO3\CMS\Core\Utility\StringUtility;
+use TYPO3\CMS\Core\Utility\VersionNumberUtility;
+
+/**
+ *
+ */
+
+/**
+ * T3D file Import library (TYPO3 Record Document)
+ */
+class Import extends ImportExport
+{
+    /**
+     * Used to register the forged UID values for imported records that we want
+     * to create with the same UIDs as in the import file. Admin-only feature.
+     *
+     * @var array
+     */
+    public $suggestedInsertUids = array();
+
+    /**
+     * Disable logging when importing
+     *
+     * @var bool
+     */
+    public $enableLogging = false;
+
+    /**
+     * Keys are [tablename]:[new NEWxxx ids (or when updating it is uids)]
+     * while values are arrays with table/uid of the original record it is based on.
+     * With the array keys the new ids can be looked up inside tcemain
+     *
+     * @var array
+     */
+    public $import_newId = array();
+
+    /**
+     * Page id map for page tree (import)
+     *
+     * @var array
+     */
+    public $import_newId_pids = array();
+
+    /**
+     * Internal data accumulation for writing records during import
+     *
+     * @var array
+     */
+    public $import_data = array();
+
+    /**
+     * Array of current registered storage objects
+     *
+     * @var array
+     */
+    protected $storageObjects = array();
+
+    /**
+     * Is set, if the import file has a TYPO3 version below 6.0
+     *
+     * @var bool
+     */
+    protected $legacyImport = false;
+
+    /**
+     * @var \TYPO3\CMS\Core\Resource\Folder
+     */
+    protected $legacyImportFolder = null;
+
+    /**
+     * Related to the default storage root
+     *
+     * @var string
+     */
+    protected $legacyImportTargetPath = '_imported/';
+
+    /**
+     * Table fields to migrate
+     *
+     * @var array
+     */
+    protected $legacyImportMigrationTables = array(
+        'tt_content' => array(
+            'image' => array(
+                'titleTexts' => 'titleText',
+                'description' => 'imagecaption',
+                'links' => 'image_link',
+                'alternativeTexts' => 'altText'
+            ),
+            'media' => array(
+                'description' => 'imagecaption',
+            )
+        ),
+        'pages' => array(
+            'media' => array()
+        ),
+        'pages_language_overlay' => array(
+            'media' => array()
+        )
+    );
+
+    /**
+     * Records to be migrated after all
+     * Multidimensional array [table][uid][field] = array([related sys_file_reference uids])
+     *
+     * @var array
+     */
+    protected $legacyImportMigrationRecords = array();
+
+    /**
+     * @var NULL|string
+     */
+    protected $filesPathForImport = null;
+
+    /**
+     * @var array
+     */
+    protected $unlinkFiles = array();
+
+    /**
+     * @var array
+     */
+    protected $alternativeFileName = array();
+
+    /**
+     * @var array
+     */
+    protected $alternativeFilePath = array();
+
+    /**
+     * @var array
+     */
+    protected $filePathMap = array();
+
+    /**************************
+     * Initialize
+     *************************/
+
+    /**
+     * Init the object
+     *
+     * @return void
+     */
+    public function init()
+    {
+        parent::init();
+        $this->mode = 'import';
+    }
+
+    /***********************
+     * Import
+     ***********************/
+
+    /**
+     * Initialize all settings for the import
+     *
+     * @return void
+     */
+    protected function initializeImport()
+    {
+        // Set this flag to indicate that an import is being/has been done.
+        $this->doesImport = 1;
+        // Initialize:
+        // These vars MUST last for the whole section not being cleared. They are used by the method setRelations() which are called at the end of the import session.
+        $this->import_mapId = array();
+        $this->import_newId = array();
+        $this->import_newId_pids = array();
+        // Temporary files stack initialized:
+        $this->unlinkFiles = array();
+        $this->alternativeFileName = array();
+        $this->alternativeFilePath = array();
+
+        $this->initializeStorageObjects();
+    }
+
+    /**
+     * Initialize the all present storage objects
+     *
+     * @return void
+     */
+    protected function initializeStorageObjects()
+    {
+        /** @var $storageRepository StorageRepository */
+        $storageRepository = GeneralUtility::makeInstance(StorageRepository::class);
+        $this->storageObjects = $storageRepository->findAll();
+    }
+
+    /**
+     * Imports the internal data array to $pid.
+     *
+     * @param int $pid Page ID in which to import the content
+     * @return void
+     */
+    public function importData($pid)
+    {
+        $this->initializeImport();
+
+        // Write sys_file_storages first
+        $this->writeSysFileStorageRecords();
+        // Write sys_file records and write the binary file data
+        $this->writeSysFileRecords();
+        // Write records, first pages, then the rest
+        // Fields with "hard" relations to database, files and flexform fields are kept empty during this run
+        $this->writeRecords_pages($pid);
+        $this->writeRecords_records($pid);
+        // Finally all the file and DB record references must be fixed. This is done after all records have supposedly been written to database:
+        // $this->import_mapId will indicate two things: 1) that a record WAS written to db and 2) that it has got a new id-number.
+        $this->setRelations();
+        // And when all DB relations are in place, we can fix file and DB relations in flexform fields (since data structures often depends on relations to a DS record):
+        $this->setFlexFormRelations();
+        // Unlink temporary files:
+        $this->unlinkTempFiles();
+        // Finally, traverse all records and process softreferences with substitution attributes.
+        $this->processSoftReferences();
+        // After all migrate records using sys_file_reference now
+        if ($this->legacyImport) {
+            $this->migrateLegacyImportRecords();
+        }
+    }
+
+    /**
+     * Imports the sys_file_storage records from internal data array.
+     *
+     * @return void
+     */
+    protected function writeSysFileStorageRecords()
+    {
+        if (!isset($this->dat['header']['records']['sys_file_storage'])) {
+            return;
+        }
+        $sysFileStorageUidsToBeResetToDefaultStorage = array();
+        foreach ($this->dat['header']['records']['sys_file_storage'] as $sysFileStorageUid => $_) {
+            $storageRecord = $this->dat['records']['sys_file_storage:' . $sysFileStorageUid]['data'];
+            // continue with Local, writable and online storage only
+            if ($storageRecord['driver'] === 'Local' && $storageRecord['is_writable'] && $storageRecord['is_online']) {
+                $useThisStorageUidInsteadOfTheOneInImport = 0;
+                /** @var $localStorage \TYPO3\CMS\Core\Resource\ResourceStorage */
+                foreach ($this->storageObjects as $localStorage) {
+                    // check the available storage for Local, writable and online ones
+                    if ($localStorage->getDriverType() === 'Local' && $localStorage->isWritable() && $localStorage->isOnline()) {
+                        // check if there is already an identical storage present (same pathType and basePath)
+                        $storageRecordConfiguration = ResourceFactory::getInstance()->convertFlexFormDataToConfigurationArray($storageRecord['configuration']);
+                        $localStorageRecordConfiguration = $localStorage->getConfiguration();
+                        if (
+                            $storageRecordConfiguration['pathType'] === $localStorageRecordConfiguration['pathType']
+                            && $storageRecordConfiguration['basePath'] === $localStorageRecordConfiguration['basePath']
+                        ) {
+                            // same storage is already present
+                            $useThisStorageUidInsteadOfTheOneInImport = $localStorage->getUid();
+                            break;
+                        }
+                    }
+                }
+                if ($useThisStorageUidInsteadOfTheOneInImport > 0) {
+                    // same storage is already present; map the to be imported one to the present one
+                    $this->import_mapId['sys_file_storage'][$sysFileStorageUid] = $useThisStorageUidInsteadOfTheOneInImport;
+                } else {
+                    // Local, writable and online storage. Is allowed to be used to later write files in.
+                    $this->addSingle('sys_file_storage', $sysFileStorageUid, 0);
+                }
+            } else {
+                // Storage with non Local drivers could be imported but must not be used to saves files in, because you
+                // could not be sure, that this is supported. The default storage will be used in this case.
+                // It could happen that non writable and non online storage will be created as dupes because you could not
+                // check the detailed configuration options at this point
+                $this->addSingle('sys_file_storage', $sysFileStorageUid, 0);
+                $sysFileStorageUidsToBeResetToDefaultStorage[] = $sysFileStorageUid;
+            }
+        }
+
+        // Importing the added ones
+        $tce = $this->getNewTCE();
+        // Because all records are being submitted in their correct order with positive pid numbers - and so we should reverse submission order internally.
+        $tce->reverseOrder = 1;
+        $tce->isImporting = true;
+        $tce->start($this->import_data, array());
+        $tce->process_datamap();
+        $this->addToMapId($tce->substNEWwithIDs);
+
+        $defaultStorageUid = null;
+        // get default storage
+        $defaultStorage = ResourceFactory::getInstance()->getDefaultStorage();
+        if ($defaultStorage !== null) {
+            $defaultStorageUid = $defaultStorage->getUid();
+        }
+        foreach ($sysFileStorageUidsToBeResetToDefaultStorage as $sysFileStorageUidToBeResetToDefaultStorage) {
+            $this->import_mapId['sys_file_storage'][$sysFileStorageUidToBeResetToDefaultStorage] = $defaultStorageUid;
+        }
+
+        // unset the sys_file_storage records to prevent an import in writeRecords_records
+        unset($this->dat['header']['records']['sys_file_storage']);
+    }
+
+    /**
+     * Imports the sys_file records and the binary files data from internal data array.
+     *
+     * @return void
+     */
+    protected function writeSysFileRecords()
+    {
+        if (!isset($this->dat['header']['records']['sys_file'])) {
+            return;
+        }
+        $this->addGeneralErrorsByTable('sys_file');
+
+        // fetch fresh storage records from database
+        $storageRecords = $this->fetchStorageRecords();
+
+        $defaultStorage = ResourceFactory::getInstance()->getDefaultStorage();
+
+        $sanitizedFolderMappings = array();
+
+        foreach ($this->dat['header']['records']['sys_file'] as $sysFileUid => $_) {
+            $fileRecord = $this->dat['records']['sys_file:' . $sysFileUid]['data'];
+
+            $temporaryFile = null;
+            // check if there is the right file already in the local folder
+            if ($this->filesPathForImport !== null) {
+                if (is_file($this->filesPathForImport . '/' . $fileRecord['sha1']) && sha1_file($this->filesPathForImport . '/' . $fileRecord['sha1']) === $fileRecord['sha1']) {
+                    $temporaryFile = $this->filesPathForImport . '/' . $fileRecord['sha1'];
+                }
+            }
+
+            // save file to disk
+            if ($temporaryFile === null) {
+                $fileId = md5($fileRecord['storage'] . ':' . $fileRecord['identifier_hash']);
+                $temporaryFile = $this->writeTemporaryFileFromData($fileId);
+                if ($temporaryFile === null) {
+                    // error on writing the file. Error message was already added
+                    continue;
+                }
+            }
+
+            $originalStorageUid = $fileRecord['storage'];
+            $useStorageFromStorageRecords = false;
+
+            // replace storage id, if an alternative one was registered
+            if (isset($this->import_mapId['sys_file_storage'][$fileRecord['storage']])) {
+                $fileRecord['storage'] = $this->import_mapId['sys_file_storage'][$fileRecord['storage']];
+                $useStorageFromStorageRecords = true;
+            }
+
+            if (empty($fileRecord['storage']) && !$this->isFallbackStorage($fileRecord['storage'])) {
+                // no storage for the file is defined, mostly because of a missing default storage.
+                $this->error('Error: No storage for the file "' . $fileRecord['identifier'] . '" with storage uid "' . $originalStorageUid . '"');
+                continue;
+            }
+
+            // using a storage from the local storage is only allowed, if the uid is present in the
+            // mapping. Only in this case we could be sure, that it's a local, online and writable storage.
+            if ($useStorageFromStorageRecords && isset($storageRecords[$fileRecord['storage']])) {
+                /** @var $storage \TYPO3\CMS\Core\Resource\ResourceStorage */
+                $storage = ResourceFactory::getInstance()->getStorageObject($fileRecord['storage'], $storageRecords[$fileRecord['storage']]);
+            } elseif ($this->isFallbackStorage($fileRecord['storage'])) {
+                $storage = ResourceFactory::getInstance()->getStorageObject(0);
+            } elseif ($defaultStorage !== null) {
+                $storage = $defaultStorage;
+            } else {
+                $this->error('Error: No storage available for the file "' . $fileRecord['identifier'] . '" with storage uid "' . $fileRecord['storage'] . '"');
+                continue;
+            }
+
+            $newFile = null;
+
+            // check, if there is an identical file
+            try {
+                if ($storage->hasFile($fileRecord['identifier'])) {
+                    $file = $storage->getFile($fileRecord['identifier']);
+                    if ($file->getSha1() === $fileRecord['sha1']) {
+                        $newFile = $file;
+                    }
+                }
+            } catch (Exception $e) {
+            }
+
+            if ($newFile === null) {
+                $folderName = PathUtility::dirname(ltrim($fileRecord['identifier'], '/'));
+                if (in_array($folderName, $sanitizedFolderMappings)) {
+                    $folderName = $sanitizedFolderMappings[$folderName];
+                }
+                if (!$storage->hasFolder($folderName)) {
+                    try {
+                        $importFolder = $storage->createFolder($folderName);
+                        if ($importFolder->getIdentifier() !== $folderName && !in_array($folderName, $sanitizedFolderMappings)) {
+                            $sanitizedFolderMappings[$folderName] = $importFolder->getIdentifier();
+                        }
+                    } catch (Exception $e) {
+                        $this->error('Error: Folder could not be created for file "' . $fileRecord['identifier'] . '" with storage uid "' . $fileRecord['storage'] . '"');
+                        continue;
+                    }
+                } else {
+                    $importFolder = $storage->getFolder($folderName);
+                }
+
+                try {
+                    /** @var $newFile File */
+                    $newFile = $storage->addFile($temporaryFile, $importFolder, $fileRecord['name']);
+                } catch (Exception $e) {
+                    $this->error('Error: File could not be added to the storage: "' . $fileRecord['identifier'] . '" with storage uid "' . $fileRecord['storage'] . '"');
+                    continue;
+                }
+
+                if ($newFile->getSha1() !== $fileRecord['sha1']) {
+                    $this->error('Error: The hash of the written file is not identical to the import data! File could be corrupted! File: "' . $fileRecord['identifier'] . '" with storage uid "' . $fileRecord['storage'] . '"');
+                }
+            }
+
+            // save the new uid in the import id map
+            $this->import_mapId['sys_file'][$fileRecord['uid']] = $newFile->getUid();
+            $this->fixUidLocalInSysFileReferenceRecords($fileRecord['uid'], $newFile->getUid());
+        }
+
+        // unset the sys_file records to prevent an import in writeRecords_records
+        unset($this->dat['header']['records']['sys_file']);
+    }
+
+    /**
+     * Checks if the $storageId is the id of the fallback storage
+     *
+     * @param int|string $storageId
+     * @return bool
+     */
+    protected function isFallbackStorage($storageId)
+    {
+        return $storageId === 0 || $storageId === '0';
+    }
+
+    /**
+     * Normally the importer works like the following:
+     * Step 1: import the records with cleared field values of relation fields (see addSingle())
+     * Step 2: update the records with the right relation ids (see setRelations())
+     *
+     * In step 2 the saving fields of type "relation to sys_file_reference" checks the related sys_file_reference
+     * record (created in step 1) with the FileExtensionFilter for matching file extensions of the related file.
+     * To make this work correct, the uid_local of sys_file_reference records has to be not empty AND has to
+     * relate to the correct (imported) sys_file record uid!!!
+     *
+     * This is fixed here.
+     *
+     * @param int $oldFileUid
+     * @param int $newFileUid
+     * @return void
+    */
+    protected function fixUidLocalInSysFileReferenceRecords($oldFileUid, $newFileUid)
+    {
+        if (!isset($this->dat['header']['records']['sys_file_reference'])) {
+            return;
+        }
+
+        foreach ($this->dat['header']['records']['sys_file_reference'] as $sysFileReferenceUid => $_) {
+            $fileReferenceRecord = $this->dat['records']['sys_file_reference:' . $sysFileReferenceUid]['data'];
+            if ($fileReferenceRecord['uid_local'] == $oldFileUid) {
+                $fileReferenceRecord['uid_local'] = $newFileUid;
+                $this->dat['records']['sys_file_reference:' . $sysFileReferenceUid]['data'] = $fileReferenceRecord;
+            }
+        }
+    }
+
+    /**
+     * Initializes the folder for legacy imports as subfolder of backend users default upload folder
+     *
+     * @return void
+     */
+    protected function initializeLegacyImportFolder()
+    {
+        /** @var \TYPO3\CMS\Core\Resource\Folder $folder */
+        $folder = $this->getBackendUser()->getDefaultUploadFolder();
+        if ($folder === false) {
+            $this->error('Error: the backend users default upload folder is missing! No files will be imported!');
+        }
+        if (!$folder->hasFolder($this->legacyImportTargetPath)) {
+            try {
+                $this->legacyImportFolder = $folder->createFolder($this->legacyImportTargetPath);
+            } catch (Exception $e) {
+                $this->error('Error: the import folder in the default upload folder could not be created! No files will be imported!');
+            }
+        } else {
+            $this->legacyImportFolder = $folder->getSubFolder($this->legacyImportTargetPath);
+        }
+    }
+
+    /**
+     * Fetched fresh storage records from database because the new imported
+     * ones are not in cached data of the StorageRepository
+     *
+     * @return bool|array
+     */
+    protected function fetchStorageRecords()
+    {
+        $whereClause = BackendUtility::BEenableFields('sys_file_storage');
+        $whereClause .= BackendUtility::deleteClause('sys_file_storage');
+
+        $rows = $this->getDatabaseConnection()->exec_SELECTgetRows(
+            '*',
+            'sys_file_storage',
+            '1=1' . $whereClause,
+            '',
+            '',
+            '',
+            'uid'
+        );
+
+        return $rows;
+    }
+
+    /**
+     * Writes the file from import array to temp dir and returns the filename of it.
+     *
+     * @param string $fileId
+     * @param string $dataKey
+     * @return string Absolute filename of the temporary filename of the file
+     */
+    protected function writeTemporaryFileFromData($fileId, $dataKey = 'files_fal')
+    {
+        $temporaryFilePath = null;
+        if (is_array($this->dat[$dataKey][$fileId])) {
+            $temporaryFilePathInternal = GeneralUtility::tempnam('import_temp_');
+            GeneralUtility::writeFile($temporaryFilePathInternal, $this->dat[$dataKey][$fileId]['content']);
+            clearstatcache();
+            if (@is_file($temporaryFilePathInternal)) {
+                $this->unlinkFiles[] = $temporaryFilePathInternal;
+                if (filesize($temporaryFilePathInternal) == $this->dat[$dataKey][$fileId]['filesize']) {
+                    $temporaryFilePath = $temporaryFilePathInternal;
+                } else {
+                    $this->error('Error: temporary file ' . $temporaryFilePathInternal . ' had a size (' . filesize($temporaryFilePathInternal) . ') different from the original (' . $this->dat[$dataKey][$fileId]['filesize'] . ')');
+                }
+            } else {
+                $this->error('Error: temporary file ' . $temporaryFilePathInternal . ' was not written as it should have been!');
+            }
+        } else {
+            $this->error('Error: No file found for ID ' . $fileId);
+        }
+        return $temporaryFilePath;
+    }
+
+    /**
+     * Writing pagetree/pages to database:
+     *
+     * @param int $pid PID in which to import. If the operation is an update operation, the root of the page tree inside will be moved to this PID unless it is the same as the root page from the import
+     * @return void
+     * @see writeRecords_records()
+     */
+    public function writeRecords_pages($pid)
+    {
+        // First, write page structure if any:
+        if (is_array($this->dat['header']['records']['pages'])) {
+            $this->addGeneralErrorsByTable('pages');
+            // $pageRecords is a copy of the pages array in the imported file. Records here are unset one by one when the addSingle function is called.
+            $pageRecords = $this->dat['header']['records']['pages'];
+            $this->import_data = array();
+            // First add page tree if any
+            if (is_array($this->dat['header']['pagetree'])) {
+                $pagesFromTree = $this->flatInversePageTree($this->dat['header']['pagetree']);
+                foreach ($pagesFromTree as $uid) {
+                    $thisRec = $this->dat['header']['records']['pages'][$uid];
+                    // PID: Set the main $pid, unless a NEW-id is found
+                    $setPid = isset($this->import_newId_pids[$thisRec['pid']]) ? $this->import_newId_pids[$thisRec['pid']] : $pid;
+                    $this->addSingle('pages', $uid, $setPid);
+                    unset($pageRecords[$uid]);
+                }
+            }
+            // Then add all remaining pages not in tree on root level:
+            if (!empty($pageRecords)) {
+                $remainingPageUids = array_keys($pageRecords);
+                foreach ($remainingPageUids as $pUid) {
+                    $this->addSingle('pages', $pUid, $pid);
+                }
+            }
+            // Now write to database:
+            $tce = $this->getNewTCE();
+            $tce->isImporting = true;
+            $this->callHook('before_writeRecordsPages', array(
+                'tce' => &$tce,
+                'data' => &$this->import_data
+            ));
+            $tce->suggestedInsertUids = $this->suggestedInsertUids;
+            $tce->start($this->import_data, array());
+            $tce->process_datamap();
+            $this->callHook('after_writeRecordsPages', array(
+                'tce' => &$tce
+            ));
+            // post-processing: Registering new ids (end all tcemain sessions with this)
+            $this->addToMapId($tce->substNEWwithIDs);
+            // In case of an update, order pages from the page tree correctly:
+            if ($this->update && is_array($this->dat['header']['pagetree'])) {
+                $this->writeRecords_pages_order();
+            }
+        }
+    }
+
+    /**
+     * Organize all updated pages in page tree so they are related like in the import file
+     * Only used for updates and when $this->dat['header']['pagetree'] is an array.
+     *
+     * @return void
+     * @access private
+     * @see writeRecords_pages(), writeRecords_records_order()
+     */
+    public function writeRecords_pages_order()
+    {
+        $cmd_data = array();
+        // Get uid-pid relations and traverse them in order to map to possible new IDs
+        $pidsFromTree = $this->flatInversePageTree_pid($this->dat['header']['pagetree']);
+        foreach ($pidsFromTree as $origPid => $newPid) {
+            if ($newPid >= 0 && $this->dontIgnorePid('pages', $origPid)) {
+                // If the page had a new id (because it was created) use that instead!
+                if (substr($this->import_newId_pids[$origPid], 0, 3) === 'NEW') {
+                    if ($this->import_mapId['pages'][$origPid]) {
+                        $mappedPid = $this->import_mapId['pages'][$origPid];
+                        $cmd_data['pages'][$mappedPid]['move'] = $newPid;
+                    }
+                } else {
+                    $cmd_data['pages'][$origPid]['move'] = $newPid;
+                }
+            }
+        }
+        // Execute the move commands if any:
+        if (!empty($cmd_data)) {
+            $tce = $this->getNewTCE();
+            $this->callHook('before_writeRecordsPagesOrder', array(
+                'tce' => &$tce,
+                'data' => &$cmd_data
+            ));
+            $tce->start(array(), $cmd_data);
+            $tce->process_cmdmap();
+            $this->callHook('after_writeRecordsPagesOrder', array(
+                'tce' => &$tce
+            ));
+        }
+    }
+
+    /**
+     * Recursively flattening the idH array, setting PIDs as values
+     *
+     * @param array $idH Page uid hierarchy
+     * @param array $a Accumulation array of pages (internal, don't set from outside)
+     * @param int $pid PID value (internal)
+     * @return array Array with uid-pid pairs for all pages in the page tree.
+     * @see ImportExport::flatInversePageTree()
+     */
+    public function flatInversePageTree_pid($idH, $a = array(), $pid = -1)
+    {
+        if (is_array($idH)) {
+            $idH = array_reverse($idH);
+            foreach ($idH as $v) {
+                $a[$v['uid']] = $pid;
+                if (is_array($v['subrow'])) {
+                    $a = $this->flatInversePageTree_pid($v['subrow'], $a, $v['uid']);
+                }
+            }
+        }
+        return $a;
+    }
+
+    /**
+     * Write all database records except pages (writtein in writeRecords_pages())
+     *
+     * @param int $pid Page id in which to import
+     * @return void
+     * @see writeRecords_pages()
+     */
+    public function writeRecords_records($pid)
+    {
+        // Write the rest of the records
+        $this->import_data = array();
+        if (is_array($this->dat['header']['records'])) {
+            foreach ($this->dat['header']['records'] as $table => $recs) {
+                $this->addGeneralErrorsByTable($table);
+                if ($table != 'pages') {
+                    foreach ($recs as $uid => $thisRec) {
+                        // PID: Set the main $pid, unless a NEW-id is found
+                        $setPid = isset($this->import_mapId['pages'][$thisRec['pid']])
+                            ? (int)$this->import_mapId['pages'][$thisRec['pid']]
+                            : (int)$pid;
+                        if (is_array($GLOBALS['TCA'][$table]) && isset($GLOBALS['TCA'][$table]['ctrl']['rootLevel'])) {
+                            $rootLevelSetting = (int)$GLOBALS['TCA'][$table]['ctrl']['rootLevel'];
+                            if ($rootLevelSetting === 1) {
+                                $setPid = 0;
+                            } elseif ($rootLevelSetting === 0 && $setPid === 0) {
+                                $this->error('Error: Record type ' . $table . ' is not allowed on pid 0');
+                                continue;
+                            }
+                        }
+                        // Add record:
+                        $this->addSingle($table, $uid, $setPid);
+                    }
+                }
+            }
+        } else {
+            $this->error('Error: No records defined in internal data array.');
+        }
+        // Now write to database:
+        $tce = $this->getNewTCE();
+        $this->callHook('before_writeRecordsRecords', array(
+            'tce' => &$tce,
+            'data' => &$this->import_data
+        ));
+        $tce->suggestedInsertUids = $this->suggestedInsertUids;
+        // Because all records are being submitted in their correct order with positive pid numbers - and so we should reverse submission order internally.
+        $tce->reverseOrder = 1;
+        $tce->isImporting = true;
+        $tce->start($this->import_data, array());
+        $tce->process_datamap();
+        $this->callHook('after_writeRecordsRecords', array(
+            'tce' => &$tce
+        ));
+        // post-processing: Removing files and registering new ids (end all tcemain sessions with this)
+        $this->addToMapId($tce->substNEWwithIDs);
+        // In case of an update, order pages from the page tree correctly:
+        if ($this->update) {
+            $this->writeRecords_records_order($pid);
+        }
+    }
+
+    /**
+     * Organize all updated record to their new positions.
+     * Only used for updates
+     *
+     * @param int $mainPid Main PID into which we import.
+     * @return void
+     * @access private
+     * @see writeRecords_records(), writeRecords_pages_order()
+     */
+    public function writeRecords_records_order($mainPid)
+    {
+        $cmd_data = array();
+        if (is_array($this->dat['header']['pagetree'])) {
+            $pagesFromTree = $this->flatInversePageTree($this->dat['header']['pagetree']);
+        } else {
+            $pagesFromTree = array();
+        }
+        if (is_array($this->dat['header']['pid_lookup'])) {
+            foreach ($this->dat['header']['pid_lookup'] as $pid => $recList) {
+                $newPid = isset($this->import_mapId['pages'][$pid]) ? $this->import_mapId['pages'][$pid] : $mainPid;
+                if (MathUtility::canBeInterpretedAsInteger($newPid)) {
+                    foreach ($recList as $tableName => $uidList) {
+                        // If $mainPid===$newPid then we are on root level and we can consider to move pages as well!
+                        // (they will not be in the page tree!)
+                        if (($tableName != 'pages' || !$pagesFromTree[$pid]) && is_array($uidList)) {
+                            $uidList = array_reverse(array_keys($uidList));
+                            foreach ($uidList as $uid) {
+                                if ($this->dontIgnorePid($tableName, $uid)) {
+                                    $cmd_data[$tableName][$uid]['move'] = $newPid;
+                                } else {
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        // Execute the move commands if any:
+        if (!empty($cmd_data)) {
+            $tce = $this->getNewTCE();
+            $this->callHook('before_writeRecordsRecordsOrder', array(
+                'tce' => &$tce,
+                'data' => &$cmd_data
+            ));
+            $tce->start(array(), $cmd_data);
+            $tce->process_cmdmap();
+            $this->callHook('after_writeRecordsRecordsOrder', array(
+                'tce' => &$tce
+            ));
+        }
+    }
+
+    /**
+     * Adds a single record to the $importData array. Also copies files to tempfolder.
+     * However all File/DB-references and flexform field contents are set to blank for now!
+     * That is done with setRelations() later
+     *
+     * @param string $table Table name (from import memory)
+     * @param int $uid Record UID (from import memory)
+     * @param int $pid Page id
+     * @return void
+     * @see writeRecords()
+     */
+    public function addSingle($table, $uid, $pid)
+    {
+        if ($this->import_mode[$table . ':' . $uid] === 'exclude') {
+            return;
+        }
+        $record = $this->dat['records'][$table . ':' . $uid]['data'];
+        if (is_array($record)) {
+            if ($this->update && $this->doesRecordExist($table, $uid) && $this->import_mode[$table . ':' . $uid] !== 'as_new') {
+                $ID = $uid;
+            } elseif ($table === 'sys_file_metadata' && $record['sys_language_uid'] == '0' && $this->import_mapId['sys_file'][$record['file']]) {
+                // on adding sys_file records the belonging sys_file_metadata record was also created
+                // if there is one the record need to be overwritten instead of creating a new one.
+                $recordInDatabase = $this->getDatabaseConnection()->exec_SELECTgetSingleRow(
+                    'uid',
+                    'sys_file_metadata',
+                    'file = ' . $this->import_mapId['sys_file'][$record['file']] . ' AND sys_language_uid = 0 AND pid = 0'
+                );
+                // if no record could be found, $this->import_mapId['sys_file'][$record['file']] is pointing
+                // to a file, that was already there, thus a new metadata record should be created
+                if (is_array($recordInDatabase)) {
+                    $this->import_mapId['sys_file_metadata'][$record['uid']] = $recordInDatabase['uid'];
+                    $ID = $recordInDatabase['uid'];
+                } else {
+                    $ID = StringUtility::getUniqueId('NEW');
+                }
+            } else {
+                $ID = StringUtility::getUniqueId('NEW');
+            }
+            $this->import_newId[$table . ':' . $ID] = array('table' => $table, 'uid' => $uid);
+            if ($table == 'pages') {
+                $this->import_newId_pids[$uid] = $ID;
+            }
+            // Set main record data:
+            $this->import_data[$table][$ID] = $record;
+            $this->import_data[$table][$ID]['tx_impexp_origuid'] = $this->import_data[$table][$ID]['uid'];
+            // Reset permission data:
+            if ($table === 'pages') {
+                // Have to reset the user/group IDs so pages are owned by importing user. Otherwise strange things may happen for non-admins!
+                unset($this->import_data[$table][$ID]['perms_userid']);
+                unset($this->import_data[$table][$ID]['perms_groupid']);
+            }
+            // PID and UID:
+            unset($this->import_data[$table][$ID]['uid']);
+            // Updates:
+            if (MathUtility::canBeInterpretedAsInteger($ID)) {
+                unset($this->import_data[$table][$ID]['pid']);
+            } else {
+                // Inserts:
+                $this->import_data[$table][$ID]['pid'] = $pid;
+                if (($this->import_mode[$table . ':' . $uid] === 'force_uid' && $this->update || $this->force_all_UIDS) && $this->getBackendUser()->isAdmin()) {
+                    $this->import_data[$table][$ID]['uid'] = $uid;
+                    $this->suggestedInsertUids[$table . ':' . $uid] = 'DELETE';
+                }
+            }
+            // Setting db/file blank:
+            foreach ($this->dat['records'][$table . ':' . $uid]['rels'] as $field => $config) {
+                switch ((string)$config['type']) {
+                    case 'db':
+
+                    case 'file':
+                        // Fixed later in ->setRelations() [because we need to know ALL newly created IDs before we can map relations!]
+                        // In the meantime we set NO values for relations.
+                        //
+                        // BUT for field uid_local of table sys_file_reference the relation MUST not be cleared here,
+                        // because the value is already the uid of the right imported sys_file record.
+                        // @see fixUidLocalInSysFileReferenceRecords()
+                        // If it's empty or a uid to another record the FileExtensionFilter will throw an exception or
+                        // delete the reference record if the file extension of the related record doesn't match.
+                        if ($table !== 'sys_file_reference' && $field !== 'uid_local') {
+                            $this->import_data[$table][$ID][$field] = '';
+                        }
+                        break;
+                    case 'flex':
+                        // Fixed later in setFlexFormRelations()
+                        // In the meantime we set NO value for flexforms - this is mainly because file references
+                        // inside will not be processed properly; In fact references will point to no file
+                        // or existing files (in which case there will be double-references which is a big problem of course!)
+                        $this->import_data[$table][$ID][$field] = '';
+                        break;
+                }
+            }
+        } elseif ($table . ':' . $uid != 'pages:0') {
+            // On root level we don't want this error message.
+            $this->error('Error: no record was found in data array!');
+        }
+    }
+
+    /**
+     * Registers the substNEWids in memory.
+     *
+     * @param array $substNEWwithIDs From tcemain to be merged into internal mapping variable in this object
+     * @return void
+     * @see writeRecords()
+     */
+    public function addToMapId($substNEWwithIDs)
+    {
+        foreach ($this->import_data as $table => $recs) {
+            foreach ($recs as $id => $value) {
+                $old_uid = $this->import_newId[$table . ':' . $id]['uid'];
+                if (isset($substNEWwithIDs[$id])) {
+                    $this->import_mapId[$table][$old_uid] = $substNEWwithIDs[$id];
+                } elseif ($this->update) {
+                    // Map same ID to same ID....
+                    $this->import_mapId[$table][$old_uid] = $id;
+                } else {
+                    // if $this->import_mapId contains already the right mapping, skip the error msg.
+                    // See special handling of sys_file_metadata in addSingle() => nothing to do
+                    if (!($table === 'sys_file_metadata' && isset($this->import_mapId[$table][$old_uid]) && $this->import_mapId[$table][$old_uid] == $id)) {
+                        $this->error('Possible error: ' . $table . ':' . $old_uid . ' had no new id assigned to it. This indicates that the record was not added to database during import. Please check changelog!');
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns a new $TCE object
+     *
+     * @return DataHandler $TCE object
+     */
+    public function getNewTCE()
+    {
+        $tce = GeneralUtility::makeInstance(DataHandler::class);
+        $tce->dontProcessTransformations = 1;
+        $tce->enableLogging = $this->enableLogging;
+        $tce->alternativeFileName = $this->alternativeFileName;
+        $tce->alternativeFilePath = $this->alternativeFilePath;
+        return $tce;
+    }
+
+    /**
+     * Cleaning up all the temporary files stored in typo3temp/ folder
+     *
+     * @return void
+     */
+    public function unlinkTempFiles()
+    {
+        foreach ($this->unlinkFiles as $fileName) {
+            if (GeneralUtility::isFirstPartOfStr($fileName, PATH_site . 'typo3temp/')) {
+                GeneralUtility::unlink_tempfile($fileName);
+                clearstatcache();
+                if (is_file($fileName)) {
+                    $this->error('Error: ' . $fileName . ' was NOT unlinked as it should have been!');
+                }
+            } else {
+                $this->error('Error: ' . $fileName . ' was not in temp-path. Not removed!');
+            }
+        }
+        $this->unlinkFiles = array();
+    }
+
+    /***************************
+     * Import / Relations setting
+     ***************************/
+
+    /**
+     * At the end of the import process all file and DB relations should be set properly (that is relations
+     * to imported records are all re-created so imported records are correctly related again)
+     * Relations in flexform fields are processed in setFlexFormRelations() after this function
+     *
+     * @return void
+     * @see setFlexFormRelations()
+     */
+    public function setRelations()
+    {
+        $updateData = array();
+        // import_newId contains a register of all records that was in the import memorys "records" key
+        foreach ($this->import_newId as $nId => $dat) {
+            $table = $dat['table'];
+            $uid = $dat['uid'];
+            // original UID - NOT the new one!
+            // If the record has been written and received a new id, then proceed:
+            if (is_array($this->import_mapId[$table]) && isset($this->import_mapId[$table][$uid])) {
+                $thisNewUid = BackendUtility::wsMapId($table, $this->import_mapId[$table][$uid]);
+                if (is_array($this->dat['records'][$table . ':' . $uid]['rels'])) {
+                    $thisNewPageUid = 0;
+                    if ($this->legacyImport) {
+                        if ($table != 'pages') {
+                            $oldPid = $this->dat['records'][$table . ':' . $uid]['data']['pid'];
+                            $thisNewPageUid = BackendUtility::wsMapId($table, $this->import_mapId['pages'][$oldPid]);
+                        } else {
+                            $thisNewPageUid = $thisNewUid;
+                        }
+                    }
+                    // Traverse relation fields of each record
+                    foreach ($this->dat['records'][$table . ':' . $uid]['rels'] as $field => $config) {
+                        // uid_local of sys_file_reference needs no update because the correct reference uid was already written
+                        // @see ImportExport::fixUidLocalInSysFileReferenceRecords()
+                        if ($table === 'sys_file_reference' && $field === 'uid_local') {
+                            continue;
+                        }
+                        switch ((string)$config['type']) {
+                            case 'db':
+                                if (is_array($config['itemArray']) && !empty($config['itemArray'])) {
+                                    $itemConfig = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
+                                    $valArray = $this->setRelations_db($config['itemArray'], $itemConfig);
+                                    $updateData[$table][$thisNewUid][$field] = implode(',', $valArray);
+                                }
+                                break;
+                            case 'file':
+                                if (is_array($config['newValueFiles']) && !empty($config['newValueFiles'])) {
+                                    $valArr = array();
+                                    foreach ($config['newValueFiles'] as $fI) {
+                                        $valArr[] = $this->import_addFileNameToBeCopied($fI);
+                                    }
+                                    if ($this->legacyImport && $this->legacyImportFolder === null && isset($this->legacyImportMigrationTables[$table][$field])) {
+                                        // Do nothing - the legacy import folder is missing
+                                    } elseif ($this->legacyImport && $this->legacyImportFolder !== null && isset($this->legacyImportMigrationTables[$table][$field])) {
+                                        $refIds = array();
+                                        foreach ($valArr as $tempFile) {
+                                            $fileName = $this->alternativeFileName[$tempFile];
+                                            $fileObject = null;
+
+                                            try {
+                                                // check, if there is alreay the same file in the folder
+                                                if ($this->legacyImportFolder->hasFile($fileName)) {
+                                                    $fileStorage = $this->legacyImportFolder->getStorage();
+                                                    $file = $fileStorage->getFile($this->legacyImportFolder->getIdentifier() . $fileName);
+                                                    if ($file->getSha1() === sha1_file($tempFile)) {
+                                                        $fileObject = $file;
+                                                    }
+                                                }
+                                            } catch (Exception $e) {
+                                            }
+
+                                            if ($fileObject === null) {
+                                                try {
+                                                    $fileObject = $this->legacyImportFolder->addFile($tempFile, $fileName, DuplicationBehavior::RENAME);
+                                                } catch (Exception $e) {
+                                                    $this->error('Error: no file could be added to the storage for file name' . $this->alternativeFileName[$tempFile]);
+                                                }
+                                            }
+                                            if ($fileObject !== null) {
+                                                $refId = StringUtility::getUniqueId('NEW');
+                                                $refIds[] = $refId;
+                                                $updateData['sys_file_reference'][$refId] = array(
+                                                    'uid_local' => $fileObject->getUid(),
+                                                    'uid_foreign' => $thisNewUid, // uid of your content record
+                                                    'tablenames' => $table,
+                                                    'fieldname' => $field,
+                                                    'pid' => $thisNewPageUid, // parent id of the parent page
+                                                    'table_local' => 'sys_file',
+                                                );
+                                            }
+                                        }
+                                        $updateData[$table][$thisNewUid][$field] = implode(',', $refIds);
+                                        if (!empty($this->legacyImportMigrationTables[$table][$field])) {
+                                            $this->legacyImportMigrationRecords[$table][$thisNewUid][$field] = $refIds;
+                                        }
+                                    } else {
+                                        $updateData[$table][$thisNewUid][$field] = implode(',', $valArr);
+                                    }
+                                }
+                                break;
+                        }
+                    }
+                } else {
+                    $this->error('Error: no record was found in data array!');
+                }
+            } else {
+                $this->error('Error: this records is NOT created it seems! (' . $table . ':' . $uid . ')');
+            }
+        }
+        if (!empty($updateData)) {
+            $tce = $this->getNewTCE();
+            $tce->isImporting = true;
+            $this->callHook('before_setRelation', array(
+                'tce' => &$tce,
+                'data' => &$updateData
+            ));
+            $tce->start($updateData, array());
+            $tce->process_datamap();
+            // Replace the temporary "NEW" ids with the final ones.
+            foreach ($this->legacyImportMigrationRecords as $table => $records) {
+                foreach ($records as $uid => $fields) {
+                    foreach ($fields as $field => $referenceIds) {
+                        foreach ($referenceIds as $key => $referenceId) {
+                            $this->legacyImportMigrationRecords[$table][$uid][$field][$key] = $tce->substNEWwithIDs[$referenceId];
+                        }
+                    }
+                }
+            }
+            $this->callHook('after_setRelations', array(
+                'tce' => &$tce
+            ));
+        }
+    }
+
+    /**
+     * Maps relations for database
+     *
+     * @param array $itemArray Array of item sets (table/uid) from a dbAnalysis object
+     * @param array $itemConfig Array of TCA config of the field the relation to be set on
+     * @return array Array with values [table]_[uid] or [uid] for field of type group / internal_type file_reference. These values have the regular tcemain-input group/select type which means they will automatically be processed into a uid-list or MM relations.
+     */
+    public function setRelations_db($itemArray, $itemConfig)
+    {
+        $valArray = array();
+        foreach ($itemArray as $relDat) {
+            if (is_array($this->import_mapId[$relDat['table']]) && isset($this->import_mapId[$relDat['table']][$relDat['id']])) {
+                // Since non FAL file relation type group internal_type file_reference are handled as reference to
+                // sys_file records Datahandler requires the value as uid of the the related sys_file record only
+                if ($itemConfig['type'] === 'group' && $itemConfig['internal_type'] === 'file_reference') {
+                    $value = $this->import_mapId[$relDat['table']][$relDat['id']];
+                } elseif ($itemConfig['type'] === 'input' && isset($itemConfig['wizards']['link'])) {
+                    // If an input field has a relation to a sys_file record this need to be converted back to
+                    // the public path. But use getPublicUrl here, because could normally only be a local file path.
+                    $fileUid = $this->import_mapId[$relDat['table']][$relDat['id']];
+                    // Fallback value
+                    $value = 'file:' . $fileUid;
+                    try {
+                        $file = ResourceFactory::getInstance()->retrieveFileOrFolderObject($fileUid);
+                    } catch (\Exception $e) {
+                        $file = null;
+                    }
+                    if ($file instanceof FileInterface) {
+                        $value = $file->getPublicUrl();
+                    }
+                } else {
+                    $value = $relDat['table'] . '_' . $this->import_mapId[$relDat['table']][$relDat['id']];
+                }
+                $valArray[] = $value;
+            } elseif ($this->isTableStatic($relDat['table']) || $this->isExcluded($relDat['table'], $relDat['id']) || $relDat['id'] < 0) {
+                // Checking for less than zero because some select types could contain negative values,
+                // eg. fe_groups (-1, -2) and sys_language (-1 = ALL languages). This must be handled on both export and import.
+                $valArray[] = $relDat['table'] . '_' . $relDat['id'];
+            } else {
+                $this->error('Lost relation: ' . $relDat['table'] . ':' . $relDat['id']);
+            }
+        }
+        return $valArray;
+    }
+
+    /**
+     * Writes the file from import array to temp dir and returns the filename of it.
+     *
+     * @param array $fI File information with three keys: "filename" = filename without path, "ID_absFile" = absolute filepath to the file (including the filename), "ID" = md5 hash of "ID_absFile
+     * @return string|NULL Absolute filename of the temporary filename of the file. In ->alternativeFileName the original name is set.
+     */
+    public function import_addFileNameToBeCopied($fI)
+    {
+        if (is_array($this->dat['files'][$fI['ID']])) {
+            $tmpFile = null;
+            // check if there is the right file already in the local folder
+            if ($this->filesPathForImport !== null) {
+                if (is_file($this->filesPathForImport . '/' . $this->dat['files'][$fI['ID']]['content_md5']) &&
+                    md5_file($this->filesPathForImport . '/' . $this->dat['files'][$fI['ID']]['content_md5']) === $this->dat['files'][$fI['ID']]['content_md5']) {
+                    $tmpFile = $this->filesPathForImport . '/' . $this->dat['files'][$fI['ID']]['content_md5'];
+                }
+            }
+            if ($tmpFile === null) {
+                $tmpFile = GeneralUtility::tempnam('import_temp_');
+                GeneralUtility::writeFile($tmpFile, $this->dat['files'][$fI['ID']]['content']);
+            }
+            clearstatcache();
+            if (@is_file($tmpFile)) {
+                $this->unlinkFiles[] = $tmpFile;
+                if (filesize($tmpFile) == $this->dat['files'][$fI['ID']]['filesize']) {
+                    $this->alternativeFileName[$tmpFile] = $fI['filename'];
+                    $this->alternativeFilePath[$tmpFile] = $this->dat['files'][$fI['ID']]['relFileRef'];
+                    return $tmpFile;
+                } else {
+                    $this->error('Error: temporary file ' . $tmpFile . ' had a size (' . filesize($tmpFile) . ') different from the original (' . $this->dat['files'][$fI['ID']]['filesize'] . ')');
+                }
+            } else {
+                $this->error('Error: temporary file ' . $tmpFile . ' was not written as it should have been!');
+            }
+        } else {
+            $this->error('Error: No file found for ID ' . $fI['ID']);
+        }
+        return null;
+    }
+
+    /**
+     * After all DB relations has been set in the end of the import (see setRelations()) then it is time to correct all relations inside of FlexForm fields.
+     * The reason for doing this after is that the setting of relations may affect (quite often!) which data structure is used for the flexforms field!
+     *
+     * @return void
+     * @see setRelations()
+     */
+    public function setFlexFormRelations()
+    {
+        $updateData = array();
+        // import_newId contains a register of all records that was in the import memorys "records" key
+        foreach ($this->import_newId as $nId => $dat) {
+            $table = $dat['table'];
+            $uid = $dat['uid'];
+            // original UID - NOT the new one!
+            // If the record has been written and received a new id, then proceed:
+            if (!isset($this->import_mapId[$table][$uid])) {
+                $this->error('Error: this records is NOT created it seems! (' . $table . ':' . $uid . ')');
+                continue;
+            }
+
+            if (!is_array($this->dat['records'][$table . ':' . $uid]['rels'])) {
+                $this->error('Error: no record was found in data array!');
+                continue;
+            }
+            $thisNewUid = BackendUtility::wsMapId($table, $this->import_mapId[$table][$uid]);
+            // Traverse relation fields of each record
+            foreach ($this->dat['records'][$table . ':' . $uid]['rels'] as $field => $config) {
+                switch ((string)$config['type']) {
+                    case 'flex':
+                        // Get XML content and set as default value (string, non-processed):
+                        $updateData[$table][$thisNewUid][$field] = $this->dat['records'][$table . ':' . $uid]['data'][$field];
+                        // If there has been registered relations inside the flex form field, run processing on the content:
+                        if (!empty($config['flexFormRels']['db']) || !empty($config['flexFormRels']['file'])) {
+                            $origRecordRow = BackendUtility::getRecord($table, $thisNewUid, '*');
+                            // This will fetch the new row for the element (which should be updated with any references to data structures etc.)
+                            $conf = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
+                            if (is_array($origRecordRow) && is_array($conf) && $conf['type'] === 'flex') {
+                                // Get current data structure and value array:
+                                $dataStructArray = BackendUtility::getFlexFormDS($conf, $origRecordRow, $table, $field);
+                                $currentValueArray = GeneralUtility::xml2array($updateData[$table][$thisNewUid][$field]);
+                                // Do recursive processing of the XML data:
+                                $iteratorObj = GeneralUtility::makeInstance(DataHandler::class);
+                                $iteratorObj->callBackObj = $this;
+                                $currentValueArray['data'] = $iteratorObj->checkValue_flex_procInData(
+                                    $currentValueArray['data'],
+                                    array(),
+                                    array(),
+                                    $dataStructArray,
+                                    array($table, $thisNewUid, $field, $config),
+                                    'remapListedDBRecords_flexFormCallBack'
+                                );
+                                // The return value is set as an array which means it will be processed by tcemain for file and DB references!
+                                if (is_array($currentValueArray['data'])) {
+                                    $updateData[$table][$thisNewUid][$field] = $currentValueArray;
+                                }
+                            }
+                        }
+                        break;
+                }
+            }
+        }
+        if (!empty($updateData)) {
+            $tce = $this->getNewTCE();
+            $tce->isImporting = true;
+            $this->callHook('before_setFlexFormRelations', array(
+                'tce' => &$tce,
+                'data' => &$updateData
+            ));
+            $tce->start($updateData, array());
+            $tce->process_datamap();
+            $this->callHook('after_setFlexFormRelations', array(
+                'tce' => &$tce
+            ));
+        }
+    }
+
+    /**
+     * Callback function for traversing the FlexForm structure in relation to remapping database relations
+     *
+     * @param array $pParams Set of parameters in numeric array: table, uid, field
+     * @param array $dsConf TCA config for field (from Data Structure of course)
+     * @param string $dataValue Field value (from FlexForm XML)
+     * @param string $dataValue_ext1 Not used
+     * @param string $dataValue_ext2 Not used
+     * @param string $path Path of where the data structure of the element is found
+     * @return array Array where the "value" key carries the value.
+     * @see setFlexFormRelations()
+     */
+    public function remapListedDBRecords_flexFormCallBack($pParams, $dsConf, $dataValue, $dataValue_ext1, $dataValue_ext2, $path)
+    {
+        // Extract parameters:
+        list($table, $uid, $field, $config) = $pParams;
+        // In case the $path is used as index without a trailing slash we will remove that
+        if (!is_array($config['flexFormRels']['db'][$path]) && is_array($config['flexFormRels']['db'][rtrim($path, '/')])) {
+            $path = rtrim($path, '/');
+        }
+        if (is_array($config['flexFormRels']['db'][$path])) {
+            $valArray = $this->setRelations_db($config['flexFormRels']['db'][$path], $dsConf);
+            $dataValue = implode(',', $valArray);
+        }
+        if (is_array($config['flexFormRels']['file'][$path])) {
+            $valArr = array();
+            foreach ($config['flexFormRels']['file'][$path] as $fI) {
+                $valArr[] = $this->import_addFileNameToBeCopied($fI);
+            }
+            $dataValue = implode(',', $valArr);
+        }
+        return array('value' => $dataValue);
+    }
+
+    /**************************
+     * Import / Soft References
+     *************************/
+
+    /**
+     * Processing of soft references
+     *
+     * @return void
+     */
+    public function processSoftReferences()
+    {
+        // Initialize:
+        $inData = array();
+        // Traverse records:
+        if (is_array($this->dat['header']['records'])) {
+            foreach ($this->dat['header']['records'] as $table => $recs) {
+                foreach ($recs as $uid => $thisRec) {
+                    // If there are soft references defined, traverse those:
+                    if (isset($GLOBALS['TCA'][$table]) && is_array($thisRec['softrefs'])) {
+                        // First traversal is to collect softref configuration and split them up based on fields.
+                        // This could probably also have been done with the "records" key instead of the header.
+                        $fieldsIndex = array();
+                        foreach ($thisRec['softrefs'] as $softrefDef) {
+                            // If a substitution token is set:
+                            if ($softrefDef['field'] && is_array($softrefDef['subst']) && $softrefDef['subst']['tokenID']) {
+                                $fieldsIndex[$softrefDef['field']][$softrefDef['subst']['tokenID']] = $softrefDef;
+                            }
+                        }
+                        // The new id:
+                        $thisNewUid = BackendUtility::wsMapId($table, $this->import_mapId[$table][$uid]);
+                        // Now, if there are any fields that require substitution to be done, lets go for that:
+                        foreach ($fieldsIndex as $field => $softRefCfgs) {
+                            if (is_array($GLOBALS['TCA'][$table]['columns'][$field])) {
+                                $conf = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
+                                if ($conf['type'] === 'flex') {
+                                    // This will fetch the new row for the element (which should be updated with any references to data structures etc.)
+                                    $origRecordRow = BackendUtility::getRecord($table, $thisNewUid, '*');
+                                    if (is_array($origRecordRow)) {
+                                        // Get current data structure and value array:
+                                        $dataStructArray = BackendUtility::getFlexFormDS($conf, $origRecordRow, $table, $field);
+                                        $currentValueArray = GeneralUtility::xml2array($origRecordRow[$field]);
+                                        // Do recursive processing of the XML data:
+                                        /** @var $iteratorObj DataHandler */
+                                        $iteratorObj = GeneralUtility::makeInstance(DataHandler::class);
+                                        $iteratorObj->callBackObj = $this;
+                                        $currentValueArray['data'] = $iteratorObj->checkValue_flex_procInData($currentValueArray['data'], array(), array(), $dataStructArray, array($table, $uid, $field, $softRefCfgs), 'processSoftReferences_flexFormCallBack');
+                                        // The return value is set as an array which means it will be processed by tcemain for file and DB references!
+                                        if (is_array($currentValueArray['data'])) {
+                                            $inData[$table][$thisNewUid][$field] = $currentValueArray;
+                                        }
+                                    }
+                                } else {
+                                    // Get tokenizedContent string and proceed only if that is not blank:
+                                    $tokenizedContent = $this->dat['records'][$table . ':' . $uid]['rels'][$field]['softrefs']['tokenizedContent'];
+                                    if (strlen($tokenizedContent) && is_array($softRefCfgs)) {
+                                        $inData[$table][$thisNewUid][$field] = $this->processSoftReferences_substTokens($tokenizedContent, $softRefCfgs, $table, $uid);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        // Now write to database:
+        $tce = $this->getNewTCE();
+        $tce->isImporting = true;
+        $this->callHook('before_processSoftReferences', array(
+            'tce' => $tce,
+            'data' => &$inData
+        ));
+        $tce->enableLogging = true;
+        $tce->start($inData, array());
+        $tce->process_datamap();
+        $this->callHook('after_processSoftReferences', array(
+            'tce' => $tce
+        ));
+    }
+
+    /**
+     * Callback function for traversing the FlexForm structure in relation to remapping softreference relations
+     *
+     * @param array $pParams Set of parameters in numeric array: table, uid, field
+     * @param array $dsConf TCA config for field (from Data Structure of course)
+     * @param string $dataValue Field value (from FlexForm XML)
+     * @param string $dataValue_ext1 Not used
+     * @param string $dataValue_ext2 Not used
+     * @param string $path Path of where the data structure where the element is found
+     * @return array Array where the "value" key carries the value.
+     * @see setFlexFormRelations()
+     */
+    public function processSoftReferences_flexFormCallBack($pParams, $dsConf, $dataValue, $dataValue_ext1, $dataValue_ext2, $path)
+    {
+        // Extract parameters:
+        list($table, $origUid, $field, $softRefCfgs) = $pParams;
+        if (is_array($softRefCfgs)) {
+            // First, find all soft reference configurations for this structure path (they are listed flat in the header):
+            $thisSoftRefCfgList = array();
+            foreach ($softRefCfgs as $sK => $sV) {
+                if ($sV['structurePath'] === $path) {
+                    $thisSoftRefCfgList[$sK] = $sV;
+                }
+            }
+            // If any was found, do processing:
+            if (!empty($thisSoftRefCfgList)) {
+                // Get tokenizedContent string and proceed only if that is not blank:
+                $tokenizedContent = $this->dat['records'][$table . ':' . $origUid]['rels'][$field]['flexFormRels']['softrefs'][$path]['tokenizedContent'];
+                if (strlen($tokenizedContent)) {
+                    $dataValue = $this->processSoftReferences_substTokens($tokenizedContent, $thisSoftRefCfgList, $table, $origUid);
+                }
+            }
+        }
+        // Return
+        return array('value' => $dataValue);
+    }
+
+    /**
+     * Substition of softreference tokens
+     *
+     * @param string $tokenizedContent Content of field with soft reference tokens in.
+     * @param array $softRefCfgs Soft reference configurations
+     * @param string $table Table for which the processing occurs
+     * @param string $uid UID of record from table
+     * @return string The input content with tokens substituted according to entries in softRefCfgs
+     */
+    public function processSoftReferences_substTokens($tokenizedContent, $softRefCfgs, $table, $uid)
+    {
+        // traverse each softref type for this field:
+        foreach ($softRefCfgs as $cfg) {
+            // Get token ID:
+            $tokenID = $cfg['subst']['tokenID'];
+            // Default is current token value:
+            $insertValue = $cfg['subst']['tokenValue'];
+            // Based on mode:
+            switch ((string)$this->softrefCfg[$tokenID]['mode']) {
+                case 'exclude':
+                    // Exclude is a simple passthrough of the value
+                    break;
+                case 'editable':
+                    // Editable always picks up the value from this input array:
+                    $insertValue = $this->softrefInputValues[$tokenID];
+                    break;
+                default:
+                    // Mapping IDs/creating files: Based on type, look up new value:
+                    switch ((string)$cfg['subst']['type']) {
+                        case 'file':
+                            // Create / Overwrite file:
+                            $insertValue = $this->processSoftReferences_saveFile($cfg['subst']['relFileName'], $cfg, $table, $uid);
+                            break;
+                        case 'db':
+                        default:
+                            // Trying to map database element if found in the mapID array:
+                            list($tempTable, $tempUid) = explode(':', $cfg['subst']['recordRef']);
+                            if (isset($this->import_mapId[$tempTable][$tempUid])) {
+                                $insertValue = BackendUtility::wsMapId($tempTable, $this->import_mapId[$tempTable][$tempUid]);
+                                // Look if reference is to a page and the original token value was NOT an integer - then we assume is was an alias and try to look up the new one!
+                                if ($tempTable === 'pages' && !MathUtility::canBeInterpretedAsInteger($cfg['subst']['tokenValue'])) {
+                                    $recWithUniqueValue = BackendUtility::getRecord($tempTable, $insertValue, 'alias');
+                                    if ($recWithUniqueValue['alias']) {
+                                        $insertValue = $recWithUniqueValue['alias'];
+                                    }
+                                } elseif (strpos($cfg['subst']['tokenValue'], ':') !== false) {
+                                    list($tokenKey) = explode(':', $cfg['subst']['tokenValue']);
+                                    $insertValue = $tokenKey . ':' . $insertValue;
+                                }
+                            }
+                    }
+            }
+            // Finally, swap the soft reference token in tokenized content with the insert value:
+            $tokenizedContent = str_replace('{softref:' . $tokenID . '}', $insertValue, $tokenizedContent);
+        }
+        return $tokenizedContent;
+    }
+
+    /**
+     * Process a soft reference file
+     *
+     * @param string $relFileName Old Relative filename
+     * @param array $cfg soft reference configuration array
+     * @param string $table Table for which the processing occurs
+     * @param string $uid UID of record from table
+     * @return string New relative filename (value to insert instead of the softref token)
+     */
+    public function processSoftReferences_saveFile($relFileName, $cfg, $table, $uid)
+    {
+        if ($fileHeaderInfo = $this->dat['header']['files'][$cfg['file_ID']]) {
+            // Initialize; Get directory prefix for file and find possible RTE filename
+            $dirPrefix = PathUtility::dirname($relFileName) . '/';
+            $rteOrigName = $this->getRTEoriginalFilename(PathUtility::basename($relFileName));
+            // If filename looks like an RTE file, and the directory is in "uploads/", then process as a RTE file!
+            if ($rteOrigName && GeneralUtility::isFirstPartOfStr($dirPrefix, 'uploads/')) {
+                // RTE:
+                // First, find unique RTE file name:
+                if (@is_dir((PATH_site . $dirPrefix))) {
+                    // From the "original" RTE filename, produce a new "original" destination filename which is unused.
+                    // Even if updated, the image should be unique. Currently the problem with this is that it leaves a lot of unused RTE images...
+                    $fileProcObj = $this->getFileProcObj();
+                    $origDestName = $fileProcObj->getUniqueName($rteOrigName, PATH_site . $dirPrefix);
+                    // Create copy file name:
+                    $pI = pathinfo($relFileName);
+                    $copyDestName = PathUtility::dirname($origDestName) . '/RTEmagicC_' . substr(PathUtility::basename($origDestName), 10) . '.' . $pI['extension'];
+                    if (
+                        !@is_file($copyDestName) && !@is_file($origDestName)
+                        && $origDestName === GeneralUtility::getFileAbsFileName($origDestName)
+                        && $copyDestName === GeneralUtility::getFileAbsFileName($copyDestName)
+                    ) {
+                        if ($this->dat['header']['files'][$fileHeaderInfo['RTE_ORIG_ID']]) {
+                            if ($this->legacyImport) {
+                                $fileName = PathUtility::basename($copyDestName);
+                                $this->writeSysFileResourceForLegacyImport($fileName, $cfg['file_ID']);
+                                $relFileName = $this->filePathMap[$cfg['file_ID']] . '" data-htmlarea-file-uid="' . $fileName . '" data-htmlarea-file-table="sys_file';
+                                // Also save the original file
+                                $originalFileName = PathUtility::basename($origDestName);
+                                $this->writeSysFileResourceForLegacyImport($originalFileName, $fileHeaderInfo['RTE_ORIG_ID']);
+                            } else {
+                                // Write the copy and original RTE file to the respective filenames:
+                                $this->writeFileVerify($copyDestName, $cfg['file_ID'], true);
+                                $this->writeFileVerify($origDestName, $fileHeaderInfo['RTE_ORIG_ID'], true);
+                                // Return the relative path of the copy file name:
+                                return PathUtility::stripPathSitePrefix($copyDestName);
+                            }
+                        } else {
+                            $this->error('ERROR: Could not find original file ID');
+                        }
+                    } else {
+                        $this->error('ERROR: The destination filenames "' . $copyDestName . '" and "' . $origDestName . '" either existed or have non-valid names');
+                    }
+                } else {
+                    $this->error('ERROR: "' . PATH_site . $dirPrefix . '" was not a directory, so could not process file "' . $relFileName . '"');
+                }
+            } elseif (GeneralUtility::isFirstPartOfStr($dirPrefix, $this->fileadminFolderName . '/')) {
+                // File in fileadmin/ folder:
+                // Create file (and possible resources)
+                $newFileName = $this->processSoftReferences_saveFile_createRelFile($dirPrefix, PathUtility::basename($relFileName), $cfg['file_ID'], $table, $uid);
+                if (strlen($newFileName)) {
+                    $relFileName = $newFileName;
+                } else {
+                    $this->error('ERROR: No new file created for "' . $relFileName . '"');
+                }
+            } else {
+                $this->error('ERROR: Sorry, cannot operate on non-RTE files which are outside the fileadmin folder.');
+            }
+        } else {
+            $this->error('ERROR: Could not find file ID in header.');
+        }
+        // Return (new) filename relative to PATH_site:
+        return $relFileName;
+    }
+
+    /**
+     * Create file in directory and return the new (unique) filename
+     *
+     * @param string $origDirPrefix Directory prefix, relative, with trailing slash
+     * @param string $fileName Filename (without path)
+     * @param string $fileID File ID from import memory
+     * @param string $table Table for which the processing occurs
+     * @param string $uid UID of record from table
+     * @return string|NULL New relative filename, if any
+     */
+    public function processSoftReferences_saveFile_createRelFile($origDirPrefix, $fileName, $fileID, $table, $uid)
+    {
+        // If the fileID map contains an entry for this fileID then just return the relative filename of that entry;
+        // we don't want to write another unique filename for this one!
+        if (isset($this->fileIDMap[$fileID])) {
+            return PathUtility::stripPathSitePrefix($this->fileIDMap[$fileID]);
+        }
+        if ($this->legacyImport) {
+            // set dirPrefix to fileadmin because the right target folder is set and checked for permissions later
+            $dirPrefix = $this->fileadminFolderName . '/';
+        } else {
+            // Verify FileMount access to dir-prefix. Returns the best alternative relative path if any
+            $dirPrefix = $this->verifyFolderAccess($origDirPrefix);
+        }
+        if ($dirPrefix && (!$this->update || $origDirPrefix === $dirPrefix) && $this->checkOrCreateDir($dirPrefix)) {
+            $fileHeaderInfo = $this->dat['header']['files'][$fileID];
+            $updMode = $this->update && $this->import_mapId[$table][$uid] === $uid && $this->import_mode[$table . ':' . $uid] !== 'as_new';
+            // Create new name for file:
+            // Must have same ID in map array (just for security, is not really needed) and NOT be set "as_new".
+
+            // Write main file:
+            if ($this->legacyImport) {
+                $fileWritten = $this->writeSysFileResourceForLegacyImport($fileName, $fileID);
+                if ($fileWritten) {
+                    $newName = 'file:' . $fileName;
+                    return $newName;
+                    // no support for HTML/CSS file resources attached ATM - see below
+                }
+            } else {
+                if ($updMode) {
+                    $newName = PATH_site . $dirPrefix . $fileName;
+                } else {
+                    // Create unique filename:
+                    $fileProcObj = $this->getFileProcObj();
+                    $newName = $fileProcObj->getUniqueName($fileName, PATH_site . $dirPrefix);
+                }
+                if ($this->writeFileVerify($newName, $fileID)) {
+                    // If the resource was an HTML/CSS file with resources attached, we will write those as well!
+                    if (is_array($fileHeaderInfo['EXT_RES_ID'])) {
+                        $tokenizedContent = $this->dat['files'][$fileID]['tokenizedContent'];
+                        $tokenSubstituted = false;
+                        $fileProcObj = $this->getFileProcObj();
+                        if ($updMode) {
+                            foreach ($fileHeaderInfo['EXT_RES_ID'] as $res_fileID) {
+                                if ($this->dat['files'][$res_fileID]['filename']) {
+                                    // Resolve original filename:
+                                    $relResourceFileName = $this->dat['files'][$res_fileID]['parentRelFileName'];
+                                    $absResourceFileName = GeneralUtility::resolveBackPath(PATH_site . $origDirPrefix . $relResourceFileName);
+                                    $absResourceFileName = GeneralUtility::getFileAbsFileName($absResourceFileName);
+                                    if ($absResourceFileName && GeneralUtility::isFirstPartOfStr($absResourceFileName, PATH_site . $this->fileadminFolderName . '/')) {
+                                        $destDir = PathUtility::stripPathSitePrefix(PathUtility::dirname($absResourceFileName) . '/');
+                                        if ($this->verifyFolderAccess($destDir, true) && $this->checkOrCreateDir($destDir)) {
+                                            $this->writeFileVerify($absResourceFileName, $res_fileID);
+                                        } else {
+                                            $this->error('ERROR: Could not create file in directory "' . $destDir . '"');
+                                        }
+                                    } else {
+                                        $this->error('ERROR: Could not resolve path for "' . $relResourceFileName . '"');
+                                    }
+                                    $tokenizedContent = str_replace('{EXT_RES_ID:' . $res_fileID . '}', $relResourceFileName, $tokenizedContent);
+                                    $tokenSubstituted = true;
+                                }
+                            }
+                        } else {
+                            // Create the resouces directory name (filename without extension, suffixed "_FILES")
+                            $resourceDir = PathUtility::dirname($newName) . '/' . preg_replace('/\\.[^.]*$/', '', PathUtility::basename($newName)) . '_FILES';
+                            if (GeneralUtility::mkdir($resourceDir)) {
+                                foreach ($fileHeaderInfo['EXT_RES_ID'] as $res_fileID) {
+                                    if ($this->dat['files'][$res_fileID]['filename']) {
+                                        $absResourceFileName = $fileProcObj->getUniqueName($this->dat['files'][$res_fileID]['filename'], $resourceDir);
+                                        $relResourceFileName = substr($absResourceFileName, strlen(PathUtility::dirname($resourceDir)) + 1);
+                                        $this->writeFileVerify($absResourceFileName, $res_fileID);
+                                        $tokenizedContent = str_replace('{EXT_RES_ID:' . $res_fileID . '}', $relResourceFileName, $tokenizedContent);
+                                        $tokenSubstituted = true;
+                                    }
+                                }
+                            }
+                        }
+                        // If substitutions has been made, write the content to the file again:
+                        if ($tokenSubstituted) {
+                            GeneralUtility::writeFile($newName, $tokenizedContent);
+                        }
+                    }
+                    return PathUtility::stripPathSitePrefix($newName);
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Writes a file from the import memory having $fileID to file name $fileName which must be an absolute path inside PATH_site
+     *
+     * @param string $fileName Absolute filename inside PATH_site to write to
+     * @param string $fileID File ID from import memory
+     * @param bool $bypassMountCheck Bypasses the checking against filemounts - only for RTE files!
+     * @return bool Returns TRUE if it went well. Notice that the content of the file is read again, and md5 from import memory is validated.
+     */
+    public function writeFileVerify($fileName, $fileID, $bypassMountCheck = false)
+    {
+        $fileProcObj = $this->getFileProcObj();
+        if (!$fileProcObj->actionPerms['addFile']) {
+            $this->error('ERROR: You did not have sufficient permissions to write the file "' . $fileName . '"');
+            return false;
+        }
+        // Just for security, check again. Should actually not be necessary.
+        if (!$fileProcObj->checkPathAgainstMounts($fileName) && !$bypassMountCheck) {
+            $this->error('ERROR: Filename "' . $fileName . '" was not allowed in destination path!');
+            return false;
+        }
+        $fI = GeneralUtility::split_fileref($fileName);
+        if (!$fileProcObj->checkIfAllowed($fI['fileext'], $fI['path'], $fI['file']) && (!$this->allowPHPScripts || !$this->getBackendUser()->isAdmin())) {
+            $this->error('ERROR: Filename "' . $fileName . '" failed against extension check or deny-pattern!');
+            return false;
+        }
+        if (!GeneralUtility::getFileAbsFileName($fileName)) {
+            $this->error('ERROR: Filename "' . $fileName . '" was not a valid relative file path!');
+            return false;
+        }
+        if (!$this->dat['files'][$fileID]) {
+            $this->error('ERROR: File ID "' . $fileID . '" could not be found');
+            return false;
+        }
+        GeneralUtility::writeFile($fileName, $this->dat['files'][$fileID]['content']);
+        $this->fileIDMap[$fileID] = $fileName;
+        if (md5(GeneralUtility::getUrl($fileName)) == $this->dat['files'][$fileID]['content_md5']) {
+            return true;
+        } else {
+            $this->error('ERROR: File content "' . $fileName . '" was corrupted');
+            return false;
+        }
+    }
+
+    /**
+     * Writes the file with the is $fileId to the legacy import folder. The file name will used from
+     * argument $fileName and the file was successfully created or an identical file was already found,
+     * $fileName will held the uid of the new created file record.
+     *
+     * @param string $fileName The file name for the new file. Value would be changed to the uid of the new created file record.
+     * @param int $fileId The id of the file in data array
+     * @return bool
+     */
+    protected function writeSysFileResourceForLegacyImport(&$fileName, $fileId)
+    {
+        if ($this->legacyImportFolder === null) {
+            return false;
+        }
+
+        if (!isset($this->dat['files'][$fileId])) {
+            $this->error('ERROR: File ID "' . $fileId . '" could not be found');
+            return false;
+        }
+
+        $temporaryFile = $this->writeTemporaryFileFromData($fileId, 'files');
+        if ($temporaryFile === null) {
+            // error on writing the file. Error message was already added
+            return false;
+        }
+
+        $importFolder = $this->legacyImportFolder;
+
+        if (isset($this->dat['files'][$fileId]['relFileName'])) {
+            $relativeFilePath = PathUtility::dirname($this->dat['files'][$fileId]['relFileName']);
+
+            if (!$this->legacyImportFolder->hasFolder($relativeFilePath)) {
+                $this->legacyImportFolder->createFolder($relativeFilePath);
+            }
+            $importFolder = $this->legacyImportFolder->getSubfolder($relativeFilePath);
+        }
+
+        $fileObject = null;
+
+        try {
+            // check, if there is alreay the same file in the folder
+            if ($importFolder->hasFile($fileName)) {
+                $fileStorage = $importFolder->getStorage();
+                $file = $fileStorage->getFile($importFolder->getIdentifier() . $fileName);
+                if ($file->getSha1() === sha1_file($temporaryFile)) {
+                    $fileObject = $file;
+                }
+            }
+        } catch (Exception $e) {
+        }
+
+        if ($fileObject === null) {
+            try {
+                $fileObject = $importFolder->addFile($temporaryFile, $fileName, DuplicationBehavior::RENAME);
+            } catch (Exception $e) {
+                $this->error('Error: no file could be added to the storage for file name ' . $this->alternativeFileName[$temporaryFile]);
+            }
+        }
+
+        if (md5_file(PATH_site . $fileObject->getPublicUrl()) == $this->dat['files'][$fileId]['content_md5']) {
+            $fileName = $fileObject->getUid();
+            $this->fileIDMap[$fileId] = $fileName;
+            $this->filePathMap[$fileId] = $fileObject->getPublicUrl();
+            return true;
+        } else {
+            $this->error('ERROR: File content "' . $this->dat['files'][$fileId]['relFileName'] . '" was corrupted');
+        }
+
+        return false;
+    }
+
+    /**
+     * Migrate legacy import records
+     *
+     * @return void
+     */
+    protected function migrateLegacyImportRecords()
+    {
+        $updateData= array();
+
+        foreach ($this->legacyImportMigrationRecords as $table => $records) {
+            foreach ($records as $uid => $fields) {
+                $row = BackendUtility::getRecord($table, $uid);
+                if (empty($row)) {
+                    continue;
+                }
+
+                foreach ($fields as $field => $referenceIds) {
+                    $fieldConfiguration = $this->legacyImportMigrationTables[$table][$field];
+
+                    if (isset($fieldConfiguration['titleTexts'])) {
+                        $titleTextField = $fieldConfiguration['titleTexts'];
+                        if (isset($row[$titleTextField]) && $row[$titleTextField] !== '') {
+                            $titleTextContents = explode(LF, $row[$titleTextField]);
+                            $updateData[$table][$uid][$titleTextField] = '';
+                        }
+                    }
+
+                    if (isset($fieldConfiguration['alternativeTexts'])) {
+                        $alternativeTextField = $fieldConfiguration['alternativeTexts'];
+                        if (isset($row[$alternativeTextField]) && $row[$alternativeTextField] !== '') {
+                            $alternativeTextContents = explode(LF, $row[$alternativeTextField]);
+                            $updateData[$table][$uid][$alternativeTextField] = '';
+                        }
+                    }
+                    if (isset($fieldConfiguration['description'])) {
+                        $descriptionField = $fieldConfiguration['description'];
+                        if ($row[$descriptionField] !== '') {
+                            $descriptionContents = explode(LF, $row[$descriptionField]);
+                            $updateData[$table][$uid][$descriptionField] = '';
+                        }
+                    }
+                    if (isset($fieldConfiguration['links'])) {
+                        $linkField = $fieldConfiguration['links'];
+                        if ($row[$linkField] !== '') {
+                            $linkContents = explode(LF, $row[$linkField]);
+                            $updateData[$table][$uid][$linkField] = '';
+                        }
+                    }
+
+                    foreach ($referenceIds as $key => $referenceId) {
+                        if (isset($titleTextContents[$key])) {
+                            $updateData['sys_file_reference'][$referenceId]['title'] = trim($titleTextContents[$key]);
+                        }
+                        if (isset($alternativeTextContents[$key])) {
+                            $updateData['sys_file_reference'][$referenceId]['alternative'] = trim($alternativeTextContents[$key]);
+                        }
+                        if (isset($descriptionContents[$key])) {
+                            $updateData['sys_file_reference'][$referenceId]['description'] = trim($descriptionContents[$key]);
+                        }
+                        if (isset($linkContents[$key])) {
+                            $updateData['sys_file_reference'][$referenceId]['link'] = trim($linkContents[$key]);
+                        }
+                    }
+                }
+            }
+        }
+
+        // update
+        $tce = $this->getNewTCE();
+        $tce->isImporting = true;
+        $tce->start($updateData, array());
+        $tce->process_datamap();
+    }
+
+    /**
+     * Returns TRUE if directory exists  and if it doesn't it will create directory and return TRUE if that succeeded.
+     *
+     * @param string $dirPrefix Directory to create. Having a trailing slash. Must be in fileadmin/. Relative to PATH_site
+     * @return bool TRUE, if directory exists (was created)
+     */
+    public function checkOrCreateDir($dirPrefix)
+    {
+        // Split dir path and remove first directory (which should be "fileadmin")
+        $filePathParts = explode('/', $dirPrefix);
+        $firstDir = array_shift($filePathParts);
+        if ($firstDir === $this->fileadminFolderName && GeneralUtility::getFileAbsFileName($dirPrefix)) {
+            $pathAcc = '';
+            foreach ($filePathParts as $dirname) {
+                $pathAcc .= '/' . $dirname;
+                if (strlen($dirname)) {
+                    if (!@is_dir((PATH_site . $this->fileadminFolderName . $pathAcc))) {
+                        if (!GeneralUtility::mkdir((PATH_site . $this->fileadminFolderName . $pathAcc))) {
+                            $this->error('ERROR: Directory could not be created....B');
+                            return false;
+                        }
+                    }
+                } elseif ($dirPrefix === $this->fileadminFolderName . $pathAcc) {
+                    return true;
+                } else {
+                    $this->error('ERROR: Directory could not be created....A');
+                }
+            }
+        }
+        return false;
+    }
+
+    /**************************
+     * File Input
+     *************************/
+
+    /**
+     * Loads the header section/all of the $filename into memory
+     *
+     * @param string $filename Filename, absolute
+     * @param bool $all If set, all information is loaded (header, records and files). Otherwise the default is to read only the header information
+     * @return bool TRUE if the operation went well
+     */
+    public function loadFile($filename, $all = false)
+    {
+        if (!@is_file($filename)) {
+            $this->error('Filename not found: ' . $filename);
+            return false;
+        }
+        $fI = pathinfo($filename);
+        if (@is_dir($filename . '.files')) {
+            if (GeneralUtility::isAllowedAbsPath($filename . '.files')) {
+                // copy the folder lowlevel to typo3temp, because the files would be deleted after import
+                $temporaryFolderName = $this->getTemporaryFolderName();
+                GeneralUtility::copyDirectory($filename . '.files', $temporaryFolderName);
+                $this->filesPathForImport = $temporaryFolderName;
+            } else {
+                $this->error('External import files for the given import source is currently not supported.');
+            }
+        }
+        if (strtolower($fI['extension']) == 'xml') {
+            // XML:
+            $xmlContent = GeneralUtility::getUrl($filename);
+            if (strlen($xmlContent)) {
+                $this->dat = GeneralUtility::xml2array($xmlContent, '', true);
+                if (is_array($this->dat)) {
+                    if ($this->dat['_DOCUMENT_TAG'] === 'T3RecordDocument' && is_array($this->dat['header']) && is_array($this->dat['records'])) {
+                        $this->loadInit();
+                        return true;
+                    } else {
+                        $this->error('XML file did not contain proper XML for TYPO3 Import');
+                    }
+                } else {
+                    $this->error('XML could not be parsed: ' . $this->dat);
+                }
+            } else {
+                $this->error('Error opening file: ' . $filename);
+            }
+        } else {
+            // T3D
+            if ($fd = fopen($filename, 'rb')) {
+                $this->dat['header'] = $this->getNextFilePart($fd, 1, 'header');
+                if ($all) {
+                    $this->dat['records'] = $this->getNextFilePart($fd, 1, 'records');
+                    $this->dat['files'] = $this->getNextFilePart($fd, 1, 'files');
+                    $this->dat['files_fal'] = $this->getNextFilePart($fd, 1, 'files_fal');
+                }
+                $this->loadInit();
+                return true;
+            } else {
+                $this->error('Error opening file: ' . $filename);
+            }
+            fclose($fd);
+        }
+        return false;
+    }
+
+    /**
+     * Returns the next content part form the fileresource (t3d), $fd
+     *
+     * @param resource $fd File pointer
+     * @param bool $unserialize If set, the returned content is unserialized into an array, otherwise you get the raw string
+     * @param string $name For error messages this indicates the section of the problem.
+     * @return string|NULL Data string or NULL in case of an error
+     * @access private
+     * @see loadFile()
+     */
+    public function getNextFilePart($fd, $unserialize = false, $name = '')
+    {
+        $initStrLen = 32 + 1 + 1 + 1 + 10 + 1;
+        // Getting header data
+        $initStr = fread($fd, $initStrLen);
+        if (empty($initStr)) {
+            $this->error('File does not contain data for "' . $name . '"');
+            return null;
+        }
+        $initStrDat = explode(':', $initStr);
+        if (strstr($initStrDat[0], 'Warning')) {
+            $this->error('File read error: Warning message in file. (' . $initStr . fgets($fd) . ')');
+            return null;
+        }
+        if ((string)$initStrDat[3] !== '') {
+            $this->error('File read error: InitString had a wrong length. (' . $name . ')');
+            return null;
+        }
+        $datString = fread($fd, (int)$initStrDat[2]);
+        fread($fd, 1);
+        if (md5($datString) === $initStrDat[0]) {
+            if ($initStrDat[1]) {
+                if ($this->compress) {
+                    $datString = gzuncompress($datString);
+                    return $unserialize ? unserialize($datString) : $datString;
+                } else {
+                    $this->error('Content read error: This file requires decompression, but this server does not offer gzcompress()/gzuncompress() functions.');
+                }
+            }
+        } else {
+            $this->error('MD5 check failed (' . $name . ')');
+        }
+        return null;
+    }
+
+    /**
+     * Loads T3D file content into the $this->dat array
+     * (This function can be used to test the output strings from ->compileMemoryToFileContent())
+     *
+     * @param string $filecontent File content
+     * @return void
+     */
+    public function loadContent($filecontent)
+    {
+        $pointer = 0;
+        $this->dat['header'] = $this->getNextContentPart($filecontent, $pointer, 1, 'header');
+        $this->dat['records'] = $this->getNextContentPart($filecontent, $pointer, 1, 'records');
+        $this->dat['files'] = $this->getNextContentPart($filecontent, $pointer, 1, 'files');
+        $this->loadInit();
+    }
+
+    /**
+     * Returns the next content part from the $filecontent
+     *
+     * @param string $filecontent File content string
+     * @param int $pointer File pointer (where to read from)
+     * @param bool $unserialize If set, the returned content is unserialized into an array, otherwise you get the raw string
+     * @param string $name For error messages this indicates the section of the problem.
+     * @return string|NULL Data string
+     */
+    public function getNextContentPart($filecontent, &$pointer, $unserialize = false, $name = '')
+    {
+        $initStrLen = 32 + 1 + 1 + 1 + 10 + 1;
+        // getting header data
+        $initStr = substr($filecontent, $pointer, $initStrLen);
+        $pointer += $initStrLen;
+        $initStrDat = explode(':', $initStr);
+        if ((string)$initStrDat[3] !== '') {
+            $this->error('Content read error: InitString had a wrong length. (' . $name . ')');
+            return null;
+        }
+        $datString = substr($filecontent, $pointer, (int)$initStrDat[2]);
+        $pointer += (int)$initStrDat[2] + 1;
+        if (md5($datString) === $initStrDat[0]) {
+            if ($initStrDat[1]) {
+                if ($this->compress) {
+                    $datString = gzuncompress($datString);
+                    return $unserialize ? unserialize($datString) : $datString;
+                } else {
+                    $this->error('Content read error: This file requires decompression, but this server does not offer gzcompress()/gzuncompress() functions.');
+                }
+            }
+        } else {
+            $this->error('MD5 check failed (' . $name . ')');
+        }
+        return null;
+    }
+
+    /**
+     * Setting up the object based on the recently loaded ->dat array
+     *
+     * @return void
+     */
+    public function loadInit()
+    {
+        $this->relStaticTables = (array)$this->dat['header']['relStaticTables'];
+        $this->excludeMap = (array)$this->dat['header']['excludeMap'];
+        $this->softrefCfg = (array)$this->dat['header']['softrefCfg'];
+        $this->extensionDependencies = (array)$this->dat['header']['extensionDependencies'];
+        $this->fixCharsets();
+        if (
+            isset($this->dat['header']['meta']['TYPO3_version'])
+            && VersionNumberUtility::convertVersionNumberToInteger($this->dat['header']['meta']['TYPO3_version']) < 6000000
+        ) {
+            $this->legacyImport = true;
+            $this->initializeLegacyImportFolder();
+        }
+    }
+
+    /**
+     * Fix charset of import memory if different from system charset
+     *
+     * @return void
+     * @see loadInit()
+     */
+    public function fixCharsets()
+    {
+        $importCharset = $this->dat['header']['charset'];
+        if ($importCharset) {
+            if ($importCharset !== $this->getLanguageService()->charSet) {
+                $this->error('CHARSET: Converting charset of input file (' . $importCharset . ') to the system charset (' . $this->getLanguageService()->charSet . ')');
+                // Convert meta data:
+                if (is_array($this->dat['header']['meta'])) {
+                    $this->getLanguageService()->csConvObj->convArray($this->dat['header']['meta'], $importCharset, $this->getLanguageService()->charSet);
+                }
+                // Convert record headers:
+                if (is_array($this->dat['header']['records'])) {
+                    $this->getLanguageService()->csConvObj->convArray($this->dat['header']['records'], $importCharset, $this->getLanguageService()->charSet);
+                }
+                // Convert records themselves:
+                if (is_array($this->dat['records'])) {
+                    $this->getLanguageService()->csConvObj->convArray($this->dat['records'], $importCharset, $this->getLanguageService()->charSet);
+                }
+            }
+        } else {
+            $this->error('CHARSET: No charset found in import file!');
+        }
+    }
+}
diff --git a/typo3/sysext/impexp/Classes/ImportExport.php b/typo3/sysext/impexp/Classes/ImportExport.php
index c11515af61b0b738222adf6c436a19183b9651b4..3832a34217e2a50407df8c1f49ad96e7bd24854e 100644
--- a/typo3/sysext/impexp/Classes/ImportExport.php
+++ b/typo3/sysext/impexp/Classes/ImportExport.php
@@ -17,26 +17,14 @@ namespace TYPO3\CMS\Impexp;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Database\DatabaseConnection;
-use TYPO3\CMS\Core\Database\ReferenceIndex;
-use TYPO3\CMS\Core\DataHandling\DataHandler;
-use TYPO3\CMS\Core\Exception;
-use TYPO3\CMS\Core\Html\HtmlParser;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
-use TYPO3\CMS\Core\Resource\DuplicationBehavior;
-use TYPO3\CMS\Core\Resource\File;
-use TYPO3\CMS\Core\Resource\FileInterface;
-use TYPO3\CMS\Core\Resource\ResourceFactory;
-use TYPO3\CMS\Core\Resource\StorageRepository;
 use TYPO3\CMS\Core\Utility\DebugUtility;
 use TYPO3\CMS\Core\Utility\DiffUtility;
 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\File\ExtendedFileUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Core\Utility\MathUtility;
 use TYPO3\CMS\Core\Utility\PathUtility;
-use TYPO3\CMS\Core\Utility\StringUtility;
-use TYPO3\CMS\Core\Utility\VersionNumberUtility;
 use TYPO3\CMS\Lang\LanguageService;
 
 /**
@@ -72,7 +60,7 @@ use TYPO3\CMS\Lang\LanguageService;
 /**
  * T3D file Import/Export library (TYPO3 Record Document)
  */
-class ImportExport
+abstract class ImportExport
 {
     /**
      * If set, static relations (not exported) will be shown in overview as well
@@ -118,14 +106,6 @@ class ImportExport
      */
     public $display_import_pid_record = array();
 
-    /**
-     * Used to register the forged UID values for imported records that we want
-     * to create with the same UIDs as in the import file. Admin-only feature.
-     *
-     * @var array
-     */
-    public $suggestedInsertUids = array();
-
     /**
      * Setting import modes during update state: as_new, exclude, force_uid
      *
@@ -161,13 +141,6 @@ class ImportExport
      */
     public $allowPHPScripts = false;
 
-    /**
-     * Disable logging when importing
-     *
-     * @var bool
-     */
-    public $enableLogging = false;
-
     /**
      * Array of values to substitute in editable softreferences.
      *
@@ -183,3243 +156,123 @@ class ImportExport
     public $fileIDMap = array();
 
     /**
-     * 1MB max file size
-     *
-     * @var int
-     */
-    public $maxFileSize = 1000000;
-
-    /**
-     * 1MB max record size
-     *
-     * @var int
-     */
-    public $maxRecordSize = 1000000;
-
-    /**
-     * 10MB max export size
-     *
-     * @var int
-     */
-    public $maxExportSize = 10000000;
-
-    /**
-     * Add table names here which are THE ONLY ones which will be included
-     * into export if found as relations. '_ALL' will allow all tables.
-     *
-     * @var array
-     */
-    public $relOnlyTables = array();
-
-    /**
-     * Add tables names here which should not be exported with the file.
-     * (Where relations should be mapped to same UIDs in target system).
-     *
-     * @var array
-     */
-    public $relStaticTables = array();
-
-    /**
-     * Exclude map. Keys are table:uid  pairs and if set, records are not added to the export.
-     *
-     * @var array
-     */
-    public $excludeMap = array();
-
-    /**
-     * Soft Reference Token ID modes.
-     *
-     * @var array
-     */
-    public $softrefCfg = array();
-
-    /**
-     * Listing extension dependencies.
-     *
-     * @var array
-     */
-    public $extensionDependencies = array();
-
-    /**
-     * Set  by user: If set, compression in t3d files is disabled
-     *
-     * @var bool
-     */
-    public $dontCompress = false;
-
-    /**
-     * If set, HTML file resources are included.
-     *
-     * @var bool
-     */
-    public $includeExtFileResources = false;
-
-    /**
-     * Files with external media (HTML/css style references inside)
-     *
-     * @var string
-     */
-    public $extFileResourceExtensions = 'html,htm,css';
-
-    /**
-     * After records are written this array is filled with [table][original_uid] = [new_uid]
-     *
-     * @var array
-     */
-    public $import_mapId = array();
-
-    /**
-     * Keys are [tablename]:[new NEWxxx ids (or when updating it is uids)]
-     * while values are arrays with table/uid of the original record it is based on.
-     * With the array keys the new ids can be looked up inside tcemain
-     *
-     * @var array
-     */
-    public $import_newId = array();
-
-    /**
-     * Page id map for page tree (import)
-     *
-     * @var array
-     */
-    public $import_newId_pids = array();
-
-    /**
-     * Internal data accumulation for writing records during import
-     *
-     * @var array
-     */
-    public $import_data = array();
-
-    /**
-     * Error log.
-     *
-     * @var array
-     */
-    public $errorLog = array();
-
-    /**
-     * Cache for record paths
-     *
-     * @var array
-     */
-    public $cache_getRecordPath = array();
-
-    /**
-     * Cache of checkPID values.
-     *
-     * @var array
-     */
-    public $checkPID_cache = array();
-
-    /**
-     * Set internally if the gzcompress function exists
-     * Used by ImportExportController
-     *
-     * @var bool
-     */
-    public $compress = false;
-
-    /**
-     * Internal import/export memory
-     *
-     * @var array
-     */
-    public $dat = array();
-
-    /**
-     * File processing object
-     *
-     * @var ExtendedFileUtility
-     */
-    protected $fileProcObj = null;
-
-    /**
-     * Keys are [recordname], values are an array of fields to be included
-     * in the export
-     *
-     * @var array
-     */
-    protected $recordTypesIncludeFields = array();
-
-    /**
-     * Default array of fields to be included in the export
-     *
-     * @var array
-     */
-    protected $defaultRecordIncludeFields = array('uid', 'pid');
-
-    /**
-     * Array of current registered storage objects
-     *
-     * @var array
-     */
-    protected $storageObjects = array();
-
-    /**
-     * Is set, if the import file has a TYPO3 version below 6.0
-     *
-     * @var bool
-     */
-    protected $legacyImport = false;
-
-    /**
-     * @var \TYPO3\CMS\Core\Resource\Folder
-     */
-    protected $legacyImportFolder = null;
-
-    /**
-     * Related to the default storage root
-     *
-     * @var string
-     */
-    protected $legacyImportTargetPath = '_imported/';
-
-    /**
-     * Table fields to migrate
-     *
-     * @var array
-     */
-    protected $legacyImportMigrationTables = array(
-        'tt_content' => array(
-            'image' => array(
-                'titleTexts' => 'titleText',
-                'description' => 'imagecaption',
-                'links' => 'image_link',
-                'alternativeTexts' => 'altText'
-            ),
-            'media' => array(
-                'description' => 'imagecaption',
-            )
-        ),
-        'pages' => array(
-            'media' => array()
-        ),
-        'pages_language_overlay' => array(
-            'media' => array()
-        )
-    );
-
-    /**
-     * Records to be migrated after all
-     * Multidimensional array [table][uid][field] = array([related sys_file_reference uids])
-     *
-     * @var array
-     */
-    protected $legacyImportMigrationRecords = array();
-
-    /**
-     * @var bool
-     */
-    protected $saveFilesOutsideExportFile = false;
-
-    /**
-     * @var NULL|string
-     */
-    protected $temporaryFilesPathForExport = null;
-
-    /**
-     * @var NULL|string
-     */
-    protected $filesPathForImport = null;
-
-    /**
-     * @var array
-     */
-    protected $unlinkFiles = array();
-
-    /**
-     * @var array
-     */
-    protected $alternativeFileName = array();
-
-    /**
-     * @var array
-     */
-    protected $alternativeFilePath = array();
-
-    /**
-     * @var array
-     */
-    protected $filePathMap = array();
-
-    /**
-     * @var array
-     */
-    protected $remainHeader = array();
-
-    /**
-     * @var IconFactory
-     */
-    protected $iconFactory;
-
-    /**
-     * The constructor
-     */
-    public function __construct()
-    {
-        $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
-    }
-
-    /**************************
-     * Initialize
-     *************************/
-
-    /**
-     * Init the object, both import and export
-     *
-     * @param bool $dontCompress If set, compression of t3d files is disabled
-     * @param string $mode Mode of usage, either "import" or "export
-     * @return void
-     */
-    public function init($dontCompress = false, $mode = '')
-    {
-        $this->compress = function_exists('gzcompress');
-        $this->dontCompress = $dontCompress;
-        $this->mode = $mode;
-        $this->fileadminFolderName = !empty($GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir']) ? rtrim($GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'], '/') : 'fileadmin';
-    }
-
-    /**************************
-     * Export / Init + Meta Data
-     *************************/
-
-    /**
-     * Set header basics
-     *
-     * @return void
-     */
-    public function setHeaderBasics()
-    {
-        // Initializing:
-        if (is_array($this->softrefCfg)) {
-            foreach ($this->softrefCfg as $key => $value) {
-                if (!strlen($value['mode'])) {
-                    unset($this->softrefCfg[$key]);
-                }
-            }
-        }
-        // Setting in header memory:
-        // Version of file format
-        $this->dat['header']['XMLversion'] = '1.0';
-        // Initialize meta data array (to put it in top of file)
-        $this->dat['header']['meta'] = array();
-        // Add list of tables to consider static
-        $this->dat['header']['relStaticTables'] = $this->relStaticTables;
-        // The list of excluded records
-        $this->dat['header']['excludeMap'] = $this->excludeMap;
-        // Soft Reference mode for elements
-        $this->dat['header']['softrefCfg'] = $this->softrefCfg;
-        // List of extensions the import depends on.
-        $this->dat['header']['extensionDependencies'] = $this->extensionDependencies;
-    }
-
-    /**
-     * Set charset
-     *
-     * @param string $charset Charset for the content in the export. During import the character set will be converted if the target system uses another charset.
-     * @return void
-     */
-    public function setCharset($charset)
-    {
-        $this->dat['header']['charset'] = $charset;
-    }
-
-    /**
-     * Sets meta data
-     *
-     * @param string $title Title of the export
-     * @param string $description Description of the export
-     * @param string $notes Notes about the contents
-     * @param string $packager_username Backend Username of the packager (the guy making the export)
-     * @param string $packager_name Real name of the packager
-     * @param string $packager_email Email of the packager
-     * @return void
-     */
-    public function setMetaData($title, $description, $notes, $packager_username, $packager_name, $packager_email)
-    {
-        $this->dat['header']['meta'] = array(
-            'title' => $title,
-            'description' => $description,
-            'notes' => $notes,
-            'packager_username' => $packager_username,
-            'packager_name' => $packager_name,
-            'packager_email' => $packager_email,
-            'TYPO3_version' => TYPO3_version,
-            'created' => strftime('%A %e. %B %Y', $GLOBALS['EXEC_TIME'])
-        );
-    }
-
-    /**
-     * Option to enable having the files not included in the export file.
-     * The files are saved to a temporary folder instead.
-     *
-     * @param bool $saveFilesOutsideExportFile
-     * @see getTemporaryFilesPathForExport()
-     */
-    public function setSaveFilesOutsideExportFile($saveFilesOutsideExportFile)
-    {
-        $this->saveFilesOutsideExportFile = $saveFilesOutsideExportFile;
-    }
-
-    /**************************
-     * Export / Init Page tree
-     *************************/
-
-    /**
-     * Sets the page-tree array in the export header and returns the array in a flattened version
-     *
-     * @param array $idH Hierarchy of ids, the page tree: array([uid] => array("uid" => [uid], "subrow" => array(.....)), [uid] => ....)
-     * @return array The hierarchical page tree converted to a one-dimensional list of pages
-     */
-    public function setPageTree($idH)
-    {
-        $this->dat['header']['pagetree'] = $this->unsetExcludedSections($idH);
-        return $this->flatInversePageTree($this->dat['header']['pagetree']);
-    }
-
-    /**
-     * Removes entries in the page tree which are found in ->excludeMap[]
-     *
-     * @param array $idH Page uid hierarchy
-     * @return array Modified input array
-     * @access private
-     * @see setPageTree()
-     */
-    public function unsetExcludedSections($idH)
-    {
-        if (is_array($idH)) {
-            foreach ($idH as $k => $v) {
-                if ($this->excludeMap['pages:' . $idH[$k]['uid']]) {
-                    unset($idH[$k]);
-                } elseif (is_array($idH[$k]['subrow'])) {
-                    $idH[$k]['subrow'] = $this->unsetExcludedSections($idH[$k]['subrow']);
-                }
-            }
-        }
-        return $idH;
-    }
-
-    /**
-     * Recursively flattening the idH array (for setPageTree() function)
-     *
-     * @param array $idH Page uid hierarchy
-     * @param array $a Accumulation array of pages (internal, don't set from outside)
-     * @return array Array with uid-uid pairs for all pages in the page tree.
-     * @see flatInversePageTree_pid()
-     */
-    public function flatInversePageTree($idH, $a = array())
-    {
-        if (is_array($idH)) {
-            $idH = array_reverse($idH);
-            foreach ($idH as $k => $v) {
-                $a[$v['uid']] = $v['uid'];
-                if (is_array($v['subrow'])) {
-                    $a = $this->flatInversePageTree($v['subrow'], $a);
-                }
-            }
-        }
-        return $a;
-    }
-
-    /**
-     * Recursively flattening the idH array (for setPageTree() function), setting PIDs as values
-     *
-     * @param array $idH Page uid hierarchy
-     * @param array $a Accumulation array of pages (internal, don't set from outside)
-     * @param int $pid PID value (internal)
-     * @return array Array with uid-pid pairs for all pages in the page tree.
-     * @see flatInversePageTree()
-     */
-    public function flatInversePageTree_pid($idH, $a = array(), $pid = -1)
-    {
-        if (is_array($idH)) {
-            $idH = array_reverse($idH);
-            foreach ($idH as $v) {
-                $a[$v['uid']] = $pid;
-                if (is_array($v['subrow'])) {
-                    $a = $this->flatInversePageTree_pid($v['subrow'], $a, $v['uid']);
-                }
-            }
-        }
-        return $a;
-    }
-
-    /**************************
-     * Export
-     *************************/
-
-    /**
-     * Sets the fields of record types to be included in the export
-     *
-     * @param array $recordTypesIncludeFields Keys are [recordname], values are an array of fields to be included in the export
-     * @throws Exception if an array value is not type of array
-     * @return void
-     */
-    public function setRecordTypesIncludeFields(array $recordTypesIncludeFields)
-    {
-        foreach ($recordTypesIncludeFields as $table => $fields) {
-            if (!is_array($fields)) {
-                throw new Exception('The include fields for record type ' . htmlspecialchars($table) . ' are not defined by an array.', 1391440658);
-            }
-            $this->setRecordTypeIncludeFields($table, $fields);
-        }
-    }
-
-    /**
-     * Sets the fields of a record type to be included in the export
-     *
-     * @param string $table The record type
-     * @param array $fields The fields to be included
-     * @return void
-     */
-    public function setRecordTypeIncludeFields($table, array $fields)
-    {
-        $this->recordTypesIncludeFields[$table] = $fields;
-    }
-
-    /**
-     * Adds the record $row from $table.
-     * No checking for relations done here. Pure data.
-     *
-     * @param string $table Table name
-     * @param array $row Record row.
-     * @param int $relationLevel (Internal) if the record is added as a relation, this is set to the "level" it was on.
-     * @return void
-     */
-    public function export_addRecord($table, $row, $relationLevel = 0)
-    {
-        BackendUtility::workspaceOL($table, $row);
-        if ((string)$table !== '' && is_array($row) && $row['uid'] > 0 && !$this->excludeMap[$table . ':' . $row['uid']]) {
-            if ($this->checkPID($table === 'pages' ? $row['uid'] : $row['pid'])) {
-                if (!isset($this->dat['records'][$table . ':' . $row['uid']])) {
-                    // Prepare header info:
-                    $row = $this->filterRecordFields($table, $row);
-                    $headerInfo = array();
-                    $headerInfo['uid'] = $row['uid'];
-                    $headerInfo['pid'] = $row['pid'];
-                    $headerInfo['title'] = GeneralUtility::fixed_lgd_cs(BackendUtility::getRecordTitle($table, $row), 40);
-                    $headerInfo['size'] = strlen(serialize($row));
-                    if ($relationLevel) {
-                        $headerInfo['relationLevel'] = $relationLevel;
-                    }
-                    // If record content is not too large in size, set the header content and add the rest:
-                    if ($headerInfo['size'] < $this->maxRecordSize) {
-                        // Set the header summary:
-                        $this->dat['header']['records'][$table][$row['uid']] = $headerInfo;
-                        // Create entry in the PID lookup:
-                        $this->dat['header']['pid_lookup'][$row['pid']][$table][$row['uid']] = 1;
-                        // Initialize reference index object:
-                        $refIndexObj = GeneralUtility::makeInstance(ReferenceIndex::class);
-                        // Yes to workspace overlays for exporting....
-                        $refIndexObj->WSOL = true;
-                        $relations = $refIndexObj->getRelations($table, $row);
-                        $relations = $this->fixFileIDsInRelations($relations);
-                        $relations = $this->removeSoftrefsHavingTheSameDatabaseRelation($relations);
-                        // Data:
-                        $this->dat['records'][$table . ':' . $row['uid']] = array();
-                        $this->dat['records'][$table . ':' . $row['uid']]['data'] = $row;
-                        $this->dat['records'][$table . ':' . $row['uid']]['rels'] = $relations;
-                        // Add information about the relations in the record in the header:
-                        $this->dat['header']['records'][$table][$row['uid']]['rels'] = $this->flatDBrels($this->dat['records'][$table . ':' . $row['uid']]['rels']);
-                        // Add information about the softrefs to header:
-                        $this->dat['header']['records'][$table][$row['uid']]['softrefs'] = $this->flatSoftRefs($this->dat['records'][$table . ':' . $row['uid']]['rels']);
-                    } else {
-                        $this->error('Record ' . $table . ':' . $row['uid'] . ' was larger than maxRecordSize (' . GeneralUtility::formatSize($this->maxRecordSize) . ')');
-                    }
-                } else {
-                    $this->error('Record ' . $table . ':' . $row['uid'] . ' already added.');
-                }
-            } else {
-                $this->error('Record ' . $table . ':' . $row['uid'] . ' was outside your DB mounts!');
-            }
-        }
-    }
-
-    /**
-     * This changes the file reference ID from a hash based on the absolute file path
-     * (coming from ReferenceIndex) to a hash based on the relative file path.
-     *
-     * @param array $relations
-     * @return array
-     */
-    protected function fixFileIDsInRelations(array $relations)
-    {
-        foreach ($relations as $field => $relation) {
-            if (isset($relation['type']) && $relation['type'] === 'file') {
-                foreach ($relation['newValueFiles'] as $key => $fileRelationData) {
-                    $absoluteFilePath = $fileRelationData['ID_absFile'];
-                    if (GeneralUtility::isFirstPartOfStr($absoluteFilePath, PATH_site)) {
-                        $relatedFilePath = PathUtility::stripPathSitePrefix($absoluteFilePath);
-                        $relations[$field]['newValueFiles'][$key]['ID'] = md5($relatedFilePath);
-                    }
-                }
-            }
-            if ($relation['type'] === 'flex') {
-                if (is_array($relation['flexFormRels']['file'])) {
-                    foreach ($relation['flexFormRels']['file'] as $key => $subList) {
-                        foreach ($subList as $subKey => $fileRelationData) {
-                            $absoluteFilePath = $fileRelationData['ID_absFile'];
-                            if (GeneralUtility::isFirstPartOfStr($absoluteFilePath, PATH_site)) {
-                                $relatedFilePath = PathUtility::stripPathSitePrefix($absoluteFilePath);
-                                $relations[$field]['flexFormRels']['file'][$key][$subKey]['ID'] = md5($relatedFilePath);
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        return $relations;
-    }
-
-    /**
-     * Relations could contain db relations to sys_file records. Some configuration combinations of TCA and
-     * SoftReferenceIndex create also softref relation entries for the identical file. This results
-     * in double included files, one in array "files" and one in array "file_fal".
-     * This function checks the relations for this double inclusions and removes the redundant softref relation.
-     *
-     * @param array $relations
-     * @return array
-     */
-    protected function removeSoftrefsHavingTheSameDatabaseRelation($relations)
-    {
-        $fixedRelations = array();
-        foreach ($relations as $field => $relation) {
-            $newRelation = $relation;
-            if (isset($newRelation['type']) && $newRelation['type'] === 'db') {
-                foreach ($newRelation['itemArray'] as $key => $dbRelationData) {
-                    if ($dbRelationData['table'] === 'sys_file') {
-                        if (isset($newRelation['softrefs']['keys']['typolink'])) {
-                            foreach ($newRelation['softrefs']['keys']['typolink'] as $softrefKey => $softRefData) {
-                                if ($softRefData['subst']['type'] === 'file') {
-                                    $file = ResourceFactory::getInstance()->retrieveFileOrFolderObject($softRefData['subst']['relFileName']);
-                                    if ($file instanceof File) {
-                                        if ($file->getUid() == $dbRelationData['id']) {
-                                            unset($newRelation['softrefs']['keys']['typolink'][$softrefKey]);
-                                        }
-                                    }
-                                }
-                            }
-                            if (empty($newRelation['softrefs']['keys']['typolink'])) {
-                                unset($newRelation['softrefs']);
-                            }
-                        }
-                    }
-                }
-            }
-            $fixedRelations[$field] = $newRelation;
-        }
-        return $fixedRelations;
-    }
-
-    /**
-     * This analyses the existing added records, finds all database relations to records and adds these records to the export file.
-     * This function can be called repeatedly until it returns an empty array.
-     * In principle it should not allow to infinite recursivity, but you better set a limit...
-     * Call this BEFORE the ext_addFilesFromRelations (so files from added relations are also included of course)
-     *
-     * @param int $relationLevel Recursion level
-     * @return array overview of relations found and added: Keys [table]:[uid], values array with table and id
-     * @see export_addFilesFromRelations()
-     */
-    public function export_addDBRelations($relationLevel = 0)
-    {
-        // Traverse all "rels" registered for "records"
-        if (!is_array($this->dat['records'])) {
-            $this->error('There were no records available.');
-            return array();
-        }
-        $addR = array();
-        foreach ($this->dat['records'] as $k => $value) {
-            if (!is_array($this->dat['records'][$k])) {
-                continue;
-            }
-            foreach ($this->dat['records'][$k]['rels'] as $fieldname => $vR) {
-                // For all DB types of relations:
-                if ($vR['type'] == 'db') {
-                    foreach ($vR['itemArray'] as $fI) {
-                        $this->export_addDBRelations_registerRelation($fI, $addR);
-                    }
-                }
-                // For all flex/db types of relations:
-                if ($vR['type'] == 'flex') {
-                    // DB relations in flex form fields:
-                    if (is_array($vR['flexFormRels']['db'])) {
-                        foreach ($vR['flexFormRels']['db'] as $subList) {
-                            foreach ($subList as $fI) {
-                                $this->export_addDBRelations_registerRelation($fI, $addR);
-                            }
-                        }
-                    }
-                    // DB oriented soft references in flex form fields:
-                    if (is_array($vR['flexFormRels']['softrefs'])) {
-                        foreach ($vR['flexFormRels']['softrefs'] as $subList) {
-                            foreach ($subList['keys'] as $spKey => $elements) {
-                                foreach ($elements as $el) {
-                                    if ($el['subst']['type'] === 'db' && $this->includeSoftref($el['subst']['tokenID'])) {
-                                        list($tempTable, $tempUid) = explode(':', $el['subst']['recordRef']);
-                                        $fI = array(
-                                            'table' => $tempTable,
-                                            'id' => $tempUid
-                                        );
-                                        $this->export_addDBRelations_registerRelation($fI, $addR, $el['subst']['tokenID']);
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-                // In any case, if there are soft refs:
-                if (is_array($vR['softrefs']['keys'])) {
-                    foreach ($vR['softrefs']['keys'] as $spKey => $elements) {
-                        foreach ($elements as $el) {
-                            if ($el['subst']['type'] === 'db' && $this->includeSoftref($el['subst']['tokenID'])) {
-                                list($tempTable, $tempUid) = explode(':', $el['subst']['recordRef']);
-                                $fI = array(
-                                    'table' => $tempTable,
-                                    'id' => $tempUid
-                                );
-                                $this->export_addDBRelations_registerRelation($fI, $addR, $el['subst']['tokenID']);
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        // Now, if there were new records to add, do so:
-        if (!empty($addR)) {
-            foreach ($addR as $fI) {
-                // Get and set record:
-                $row = BackendUtility::getRecord($fI['table'], $fI['id']);
-                if (is_array($row)) {
-                    $this->export_addRecord($fI['table'], $row, $relationLevel + 1);
-                }
-                // Set status message
-                // Relation pointers always larger than zero except certain "select" types with
-                // negative values pointing to uids - but that is not supported here.
-                if ($fI['id'] > 0) {
-                    $rId = $fI['table'] . ':' . $fI['id'];
-                    if (!isset($this->dat['records'][$rId])) {
-                        $this->dat['records'][$rId] = 'NOT_FOUND';
-                        $this->error('Relation record ' . $rId . ' was not found!');
-                    }
-                }
-            }
-        }
-        // Return overview of relations found and added
-        return $addR;
-    }
-
-    /**
-     * Helper function for export_addDBRelations()
-     *
-     * @param array $fI Array with table/id keys to add
-     * @param array $addR Add array, passed by reference to be modified
-     * @param string $tokenID Softref Token ID, if applicable.
-     * @return void
-     * @see export_addDBRelations()
-     */
-    public function export_addDBRelations_registerRelation($fI, &$addR, $tokenID = '')
-    {
-        $rId = $fI['table'] . ':' . $fI['id'];
-        if (
-            isset($GLOBALS['TCA'][$fI['table']]) && !$this->isTableStatic($fI['table']) && !$this->isExcluded($fI['table'], $fI['id'])
-            && (!$tokenID || $this->includeSoftref($tokenID)) && $this->inclRelation($fI['table'])
-        ) {
-            if (!isset($this->dat['records'][$rId])) {
-                // Set this record to be included since it is not already.
-                $addR[$rId] = $fI;
-            }
-        }
-    }
-
-    /**
-     * This adds all files in relations.
-     * Call this method AFTER adding all records including relations.
-     *
-     * @return void
-     * @see export_addDBRelations()
-     */
-    public function export_addFilesFromRelations()
-    {
-        // Traverse all "rels" registered for "records"
-        if (!is_array($this->dat['records'])) {
-            $this->error('There were no records available.');
-            return;
-        }
-        foreach ($this->dat['records'] as $k => $value) {
-            if (!isset($this->dat['records'][$k]['rels']) || !is_array($this->dat['records'][$k]['rels'])) {
-                continue;
-            }
-            foreach ($this->dat['records'][$k]['rels'] as $fieldname => $vR) {
-                // For all file type relations:
-                if ($vR['type'] == 'file') {
-                    foreach ($vR['newValueFiles'] as $key => $fI) {
-                        $this->export_addFile($fI, $k, $fieldname);
-                        // Remove the absolute reference to the file so it doesn't expose absolute paths from source server:
-                        unset($this->dat['records'][$k]['rels'][$fieldname]['newValueFiles'][$key]['ID_absFile']);
-                    }
-                }
-                // For all flex type relations:
-                if ($vR['type'] == 'flex') {
-                    if (is_array($vR['flexFormRels']['file'])) {
-                        foreach ($vR['flexFormRels']['file'] as $key => $subList) {
-                            foreach ($subList as $subKey => $fI) {
-                                $this->export_addFile($fI, $k, $fieldname);
-                                // Remove the absolute reference to the file so it doesn't expose absolute paths from source server:
-                                unset($this->dat['records'][$k]['rels'][$fieldname]['flexFormRels']['file'][$key][$subKey]['ID_absFile']);
-                            }
-                        }
-                    }
-                    // DB oriented soft references in flex form fields:
-                    if (is_array($vR['flexFormRels']['softrefs'])) {
-                        foreach ($vR['flexFormRels']['softrefs'] as $key => $subList) {
-                            foreach ($subList['keys'] as $spKey => $elements) {
-                                foreach ($elements as $subKey => $el) {
-                                    if ($el['subst']['type'] === 'file' && $this->includeSoftref($el['subst']['tokenID'])) {
-                                        // Create abs path and ID for file:
-                                        $ID_absFile = GeneralUtility::getFileAbsFileName(PATH_site . $el['subst']['relFileName']);
-                                        $ID = md5($el['subst']['relFileName']);
-                                        if ($ID_absFile) {
-                                            if (!$this->dat['files'][$ID]) {
-                                                $fI = array(
-                                                    'filename' => PathUtility::basename($ID_absFile),
-                                                    'ID_absFile' => $ID_absFile,
-                                                    'ID' => $ID,
-                                                    'relFileName' => $el['subst']['relFileName']
-                                                );
-                                                $this->export_addFile($fI, '_SOFTREF_');
-                                            }
-                                            $this->dat['records'][$k]['rels'][$fieldname]['flexFormRels']['softrefs'][$key]['keys'][$spKey][$subKey]['file_ID'] = $ID;
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-                // In any case, if there are soft refs:
-                if (is_array($vR['softrefs']['keys'])) {
-                    foreach ($vR['softrefs']['keys'] as $spKey => $elements) {
-                        foreach ($elements as $subKey => $el) {
-                            if ($el['subst']['type'] === 'file' && $this->includeSoftref($el['subst']['tokenID'])) {
-                                // Create abs path and ID for file:
-                                $ID_absFile = GeneralUtility::getFileAbsFileName(PATH_site . $el['subst']['relFileName']);
-                                $ID = md5($el['subst']['relFileName']);
-                                if ($ID_absFile) {
-                                    if (!$this->dat['files'][$ID]) {
-                                        $fI = array(
-                                            'filename' => PathUtility::basename($ID_absFile),
-                                            'ID_absFile' => $ID_absFile,
-                                            'ID' => $ID,
-                                            'relFileName' => $el['subst']['relFileName']
-                                        );
-                                        $this->export_addFile($fI, '_SOFTREF_');
-                                    }
-                                    $this->dat['records'][$k]['rels'][$fieldname]['softrefs']['keys'][$spKey][$subKey]['file_ID'] = $ID;
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * This adds all files from sys_file records
-     *
-     * @return void
-     */
-    public function export_addFilesFromSysFilesRecords()
-    {
-        if (!isset($this->dat['header']['records']['sys_file']) || !is_array($this->dat['header']['records']['sys_file'])) {
-            return;
-        }
-        foreach ($this->dat['header']['records']['sys_file'] as $sysFileUid => $_) {
-            $recordData = $this->dat['records']['sys_file:' . $sysFileUid]['data'];
-            $file = ResourceFactory::getInstance()->createFileObject($recordData);
-            $this->export_addSysFile($file);
-        }
-    }
-
-    /**
-     * Adds a files content from a sys file record to the export memory
-     *
-     * @param File $file
-     * @return void
-     */
-    public function export_addSysFile(File $file)
-    {
-        if ($file->getProperty('size') >= $this->maxFileSize) {
-            $this->error('File ' . $file->getPublicUrl() . ' was larger (' . GeneralUtility::formatSize($file->getProperty('size')) . ') than the maxFileSize (' . GeneralUtility::formatSize($this->maxFileSize) . ')! Skipping.');
-            return;
-        }
-        $fileContent = '';
-        try {
-            if (!$this->saveFilesOutsideExportFile) {
-                $fileContent = $file->getContents();
-            } else {
-                $file->checkActionPermission('read');
-            }
-        } catch (\Exception $e) {
-            $this->error('Error when trying to add file ' . $file->getCombinedIdentifier() . ': ' . $e->getMessage());
-            return;
-        }
-        $fileUid = $file->getUid();
-        $fileInfo = $file->getStorage()->getFileInfo($file);
-        // we sadly have to cast it to string here, because the size property is also returning a string
-        $fileSize = (string)$fileInfo['size'];
-        if ($fileSize !== $file->getProperty('size')) {
-            $this->error('File size of ' . $file->getCombinedIdentifier() . ' is not up-to-date in index! File added with current size.');
-            $this->dat['records']['sys_file:' . $fileUid]['data']['size'] = $fileSize;
-        }
-        $fileSha1 = $file->getStorage()->hashFile($file, 'sha1');
-        if ($fileSha1 !== $file->getProperty('sha1')) {
-            $this->error('File sha1 hash of ' . $file->getCombinedIdentifier() . ' is not up-to-date in index! File added on current sha1.');
-            $this->dat['records']['sys_file:' . $fileUid]['data']['sha1'] = $fileSha1;
-        }
-
-        $fileRec = array();
-        $fileRec['filesize'] = $fileSize;
-        $fileRec['filename'] = $file->getProperty('name');
-        $fileRec['filemtime'] = $file->getProperty('modification_date');
-
-        // build unique id based on the storage and the file identifier
-        $fileId = md5($file->getStorage()->getUid() . ':' . $file->getProperty('identifier_hash'));
-
-        // Setting this data in the header
-        $this->dat['header']['files_fal'][$fileId] = $fileRec;
-
-        if (!$this->saveFilesOutsideExportFile) {
-            // ... and finally add the heavy stuff:
-            $fileRec['content'] = $fileContent;
-        } else {
-            GeneralUtility::upload_copy_move($file->getForLocalProcessing(false), $this->getTemporaryFilesPathForExport() . $file->getProperty('sha1'));
-        }
-        $fileRec['content_sha1'] = $fileSha1;
-
-        $this->dat['files_fal'][$fileId] = $fileRec;
-    }
-
-    /**
-     * Adds a files content to the export memory
-     *
-     * @param array $fI File information with three keys: "filename" = filename without path, "ID_absFile" = absolute filepath to the file (including the filename), "ID" = md5 hash of "ID_absFile". "relFileName" is optional for files attached to records, but mandatory for soft referenced files (since the relFileName determines where such a file should be stored!)
-     * @param string $recordRef If the file is related to a record, this is the id on the form [table]:[id]. Information purposes only.
-     * @param string $fieldname If the file is related to a record, this is the field name it was related to. Information purposes only.
-     * @return void
-     */
-    public function export_addFile($fI, $recordRef = '', $fieldname = '')
-    {
-        if (!@is_file($fI['ID_absFile'])) {
-            $this->error($fI['ID_absFile'] . ' was not a file! Skipping.');
-            return;
-        }
-        if (filesize($fI['ID_absFile']) >= $this->maxFileSize) {
-            $this->error($fI['ID_absFile'] . ' was larger (' . GeneralUtility::formatSize(filesize($fI['ID_absFile'])) . ') than the maxFileSize (' . GeneralUtility::formatSize($this->maxFileSize) . ')! Skipping.');
-            return;
-        }
-        $fileInfo = stat($fI['ID_absFile']);
-        $fileRec = array();
-        $fileRec['filesize'] = $fileInfo['size'];
-        $fileRec['filename'] = PathUtility::basename($fI['ID_absFile']);
-        $fileRec['filemtime'] = $fileInfo['mtime'];
-        //for internal type file_reference
-        $fileRec['relFileRef'] = PathUtility::stripPathSitePrefix($fI['ID_absFile']);
-        if ($recordRef) {
-            $fileRec['record_ref'] = $recordRef . '/' . $fieldname;
-        }
-        if ($fI['relFileName']) {
-            $fileRec['relFileName'] = $fI['relFileName'];
-        }
-        // Setting this data in the header
-        $this->dat['header']['files'][$fI['ID']] = $fileRec;
-        // ... and for the recordlisting, why not let us know WHICH relations there was...
-        if ($recordRef && $recordRef !== '_SOFTREF_') {
-            $refParts = explode(':', $recordRef, 2);
-            if (!is_array($this->dat['header']['records'][$refParts[0]][$refParts[1]]['filerefs'])) {
-                $this->dat['header']['records'][$refParts[0]][$refParts[1]]['filerefs'] = array();
-            }
-            $this->dat['header']['records'][$refParts[0]][$refParts[1]]['filerefs'][] = $fI['ID'];
-        }
-        $fileMd5 = md5_file($fI['ID_absFile']);
-        if (!$this->saveFilesOutsideExportFile) {
-            // ... and finally add the heavy stuff:
-            $fileRec['content'] = GeneralUtility::getUrl($fI['ID_absFile']);
-        } else {
-            GeneralUtility::upload_copy_move($fI['ID_absFile'], $this->getTemporaryFilesPathForExport() . $fileMd5);
-        }
-        $fileRec['content_md5'] = $fileMd5;
-        $this->dat['files'][$fI['ID']] = $fileRec;
-        // For soft references, do further processing:
-        if ($recordRef === '_SOFTREF_') {
-            // RTE files?
-            if ($RTEoriginal = $this->getRTEoriginalFilename(PathUtility::basename($fI['ID_absFile']))) {
-                $RTEoriginal_absPath = PathUtility::dirname($fI['ID_absFile']) . '/' . $RTEoriginal;
-                if (@is_file($RTEoriginal_absPath)) {
-                    $RTEoriginal_ID = md5($RTEoriginal_absPath);
-                    $fileInfo = stat($RTEoriginal_absPath);
-                    $fileRec = array();
-                    $fileRec['filesize'] = $fileInfo['size'];
-                    $fileRec['filename'] = PathUtility::basename($RTEoriginal_absPath);
-                    $fileRec['filemtime'] = $fileInfo['mtime'];
-                    $fileRec['record_ref'] = '_RTE_COPY_ID:' . $fI['ID'];
-                    $this->dat['header']['files'][$fI['ID']]['RTE_ORIG_ID'] = $RTEoriginal_ID;
-                    // Setting this data in the header
-                    $this->dat['header']['files'][$RTEoriginal_ID] = $fileRec;
-                    $fileMd5 = md5_file($RTEoriginal_absPath);
-                    if (!$this->saveFilesOutsideExportFile) {
-                        // ... and finally add the heavy stuff:
-                        $fileRec['content'] = GeneralUtility::getUrl($RTEoriginal_absPath);
-                    } else {
-                        GeneralUtility::upload_copy_move($RTEoriginal_absPath, $this->getTemporaryFilesPathForExport() . $fileMd5);
-                    }
-                    $fileRec['content_md5'] = $fileMd5;
-                    $this->dat['files'][$RTEoriginal_ID] = $fileRec;
-                } else {
-                    $this->error('RTE original file "' . PathUtility::stripPathSitePrefix($RTEoriginal_absPath) . '" was not found!');
-                }
-            }
-            // Files with external media?
-            // This is only done with files grabbed by a softreference parser since it is deemed improbable that hard-referenced files should undergo this treatment.
-            $html_fI = pathinfo(PathUtility::basename($fI['ID_absFile']));
-            if ($this->includeExtFileResources && GeneralUtility::inList($this->extFileResourceExtensions, strtolower($html_fI['extension']))) {
-                $uniquePrefix = '###' . md5($GLOBALS['EXEC_TIME']) . '###';
-                if (strtolower($html_fI['extension']) === 'css') {
-                    $prefixedMedias = explode($uniquePrefix, preg_replace('/(url[[:space:]]*\\([[:space:]]*["\']?)([^"\')]*)(["\']?[[:space:]]*\\))/i', '\\1' . $uniquePrefix . '\\2' . $uniquePrefix . '\\3', $fileRec['content']));
-                } else {
-                    // html, htm:
-                    $htmlParser = GeneralUtility::makeInstance(HtmlParser::class);
-                    $prefixedMedias = explode($uniquePrefix, $htmlParser->prefixResourcePath($uniquePrefix, $fileRec['content'], array(), $uniquePrefix));
-                }
-                $htmlResourceCaptured = false;
-                foreach ($prefixedMedias as $k => $v) {
-                    if ($k % 2) {
-                        $EXTres_absPath = GeneralUtility::resolveBackPath(PathUtility::dirname($fI['ID_absFile']) . '/' . $v);
-                        $EXTres_absPath = GeneralUtility::getFileAbsFileName($EXTres_absPath);
-                        if ($EXTres_absPath && GeneralUtility::isFirstPartOfStr($EXTres_absPath, PATH_site . $this->fileadminFolderName . '/') && @is_file($EXTres_absPath)) {
-                            $htmlResourceCaptured = true;
-                            $EXTres_ID = md5($EXTres_absPath);
-                            $this->dat['header']['files'][$fI['ID']]['EXT_RES_ID'][] = $EXTres_ID;
-                            $prefixedMedias[$k] = '{EXT_RES_ID:' . $EXTres_ID . '}';
-                            // Add file to memory if it is not set already:
-                            if (!isset($this->dat['header']['files'][$EXTres_ID])) {
-                                $fileInfo = stat($EXTres_absPath);
-                                $fileRec = array();
-                                $fileRec['filesize'] = $fileInfo['size'];
-                                $fileRec['filename'] = PathUtility::basename($EXTres_absPath);
-                                $fileRec['filemtime'] = $fileInfo['mtime'];
-                                $fileRec['record_ref'] = '_EXT_PARENT_:' . $fI['ID'];
-                                // Media relative to the HTML file.
-                                $fileRec['parentRelFileName'] = $v;
-                                // Setting this data in the header
-                                $this->dat['header']['files'][$EXTres_ID] = $fileRec;
-                                // ... and finally add the heavy stuff:
-                                $fileRec['content'] = GeneralUtility::getUrl($EXTres_absPath);
-                                $fileRec['content_md5'] = md5($fileRec['content']);
-                                $this->dat['files'][$EXTres_ID] = $fileRec;
-                            }
-                        }
-                    }
-                }
-                if ($htmlResourceCaptured) {
-                    $this->dat['files'][$fI['ID']]['tokenizedContent'] = implode('', $prefixedMedias);
-                }
-            }
-        }
-    }
-
-    /**
-     * If saveFilesOutsideExportFile is enabled, this function returns the path
-     * where the files referenced in the export are copied to.
-     *
-     * @return string
-     * @throws \RuntimeException
-     * @see setSaveFilesOutsideExportFile()
-     */
-    public function getTemporaryFilesPathForExport()
-    {
-        if (!$this->saveFilesOutsideExportFile) {
-            throw new \RuntimeException('You need to set saveFilesOutsideExportFile to TRUE before you want to get the temporary files path for export.', 1401205213);
-        }
-        if ($this->temporaryFilesPathForExport === null) {
-            $temporaryFolderName = $this->getTemporaryFolderName();
-            $this->temporaryFilesPathForExport = $temporaryFolderName . '/';
-        }
-        return $this->temporaryFilesPathForExport;
-    }
-
-    /**
-     *
-     * @return string
-     */
-    protected function getTemporaryFolderName()
-    {
-        $temporaryPath = PATH_site . 'typo3temp/';
-        do {
-            $temporaryFolderName = $temporaryPath . 'export_temp_files_' . mt_rand(1, PHP_INT_MAX);
-        } while (is_dir($temporaryFolderName));
-        GeneralUtility::mkdir($temporaryFolderName);
-        return $temporaryFolderName;
-    }
-
-    /**
-     * DB relations flattend to 1-dim array.
-     * The list will be unique, no table/uid combination will appear twice.
-     *
-     * @param array $dbrels 2-dim Array of database relations organized by table key
-     * @return array 1-dim array where entries are table:uid and keys are array with table/id
-     */
-    public function flatDBrels($dbrels)
-    {
-        $list = array();
-        foreach ($dbrels as $dat) {
-            if ($dat['type'] == 'db') {
-                foreach ($dat['itemArray'] as $i) {
-                    $list[$i['table'] . ':' . $i['id']] = $i;
-                }
-            }
-            if ($dat['type'] == 'flex' && is_array($dat['flexFormRels']['db'])) {
-                foreach ($dat['flexFormRels']['db'] as $subList) {
-                    foreach ($subList as $i) {
-                        $list[$i['table'] . ':' . $i['id']] = $i;
-                    }
-                }
-            }
-        }
-        return $list;
-    }
-
-    /**
-     * Soft References flattend to 1-dim array.
-     *
-     * @param array $dbrels 2-dim Array of database relations organized by table key
-     * @return array 1-dim array where entries are arrays with properties of the soft link found and keys are a unique combination of field, spKey, structure path if applicable and token ID
-     */
-    public function flatSoftRefs($dbrels)
-    {
-        $list = array();
-        foreach ($dbrels as $field => $dat) {
-            if (is_array($dat['softrefs']['keys'])) {
-                foreach ($dat['softrefs']['keys'] as $spKey => $elements) {
-                    if (is_array($elements)) {
-                        foreach ($elements as $subKey => $el) {
-                            $lKey = $field . ':' . $spKey . ':' . $subKey;
-                            $list[$lKey] = array_merge(array('field' => $field, 'spKey' => $spKey), $el);
-                            // Add file_ID key to header - slightly "risky" way of doing this because if the calculation
-                            // changes for the same value in $this->records[...] this will not work anymore!
-                            if ($el['subst'] && $el['subst']['relFileName']) {
-                                $list[$lKey]['file_ID'] = md5(PATH_site . $el['subst']['relFileName']);
-                            }
-                        }
-                    }
-                }
-            }
-            if ($dat['type'] == 'flex' && is_array($dat['flexFormRels']['softrefs'])) {
-                foreach ($dat['flexFormRels']['softrefs'] as $structurePath => $subSoftrefs) {
-                    if (is_array($subSoftrefs['keys'])) {
-                        foreach ($subSoftrefs['keys'] as $spKey => $elements) {
-                            foreach ($elements as $subKey => $el) {
-                                $lKey = $field . ':' . $structurePath . ':' . $spKey . ':' . $subKey;
-                                $list[$lKey] = array_merge(array('field' => $field, 'spKey' => $spKey, 'structurePath' => $structurePath), $el);
-                                // Add file_ID key to header - slightly "risky" way of doing this because if the calculation
-                                // changes for the same value in $this->records[...] this will not work anymore!
-                                if ($el['subst'] && $el['subst']['relFileName']) {
-                                    $list[$lKey]['file_ID'] = md5(PATH_site . $el['subst']['relFileName']);
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        return $list;
-    }
-
-    /**
-     * If include fields for a specific record type are set, the data
-     * are filtered out with fields are not included in the fields.
-     *
-     * @param string $table The record type to be filtered
-     * @param array $row The data to be filtered
-     * @return array The filtered record row
-     */
-    protected function filterRecordFields($table, array $row)
-    {
-        if (isset($this->recordTypesIncludeFields[$table])) {
-            $includeFields = array_unique(array_merge(
-                $this->recordTypesIncludeFields[$table],
-                $this->defaultRecordIncludeFields
-            ));
-            $newRow = array();
-            foreach ($row as $key => $value) {
-                if (in_array($key, $includeFields)) {
-                    $newRow[$key] = $value;
-                }
-            }
-        } else {
-            $newRow = $row;
-        }
-        return $newRow;
-    }
-
-    /**************************
-     * File Output
-     *************************/
-
-    /**
-     * This compiles and returns the data content for an exported file
-     *
-     * @param string $type Type of output; "xml" gives xml, otherwise serialized array, possibly compressed.
-     * @return string The output file stream
-     */
-    public function compileMemoryToFileContent($type = '')
-    {
-        if ($type == 'xml') {
-            $out = $this->createXML();
-        } else {
-            $compress = $this->doOutputCompress();
-            $out = '';
-            // adding header:
-            $out .= $this->addFilePart(serialize($this->dat['header']), $compress);
-            // adding records:
-            $out .= $this->addFilePart(serialize($this->dat['records']), $compress);
-            // adding files:
-            $out .= $this->addFilePart(serialize($this->dat['files']), $compress);
-            // adding files_fal:
-            $out .= $this->addFilePart(serialize($this->dat['files_fal']), $compress);
-        }
-        return $out;
-    }
-
-    /**
-     * Creates XML string from input array
-     *
-     * @return string XML content
-     */
-    public function createXML()
-    {
-        // Options:
-        $options = array(
-            'alt_options' => array(
-                '/header' => array(
-                    'disableTypeAttrib' => true,
-                    'clearStackPath' => true,
-                    'parentTagMap' => array(
-                        'files' => 'file',
-                        'files_fal' => 'file',
-                        'records' => 'table',
-                        'table' => 'rec',
-                        'rec:rels' => 'relations',
-                        'relations' => 'element',
-                        'filerefs' => 'file',
-                        'pid_lookup' => 'page_contents',
-                        'header:relStaticTables' => 'static_tables',
-                        'static_tables' => 'tablename',
-                        'excludeMap' => 'item',
-                        'softrefCfg' => 'softrefExportMode',
-                        'extensionDependencies' => 'extkey',
-                        'softrefs' => 'softref_element'
-                    ),
-                    'alt_options' => array(
-                        '/pagetree' => array(
-                            'disableTypeAttrib' => true,
-                            'useIndexTagForNum' => 'node',
-                            'parentTagMap' => array(
-                                'node:subrow' => 'node'
-                            )
-                        ),
-                        '/pid_lookup/page_contents' => array(
-                            'disableTypeAttrib' => true,
-                            'parentTagMap' => array(
-                                'page_contents' => 'table'
-                            ),
-                            'grandParentTagMap' => array(
-                                'page_contents/table' => 'item'
-                            )
-                        )
-                    )
-                ),
-                '/records' => array(
-                    'disableTypeAttrib' => true,
-                    'parentTagMap' => array(
-                        'records' => 'tablerow',
-                        'tablerow:data' => 'fieldlist',
-                        'tablerow:rels' => 'related',
-                        'related' => 'field',
-                        'field:itemArray' => 'relations',
-                        'field:newValueFiles' => 'filerefs',
-                        'field:flexFormRels' => 'flexform',
-                        'relations' => 'element',
-                        'filerefs' => 'file',
-                        'flexform:db' => 'db_relations',
-                        'flexform:file' => 'file_relations',
-                        'flexform:softrefs' => 'softref_relations',
-                        'softref_relations' => 'structurePath',
-                        'db_relations' => 'path',
-                        'file_relations' => 'path',
-                        'path' => 'element',
-                        'keys' => 'softref_key',
-                        'softref_key' => 'softref_element'
-                    ),
-                    'alt_options' => array(
-                        '/records/tablerow/fieldlist' => array(
-                            'useIndexTagForAssoc' => 'field'
-                        )
-                    )
-                ),
-                '/files' => array(
-                    'disableTypeAttrib' => true,
-                    'parentTagMap' => array(
-                        'files' => 'file'
-                    )
-                ),
-                '/files_fal' => array(
-                    'disableTypeAttrib' => true,
-                    'parentTagMap' => array(
-                        'files_fal' => 'file'
-                    )
-                )
-            )
-        );
-        // Creating XML file from $outputArray:
-        $charset = $this->dat['header']['charset'] ?: 'utf-8';
-        $XML = '<?xml version="1.0" encoding="' . $charset . '" standalone="yes" ?>' . LF;
-        $XML .= GeneralUtility::array2xml($this->dat, '', 0, 'T3RecordDocument', 0, $options);
-        return $XML;
-    }
-
-    /**
-     * Returns TRUE if the output should be compressed.
-     *
-     * @return bool TRUE if compression is possible AND requested.
-     */
-    public function doOutputCompress()
-    {
-        return $this->compress && !$this->dontCompress;
-    }
-
-    /**
-     * Returns a content part for a filename being build.
-     *
-     * @param array $data Data to store in part
-     * @param bool $compress Compress file?
-     * @return string Content stream.
-     */
-    public function addFilePart($data, $compress = false)
-    {
-        if ($compress) {
-            $data = gzcompress($data);
-        }
-        return md5($data) . ':' . ($compress ? '1' : '0') . ':' . str_pad(strlen($data), 10, '0', STR_PAD_LEFT) . ':' . $data . ':';
-    }
-
-    /***********************
-     * Import
-     ***********************/
-
-    /**
-     * Initialize all settings for the import
-     *
-     * @return void
-     */
-    protected function initializeImport()
-    {
-        // Set this flag to indicate that an import is being/has been done.
-        $this->doesImport = 1;
-        // Initialize:
-        // These vars MUST last for the whole section not being cleared. They are used by the method setRelations() which are called at the end of the import session.
-        $this->import_mapId = array();
-        $this->import_newId = array();
-        $this->import_newId_pids = array();
-        // Temporary files stack initialized:
-        $this->unlinkFiles = array();
-        $this->alternativeFileName = array();
-        $this->alternativeFilePath = array();
-
-        $this->initializeStorageObjects();
-    }
-
-    /**
-     * Initialize the all present storage objects
-     *
-     * @return void
-     */
-    protected function initializeStorageObjects()
-    {
-        /** @var $storageRepository StorageRepository */
-        $storageRepository = GeneralUtility::makeInstance(StorageRepository::class);
-        $this->storageObjects = $storageRepository->findAll();
-    }
-
-    /**
-     * Imports the internal data array to $pid.
-     *
-     * @param int $pid Page ID in which to import the content
-     * @return void
-     */
-    public function importData($pid)
-    {
-        $this->initializeImport();
-
-        // Write sys_file_storages first
-        $this->writeSysFileStorageRecords();
-        // Write sys_file records and write the binary file data
-        $this->writeSysFileRecords();
-        // Write records, first pages, then the rest
-        // Fields with "hard" relations to database, files and flexform fields are kept empty during this run
-        $this->writeRecords_pages($pid);
-        $this->writeRecords_records($pid);
-        // Finally all the file and DB record references must be fixed. This is done after all records have supposedly been written to database:
-        // $this->import_mapId will indicate two things: 1) that a record WAS written to db and 2) that it has got a new id-number.
-        $this->setRelations();
-        // And when all DB relations are in place, we can fix file and DB relations in flexform fields (since data structures often depends on relations to a DS record):
-        $this->setFlexFormRelations();
-        // Unlink temporary files:
-        $this->unlinkTempFiles();
-        // Finally, traverse all records and process softreferences with substitution attributes.
-        $this->processSoftReferences();
-        // After all migrate records using sys_file_reference now
-        if ($this->legacyImport) {
-            $this->migrateLegacyImportRecords();
-        }
-    }
-
-    /**
-     * Imports the sys_file_storage records from internal data array.
-     *
-     * @return void
-     */
-    protected function writeSysFileStorageRecords()
-    {
-        if (!isset($this->dat['header']['records']['sys_file_storage'])) {
-            return;
-        }
-        $sysFileStorageUidsToBeResetToDefaultStorage = array();
-        foreach ($this->dat['header']['records']['sys_file_storage'] as $sysFileStorageUid => $_) {
-            $storageRecord = $this->dat['records']['sys_file_storage:' . $sysFileStorageUid]['data'];
-            // continue with Local, writable and online storage only
-            if ($storageRecord['driver'] === 'Local' && $storageRecord['is_writable'] && $storageRecord['is_online']) {
-                $useThisStorageUidInsteadOfTheOneInImport = 0;
-                /** @var $localStorage \TYPO3\CMS\Core\Resource\ResourceStorage */
-                foreach ($this->storageObjects as $localStorage) {
-                    // check the available storage for Local, writable and online ones
-                    if ($localStorage->getDriverType() === 'Local' && $localStorage->isWritable() && $localStorage->isOnline()) {
-                        // check if there is already an identical storage present (same pathType and basePath)
-                        $storageRecordConfiguration = ResourceFactory::getInstance()->convertFlexFormDataToConfigurationArray($storageRecord['configuration']);
-                        $localStorageRecordConfiguration = $localStorage->getConfiguration();
-                        if (
-                            $storageRecordConfiguration['pathType'] === $localStorageRecordConfiguration['pathType']
-                            && $storageRecordConfiguration['basePath'] === $localStorageRecordConfiguration['basePath']
-                        ) {
-                            // same storage is already present
-                            $useThisStorageUidInsteadOfTheOneInImport = $localStorage->getUid();
-                            break;
-                        }
-                    }
-                }
-                if ($useThisStorageUidInsteadOfTheOneInImport > 0) {
-                    // same storage is already present; map the to be imported one to the present one
-                    $this->import_mapId['sys_file_storage'][$sysFileStorageUid] = $useThisStorageUidInsteadOfTheOneInImport;
-                } else {
-                    // Local, writable and online storage. Is allowed to be used to later write files in.
-                    $this->addSingle('sys_file_storage', $sysFileStorageUid, 0);
-                }
-            } else {
-                // Storage with non Local drivers could be imported but must not be used to saves files in, because you
-                // could not be sure, that this is supported. The default storage will be used in this case.
-                // It could happen that non writable and non online storage will be created as dupes because you could not
-                // check the detailed configuration options at this point
-                $this->addSingle('sys_file_storage', $sysFileStorageUid, 0);
-                $sysFileStorageUidsToBeResetToDefaultStorage[] = $sysFileStorageUid;
-            }
-        }
-
-        // Importing the added ones
-        $tce = $this->getNewTCE();
-        // Because all records are being submitted in their correct order with positive pid numbers - and so we should reverse submission order internally.
-        $tce->reverseOrder = 1;
-        $tce->isImporting = true;
-        $tce->start($this->import_data, array());
-        $tce->process_datamap();
-        $this->addToMapId($tce->substNEWwithIDs);
-
-        $defaultStorageUid = null;
-        // get default storage
-        $defaultStorage = ResourceFactory::getInstance()->getDefaultStorage();
-        if ($defaultStorage !== null) {
-            $defaultStorageUid = $defaultStorage->getUid();
-        }
-        foreach ($sysFileStorageUidsToBeResetToDefaultStorage as $sysFileStorageUidToBeResetToDefaultStorage) {
-            $this->import_mapId['sys_file_storage'][$sysFileStorageUidToBeResetToDefaultStorage] = $defaultStorageUid;
-        }
-
-        // unset the sys_file_storage records to prevent an import in writeRecords_records
-        unset($this->dat['header']['records']['sys_file_storage']);
-    }
-
-    /**
-     * Imports the sys_file records and the binary files data from internal data array.
-     *
-     * @return void
-     */
-    protected function writeSysFileRecords()
-    {
-        if (!isset($this->dat['header']['records']['sys_file'])) {
-            return;
-        }
-        $this->addGeneralErrorsByTable('sys_file');
-
-        // fetch fresh storage records from database
-        $storageRecords = $this->fetchStorageRecords();
-
-        $defaultStorage = ResourceFactory::getInstance()->getDefaultStorage();
-
-        $sanitizedFolderMappings = array();
-
-        foreach ($this->dat['header']['records']['sys_file'] as $sysFileUid => $_) {
-            $fileRecord = $this->dat['records']['sys_file:' . $sysFileUid]['data'];
-
-            $temporaryFile = null;
-            // check if there is the right file already in the local folder
-            if ($this->filesPathForImport !== null) {
-                if (is_file($this->filesPathForImport . '/' . $fileRecord['sha1']) && sha1_file($this->filesPathForImport . '/' . $fileRecord['sha1']) === $fileRecord['sha1']) {
-                    $temporaryFile = $this->filesPathForImport . '/' . $fileRecord['sha1'];
-                }
-            }
-
-            // save file to disk
-            if ($temporaryFile === null) {
-                $fileId = md5($fileRecord['storage'] . ':' . $fileRecord['identifier_hash']);
-                $temporaryFile = $this->writeTemporaryFileFromData($fileId);
-                if ($temporaryFile === null) {
-                    // error on writing the file. Error message was already added
-                    continue;
-                }
-            }
-
-            $originalStorageUid = $fileRecord['storage'];
-            $useStorageFromStorageRecords = false;
-
-            // replace storage id, if an alternative one was registered
-            if (isset($this->import_mapId['sys_file_storage'][$fileRecord['storage']])) {
-                $fileRecord['storage'] = $this->import_mapId['sys_file_storage'][$fileRecord['storage']];
-                $useStorageFromStorageRecords = true;
-            }
-
-            if (empty($fileRecord['storage']) && !$this->isFallbackStorage($fileRecord['storage'])) {
-                // no storage for the file is defined, mostly because of a missing default storage.
-                $this->error('Error: No storage for the file "' . $fileRecord['identifier'] . '" with storage uid "' . $originalStorageUid . '"');
-                continue;
-            }
-
-            // using a storage from the local storage is only allowed, if the uid is present in the
-            // mapping. Only in this case we could be sure, that it's a local, online and writable storage.
-            if ($useStorageFromStorageRecords && isset($storageRecords[$fileRecord['storage']])) {
-                /** @var $storage \TYPO3\CMS\Core\Resource\ResourceStorage */
-                $storage = ResourceFactory::getInstance()->getStorageObject($fileRecord['storage'], $storageRecords[$fileRecord['storage']]);
-            } elseif ($this->isFallbackStorage($fileRecord['storage'])) {
-                $storage = ResourceFactory::getInstance()->getStorageObject(0);
-            } elseif ($defaultStorage !== null) {
-                $storage = $defaultStorage;
-            } else {
-                $this->error('Error: No storage available for the file "' . $fileRecord['identifier'] . '" with storage uid "' . $fileRecord['storage'] . '"');
-                continue;
-            }
-
-            $newFile = null;
-
-            // check, if there is an identical file
-            try {
-                if ($storage->hasFile($fileRecord['identifier'])) {
-                    $file = $storage->getFile($fileRecord['identifier']);
-                    if ($file->getSha1() === $fileRecord['sha1']) {
-                        $newFile = $file;
-                    }
-                }
-            } catch (Exception $e) {
-            }
-
-            if ($newFile === null) {
-                $folderName = PathUtility::dirname(ltrim($fileRecord['identifier'], '/'));
-                if (in_array($folderName, $sanitizedFolderMappings)) {
-                    $folderName = $sanitizedFolderMappings[$folderName];
-                }
-                if (!$storage->hasFolder($folderName)) {
-                    try {
-                        $importFolder = $storage->createFolder($folderName);
-                        if ($importFolder->getIdentifier() !== $folderName && !in_array($folderName, $sanitizedFolderMappings)) {
-                            $sanitizedFolderMappings[$folderName] = $importFolder->getIdentifier();
-                        }
-                    } catch (Exception $e) {
-                        $this->error('Error: Folder could not be created for file "' . $fileRecord['identifier'] . '" with storage uid "' . $fileRecord['storage'] . '"');
-                        continue;
-                    }
-                } else {
-                    $importFolder = $storage->getFolder($folderName);
-                }
-
-                try {
-                    /** @var $newFile File */
-                    $newFile = $storage->addFile($temporaryFile, $importFolder, $fileRecord['name']);
-                } catch (Exception $e) {
-                    $this->error('Error: File could not be added to the storage: "' . $fileRecord['identifier'] . '" with storage uid "' . $fileRecord['storage'] . '"');
-                    continue;
-                }
-
-                if ($newFile->getSha1() !== $fileRecord['sha1']) {
-                    $this->error('Error: The hash of the written file is not identical to the import data! File could be corrupted! File: "' . $fileRecord['identifier'] . '" with storage uid "' . $fileRecord['storage'] . '"');
-                }
-            }
-
-            // save the new uid in the import id map
-            $this->import_mapId['sys_file'][$fileRecord['uid']] = $newFile->getUid();
-            $this->fixUidLocalInSysFileReferenceRecords($fileRecord['uid'], $newFile->getUid());
-        }
-
-        // unset the sys_file records to prevent an import in writeRecords_records
-        unset($this->dat['header']['records']['sys_file']);
-    }
-
-    /**
-     * Checks if the $storageId is the id of the fallback storage
-     *
-     * @param int|string $storageId
-     * @return bool
-     */
-    protected function isFallbackStorage($storageId)
-    {
-        return $storageId === 0 || $storageId === '0';
-    }
-
-    /**
-     * Normally the importer works like the following:
-     * Step 1: import the records with cleared field values of relation fields (see addSingle())
-     * Step 2: update the records with the right relation ids (see setRelations())
-     *
-     * In step 2 the saving fields of type "relation to sys_file_reference" checks the related sys_file_reference
-     * record (created in step 1) with the FileExtensionFilter for matching file extensions of the related file.
-     * To make this work correct, the uid_local of sys_file_reference records has to be not empty AND has to
-     * relate to the correct (imported) sys_file record uid!!!
-     *
-     * This is fixed here.
-     *
-     * @param int $oldFileUid
-     * @param int $newFileUid
-     * @return void
-    */
-    protected function fixUidLocalInSysFileReferenceRecords($oldFileUid, $newFileUid)
-    {
-        if (!isset($this->dat['header']['records']['sys_file_reference'])) {
-            return;
-        }
-
-        foreach ($this->dat['header']['records']['sys_file_reference'] as $sysFileReferenceUid => $_) {
-            $fileReferenceRecord = $this->dat['records']['sys_file_reference:' . $sysFileReferenceUid]['data'];
-            if ($fileReferenceRecord['uid_local'] == $oldFileUid) {
-                $fileReferenceRecord['uid_local'] = $newFileUid;
-                $this->dat['records']['sys_file_reference:' . $sysFileReferenceUid]['data'] = $fileReferenceRecord;
-            }
-        }
-    }
-
-    /**
-     * Initializes the folder for legacy imports as subfolder of backend users default upload folder
-     *
-     * @return void
-     */
-    protected function initializeLegacyImportFolder()
-    {
-        /** @var \TYPO3\CMS\Core\Resource\Folder $folder */
-        $folder = $this->getBackendUser()->getDefaultUploadFolder();
-        if ($folder === false) {
-            $this->error('Error: the backend users default upload folder is missing! No files will be imported!');
-        }
-        if (!$folder->hasFolder($this->legacyImportTargetPath)) {
-            try {
-                $this->legacyImportFolder = $folder->createFolder($this->legacyImportTargetPath);
-            } catch (Exception $e) {
-                $this->error('Error: the import folder in the default upload folder could not be created! No files will be imported!');
-            }
-        } else {
-            $this->legacyImportFolder = $folder->getSubFolder($this->legacyImportTargetPath);
-        }
-    }
-
-    /**
-     * Fetched fresh storage records from database because the new imported
-     * ones are not in cached data of the StorageRepository
-     *
-     * @return bool|array
-     */
-    protected function fetchStorageRecords()
-    {
-        $whereClause = BackendUtility::BEenableFields('sys_file_storage');
-        $whereClause .= BackendUtility::deleteClause('sys_file_storage');
-
-        $rows = $this->getDatabaseConnection()->exec_SELECTgetRows(
-            '*',
-            'sys_file_storage',
-            '1=1' . $whereClause,
-            '',
-            '',
-            '',
-            'uid'
-        );
-
-        return $rows;
-    }
-
-    /**
-     * Writes the file from import array to temp dir and returns the filename of it.
-     *
-     * @param string $fileId
-     * @param string $dataKey
-     * @return string Absolute filename of the temporary filename of the file
-     */
-    protected function writeTemporaryFileFromData($fileId, $dataKey = 'files_fal')
-    {
-        $temporaryFilePath = null;
-        if (is_array($this->dat[$dataKey][$fileId])) {
-            $temporaryFilePathInternal = GeneralUtility::tempnam('import_temp_');
-            GeneralUtility::writeFile($temporaryFilePathInternal, $this->dat[$dataKey][$fileId]['content']);
-            clearstatcache();
-            if (@is_file($temporaryFilePathInternal)) {
-                $this->unlinkFiles[] = $temporaryFilePathInternal;
-                if (filesize($temporaryFilePathInternal) == $this->dat[$dataKey][$fileId]['filesize']) {
-                    $temporaryFilePath = $temporaryFilePathInternal;
-                } else {
-                    $this->error('Error: temporary file ' . $temporaryFilePathInternal . ' had a size (' . filesize($temporaryFilePathInternal) . ') different from the original (' . $this->dat[$dataKey][$fileId]['filesize'] . ')');
-                }
-            } else {
-                $this->error('Error: temporary file ' . $temporaryFilePathInternal . ' was not written as it should have been!');
-            }
-        } else {
-            $this->error('Error: No file found for ID ' . $fileId);
-        }
-        return $temporaryFilePath;
-    }
-
-    /**
-     * Writing pagetree/pages to database:
-     *
-     * @param int $pid PID in which to import. If the operation is an update operation, the root of the page tree inside will be moved to this PID unless it is the same as the root page from the import
-     * @return void
-     * @see writeRecords_records()
-     */
-    public function writeRecords_pages($pid)
-    {
-        // First, write page structure if any:
-        if (is_array($this->dat['header']['records']['pages'])) {
-            $this->addGeneralErrorsByTable('pages');
-            // $pageRecords is a copy of the pages array in the imported file. Records here are unset one by one when the addSingle function is called.
-            $pageRecords = $this->dat['header']['records']['pages'];
-            $this->import_data = array();
-            // First add page tree if any
-            if (is_array($this->dat['header']['pagetree'])) {
-                $pagesFromTree = $this->flatInversePageTree($this->dat['header']['pagetree']);
-                foreach ($pagesFromTree as $uid) {
-                    $thisRec = $this->dat['header']['records']['pages'][$uid];
-                    // PID: Set the main $pid, unless a NEW-id is found
-                    $setPid = isset($this->import_newId_pids[$thisRec['pid']]) ? $this->import_newId_pids[$thisRec['pid']] : $pid;
-                    $this->addSingle('pages', $uid, $setPid);
-                    unset($pageRecords[$uid]);
-                }
-            }
-            // Then add all remaining pages not in tree on root level:
-            if (!empty($pageRecords)) {
-                $remainingPageUids = array_keys($pageRecords);
-                foreach ($remainingPageUids as $pUid) {
-                    $this->addSingle('pages', $pUid, $pid);
-                }
-            }
-            // Now write to database:
-            $tce = $this->getNewTCE();
-            $tce->isImporting = true;
-            $this->callHook('before_writeRecordsPages', array(
-                'tce' => &$tce,
-                'data' => &$this->import_data
-            ));
-            $tce->suggestedInsertUids = $this->suggestedInsertUids;
-            $tce->start($this->import_data, array());
-            $tce->process_datamap();
-            $this->callHook('after_writeRecordsPages', array(
-                'tce' => &$tce
-            ));
-            // post-processing: Registering new ids (end all tcemain sessions with this)
-            $this->addToMapId($tce->substNEWwithIDs);
-            // In case of an update, order pages from the page tree correctly:
-            if ($this->update && is_array($this->dat['header']['pagetree'])) {
-                $this->writeRecords_pages_order();
-            }
-        }
-    }
-
-    /**
-     * Organize all updated pages in page tree so they are related like in the import file
-     * Only used for updates and when $this->dat['header']['pagetree'] is an array.
-     *
-     * @return void
-     * @access private
-     * @see writeRecords_pages(), writeRecords_records_order()
-     */
-    public function writeRecords_pages_order()
-    {
-        $cmd_data = array();
-        // Get uid-pid relations and traverse them in order to map to possible new IDs
-        $pidsFromTree = $this->flatInversePageTree_pid($this->dat['header']['pagetree']);
-        foreach ($pidsFromTree as $origPid => $newPid) {
-            if ($newPid >= 0 && $this->dontIgnorePid('pages', $origPid)) {
-                // If the page had a new id (because it was created) use that instead!
-                if (substr($this->import_newId_pids[$origPid], 0, 3) === 'NEW') {
-                    if ($this->import_mapId['pages'][$origPid]) {
-                        $mappedPid = $this->import_mapId['pages'][$origPid];
-                        $cmd_data['pages'][$mappedPid]['move'] = $newPid;
-                    }
-                } else {
-                    $cmd_data['pages'][$origPid]['move'] = $newPid;
-                }
-            }
-        }
-        // Execute the move commands if any:
-        if (!empty($cmd_data)) {
-            $tce = $this->getNewTCE();
-            $this->callHook('before_writeRecordsPagesOrder', array(
-                'tce' => &$tce,
-                'data' => &$cmd_data
-            ));
-            $tce->start(array(), $cmd_data);
-            $tce->process_cmdmap();
-            $this->callHook('after_writeRecordsPagesOrder', array(
-                'tce' => &$tce
-            ));
-        }
-    }
-
-    /**
-     * Write all database records except pages (writtein in writeRecords_pages())
-     *
-     * @param int $pid Page id in which to import
-     * @return void
-     * @see writeRecords_pages()
-     */
-    public function writeRecords_records($pid)
-    {
-        // Write the rest of the records
-        $this->import_data = array();
-        if (is_array($this->dat['header']['records'])) {
-            foreach ($this->dat['header']['records'] as $table => $recs) {
-                $this->addGeneralErrorsByTable($table);
-                if ($table != 'pages') {
-                    foreach ($recs as $uid => $thisRec) {
-                        // PID: Set the main $pid, unless a NEW-id is found
-                        $setPid = isset($this->import_mapId['pages'][$thisRec['pid']])
-                            ? (int)$this->import_mapId['pages'][$thisRec['pid']]
-                            : (int)$pid;
-                        if (is_array($GLOBALS['TCA'][$table]) && isset($GLOBALS['TCA'][$table]['ctrl']['rootLevel'])) {
-                            $rootLevelSetting = (int)$GLOBALS['TCA'][$table]['ctrl']['rootLevel'];
-                            if ($rootLevelSetting === 1) {
-                                $setPid = 0;
-                            } elseif ($rootLevelSetting === 0 && $setPid === 0) {
-                                $this->error('Error: Record type ' . $table . ' is not allowed on pid 0');
-                                continue;
-                            }
-                        }
-                        // Add record:
-                        $this->addSingle($table, $uid, $setPid);
-                    }
-                }
-            }
-        } else {
-            $this->error('Error: No records defined in internal data array.');
-        }
-        // Now write to database:
-        $tce = $this->getNewTCE();
-        $this->callHook('before_writeRecordsRecords', array(
-            'tce' => &$tce,
-            'data' => &$this->import_data
-        ));
-        $tce->suggestedInsertUids = $this->suggestedInsertUids;
-        // Because all records are being submitted in their correct order with positive pid numbers - and so we should reverse submission order internally.
-        $tce->reverseOrder = 1;
-        $tce->isImporting = true;
-        $tce->start($this->import_data, array());
-        $tce->process_datamap();
-        $this->callHook('after_writeRecordsRecords', array(
-            'tce' => &$tce
-        ));
-        // post-processing: Removing files and registering new ids (end all tcemain sessions with this)
-        $this->addToMapId($tce->substNEWwithIDs);
-        // In case of an update, order pages from the page tree correctly:
-        if ($this->update) {
-            $this->writeRecords_records_order($pid);
-        }
-    }
-
-    /**
-     * Organize all updated record to their new positions.
-     * Only used for updates
-     *
-     * @param int $mainPid Main PID into which we import.
-     * @return void
-     * @access private
-     * @see writeRecords_records(), writeRecords_pages_order()
-     */
-    public function writeRecords_records_order($mainPid)
-    {
-        $cmd_data = array();
-        if (is_array($this->dat['header']['pagetree'])) {
-            $pagesFromTree = $this->flatInversePageTree($this->dat['header']['pagetree']);
-        } else {
-            $pagesFromTree = array();
-        }
-        if (is_array($this->dat['header']['pid_lookup'])) {
-            foreach ($this->dat['header']['pid_lookup'] as $pid => $recList) {
-                $newPid = isset($this->import_mapId['pages'][$pid]) ? $this->import_mapId['pages'][$pid] : $mainPid;
-                if (MathUtility::canBeInterpretedAsInteger($newPid)) {
-                    foreach ($recList as $tableName => $uidList) {
-                        // If $mainPid===$newPid then we are on root level and we can consider to move pages as well!
-                        // (they will not be in the page tree!)
-                        if (($tableName != 'pages' || !$pagesFromTree[$pid]) && is_array($uidList)) {
-                            $uidList = array_reverse(array_keys($uidList));
-                            foreach ($uidList as $uid) {
-                                if ($this->dontIgnorePid($tableName, $uid)) {
-                                    $cmd_data[$tableName][$uid]['move'] = $newPid;
-                                } else {
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        // Execute the move commands if any:
-        if (!empty($cmd_data)) {
-            $tce = $this->getNewTCE();
-            $this->callHook('before_writeRecordsRecordsOrder', array(
-                'tce' => &$tce,
-                'data' => &$cmd_data
-            ));
-            $tce->start(array(), $cmd_data);
-            $tce->process_cmdmap();
-            $this->callHook('after_writeRecordsRecordsOrder', array(
-                'tce' => &$tce
-            ));
-        }
-    }
-
-    /**
-     * Adds a single record to the $importData array. Also copies files to tempfolder.
-     * However all File/DB-references and flexform field contents are set to blank for now!
-     * That is done with setRelations() later
-     *
-     * @param string $table Table name (from import memory)
-     * @param int $uid Record UID (from import memory)
-     * @param int $pid Page id
-     * @return void
-     * @see writeRecords()
-     */
-    public function addSingle($table, $uid, $pid)
-    {
-        if ($this->import_mode[$table . ':' . $uid] === 'exclude') {
-            return;
-        }
-        $record = $this->dat['records'][$table . ':' . $uid]['data'];
-        if (is_array($record)) {
-            if ($this->update && $this->doesRecordExist($table, $uid) && $this->import_mode[$table . ':' . $uid] !== 'as_new') {
-                $ID = $uid;
-            } elseif ($table === 'sys_file_metadata' && $record['sys_language_uid'] == '0' && $this->import_mapId['sys_file'][$record['file']]) {
-                // on adding sys_file records the belonging sys_file_metadata record was also created
-                // if there is one the record need to be overwritten instead of creating a new one.
-                $recordInDatabase = $this->getDatabaseConnection()->exec_SELECTgetSingleRow(
-                    'uid',
-                    'sys_file_metadata',
-                    'file = ' . $this->import_mapId['sys_file'][$record['file']] . ' AND sys_language_uid = 0 AND pid = 0'
-                );
-                // if no record could be found, $this->import_mapId['sys_file'][$record['file']] is pointing
-                // to a file, that was already there, thus a new metadata record should be created
-                if (is_array($recordInDatabase)) {
-                    $this->import_mapId['sys_file_metadata'][$record['uid']] = $recordInDatabase['uid'];
-                    $ID = $recordInDatabase['uid'];
-                } else {
-                    $ID = StringUtility::getUniqueId('NEW');
-                }
-            } else {
-                $ID = StringUtility::getUniqueId('NEW');
-            }
-            $this->import_newId[$table . ':' . $ID] = array('table' => $table, 'uid' => $uid);
-            if ($table == 'pages') {
-                $this->import_newId_pids[$uid] = $ID;
-            }
-            // Set main record data:
-            $this->import_data[$table][$ID] = $record;
-            $this->import_data[$table][$ID]['tx_impexp_origuid'] = $this->import_data[$table][$ID]['uid'];
-            // Reset permission data:
-            if ($table === 'pages') {
-                // Have to reset the user/group IDs so pages are owned by importing user. Otherwise strange things may happen for non-admins!
-                unset($this->import_data[$table][$ID]['perms_userid']);
-                unset($this->import_data[$table][$ID]['perms_groupid']);
-            }
-            // PID and UID:
-            unset($this->import_data[$table][$ID]['uid']);
-            // Updates:
-            if (MathUtility::canBeInterpretedAsInteger($ID)) {
-                unset($this->import_data[$table][$ID]['pid']);
-            } else {
-                // Inserts:
-                $this->import_data[$table][$ID]['pid'] = $pid;
-                if (($this->import_mode[$table . ':' . $uid] === 'force_uid' && $this->update || $this->force_all_UIDS) && $this->getBackendUser()->isAdmin()) {
-                    $this->import_data[$table][$ID]['uid'] = $uid;
-                    $this->suggestedInsertUids[$table . ':' . $uid] = 'DELETE';
-                }
-            }
-            // Setting db/file blank:
-            foreach ($this->dat['records'][$table . ':' . $uid]['rels'] as $field => $config) {
-                switch ((string)$config['type']) {
-                    case 'db':
-
-                    case 'file':
-                        // Fixed later in ->setRelations() [because we need to know ALL newly created IDs before we can map relations!]
-                        // In the meantime we set NO values for relations.
-                        //
-                        // BUT for field uid_local of table sys_file_reference the relation MUST not be cleared here,
-                        // because the value is already the uid of the right imported sys_file record.
-                        // @see fixUidLocalInSysFileReferenceRecords()
-                        // If it's empty or a uid to another record the FileExtensionFilter will throw an exception or
-                        // delete the reference record if the file extension of the related record doesn't match.
-                        if ($table !== 'sys_file_reference' && $field !== 'uid_local') {
-                            $this->import_data[$table][$ID][$field] = '';
-                        }
-                        break;
-                    case 'flex':
-                        // Fixed later in setFlexFormRelations()
-                        // In the meantime we set NO value for flexforms - this is mainly because file references
-                        // inside will not be processed properly; In fact references will point to no file
-                        // or existing files (in which case there will be double-references which is a big problem of course!)
-                        $this->import_data[$table][$ID][$field] = '';
-                        break;
-                }
-            }
-        } elseif ($table . ':' . $uid != 'pages:0') {
-            // On root level we don't want this error message.
-            $this->error('Error: no record was found in data array!');
-        }
-    }
-
-    /**
-     * Registers the substNEWids in memory.
-     *
-     * @param array $substNEWwithIDs From tcemain to be merged into internal mapping variable in this object
-     * @return void
-     * @see writeRecords()
-     */
-    public function addToMapId($substNEWwithIDs)
-    {
-        foreach ($this->import_data as $table => $recs) {
-            foreach ($recs as $id => $value) {
-                $old_uid = $this->import_newId[$table . ':' . $id]['uid'];
-                if (isset($substNEWwithIDs[$id])) {
-                    $this->import_mapId[$table][$old_uid] = $substNEWwithIDs[$id];
-                } elseif ($this->update) {
-                    // Map same ID to same ID....
-                    $this->import_mapId[$table][$old_uid] = $id;
-                } else {
-                    // if $this->import_mapId contains already the right mapping, skip the error msg.
-                    // See special handling of sys_file_metadata in addSingle() => nothing to do
-                    if (!($table === 'sys_file_metadata' && isset($this->import_mapId[$table][$old_uid]) && $this->import_mapId[$table][$old_uid] == $id)) {
-                        $this->error('Possible error: ' . $table . ':' . $old_uid . ' had no new id assigned to it. This indicates that the record was not added to database during import. Please check changelog!');
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Returns a new $TCE object
-     *
-     * @return DataHandler $TCE object
-     */
-    public function getNewTCE()
-    {
-        $tce = GeneralUtility::makeInstance(DataHandler::class);
-        $tce->dontProcessTransformations = 1;
-        $tce->enableLogging = $this->enableLogging;
-        $tce->alternativeFileName = $this->alternativeFileName;
-        $tce->alternativeFilePath = $this->alternativeFilePath;
-        return $tce;
-    }
-
-    /**
-     * Cleaning up all the temporary files stored in typo3temp/ folder
-     *
-     * @return void
-     */
-    public function unlinkTempFiles()
-    {
-        foreach ($this->unlinkFiles as $fileName) {
-            if (GeneralUtility::isFirstPartOfStr($fileName, PATH_site . 'typo3temp/')) {
-                GeneralUtility::unlink_tempfile($fileName);
-                clearstatcache();
-                if (is_file($fileName)) {
-                    $this->error('Error: ' . $fileName . ' was NOT unlinked as it should have been!');
-                }
-            } else {
-                $this->error('Error: ' . $fileName . ' was not in temp-path. Not removed!');
-            }
-        }
-        $this->unlinkFiles = array();
-    }
-
-    /***************************
-     * Import / Relations setting
-     ***************************/
-
-    /**
-     * At the end of the import process all file and DB relations should be set properly (that is relations
-     * to imported records are all re-created so imported records are correctly related again)
-     * Relations in flexform fields are processed in setFlexFormRelations() after this function
-     *
-     * @return void
-     * @see setFlexFormRelations()
-     */
-    public function setRelations()
-    {
-        $updateData = array();
-        // import_newId contains a register of all records that was in the import memorys "records" key
-        foreach ($this->import_newId as $nId => $dat) {
-            $table = $dat['table'];
-            $uid = $dat['uid'];
-            // original UID - NOT the new one!
-            // If the record has been written and received a new id, then proceed:
-            if (is_array($this->import_mapId[$table]) && isset($this->import_mapId[$table][$uid])) {
-                $thisNewUid = BackendUtility::wsMapId($table, $this->import_mapId[$table][$uid]);
-                if (is_array($this->dat['records'][$table . ':' . $uid]['rels'])) {
-                    $thisNewPageUid = 0;
-                    if ($this->legacyImport) {
-                        if ($table != 'pages') {
-                            $oldPid = $this->dat['records'][$table . ':' . $uid]['data']['pid'];
-                            $thisNewPageUid = BackendUtility::wsMapId($table, $this->import_mapId['pages'][$oldPid]);
-                        } else {
-                            $thisNewPageUid = $thisNewUid;
-                        }
-                    }
-                    // Traverse relation fields of each record
-                    foreach ($this->dat['records'][$table . ':' . $uid]['rels'] as $field => $config) {
-                        // uid_local of sys_file_reference needs no update because the correct reference uid was already written
-                        // @see ImportExport::fixUidLocalInSysFileReferenceRecords()
-                        if ($table === 'sys_file_reference' && $field === 'uid_local') {
-                            continue;
-                        }
-                        switch ((string)$config['type']) {
-                            case 'db':
-                                if (is_array($config['itemArray']) && !empty($config['itemArray'])) {
-                                    $itemConfig = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
-                                    $valArray = $this->setRelations_db($config['itemArray'], $itemConfig);
-                                    $updateData[$table][$thisNewUid][$field] = implode(',', $valArray);
-                                }
-                                break;
-                            case 'file':
-                                if (is_array($config['newValueFiles']) && !empty($config['newValueFiles'])) {
-                                    $valArr = array();
-                                    foreach ($config['newValueFiles'] as $fI) {
-                                        $valArr[] = $this->import_addFileNameToBeCopied($fI);
-                                    }
-                                    if ($this->legacyImport && $this->legacyImportFolder === null && isset($this->legacyImportMigrationTables[$table][$field])) {
-                                        // Do nothing - the legacy import folder is missing
-                                    } elseif ($this->legacyImport && $this->legacyImportFolder !== null && isset($this->legacyImportMigrationTables[$table][$field])) {
-                                        $refIds = array();
-                                        foreach ($valArr as $tempFile) {
-                                            $fileName = $this->alternativeFileName[$tempFile];
-                                            $fileObject = null;
-
-                                            try {
-                                                // check, if there is alreay the same file in the folder
-                                                if ($this->legacyImportFolder->hasFile($fileName)) {
-                                                    $fileStorage = $this->legacyImportFolder->getStorage();
-                                                    $file = $fileStorage->getFile($this->legacyImportFolder->getIdentifier() . $fileName);
-                                                    if ($file->getSha1() === sha1_file($tempFile)) {
-                                                        $fileObject = $file;
-                                                    }
-                                                }
-                                            } catch (Exception $e) {
-                                            }
-
-                                            if ($fileObject === null) {
-                                                try {
-                                                    $fileObject = $this->legacyImportFolder->addFile($tempFile, $fileName, DuplicationBehavior::RENAME);
-                                                } catch (Exception $e) {
-                                                    $this->error('Error: no file could be added to the storage for file name' . $this->alternativeFileName[$tempFile]);
-                                                }
-                                            }
-                                            if ($fileObject !== null) {
-                                                $refId = StringUtility::getUniqueId('NEW');
-                                                $refIds[] = $refId;
-                                                $updateData['sys_file_reference'][$refId] = array(
-                                                    'uid_local' => $fileObject->getUid(),
-                                                    'uid_foreign' => $thisNewUid, // uid of your content record
-                                                    'tablenames' => $table,
-                                                    'fieldname' => $field,
-                                                    'pid' => $thisNewPageUid, // parent id of the parent page
-                                                    'table_local' => 'sys_file',
-                                                );
-                                            }
-                                        }
-                                        $updateData[$table][$thisNewUid][$field] = implode(',', $refIds);
-                                        if (!empty($this->legacyImportMigrationTables[$table][$field])) {
-                                            $this->legacyImportMigrationRecords[$table][$thisNewUid][$field] = $refIds;
-                                        }
-                                    } else {
-                                        $updateData[$table][$thisNewUid][$field] = implode(',', $valArr);
-                                    }
-                                }
-                                break;
-                        }
-                    }
-                } else {
-                    $this->error('Error: no record was found in data array!');
-                }
-            } else {
-                $this->error('Error: this records is NOT created it seems! (' . $table . ':' . $uid . ')');
-            }
-        }
-        if (!empty($updateData)) {
-            $tce = $this->getNewTCE();
-            $tce->isImporting = true;
-            $this->callHook('before_setRelation', array(
-                'tce' => &$tce,
-                'data' => &$updateData
-            ));
-            $tce->start($updateData, array());
-            $tce->process_datamap();
-            // Replace the temporary "NEW" ids with the final ones.
-            foreach ($this->legacyImportMigrationRecords as $table => $records) {
-                foreach ($records as $uid => $fields) {
-                    foreach ($fields as $field => $referenceIds) {
-                        foreach ($referenceIds as $key => $referenceId) {
-                            $this->legacyImportMigrationRecords[$table][$uid][$field][$key] = $tce->substNEWwithIDs[$referenceId];
-                        }
-                    }
-                }
-            }
-            $this->callHook('after_setRelations', array(
-                'tce' => &$tce
-            ));
-        }
-    }
-
-    /**
-     * Maps relations for database
-     *
-     * @param array $itemArray Array of item sets (table/uid) from a dbAnalysis object
-     * @param array $itemConfig Array of TCA config of the field the relation to be set on
-     * @return array Array with values [table]_[uid] or [uid] for field of type group / internal_type file_reference. These values have the regular tcemain-input group/select type which means they will automatically be processed into a uid-list or MM relations.
-     */
-    public function setRelations_db($itemArray, $itemConfig)
-    {
-        $valArray = array();
-        foreach ($itemArray as $relDat) {
-            if (is_array($this->import_mapId[$relDat['table']]) && isset($this->import_mapId[$relDat['table']][$relDat['id']])) {
-                // Since non FAL file relation type group internal_type file_reference are handled as reference to
-                // sys_file records Datahandler requires the value as uid of the the related sys_file record only
-                if ($itemConfig['type'] === 'group' && $itemConfig['internal_type'] === 'file_reference') {
-                    $value = $this->import_mapId[$relDat['table']][$relDat['id']];
-                } elseif ($itemConfig['type'] === 'input' && isset($itemConfig['wizards']['link'])) {
-                    // If an input field has a relation to a sys_file record this need to be converted back to
-                    // the public path. But use getPublicUrl here, because could normally only be a local file path.
-                    $fileUid = $this->import_mapId[$relDat['table']][$relDat['id']];
-                    // Fallback value
-                    $value = 'file:' . $fileUid;
-                    try {
-                        $file = ResourceFactory::getInstance()->retrieveFileOrFolderObject($fileUid);
-                    } catch (\Exception $e) {
-                        $file = null;
-                    }
-                    if ($file instanceof FileInterface) {
-                        $value = $file->getPublicUrl();
-                    }
-                } else {
-                    $value = $relDat['table'] . '_' . $this->import_mapId[$relDat['table']][$relDat['id']];
-                }
-                $valArray[] = $value;
-            } elseif ($this->isTableStatic($relDat['table']) || $this->isExcluded($relDat['table'], $relDat['id']) || $relDat['id'] < 0) {
-                // Checking for less than zero because some select types could contain negative values,
-                // eg. fe_groups (-1, -2) and sys_language (-1 = ALL languages). This must be handled on both export and import.
-                $valArray[] = $relDat['table'] . '_' . $relDat['id'];
-            } else {
-                $this->error('Lost relation: ' . $relDat['table'] . ':' . $relDat['id']);
-            }
-        }
-        return $valArray;
-    }
-
-    /**
-     * Writes the file from import array to temp dir and returns the filename of it.
-     *
-     * @param array $fI File information with three keys: "filename" = filename without path, "ID_absFile" = absolute filepath to the file (including the filename), "ID" = md5 hash of "ID_absFile
-     * @return string|NULL Absolute filename of the temporary filename of the file. In ->alternativeFileName the original name is set.
-     */
-    public function import_addFileNameToBeCopied($fI)
-    {
-        if (is_array($this->dat['files'][$fI['ID']])) {
-            $tmpFile = null;
-            // check if there is the right file already in the local folder
-            if ($this->filesPathForImport !== null) {
-                if (is_file($this->filesPathForImport . '/' . $this->dat['files'][$fI['ID']]['content_md5']) &&
-                    md5_file($this->filesPathForImport . '/' . $this->dat['files'][$fI['ID']]['content_md5']) === $this->dat['files'][$fI['ID']]['content_md5']) {
-                    $tmpFile = $this->filesPathForImport . '/' . $this->dat['files'][$fI['ID']]['content_md5'];
-                }
-            }
-            if ($tmpFile === null) {
-                $tmpFile = GeneralUtility::tempnam('import_temp_');
-                GeneralUtility::writeFile($tmpFile, $this->dat['files'][$fI['ID']]['content']);
-            }
-            clearstatcache();
-            if (@is_file($tmpFile)) {
-                $this->unlinkFiles[] = $tmpFile;
-                if (filesize($tmpFile) == $this->dat['files'][$fI['ID']]['filesize']) {
-                    $this->alternativeFileName[$tmpFile] = $fI['filename'];
-                    $this->alternativeFilePath[$tmpFile] = $this->dat['files'][$fI['ID']]['relFileRef'];
-                    return $tmpFile;
-                } else {
-                    $this->error('Error: temporary file ' . $tmpFile . ' had a size (' . filesize($tmpFile) . ') different from the original (' . $this->dat['files'][$fI['ID']]['filesize'] . ')');
-                }
-            } else {
-                $this->error('Error: temporary file ' . $tmpFile . ' was not written as it should have been!');
-            }
-        } else {
-            $this->error('Error: No file found for ID ' . $fI['ID']);
-        }
-        return null;
-    }
-
-    /**
-     * After all DB relations has been set in the end of the import (see setRelations()) then it is time to correct all relations inside of FlexForm fields.
-     * The reason for doing this after is that the setting of relations may affect (quite often!) which data structure is used for the flexforms field!
-     *
-     * @return void
-     * @see setRelations()
-     */
-    public function setFlexFormRelations()
-    {
-        $updateData = array();
-        // import_newId contains a register of all records that was in the import memorys "records" key
-        foreach ($this->import_newId as $nId => $dat) {
-            $table = $dat['table'];
-            $uid = $dat['uid'];
-            // original UID - NOT the new one!
-            // If the record has been written and received a new id, then proceed:
-            if (!isset($this->import_mapId[$table][$uid])) {
-                $this->error('Error: this records is NOT created it seems! (' . $table . ':' . $uid . ')');
-                continue;
-            }
-
-            if (!is_array($this->dat['records'][$table . ':' . $uid]['rels'])) {
-                $this->error('Error: no record was found in data array!');
-                continue;
-            }
-            $thisNewUid = BackendUtility::wsMapId($table, $this->import_mapId[$table][$uid]);
-            // Traverse relation fields of each record
-            foreach ($this->dat['records'][$table . ':' . $uid]['rels'] as $field => $config) {
-                switch ((string)$config['type']) {
-                    case 'flex':
-                        // Get XML content and set as default value (string, non-processed):
-                        $updateData[$table][$thisNewUid][$field] = $this->dat['records'][$table . ':' . $uid]['data'][$field];
-                        // If there has been registered relations inside the flex form field, run processing on the content:
-                        if (!empty($config['flexFormRels']['db']) || !empty($config['flexFormRels']['file'])) {
-                            $origRecordRow = BackendUtility::getRecord($table, $thisNewUid, '*');
-                            // This will fetch the new row for the element (which should be updated with any references to data structures etc.)
-                            $conf = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
-                            if (is_array($origRecordRow) && is_array($conf) && $conf['type'] === 'flex') {
-                                // Get current data structure and value array:
-                                $dataStructArray = BackendUtility::getFlexFormDS($conf, $origRecordRow, $table, $field);
-                                $currentValueArray = GeneralUtility::xml2array($updateData[$table][$thisNewUid][$field]);
-                                // Do recursive processing of the XML data:
-                                $iteratorObj = GeneralUtility::makeInstance(DataHandler::class);
-                                $iteratorObj->callBackObj = $this;
-                                $currentValueArray['data'] = $iteratorObj->checkValue_flex_procInData(
-                                    $currentValueArray['data'],
-                                    array(),
-                                    array(),
-                                    $dataStructArray,
-                                    array($table, $thisNewUid, $field, $config),
-                                    'remapListedDBRecords_flexFormCallBack'
-                                );
-                                // The return value is set as an array which means it will be processed by tcemain for file and DB references!
-                                if (is_array($currentValueArray['data'])) {
-                                    $updateData[$table][$thisNewUid][$field] = $currentValueArray;
-                                }
-                            }
-                        }
-                        break;
-                }
-            }
-        }
-        if (!empty($updateData)) {
-            $tce = $this->getNewTCE();
-            $tce->isImporting = true;
-            $this->callHook('before_setFlexFormRelations', array(
-                'tce' => &$tce,
-                'data' => &$updateData
-            ));
-            $tce->start($updateData, array());
-            $tce->process_datamap();
-            $this->callHook('after_setFlexFormRelations', array(
-                'tce' => &$tce
-            ));
-        }
-    }
-
-    /**
-     * Callback function for traversing the FlexForm structure in relation to remapping database relations
-     *
-     * @param array $pParams Set of parameters in numeric array: table, uid, field
-     * @param array $dsConf TCA config for field (from Data Structure of course)
-     * @param string $dataValue Field value (from FlexForm XML)
-     * @param string $dataValue_ext1 Not used
-     * @param string $dataValue_ext2 Not used
-     * @param string $path Path of where the data structure of the element is found
-     * @return array Array where the "value" key carries the value.
-     * @see setFlexFormRelations()
-     */
-    public function remapListedDBRecords_flexFormCallBack($pParams, $dsConf, $dataValue, $dataValue_ext1, $dataValue_ext2, $path)
-    {
-        // Extract parameters:
-        list($table, $uid, $field, $config) = $pParams;
-        // In case the $path is used as index without a trailing slash we will remove that
-        if (!is_array($config['flexFormRels']['db'][$path]) && is_array($config['flexFormRels']['db'][rtrim($path, '/')])) {
-            $path = rtrim($path, '/');
-        }
-        if (is_array($config['flexFormRels']['db'][$path])) {
-            $valArray = $this->setRelations_db($config['flexFormRels']['db'][$path], $dsConf);
-            $dataValue = implode(',', $valArray);
-        }
-        if (is_array($config['flexFormRels']['file'][$path])) {
-            $valArr = array();
-            foreach ($config['flexFormRels']['file'][$path] as $fI) {
-                $valArr[] = $this->import_addFileNameToBeCopied($fI);
-            }
-            $dataValue = implode(',', $valArr);
-        }
-        return array('value' => $dataValue);
-    }
-
-    /**************************
-     * Import / Soft References
-     *************************/
-
-    /**
-     * Processing of soft references
-     *
-     * @return void
-     */
-    public function processSoftReferences()
-    {
-        // Initialize:
-        $inData = array();
-        // Traverse records:
-        if (is_array($this->dat['header']['records'])) {
-            foreach ($this->dat['header']['records'] as $table => $recs) {
-                foreach ($recs as $uid => $thisRec) {
-                    // If there are soft references defined, traverse those:
-                    if (isset($GLOBALS['TCA'][$table]) && is_array($thisRec['softrefs'])) {
-                        // First traversal is to collect softref configuration and split them up based on fields.
-                        // This could probably also have been done with the "records" key instead of the header.
-                        $fieldsIndex = array();
-                        foreach ($thisRec['softrefs'] as $softrefDef) {
-                            // If a substitution token is set:
-                            if ($softrefDef['field'] && is_array($softrefDef['subst']) && $softrefDef['subst']['tokenID']) {
-                                $fieldsIndex[$softrefDef['field']][$softrefDef['subst']['tokenID']] = $softrefDef;
-                            }
-                        }
-                        // The new id:
-                        $thisNewUid = BackendUtility::wsMapId($table, $this->import_mapId[$table][$uid]);
-                        // Now, if there are any fields that require substitution to be done, lets go for that:
-                        foreach ($fieldsIndex as $field => $softRefCfgs) {
-                            if (is_array($GLOBALS['TCA'][$table]['columns'][$field])) {
-                                $conf = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
-                                if ($conf['type'] === 'flex') {
-                                    // This will fetch the new row for the element (which should be updated with any references to data structures etc.)
-                                    $origRecordRow = BackendUtility::getRecord($table, $thisNewUid, '*');
-                                    if (is_array($origRecordRow)) {
-                                        // Get current data structure and value array:
-                                        $dataStructArray = BackendUtility::getFlexFormDS($conf, $origRecordRow, $table, $field);
-                                        $currentValueArray = GeneralUtility::xml2array($origRecordRow[$field]);
-                                        // Do recursive processing of the XML data:
-                                        /** @var $iteratorObj DataHandler */
-                                        $iteratorObj = GeneralUtility::makeInstance(DataHandler::class);
-                                        $iteratorObj->callBackObj = $this;
-                                        $currentValueArray['data'] = $iteratorObj->checkValue_flex_procInData($currentValueArray['data'], array(), array(), $dataStructArray, array($table, $uid, $field, $softRefCfgs), 'processSoftReferences_flexFormCallBack');
-                                        // The return value is set as an array which means it will be processed by tcemain for file and DB references!
-                                        if (is_array($currentValueArray['data'])) {
-                                            $inData[$table][$thisNewUid][$field] = $currentValueArray;
-                                        }
-                                    }
-                                } else {
-                                    // Get tokenizedContent string and proceed only if that is not blank:
-                                    $tokenizedContent = $this->dat['records'][$table . ':' . $uid]['rels'][$field]['softrefs']['tokenizedContent'];
-                                    if (strlen($tokenizedContent) && is_array($softRefCfgs)) {
-                                        $inData[$table][$thisNewUid][$field] = $this->processSoftReferences_substTokens($tokenizedContent, $softRefCfgs, $table, $uid);
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        // Now write to database:
-        $tce = $this->getNewTCE();
-        $tce->isImporting = true;
-        $this->callHook('before_processSoftReferences', array(
-            'tce' => $tce,
-            'data' => &$inData
-        ));
-        $tce->enableLogging = true;
-        $tce->start($inData, array());
-        $tce->process_datamap();
-        $this->callHook('after_processSoftReferences', array(
-            'tce' => $tce
-        ));
-    }
-
-    /**
-     * Callback function for traversing the FlexForm structure in relation to remapping softreference relations
-     *
-     * @param array $pParams Set of parameters in numeric array: table, uid, field
-     * @param array $dsConf TCA config for field (from Data Structure of course)
-     * @param string $dataValue Field value (from FlexForm XML)
-     * @param string $dataValue_ext1 Not used
-     * @param string $dataValue_ext2 Not used
-     * @param string $path Path of where the data structure where the element is found
-     * @return array Array where the "value" key carries the value.
-     * @see setFlexFormRelations()
-     */
-    public function processSoftReferences_flexFormCallBack($pParams, $dsConf, $dataValue, $dataValue_ext1, $dataValue_ext2, $path)
-    {
-        // Extract parameters:
-        list($table, $origUid, $field, $softRefCfgs) = $pParams;
-        if (is_array($softRefCfgs)) {
-            // First, find all soft reference configurations for this structure path (they are listed flat in the header):
-            $thisSoftRefCfgList = array();
-            foreach ($softRefCfgs as $sK => $sV) {
-                if ($sV['structurePath'] === $path) {
-                    $thisSoftRefCfgList[$sK] = $sV;
-                }
-            }
-            // If any was found, do processing:
-            if (!empty($thisSoftRefCfgList)) {
-                // Get tokenizedContent string and proceed only if that is not blank:
-                $tokenizedContent = $this->dat['records'][$table . ':' . $origUid]['rels'][$field]['flexFormRels']['softrefs'][$path]['tokenizedContent'];
-                if (strlen($tokenizedContent)) {
-                    $dataValue = $this->processSoftReferences_substTokens($tokenizedContent, $thisSoftRefCfgList, $table, $origUid);
-                }
-            }
-        }
-        // Return
-        return array('value' => $dataValue);
-    }
-
-    /**
-     * Substition of softreference tokens
-     *
-     * @param string $tokenizedContent Content of field with soft reference tokens in.
-     * @param array $softRefCfgs Soft reference configurations
-     * @param string $table Table for which the processing occurs
-     * @param string $uid UID of record from table
-     * @return string The input content with tokens substituted according to entries in softRefCfgs
-     */
-    public function processSoftReferences_substTokens($tokenizedContent, $softRefCfgs, $table, $uid)
-    {
-        // traverse each softref type for this field:
-        foreach ($softRefCfgs as $cfg) {
-            // Get token ID:
-            $tokenID = $cfg['subst']['tokenID'];
-            // Default is current token value:
-            $insertValue = $cfg['subst']['tokenValue'];
-            // Based on mode:
-            switch ((string)$this->softrefCfg[$tokenID]['mode']) {
-                case 'exclude':
-                    // Exclude is a simple passthrough of the value
-                    break;
-                case 'editable':
-                    // Editable always picks up the value from this input array:
-                    $insertValue = $this->softrefInputValues[$tokenID];
-                    break;
-                default:
-                    // Mapping IDs/creating files: Based on type, look up new value:
-                    switch ((string)$cfg['subst']['type']) {
-                        case 'file':
-                            // Create / Overwrite file:
-                            $insertValue = $this->processSoftReferences_saveFile($cfg['subst']['relFileName'], $cfg, $table, $uid);
-                            break;
-                        case 'db':
-                        default:
-                            // Trying to map database element if found in the mapID array:
-                            list($tempTable, $tempUid) = explode(':', $cfg['subst']['recordRef']);
-                            if (isset($this->import_mapId[$tempTable][$tempUid])) {
-                                $insertValue = BackendUtility::wsMapId($tempTable, $this->import_mapId[$tempTable][$tempUid]);
-                                // Look if reference is to a page and the original token value was NOT an integer - then we assume is was an alias and try to look up the new one!
-                                if ($tempTable === 'pages' && !MathUtility::canBeInterpretedAsInteger($cfg['subst']['tokenValue'])) {
-                                    $recWithUniqueValue = BackendUtility::getRecord($tempTable, $insertValue, 'alias');
-                                    if ($recWithUniqueValue['alias']) {
-                                        $insertValue = $recWithUniqueValue['alias'];
-                                    }
-                                } elseif (strpos($cfg['subst']['tokenValue'], ':') !== false) {
-                                    list($tokenKey) = explode(':', $cfg['subst']['tokenValue']);
-                                    $insertValue = $tokenKey . ':' . $insertValue;
-                                }
-                            }
-                    }
-            }
-            // Finally, swap the soft reference token in tokenized content with the insert value:
-            $tokenizedContent = str_replace('{softref:' . $tokenID . '}', $insertValue, $tokenizedContent);
-        }
-        return $tokenizedContent;
-    }
-
-    /**
-     * Process a soft reference file
-     *
-     * @param string $relFileName Old Relative filename
-     * @param array $cfg soft reference configuration array
-     * @param string $table Table for which the processing occurs
-     * @param string $uid UID of record from table
-     * @return string New relative filename (value to insert instead of the softref token)
-     */
-    public function processSoftReferences_saveFile($relFileName, $cfg, $table, $uid)
-    {
-        if ($fileHeaderInfo = $this->dat['header']['files'][$cfg['file_ID']]) {
-            // Initialize; Get directory prefix for file and find possible RTE filename
-            $dirPrefix = PathUtility::dirname($relFileName) . '/';
-            $rteOrigName = $this->getRTEoriginalFilename(PathUtility::basename($relFileName));
-            // If filename looks like an RTE file, and the directory is in "uploads/", then process as a RTE file!
-            if ($rteOrigName && GeneralUtility::isFirstPartOfStr($dirPrefix, 'uploads/')) {
-                // RTE:
-                // First, find unique RTE file name:
-                if (@is_dir((PATH_site . $dirPrefix))) {
-                    // From the "original" RTE filename, produce a new "original" destination filename which is unused.
-                    // Even if updated, the image should be unique. Currently the problem with this is that it leaves a lot of unused RTE images...
-                    $fileProcObj = $this->getFileProcObj();
-                    $origDestName = $fileProcObj->getUniqueName($rteOrigName, PATH_site . $dirPrefix);
-                    // Create copy file name:
-                    $pI = pathinfo($relFileName);
-                    $copyDestName = PathUtility::dirname($origDestName) . '/RTEmagicC_' . substr(PathUtility::basename($origDestName), 10) . '.' . $pI['extension'];
-                    if (
-                        !@is_file($copyDestName) && !@is_file($origDestName)
-                        && $origDestName === GeneralUtility::getFileAbsFileName($origDestName)
-                        && $copyDestName === GeneralUtility::getFileAbsFileName($copyDestName)
-                    ) {
-                        if ($this->dat['header']['files'][$fileHeaderInfo['RTE_ORIG_ID']]) {
-                            if ($this->legacyImport) {
-                                $fileName = PathUtility::basename($copyDestName);
-                                $this->writeSysFileResourceForLegacyImport($fileName, $cfg['file_ID']);
-                                $relFileName = $this->filePathMap[$cfg['file_ID']] . '" data-htmlarea-file-uid="' . $fileName . '" data-htmlarea-file-table="sys_file';
-                                // Also save the original file
-                                $originalFileName = PathUtility::basename($origDestName);
-                                $this->writeSysFileResourceForLegacyImport($originalFileName, $fileHeaderInfo['RTE_ORIG_ID']);
-                            } else {
-                                // Write the copy and original RTE file to the respective filenames:
-                                $this->writeFileVerify($copyDestName, $cfg['file_ID'], true);
-                                $this->writeFileVerify($origDestName, $fileHeaderInfo['RTE_ORIG_ID'], true);
-                                // Return the relative path of the copy file name:
-                                return PathUtility::stripPathSitePrefix($copyDestName);
-                            }
-                        } else {
-                            $this->error('ERROR: Could not find original file ID');
-                        }
-                    } else {
-                        $this->error('ERROR: The destination filenames "' . $copyDestName . '" and "' . $origDestName . '" either existed or have non-valid names');
-                    }
-                } else {
-                    $this->error('ERROR: "' . PATH_site . $dirPrefix . '" was not a directory, so could not process file "' . $relFileName . '"');
-                }
-            } elseif (GeneralUtility::isFirstPartOfStr($dirPrefix, $this->fileadminFolderName . '/')) {
-                // File in fileadmin/ folder:
-                // Create file (and possible resources)
-                $newFileName = $this->processSoftReferences_saveFile_createRelFile($dirPrefix, PathUtility::basename($relFileName), $cfg['file_ID'], $table, $uid);
-                if (strlen($newFileName)) {
-                    $relFileName = $newFileName;
-                } else {
-                    $this->error('ERROR: No new file created for "' . $relFileName . '"');
-                }
-            } else {
-                $this->error('ERROR: Sorry, cannot operate on non-RTE files which are outside the fileadmin folder.');
-            }
-        } else {
-            $this->error('ERROR: Could not find file ID in header.');
-        }
-        // Return (new) filename relative to PATH_site:
-        return $relFileName;
-    }
-
-    /**
-     * Create file in directory and return the new (unique) filename
-     *
-     * @param string $origDirPrefix Directory prefix, relative, with trailing slash
-     * @param string $fileName Filename (without path)
-     * @param string $fileID File ID from import memory
-     * @param string $table Table for which the processing occurs
-     * @param string $uid UID of record from table
-     * @return string|NULL New relative filename, if any
-     */
-    public function processSoftReferences_saveFile_createRelFile($origDirPrefix, $fileName, $fileID, $table, $uid)
-    {
-        // If the fileID map contains an entry for this fileID then just return the relative filename of that entry;
-        // we don't want to write another unique filename for this one!
-        if (isset($this->fileIDMap[$fileID])) {
-            return PathUtility::stripPathSitePrefix($this->fileIDMap[$fileID]);
-        }
-        if ($this->legacyImport) {
-            // set dirPrefix to fileadmin because the right target folder is set and checked for permissions later
-            $dirPrefix = $this->fileadminFolderName . '/';
-        } else {
-            // Verify FileMount access to dir-prefix. Returns the best alternative relative path if any
-            $dirPrefix = $this->verifyFolderAccess($origDirPrefix);
-        }
-        if ($dirPrefix && (!$this->update || $origDirPrefix === $dirPrefix) && $this->checkOrCreateDir($dirPrefix)) {
-            $fileHeaderInfo = $this->dat['header']['files'][$fileID];
-            $updMode = $this->update && $this->import_mapId[$table][$uid] === $uid && $this->import_mode[$table . ':' . $uid] !== 'as_new';
-            // Create new name for file:
-            // Must have same ID in map array (just for security, is not really needed) and NOT be set "as_new".
-
-            // Write main file:
-            if ($this->legacyImport) {
-                $fileWritten = $this->writeSysFileResourceForLegacyImport($fileName, $fileID);
-                if ($fileWritten) {
-                    $newName = 'file:' . $fileName;
-                    return $newName;
-                    // no support for HTML/CSS file resources attached ATM - see below
-                }
-            } else {
-                if ($updMode) {
-                    $newName = PATH_site . $dirPrefix . $fileName;
-                } else {
-                    // Create unique filename:
-                    $fileProcObj = $this->getFileProcObj();
-                    $newName = $fileProcObj->getUniqueName($fileName, PATH_site . $dirPrefix);
-                }
-                if ($this->writeFileVerify($newName, $fileID)) {
-                    // If the resource was an HTML/CSS file with resources attached, we will write those as well!
-                    if (is_array($fileHeaderInfo['EXT_RES_ID'])) {
-                        $tokenizedContent = $this->dat['files'][$fileID]['tokenizedContent'];
-                        $tokenSubstituted = false;
-                        $fileProcObj = $this->getFileProcObj();
-                        if ($updMode) {
-                            foreach ($fileHeaderInfo['EXT_RES_ID'] as $res_fileID) {
-                                if ($this->dat['files'][$res_fileID]['filename']) {
-                                    // Resolve original filename:
-                                    $relResourceFileName = $this->dat['files'][$res_fileID]['parentRelFileName'];
-                                    $absResourceFileName = GeneralUtility::resolveBackPath(PATH_site . $origDirPrefix . $relResourceFileName);
-                                    $absResourceFileName = GeneralUtility::getFileAbsFileName($absResourceFileName);
-                                    if ($absResourceFileName && GeneralUtility::isFirstPartOfStr($absResourceFileName, PATH_site . $this->fileadminFolderName . '/')) {
-                                        $destDir = PathUtility::stripPathSitePrefix(PathUtility::dirname($absResourceFileName) . '/');
-                                        if ($this->verifyFolderAccess($destDir, true) && $this->checkOrCreateDir($destDir)) {
-                                            $this->writeFileVerify($absResourceFileName, $res_fileID);
-                                        } else {
-                                            $this->error('ERROR: Could not create file in directory "' . $destDir . '"');
-                                        }
-                                    } else {
-                                        $this->error('ERROR: Could not resolve path for "' . $relResourceFileName . '"');
-                                    }
-                                    $tokenizedContent = str_replace('{EXT_RES_ID:' . $res_fileID . '}', $relResourceFileName, $tokenizedContent);
-                                    $tokenSubstituted = true;
-                                }
-                            }
-                        } else {
-                            // Create the resouces directory name (filename without extension, suffixed "_FILES")
-                            $resourceDir = PathUtility::dirname($newName) . '/' . preg_replace('/\\.[^.]*$/', '', PathUtility::basename($newName)) . '_FILES';
-                            if (GeneralUtility::mkdir($resourceDir)) {
-                                foreach ($fileHeaderInfo['EXT_RES_ID'] as $res_fileID) {
-                                    if ($this->dat['files'][$res_fileID]['filename']) {
-                                        $absResourceFileName = $fileProcObj->getUniqueName($this->dat['files'][$res_fileID]['filename'], $resourceDir);
-                                        $relResourceFileName = substr($absResourceFileName, strlen(PathUtility::dirname($resourceDir)) + 1);
-                                        $this->writeFileVerify($absResourceFileName, $res_fileID);
-                                        $tokenizedContent = str_replace('{EXT_RES_ID:' . $res_fileID . '}', $relResourceFileName, $tokenizedContent);
-                                        $tokenSubstituted = true;
-                                    }
-                                }
-                            }
-                        }
-                        // If substitutions has been made, write the content to the file again:
-                        if ($tokenSubstituted) {
-                            GeneralUtility::writeFile($newName, $tokenizedContent);
-                        }
-                    }
-                    return PathUtility::stripPathSitePrefix($newName);
-                }
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Writes a file from the import memory having $fileID to file name $fileName which must be an absolute path inside PATH_site
-     *
-     * @param string $fileName Absolute filename inside PATH_site to write to
-     * @param string $fileID File ID from import memory
-     * @param bool $bypassMountCheck Bypasses the checking against filemounts - only for RTE files!
-     * @return bool Returns TRUE if it went well. Notice that the content of the file is read again, and md5 from import memory is validated.
-     */
-    public function writeFileVerify($fileName, $fileID, $bypassMountCheck = false)
-    {
-        $fileProcObj = $this->getFileProcObj();
-        if (!$fileProcObj->actionPerms['addFile']) {
-            $this->error('ERROR: You did not have sufficient permissions to write the file "' . $fileName . '"');
-            return false;
-        }
-        // Just for security, check again. Should actually not be necessary.
-        if (!$fileProcObj->checkPathAgainstMounts($fileName) && !$bypassMountCheck) {
-            $this->error('ERROR: Filename "' . $fileName . '" was not allowed in destination path!');
-            return false;
-        }
-        $fI = GeneralUtility::split_fileref($fileName);
-        if (!$fileProcObj->checkIfAllowed($fI['fileext'], $fI['path'], $fI['file']) && (!$this->allowPHPScripts || !$this->getBackendUser()->isAdmin())) {
-            $this->error('ERROR: Filename "' . $fileName . '" failed against extension check or deny-pattern!');
-            return false;
-        }
-        if (!GeneralUtility::getFileAbsFileName($fileName)) {
-            $this->error('ERROR: Filename "' . $fileName . '" was not a valid relative file path!');
-            return false;
-        }
-        if (!$this->dat['files'][$fileID]) {
-            $this->error('ERROR: File ID "' . $fileID . '" could not be found');
-            return false;
-        }
-        GeneralUtility::writeFile($fileName, $this->dat['files'][$fileID]['content']);
-        $this->fileIDMap[$fileID] = $fileName;
-        if (md5(GeneralUtility::getUrl($fileName)) == $this->dat['files'][$fileID]['content_md5']) {
-            return true;
-        } else {
-            $this->error('ERROR: File content "' . $fileName . '" was corrupted');
-            return false;
-        }
-    }
-
-    /**
-     * Writes the file with the is $fileId to the legacy import folder. The file name will used from
-     * argument $fileName and the file was successfully created or an identical file was already found,
-     * $fileName will held the uid of the new created file record.
-     *
-     * @param string $fileName The file name for the new file. Value would be changed to the uid of the new created file record.
-     * @param int $fileId The id of the file in data array
-     * @return bool
-     */
-    protected function writeSysFileResourceForLegacyImport(&$fileName, $fileId)
-    {
-        if ($this->legacyImportFolder === null) {
-            return false;
-        }
-
-        if (!isset($this->dat['files'][$fileId])) {
-            $this->error('ERROR: File ID "' . $fileId . '" could not be found');
-            return false;
-        }
-
-        $temporaryFile = $this->writeTemporaryFileFromData($fileId, 'files');
-        if ($temporaryFile === null) {
-            // error on writing the file. Error message was already added
-            return false;
-        }
-
-        $importFolder = $this->legacyImportFolder;
-
-        if (isset($this->dat['files'][$fileId]['relFileName'])) {
-            $relativeFilePath = PathUtility::dirname($this->dat['files'][$fileId]['relFileName']);
-
-            if (!$this->legacyImportFolder->hasFolder($relativeFilePath)) {
-                $this->legacyImportFolder->createFolder($relativeFilePath);
-            }
-            $importFolder = $this->legacyImportFolder->getSubfolder($relativeFilePath);
-        }
-
-        $fileObject = null;
-
-        try {
-            // check, if there is alreay the same file in the folder
-            if ($importFolder->hasFile($fileName)) {
-                $fileStorage = $importFolder->getStorage();
-                $file = $fileStorage->getFile($importFolder->getIdentifier() . $fileName);
-                if ($file->getSha1() === sha1_file($temporaryFile)) {
-                    $fileObject = $file;
-                }
-            }
-        } catch (Exception $e) {
-        }
-
-        if ($fileObject === null) {
-            try {
-                $fileObject = $importFolder->addFile($temporaryFile, $fileName, DuplicationBehavior::RENAME);
-            } catch (Exception $e) {
-                $this->error('Error: no file could be added to the storage for file name ' . $this->alternativeFileName[$temporaryFile]);
-            }
-        }
-
-        if (md5_file(PATH_site . $fileObject->getPublicUrl()) == $this->dat['files'][$fileId]['content_md5']) {
-            $fileName = $fileObject->getUid();
-            $this->fileIDMap[$fileId] = $fileName;
-            $this->filePathMap[$fileId] = $fileObject->getPublicUrl();
-            return true;
-        } else {
-            $this->error('ERROR: File content "' . $this->dat['files'][$fileId]['relFileName'] . '" was corrupted');
-        }
-
-        return false;
-    }
-
-    /**
-     * Migrate legacy import records
+     * Add table names here which are THE ONLY ones which will be included
+     * into export if found as relations. '_ALL' will allow all tables.
      *
-     * @return void
+     * @var array
      */
-    protected function migrateLegacyImportRecords()
-    {
-        $updateData= array();
-
-        foreach ($this->legacyImportMigrationRecords as $table => $records) {
-            foreach ($records as $uid => $fields) {
-                $row = BackendUtility::getRecord($table, $uid);
-                if (empty($row)) {
-                    continue;
-                }
-
-                foreach ($fields as $field => $referenceIds) {
-                    $fieldConfiguration = $this->legacyImportMigrationTables[$table][$field];
-
-                    if (isset($fieldConfiguration['titleTexts'])) {
-                        $titleTextField = $fieldConfiguration['titleTexts'];
-                        if (isset($row[$titleTextField]) && $row[$titleTextField] !== '') {
-                            $titleTextContents = explode(LF, $row[$titleTextField]);
-                            $updateData[$table][$uid][$titleTextField] = '';
-                        }
-                    }
+    public $relOnlyTables = array();
 
-                    if (isset($fieldConfiguration['alternativeTexts'])) {
-                        $alternativeTextField = $fieldConfiguration['alternativeTexts'];
-                        if (isset($row[$alternativeTextField]) && $row[$alternativeTextField] !== '') {
-                            $alternativeTextContents = explode(LF, $row[$alternativeTextField]);
-                            $updateData[$table][$uid][$alternativeTextField] = '';
-                        }
-                    }
-                    if (isset($fieldConfiguration['description'])) {
-                        $descriptionField = $fieldConfiguration['description'];
-                        if ($row[$descriptionField] !== '') {
-                            $descriptionContents = explode(LF, $row[$descriptionField]);
-                            $updateData[$table][$uid][$descriptionField] = '';
-                        }
-                    }
-                    if (isset($fieldConfiguration['links'])) {
-                        $linkField = $fieldConfiguration['links'];
-                        if ($row[$linkField] !== '') {
-                            $linkContents = explode(LF, $row[$linkField]);
-                            $updateData[$table][$uid][$linkField] = '';
-                        }
-                    }
+    /**
+     * Add tables names here which should not be exported with the file.
+     * (Where relations should be mapped to same UIDs in target system).
+     *
+     * @var array
+     */
+    public $relStaticTables = array();
 
-                    foreach ($referenceIds as $key => $referenceId) {
-                        if (isset($titleTextContents[$key])) {
-                            $updateData['sys_file_reference'][$referenceId]['title'] = trim($titleTextContents[$key]);
-                        }
-                        if (isset($alternativeTextContents[$key])) {
-                            $updateData['sys_file_reference'][$referenceId]['alternative'] = trim($alternativeTextContents[$key]);
-                        }
-                        if (isset($descriptionContents[$key])) {
-                            $updateData['sys_file_reference'][$referenceId]['description'] = trim($descriptionContents[$key]);
-                        }
-                        if (isset($linkContents[$key])) {
-                            $updateData['sys_file_reference'][$referenceId]['link'] = trim($linkContents[$key]);
-                        }
-                    }
-                }
-            }
-        }
+    /**
+     * Exclude map. Keys are table:uid  pairs and if set, records are not added to the export.
+     *
+     * @var array
+     */
+    public $excludeMap = array();
 
-        // update
-        $tce = $this->getNewTCE();
-        $tce->isImporting = true;
-        $tce->start($updateData, array());
-        $tce->process_datamap();
-    }
+    /**
+     * Soft Reference Token ID modes.
+     *
+     * @var array
+     */
+    public $softrefCfg = array();
 
     /**
-     * Returns TRUE if directory exists  and if it doesn't it will create directory and return TRUE if that succeeded.
+     * Listing extension dependencies.
      *
-     * @param string $dirPrefix Directory to create. Having a trailing slash. Must be in fileadmin/. Relative to PATH_site
-     * @return bool TRUE, if directory exists (was created)
+     * @var array
      */
-    public function checkOrCreateDir($dirPrefix)
-    {
-        // Split dir path and remove first directory (which should be "fileadmin")
-        $filePathParts = explode('/', $dirPrefix);
-        $firstDir = array_shift($filePathParts);
-        if ($firstDir === $this->fileadminFolderName && GeneralUtility::getFileAbsFileName($dirPrefix)) {
-            $pathAcc = '';
-            foreach ($filePathParts as $dirname) {
-                $pathAcc .= '/' . $dirname;
-                if (strlen($dirname)) {
-                    if (!@is_dir((PATH_site . $this->fileadminFolderName . $pathAcc))) {
-                        if (!GeneralUtility::mkdir((PATH_site . $this->fileadminFolderName . $pathAcc))) {
-                            $this->error('ERROR: Directory could not be created....B');
-                            return false;
-                        }
-                    }
-                } elseif ($dirPrefix === $this->fileadminFolderName . $pathAcc) {
-                    return true;
-                } else {
-                    $this->error('ERROR: Directory could not be created....A');
-                }
-            }
-        }
-        return false;
-    }
+    public $extensionDependencies = array();
 
     /**
-     * Verifies that the input path (relative to PATH_site) is found in the backend users filemounts.
-     * If it doesn't it will try to find another relative filemount for the user and return an alternative path prefix for the file.
+     * After records are written this array is filled with [table][original_uid] = [new_uid]
      *
-     * @param string $dirPrefix Path relative to PATH_site
-     * @param bool $noAlternative If set, Do not look for alternative path! Just return FALSE
-     * @return string|bool If a path is available that will be returned, otherwise FALSE.
+     * @var array
      */
-    public function verifyFolderAccess($dirPrefix, $noAlternative = false)
-    {
-        $fileProcObj = $this->getFileProcObj();
-        // Check, if dirPrefix is inside a valid Filemount for user:
-        $result = $fileProcObj->checkPathAgainstMounts(PATH_site . $dirPrefix);
-        // If not, try to find another relative filemount and use that instead:
-        if (!$result) {
-            if ($noAlternative) {
-                return false;
-            }
-            // Find first web folder:
-            $result = $fileProcObj->findFirstWebFolder();
-            // If that succeeded, return the path to it:
-            if ($result) {
-                // Remove the "fileadmin/" prefix of input path - and append the rest to the return value:
-                if (GeneralUtility::isFirstPartOfStr($dirPrefix, $this->fileadminFolderName . '/')) {
-                    $dirPrefix = substr($dirPrefix, strlen($this->fileadminFolderName . '/'));
-                }
-                return PathUtility::stripPathSitePrefix($fileProcObj->mounts[$result]['path'] . $dirPrefix);
-            }
-        } else {
-            return $dirPrefix;
-        }
-        return false;
-    }
+    public $import_mapId = array();
 
-    /**************************
-     * File Input
-     *************************/
+    /**
+     * Error log.
+     *
+     * @var array
+     */
+    public $errorLog = array();
 
     /**
-     * Loads the header section/all of the $filename into memory
+     * Cache for record paths
      *
-     * @param string $filename Filename, absolute
-     * @param bool $all If set, all information is loaded (header, records and files). Otherwise the default is to read only the header information
-     * @return bool TRUE if the operation went well
+     * @var array
      */
-    public function loadFile($filename, $all = false)
-    {
-        if (!@is_file($filename)) {
-            $this->error('Filename not found: ' . $filename);
-            return false;
-        }
-        $fI = pathinfo($filename);
-        if (@is_dir($filename . '.files')) {
-            if (GeneralUtility::isAllowedAbsPath($filename . '.files')) {
-                // copy the folder lowlevel to typo3temp, because the files would be deleted after import
-                $temporaryFolderName = $this->getTemporaryFolderName();
-                GeneralUtility::copyDirectory($filename . '.files', $temporaryFolderName);
-                $this->filesPathForImport = $temporaryFolderName;
-            } else {
-                $this->error('External import files for the given import source is currently not supported.');
-            }
-        }
-        if (strtolower($fI['extension']) == 'xml') {
-            // XML:
-            $xmlContent = GeneralUtility::getUrl($filename);
-            if (strlen($xmlContent)) {
-                $this->dat = GeneralUtility::xml2array($xmlContent, '', true);
-                if (is_array($this->dat)) {
-                    if ($this->dat['_DOCUMENT_TAG'] === 'T3RecordDocument' && is_array($this->dat['header']) && is_array($this->dat['records'])) {
-                        $this->loadInit();
-                        return true;
-                    } else {
-                        $this->error('XML file did not contain proper XML for TYPO3 Import');
-                    }
-                } else {
-                    $this->error('XML could not be parsed: ' . $this->dat);
-                }
-            } else {
-                $this->error('Error opening file: ' . $filename);
-            }
-        } else {
-            // T3D
-            if ($fd = fopen($filename, 'rb')) {
-                $this->dat['header'] = $this->getNextFilePart($fd, 1, 'header');
-                if ($all) {
-                    $this->dat['records'] = $this->getNextFilePart($fd, 1, 'records');
-                    $this->dat['files'] = $this->getNextFilePart($fd, 1, 'files');
-                    $this->dat['files_fal'] = $this->getNextFilePart($fd, 1, 'files_fal');
-                }
-                $this->loadInit();
-                return true;
-            } else {
-                $this->error('Error opening file: ' . $filename);
-            }
-            fclose($fd);
-        }
-        return false;
-    }
+    public $cache_getRecordPath = array();
 
     /**
-     * Returns the next content part form the fileresource (t3d), $fd
+     * Cache of checkPID values.
      *
-     * @param resource $fd File pointer
-     * @param bool $unserialize If set, the returned content is unserialized into an array, otherwise you get the raw string
-     * @param string $name For error messages this indicates the section of the problem.
-     * @return string|NULL Data string or NULL in case of an error
-     * @access private
-     * @see loadFile()
+     * @var array
      */
-    public function getNextFilePart($fd, $unserialize = false, $name = '')
-    {
-        $initStrLen = 32 + 1 + 1 + 1 + 10 + 1;
-        // Getting header data
-        $initStr = fread($fd, $initStrLen);
-        if (empty($initStr)) {
-            $this->error('File does not contain data for "' . $name . '"');
-            return null;
-        }
-        $initStrDat = explode(':', $initStr);
-        if (strstr($initStrDat[0], 'Warning')) {
-            $this->error('File read error: Warning message in file. (' . $initStr . fgets($fd) . ')');
-            return null;
-        }
-        if ((string)$initStrDat[3] !== '') {
-            $this->error('File read error: InitString had a wrong length. (' . $name . ')');
-            return null;
-        }
-        $datString = fread($fd, (int)$initStrDat[2]);
-        fread($fd, 1);
-        if (md5($datString) === $initStrDat[0]) {
-            if ($initStrDat[1]) {
-                if ($this->compress) {
-                    $datString = gzuncompress($datString);
-                    return $unserialize ? unserialize($datString) : $datString;
-                } else {
-                    $this->error('Content read error: This file requires decompression, but this server does not offer gzcompress()/gzuncompress() functions.');
-                }
-            }
-        } else {
-            $this->error('MD5 check failed (' . $name . ')');
-        }
-        return null;
-    }
+    public $checkPID_cache = array();
 
     /**
-     * Loads T3D file content into the $this->dat array
-     * (This function can be used to test the output strings from ->compileMemoryToFileContent())
+     * Set internally if the gzcompress function exists
+     * Used by ImportExportController
      *
-     * @param string $filecontent File content
-     * @return void
+     * @var bool
      */
-    public function loadContent($filecontent)
-    {
-        $pointer = 0;
-        $this->dat['header'] = $this->getNextContentPart($filecontent, $pointer, 1, 'header');
-        $this->dat['records'] = $this->getNextContentPart($filecontent, $pointer, 1, 'records');
-        $this->dat['files'] = $this->getNextContentPart($filecontent, $pointer, 1, 'files');
-        $this->loadInit();
-    }
+    public $compress = false;
 
     /**
-     * Returns the next content part from the $filecontent
+     * Internal import/export memory
      *
-     * @param string $filecontent File content string
-     * @param int $pointer File pointer (where to read from)
-     * @param bool $unserialize If set, the returned content is unserialized into an array, otherwise you get the raw string
-     * @param string $name For error messages this indicates the section of the problem.
-     * @return string|NULL Data string
+     * @var array
      */
-    public function getNextContentPart($filecontent, &$pointer, $unserialize = false, $name = '')
-    {
-        $initStrLen = 32 + 1 + 1 + 1 + 10 + 1;
-        // getting header data
-        $initStr = substr($filecontent, $pointer, $initStrLen);
-        $pointer += $initStrLen;
-        $initStrDat = explode(':', $initStr);
-        if ((string)$initStrDat[3] !== '') {
-            $this->error('Content read error: InitString had a wrong length. (' . $name . ')');
-            return null;
-        }
-        $datString = substr($filecontent, $pointer, (int)$initStrDat[2]);
-        $pointer += (int)$initStrDat[2] + 1;
-        if (md5($datString) === $initStrDat[0]) {
-            if ($initStrDat[1]) {
-                if ($this->compress) {
-                    $datString = gzuncompress($datString);
-                    return $unserialize ? unserialize($datString) : $datString;
-                } else {
-                    $this->error('Content read error: This file requires decompression, but this server does not offer gzcompress()/gzuncompress() functions.');
-                }
-            }
-        } else {
-            $this->error('MD5 check failed (' . $name . ')');
-        }
-        return null;
-    }
+    public $dat = array();
 
     /**
-     * Setting up the object based on the recently loaded ->dat array
+     * File processing object
      *
-     * @return void
+     * @var ExtendedFileUtility
+     */
+    protected $fileProcObj = null;
+
+    /**
+     * @var array
+     */
+    protected $remainHeader = array();
+
+    /**
+     * @var IconFactory
+     */
+    protected $iconFactory;
+
+    /**
+     * The constructor
      */
-    public function loadInit()
+    public function __construct()
     {
-        $this->relStaticTables = (array)$this->dat['header']['relStaticTables'];
-        $this->excludeMap = (array)$this->dat['header']['excludeMap'];
-        $this->softrefCfg = (array)$this->dat['header']['softrefCfg'];
-        $this->extensionDependencies = (array)$this->dat['header']['extensionDependencies'];
-        $this->fixCharsets();
-        if (
-            isset($this->dat['header']['meta']['TYPO3_version'])
-            && VersionNumberUtility::convertVersionNumberToInteger($this->dat['header']['meta']['TYPO3_version']) < 6000000
-        ) {
-            $this->legacyImport = true;
-            $this->initializeLegacyImportFolder();
-        }
+        $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
     }
 
+    /**************************
+     * Initialize
+     *************************/
+
     /**
-     * Fix charset of import memory if different from system charset
+     * Init the object, both import and export
      *
      * @return void
-     * @see loadInit()
      */
-    public function fixCharsets()
+    public function init()
     {
-        $importCharset = $this->dat['header']['charset'];
-        if ($importCharset) {
-            if ($importCharset !== $this->getLanguageService()->charSet) {
-                $this->error('CHARSET: Converting charset of input file (' . $importCharset . ') to the system charset (' . $this->getLanguageService()->charSet . ')');
-                // Convert meta data:
-                if (is_array($this->dat['header']['meta'])) {
-                    $this->getLanguageService()->csConvObj->convArray($this->dat['header']['meta'], $importCharset, $this->getLanguageService()->charSet);
-                }
-                // Convert record headers:
-                if (is_array($this->dat['header']['records'])) {
-                    $this->getLanguageService()->csConvObj->convArray($this->dat['header']['records'], $importCharset, $this->getLanguageService()->charSet);
-                }
-                // Convert records themselves:
-                if (is_array($this->dat['records'])) {
-                    $this->getLanguageService()->csConvObj->convArray($this->dat['records'], $importCharset, $this->getLanguageService()->charSet);
-                }
-            }
-        } else {
-            $this->error('CHARSET: No charset found in import file!');
-        }
+        $this->compress = function_exists('gzcompress');
+        $this->fileadminFolderName = !empty($GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir']) ? rtrim($GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'], '/') : 'fileadmin';
     }
 
     /********************************************************
@@ -3436,7 +289,7 @@ class ImportExport
         // Check extension dependencies:
         if (is_array($this->dat['header']['extensionDependencies'])) {
             foreach ($this->dat['header']['extensionDependencies'] as $extKey) {
-                if (!empty($extKey) && !ExtensionManagementUtility::isLoaded($extKey)) {
+                if (!ExtensionManagementUtility::isLoaded($extKey)) {
                     $this->error('DEPENDENCY: The extension with key "' . $extKey . '" must be installed!');
                 }
             }
@@ -4053,10 +906,80 @@ class ImportExport
         return '';
     }
 
+    /**
+     * Verifies that the input path (relative to PATH_site) is found in the backend users filemounts.
+     * If it doesn't it will try to find another relative filemount for the user and return an alternative path prefix for the file.
+     *
+     * @param string $dirPrefix Path relative to PATH_site
+     * @param bool $noAlternative If set, Do not look for alternative path! Just return FALSE
+     * @return string|bool If a path is available that will be returned, otherwise FALSE.
+     */
+    public function verifyFolderAccess($dirPrefix, $noAlternative = false)
+    {
+        $fileProcObj = $this->getFileProcObj();
+        // Check, if dirPrefix is inside a valid Filemount for user:
+        $result = $fileProcObj->checkPathAgainstMounts(PATH_site . $dirPrefix);
+        // If not, try to find another relative filemount and use that instead:
+        if (!$result) {
+            if ($noAlternative) {
+                return false;
+            }
+            // Find first web folder:
+            $result = $fileProcObj->findFirstWebFolder();
+            // If that succeeded, return the path to it:
+            if ($result) {
+                // Remove the "fileadmin/" prefix of input path - and append the rest to the return value:
+                if (GeneralUtility::isFirstPartOfStr($dirPrefix, $this->fileadminFolderName . '/')) {
+                    $dirPrefix = substr($dirPrefix, strlen($this->fileadminFolderName . '/'));
+                }
+                return PathUtility::stripPathSitePrefix($fileProcObj->mounts[$result]['path'] . $dirPrefix);
+            }
+        } else {
+            return $dirPrefix;
+        }
+        return false;
+    }
+
     /*****************************
      * Helper functions of kinds
      *****************************/
 
+    /**
+     *
+     * @return string
+     */
+    protected function getTemporaryFolderName()
+    {
+        $temporaryPath = PATH_site . 'typo3temp/';
+        do {
+            $temporaryFolderName = $temporaryPath . 'export_temp_files_' . mt_rand(1, PHP_INT_MAX);
+        } while (is_dir($temporaryFolderName));
+        GeneralUtility::mkdir($temporaryFolderName);
+        return $temporaryFolderName;
+    }
+
+    /**
+     * Recursively flattening the idH array
+     *
+     * @param array $idH Page uid hierarchy
+     * @param array $a Accumulation array of pages (internal, don't set from outside)
+     * @return array Array with uid-uid pairs for all pages in the page tree.
+     * @see Import::flatInversePageTree_pid()
+     */
+    public function flatInversePageTree($idH, $a = array())
+    {
+        if (is_array($idH)) {
+            $idH = array_reverse($idH);
+            foreach ($idH as $k => $v) {
+                $a[$v['uid']] = $v['uid'];
+                if (is_array($v['subrow'])) {
+                    $a = $this->flatInversePageTree($v['subrow'], $a);
+                }
+            }
+        }
+        return $a;
+    }
+
     /**
      * Returns TRUE if the input table name is to be regarded as a static relation (that is, not exported etc).
      *
diff --git a/typo3/sysext/impexp/Tests/Functional/Export/AbstractExportTestCase.php b/typo3/sysext/impexp/Tests/Functional/Export/AbstractExportTestCase.php
index 31b19e6e28448f8a0a81a3c719640c41e5211e49..82b0b78643595dd0b9fe30c841fb136252b0d182 100644
--- a/typo3/sysext/impexp/Tests/Functional/Export/AbstractExportTestCase.php
+++ b/typo3/sysext/impexp/Tests/Functional/Export/AbstractExportTestCase.php
@@ -18,7 +18,7 @@ use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
- * Functional test for the ImportExport
+ * Functional test for the Export
  */
 abstract class AbstractExportTestCase extends \TYPO3\CMS\Core\Tests\FunctionalTestCase
 {
@@ -28,13 +28,13 @@ abstract class AbstractExportTestCase extends \TYPO3\CMS\Core\Tests\FunctionalTe
     protected $coreExtensionsToLoad = array('impexp');
 
     /**
-     * @var \TYPO3\CMS\Impexp\ImportExport
+     * @var \TYPO3\CMS\Impexp\Export
      */
     protected $export;
 
     /**
      * Set up for set up the backend user, initialize the language object
-     * and creating the ImportExport instance
+     * and creating the Export instance
      *
      * @return void
      */
@@ -46,13 +46,13 @@ abstract class AbstractExportTestCase extends \TYPO3\CMS\Core\Tests\FunctionalTe
 
         \TYPO3\CMS\Core\Core\Bootstrap::getInstance()->initializeLanguageObject();
 
-        $this->export = GeneralUtility::makeInstance(\TYPO3\CMS\Impexp\ImportExport::class);
+        $this->export = GeneralUtility::makeInstance(\TYPO3\CMS\Impexp\Export::class);
         $this->export->init(0, 'export');
     }
 
     /**
      * Builds a flat array containing the page tree with the PageTreeView
-     * based on given start pid and depth and set it in the ImportExport object.
+     * based on given start pid and depth and set it in the Export object.
      *
      * @param int $pidToStart
      * @param int $depth
diff --git a/typo3/sysext/impexp/Tests/Functional/Export/GroupFileAndFileReferenceItem/ExportTest.php b/typo3/sysext/impexp/Tests/Functional/Export/GroupFileAndFileReferenceItem/ExportTest.php
index 9d8543ffa985a1cd4a4f200a004b3dabbf9afec9..7776f9e09a105b3013afd642394e8e5e4eacfa8d 100644
--- a/typo3/sysext/impexp/Tests/Functional/Export/GroupFileAndFileReferenceItem/ExportTest.php
+++ b/typo3/sysext/impexp/Tests/Functional/Export/GroupFileAndFileReferenceItem/ExportTest.php
@@ -17,7 +17,7 @@ namespace TYPO3\CMS\Impexp\Tests\Functional\Export\GroupFileAndFileReferenceItem
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 
 /**
- * Functional test for the ImportExport
+ * Functional test for the Export
  */
 class ExportTest extends \TYPO3\CMS\Impexp\Tests\Functional\Export\AbstractExportTestCase
 {
diff --git a/typo3/sysext/impexp/Tests/Functional/Export/GroupFileAndFileReferenceItemInFlexForm/ExportTest.php b/typo3/sysext/impexp/Tests/Functional/Export/GroupFileAndFileReferenceItemInFlexForm/ExportTest.php
index f8557a32659dac1fa7318be6fbeefb5f2ab1d135..9ad75f2f8512fc2571553e2e19a97b5d7af0f65f 100644
--- a/typo3/sysext/impexp/Tests/Functional/Export/GroupFileAndFileReferenceItemInFlexForm/ExportTest.php
+++ b/typo3/sysext/impexp/Tests/Functional/Export/GroupFileAndFileReferenceItemInFlexForm/ExportTest.php
@@ -17,7 +17,7 @@ namespace TYPO3\CMS\Impexp\Tests\Functional\Export\GroupFileAndFileReferenceItem
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 
 /**
- * Functional test for the ImportExport
+ * Functional test for the Export
  */
 class ExportTest extends \TYPO3\CMS\Impexp\Tests\Functional\Export\AbstractExportTestCase
 {
diff --git a/typo3/sysext/impexp/Tests/Functional/Export/IrreTutorialRecords/ExportTest.php b/typo3/sysext/impexp/Tests/Functional/Export/IrreTutorialRecords/ExportTest.php
index 9300a19b81e79cc95dd97969867e82ac2c6ec90d..5d68c8c2151efc34f167d94bb69e41532849c242 100644
--- a/typo3/sysext/impexp/Tests/Functional/Export/IrreTutorialRecords/ExportTest.php
+++ b/typo3/sysext/impexp/Tests/Functional/Export/IrreTutorialRecords/ExportTest.php
@@ -17,7 +17,7 @@ namespace TYPO3\CMS\Impexp\Tests\Functional\Export\IrreTutorialRecords;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 
 /**
- * Functional test for the ImportExport
+ * Functional test for the Export
  */
 class ExportTest extends \TYPO3\CMS\Impexp\Tests\Functional\Export\AbstractExportTestCase
 {
diff --git a/typo3/sysext/impexp/Tests/Functional/Export/PagesAndTtContent/ExportTest.php b/typo3/sysext/impexp/Tests/Functional/Export/PagesAndTtContent/ExportTest.php
index cd2b0798db3820b173ccb383bf51365603ac9258..6e194bb78cd2a63f1501827b1861be2a6b8c85f0 100644
--- a/typo3/sysext/impexp/Tests/Functional/Export/PagesAndTtContent/ExportTest.php
+++ b/typo3/sysext/impexp/Tests/Functional/Export/PagesAndTtContent/ExportTest.php
@@ -17,7 +17,7 @@ namespace TYPO3\CMS\Impexp\Tests\Functional\Export\PagesAndTtContent;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 
 /**
- * Functional test for the ImportExport
+ * Functional test for the Export
  */
 class ExportTest extends \TYPO3\CMS\Impexp\Tests\Functional\Export\AbstractExportTestCase
 {
diff --git a/typo3/sysext/impexp/Tests/Functional/Export/PagesAndTtContentWithImages/ExportTest.php b/typo3/sysext/impexp/Tests/Functional/Export/PagesAndTtContentWithImages/ExportTest.php
index 1fe8ed0af10044b38123868d6b6eb1961e59db39..e4d2c95a77b75dae02280cb3a9a5a5242589dd33 100644
--- a/typo3/sysext/impexp/Tests/Functional/Export/PagesAndTtContentWithImages/ExportTest.php
+++ b/typo3/sysext/impexp/Tests/Functional/Export/PagesAndTtContentWithImages/ExportTest.php
@@ -17,7 +17,7 @@ namespace TYPO3\CMS\Impexp\Tests\Functional\Export\PagesAndTtContentWithImages;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 
 /**
- * Functional test for the ImportExport
+ * Functional test for the Export
  */
 class ExportTest extends \TYPO3\CMS\Impexp\Tests\Functional\Export\AbstractExportTestCase
 {
diff --git a/typo3/sysext/impexp/Tests/Functional/Export/PagesAndTtContentWithRteImagesAndFileLink/ExportTest.php b/typo3/sysext/impexp/Tests/Functional/Export/PagesAndTtContentWithRteImagesAndFileLink/ExportTest.php
index 9465628d1279ae7faa26f79fcc0b09482dc71b6f..d382dff80c3a0db031ef223574a0ba4b9d728fc4 100644
--- a/typo3/sysext/impexp/Tests/Functional/Export/PagesAndTtContentWithRteImagesAndFileLink/ExportTest.php
+++ b/typo3/sysext/impexp/Tests/Functional/Export/PagesAndTtContentWithRteImagesAndFileLink/ExportTest.php
@@ -17,7 +17,7 @@ namespace TYPO3\CMS\Impexp\Tests\Functional\Export\PagesAndTtContentWithRteImage
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 
 /**
- * Functional test for the ImportExport
+ * Functional test for the Export
  */
 class ExportTest extends \TYPO3\CMS\Impexp\Tests\Functional\Export\AbstractExportTestCase
 {
diff --git a/typo3/sysext/impexp/Tests/Functional/Import/AbstractImportTestCase.php b/typo3/sysext/impexp/Tests/Functional/Import/AbstractImportTestCase.php
index 1e5cac61f9c006f592e200f27476569994a1f8ba..085a3fbc6d0de95a0e6eccef845b06263bbf8ffb 100644
--- a/typo3/sysext/impexp/Tests/Functional/Import/AbstractImportTestCase.php
+++ b/typo3/sysext/impexp/Tests/Functional/Import/AbstractImportTestCase.php
@@ -17,7 +17,7 @@ namespace TYPO3\CMS\Impexp\Tests\Functional\Import;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
- * Functional test for the ImportExport
+ * Functional test for the Import
  */
 abstract class AbstractImportTestCase extends \TYPO3\CMS\Core\Tests\Functional\DataHandling\AbstractDataHandlerActionTestCase
 {
@@ -27,7 +27,7 @@ abstract class AbstractImportTestCase extends \TYPO3\CMS\Core\Tests\Functional\D
     protected $coreExtensionsToLoad = array('impexp');
 
     /**
-     * @var \TYPO3\CMS\Impexp\ImportExport
+     * @var \TYPO3\CMS\Impexp\Import
      */
     protected $import;
 
@@ -40,7 +40,7 @@ abstract class AbstractImportTestCase extends \TYPO3\CMS\Core\Tests\Functional\D
     protected $testFilesToDelete = array();
 
     /**
-     * Set up for initialization of the ImportExport instance
+     * Set up for initialization of the Import instance
      *
      * @return void
      */
@@ -48,7 +48,7 @@ abstract class AbstractImportTestCase extends \TYPO3\CMS\Core\Tests\Functional\D
     {
         parent::setUp();
 
-        $this->import = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Impexp\ImportExport::class);
+        $this->import = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Impexp\Import::class);
         $this->import->init(0, 'import');
     }
 
diff --git a/typo3/sysext/impexp/Tests/Functional/Import/GroupFileAndFileReferenceItem/ImportInEmptyDatabaseTest.php b/typo3/sysext/impexp/Tests/Functional/Import/GroupFileAndFileReferenceItem/ImportInEmptyDatabaseTest.php
index 8de66852dcb2f2850fc08e744e07d444047862d3..16d2ed8d6e6202e36f378411471a4df5e785300e 100644
--- a/typo3/sysext/impexp/Tests/Functional/Import/GroupFileAndFileReferenceItem/ImportInEmptyDatabaseTest.php
+++ b/typo3/sysext/impexp/Tests/Functional/Import/GroupFileAndFileReferenceItem/ImportInEmptyDatabaseTest.php
@@ -15,7 +15,7 @@ namespace TYPO3\CMS\Impexp\Tests\Functional\Import\GroupFileAndFileReferenceItem
  */
 
 /**
- * Functional test for the ImportExport
+ * Functional test for the Import
  */
 class ImportInEmptyDatabaseTest extends \TYPO3\CMS\Impexp\Tests\Functional\Import\AbstractImportTestCase
 {
diff --git a/typo3/sysext/impexp/Tests/Functional/Import/GroupFileAndFileReferenceItemInFlexForm/ImportInEmptyDatabaseTest.php b/typo3/sysext/impexp/Tests/Functional/Import/GroupFileAndFileReferenceItemInFlexForm/ImportInEmptyDatabaseTest.php
index 39bd1bce95a2e216bea7e3a2c7d2fec7b75a167d..dd5e0da858474c4cec257c7caa1a1f37b710ddd6 100644
--- a/typo3/sysext/impexp/Tests/Functional/Import/GroupFileAndFileReferenceItemInFlexForm/ImportInEmptyDatabaseTest.php
+++ b/typo3/sysext/impexp/Tests/Functional/Import/GroupFileAndFileReferenceItemInFlexForm/ImportInEmptyDatabaseTest.php
@@ -15,7 +15,7 @@ namespace TYPO3\CMS\Impexp\Tests\Functional\Import\GroupFileAndFileReferenceItem
  */
 
 /**
- * Functional test for the ImportExport
+ * Functional test for the Import
  */
 class ImportInEmptyDatabaseTest extends \TYPO3\CMS\Impexp\Tests\Functional\Import\AbstractImportTestCase
 {
diff --git a/typo3/sysext/impexp/Tests/Functional/Import/IrreTutorialRecords/ImportInEmptyDatabaseTest.php b/typo3/sysext/impexp/Tests/Functional/Import/IrreTutorialRecords/ImportInEmptyDatabaseTest.php
index d75866abf5d476b24afff994206ff4b6d1ce4349..cc6d9c0626a6b32dae75bcd822da50fbab47cb9b 100644
--- a/typo3/sysext/impexp/Tests/Functional/Import/IrreTutorialRecords/ImportInEmptyDatabaseTest.php
+++ b/typo3/sysext/impexp/Tests/Functional/Import/IrreTutorialRecords/ImportInEmptyDatabaseTest.php
@@ -15,7 +15,7 @@ namespace TYPO3\CMS\Impexp\Tests\Functional\Import\IrreTutorialRecords;
  */
 
 /**
- * Functional test for the ImportExport
+ * Functional test for the Import
  */
 class ImportInEmptyDatabaseTest extends \TYPO3\CMS\Impexp\Tests\Functional\Import\AbstractImportTestCase
 {
diff --git a/typo3/sysext/impexp/Tests/Functional/Import/PagesAndTtContent/ImportInEmptyDatabaseTest.php b/typo3/sysext/impexp/Tests/Functional/Import/PagesAndTtContent/ImportInEmptyDatabaseTest.php
index fab4f121e0b5fd84e1c0145031fb683c3959b12b..89b3cf3c7dd6c553c1b1d37be8149cac0f2601d0 100644
--- a/typo3/sysext/impexp/Tests/Functional/Import/PagesAndTtContent/ImportInEmptyDatabaseTest.php
+++ b/typo3/sysext/impexp/Tests/Functional/Import/PagesAndTtContent/ImportInEmptyDatabaseTest.php
@@ -15,7 +15,7 @@ namespace TYPO3\CMS\Impexp\Tests\Functional\Import\PagesAndTtContent;
  */
 
 /**
- * Functional test for the ImportExport
+ * Functional test for the Import
  */
 class ImportInEmptyDatabaseTest extends \TYPO3\CMS\Impexp\Tests\Functional\Import\AbstractImportTestCase
 {
diff --git a/typo3/sysext/impexp/Tests/Functional/Import/PagesAndTtContentWithImages/ImportInEmptyDatabaseTest.php b/typo3/sysext/impexp/Tests/Functional/Import/PagesAndTtContentWithImages/ImportInEmptyDatabaseTest.php
index 8470b1da5bb824315c04cbf6fd523c7343dad8c6..cafb82310c90bf331f302f952e84aa0f1b338adf 100644
--- a/typo3/sysext/impexp/Tests/Functional/Import/PagesAndTtContentWithImages/ImportInEmptyDatabaseTest.php
+++ b/typo3/sysext/impexp/Tests/Functional/Import/PagesAndTtContentWithImages/ImportInEmptyDatabaseTest.php
@@ -15,7 +15,7 @@ namespace TYPO3\CMS\Impexp\Tests\Functional\Import\PagesAndTtContentWithImages;
  */
 
 /**
- * Functional test for the ImportExport
+ * Functional test for the Import
  */
 class ImportInEmptyDatabaseTest extends \TYPO3\CMS\Impexp\Tests\Functional\Import\AbstractImportTestCase
 {
diff --git a/typo3/sysext/impexp/Tests/Functional/Import/PagesAndTtContentWithImages/ImportInFilledDatabaseTest.php b/typo3/sysext/impexp/Tests/Functional/Import/PagesAndTtContentWithImages/ImportInFilledDatabaseTest.php
index 12c3834ff2e6b555ca321cd75c24fc60507a56ab..dd10d7b01a395ae031c74bde66cab735a5ae3482 100644
--- a/typo3/sysext/impexp/Tests/Functional/Import/PagesAndTtContentWithImages/ImportInFilledDatabaseTest.php
+++ b/typo3/sysext/impexp/Tests/Functional/Import/PagesAndTtContentWithImages/ImportInFilledDatabaseTest.php
@@ -15,7 +15,7 @@ namespace TYPO3\CMS\Impexp\Tests\Functional\Import\PagesAndTtContentWithImages;
  */
 
 /**
- * Functional test for the ImportExport
+ * Functional test for the Import
  */
 class ImportInFilledDatabaseTest extends \TYPO3\CMS\Impexp\Tests\Functional\Import\AbstractImportTestCase
 {
diff --git a/typo3/sysext/impexp/Tests/Functional/Import/PagesAndTtContentWithRteImagesAndFileLink/ImportInEmptyDatabaseTest.php b/typo3/sysext/impexp/Tests/Functional/Import/PagesAndTtContentWithRteImagesAndFileLink/ImportInEmptyDatabaseTest.php
index 97d255c6d0a6b633e03eeab8f200baf3c03a139c..996d740249c543e1e673ee844c8e70259c2f9a6f 100644
--- a/typo3/sysext/impexp/Tests/Functional/Import/PagesAndTtContentWithRteImagesAndFileLink/ImportInEmptyDatabaseTest.php
+++ b/typo3/sysext/impexp/Tests/Functional/Import/PagesAndTtContentWithRteImagesAndFileLink/ImportInEmptyDatabaseTest.php
@@ -15,7 +15,7 @@ namespace TYPO3\CMS\Impexp\Tests\Functional\Import\PagesAndTtContentWithRteImage
  */
 
 /**
- * Functional test for the ImportExport
+ * Functional test for the Import
  */
 class ImportInEmptyDatabaseTest extends \TYPO3\CMS\Impexp\Tests\Functional\Import\AbstractImportTestCase
 {
diff --git a/typo3/sysext/impexp/Tests/Functional/ImportFromVersionFourDotFive/GroupFileAndFileReferenceItem/ImportInEmptyDatabaseTest.php b/typo3/sysext/impexp/Tests/Functional/ImportFromVersionFourDotFive/GroupFileAndFileReferenceItem/ImportInEmptyDatabaseTest.php
index e8ec717af4c60ba038b7da15d18cb96369b61cd1..ed5bc524b1172c1ee2254893119126364c2a97f7 100644
--- a/typo3/sysext/impexp/Tests/Functional/ImportFromVersionFourDotFive/GroupFileAndFileReferenceItem/ImportInEmptyDatabaseTest.php
+++ b/typo3/sysext/impexp/Tests/Functional/ImportFromVersionFourDotFive/GroupFileAndFileReferenceItem/ImportInEmptyDatabaseTest.php
@@ -15,7 +15,7 @@ namespace TYPO3\CMS\Impexp\Tests\Functional\ImportFromVersionFourDotFive\GroupFi
  */
 
 /**
- * Functional test for the ImportExport
+ * Functional test for the Import
  */
 class ImportInEmptyDatabaseTest extends \TYPO3\CMS\Impexp\Tests\Functional\Import\AbstractImportTestCase
 {
diff --git a/typo3/sysext/impexp/Tests/Functional/ImportFromVersionFourDotFive/GroupFileAndFileReferenceItemInFlexForm/ImportInEmptyDatabaseTest.php b/typo3/sysext/impexp/Tests/Functional/ImportFromVersionFourDotFive/GroupFileAndFileReferenceItemInFlexForm/ImportInEmptyDatabaseTest.php
index a62ca93e90a82c366a8556190542d86d6cce08f2..c744b8acb5dd56d0ac08f792d600ab8cf9eca017 100644
--- a/typo3/sysext/impexp/Tests/Functional/ImportFromVersionFourDotFive/GroupFileAndFileReferenceItemInFlexForm/ImportInEmptyDatabaseTest.php
+++ b/typo3/sysext/impexp/Tests/Functional/ImportFromVersionFourDotFive/GroupFileAndFileReferenceItemInFlexForm/ImportInEmptyDatabaseTest.php
@@ -15,7 +15,7 @@ namespace TYPO3\CMS\Impexp\Tests\Functional\ImportFromVersionFourDotFive\GroupFi
  */
 
 /**
- * Functional test for the ImportExport
+ * Functional test for the Import
  */
 class ImportInEmptyDatabaseTest extends \TYPO3\CMS\Impexp\Tests\Functional\Import\AbstractImportTestCase
 {
diff --git a/typo3/sysext/impexp/Tests/Functional/ImportFromVersionFourDotFive/PagesAndTtContent/ImportInEmptyDatabaseTest.php b/typo3/sysext/impexp/Tests/Functional/ImportFromVersionFourDotFive/PagesAndTtContent/ImportInEmptyDatabaseTest.php
index 565057e57ff536f2b8fc4fe009ccee286956b4a1..e09510af32401b7da15371a44dd283ef19b6fd0f 100644
--- a/typo3/sysext/impexp/Tests/Functional/ImportFromVersionFourDotFive/PagesAndTtContent/ImportInEmptyDatabaseTest.php
+++ b/typo3/sysext/impexp/Tests/Functional/ImportFromVersionFourDotFive/PagesAndTtContent/ImportInEmptyDatabaseTest.php
@@ -15,7 +15,7 @@ namespace TYPO3\CMS\Impexp\Tests\Functional\ImportFromVersionFourDotFive\PagesAn
  */
 
 /**
- * Functional test for the ImportExport
+ * Functional test for the Import
  */
 class ImportInEmptyDatabaseTest extends \TYPO3\CMS\Impexp\Tests\Functional\Import\AbstractImportTestCase
 {
diff --git a/typo3/sysext/impexp/Tests/Functional/ImportFromVersionFourDotFive/PagesAndTtContentUploads/ImportInEmptyDatabaseTest.php b/typo3/sysext/impexp/Tests/Functional/ImportFromVersionFourDotFive/PagesAndTtContentUploads/ImportInEmptyDatabaseTest.php
index a32d6bba34ac48ce5d3887c93b3e694884efeac5..664647cf29c47947002d9c1e129f3bae51225fbd 100644
--- a/typo3/sysext/impexp/Tests/Functional/ImportFromVersionFourDotFive/PagesAndTtContentUploads/ImportInEmptyDatabaseTest.php
+++ b/typo3/sysext/impexp/Tests/Functional/ImportFromVersionFourDotFive/PagesAndTtContentUploads/ImportInEmptyDatabaseTest.php
@@ -15,7 +15,7 @@ namespace TYPO3\CMS\Impexp\Tests\Functional\ImportFromVersionFourDotFive\PagesAn
  */
 
 /**
- * Functional test for the ImportExport
+ * Functional test for the Import
  */
 class ImportInEmptyDatabaseTest extends \TYPO3\CMS\Impexp\Tests\Functional\Import\AbstractImportTestCase
 {
diff --git a/typo3/sysext/impexp/Tests/Functional/ImportFromVersionFourDotFive/PagesAndTtContentWithImages/ImportInEmptyDatabaseTest.php b/typo3/sysext/impexp/Tests/Functional/ImportFromVersionFourDotFive/PagesAndTtContentWithImages/ImportInEmptyDatabaseTest.php
index 841cbd8b71fa2eebfc33ec001c7a28d8d4bc5d9d..b2303001c02ad3894c87b0009b6d4b3e36aafcd0 100644
--- a/typo3/sysext/impexp/Tests/Functional/ImportFromVersionFourDotFive/PagesAndTtContentWithImages/ImportInEmptyDatabaseTest.php
+++ b/typo3/sysext/impexp/Tests/Functional/ImportFromVersionFourDotFive/PagesAndTtContentWithImages/ImportInEmptyDatabaseTest.php
@@ -15,7 +15,7 @@ namespace TYPO3\CMS\Impexp\Tests\Functional\ImportFromVersionFourDotFive\PagesAn
  */
 
 /**
- * Functional test for the ImportExport
+ * Functional test for the Import
  */
 class ImportInEmptyDatabaseTest extends \TYPO3\CMS\Impexp\Tests\Functional\Import\AbstractImportTestCase
 {
diff --git a/typo3/sysext/impexp/Tests/Functional/ImportFromVersionFourDotFive/PagesAndTtContentWithRteImagesAndFileLink/ImportInEmptyDatabaseTest.php b/typo3/sysext/impexp/Tests/Functional/ImportFromVersionFourDotFive/PagesAndTtContentWithRteImagesAndFileLink/ImportInEmptyDatabaseTest.php
index 64420c4b90c074c506d2dafd782e18fbc6f530ed..3af9eed6c1431334e8b980206de9390b75946448 100644
--- a/typo3/sysext/impexp/Tests/Functional/ImportFromVersionFourDotFive/PagesAndTtContentWithRteImagesAndFileLink/ImportInEmptyDatabaseTest.php
+++ b/typo3/sysext/impexp/Tests/Functional/ImportFromVersionFourDotFive/PagesAndTtContentWithRteImagesAndFileLink/ImportInEmptyDatabaseTest.php
@@ -15,7 +15,7 @@ namespace TYPO3\CMS\Impexp\Tests\Functional\ImportFromVersionFourDotFive\PagesAn
  */
 
 /**
- * Functional test for the ImportExport
+ * Functional test for the Import
  */
 class ImportInEmptyDatabaseTest extends \TYPO3\CMS\Impexp\Tests\Functional\Import\AbstractImportTestCase
 {
diff --git a/typo3/sysext/impexp/Tests/Functional/ImportFromVersionFourDotFive/PagesWithLanguageOverlay/ImportInEmptyDatabaseTest.php b/typo3/sysext/impexp/Tests/Functional/ImportFromVersionFourDotFive/PagesWithLanguageOverlay/ImportInEmptyDatabaseTest.php
index d9f3290f23db175a1ba040a87eef8e8888687762..992323c17408444e8f39ff0ce0d2207bd188f2ff 100644
--- a/typo3/sysext/impexp/Tests/Functional/ImportFromVersionFourDotFive/PagesWithLanguageOverlay/ImportInEmptyDatabaseTest.php
+++ b/typo3/sysext/impexp/Tests/Functional/ImportFromVersionFourDotFive/PagesWithLanguageOverlay/ImportInEmptyDatabaseTest.php
@@ -15,7 +15,7 @@ namespace TYPO3\CMS\Impexp\Tests\Functional\ImportFromVersionFourDotFive\PagesWi
  */
 
 /**
- * Functional test for the ImportExport
+ * Functional test for the Import
  */
 class ImportInEmptyDatabaseTest extends \TYPO3\CMS\Impexp\Tests\Functional\Import\AbstractImportTestCase
 {