This is an automated email from the ASF dual-hosted git repository.
leginee pushed a commit to branch bazel-migration
in repository https://gitbox.apache.org/repos/asf/openoffice.git
The following commit(s) were added to refs/heads/bazel-migration by this push:
new 9e89ecc59d fix the synchronized issue fix the save loop
9e89ecc59d is described below
commit 9e89ecc59d3872f92c74cd198787c7366b8c1162
Author: Peter Kovacs <[email protected]>
AuthorDate: Mon Jun 15 22:13:37 2026 +0200
fix the synchronized issue
fix the save loop
---
bug-readme.md | 149 ++++++++++++++++++++++++
build/tools/fcfg_merge.pl | 45 ++++++-
main/filter/source/config/fragments/BUILD.bazel | 24 ++++
main/postprocess/postprocess.bzl | 9 +-
main/staging/fundamental.ini | 18 +++
5 files changed, 241 insertions(+), 4 deletions(-)
diff --git a/bug-readme.md b/bug-readme.md
index c06ad53ca2..91a77a071a 100644
--- a/bug-readme.md
+++ b/bug-readme.md
@@ -493,3 +493,152 @@ sb!basic::SfxLibraryContainer::init+0x28
ICU build proof: `icudata` `cc_binary` `srcs = ["source/stubdata/stubdata.c"]`
([icu
overlay/BUILD.bazel:277](ext_libraries/modules/icu/49.1.2/overlay/BUILD.bazel#L277));
no
`icudt49l.dat` / `ICU_DATA` / `udata_setCommonData` staged or set.
+
+---
+
+# Follow-on findings — after Writer opens (2026-06-15)
+
+Once the ICU fix let Writer open and accept input, three further issues
surfaced while
+testing **save** and a second app (Calc). Two are real migration/staging gaps
(fixed,
+build-only); one is a debug-CRT-only latent upstream defect (out of scope).
All three were
+root-caused with cdb against the **debug** build (`MSVCR90D`).
+
+## 12. Save-As ODF dialog loops forever — empty filter UINames (FIXED)
+
+**Component:** `filter/source/config` fragment merge (build); surfaces in
`sfx2` save flow.
+**Root cause (CONFIRMED):** every filter's `UIName` is **empty** in the staged
+`share/registry/*.xcd`, because the Bazel `fcfg_merge` listed only the base
+`filters/*.xcu` fragments and **dropped the separate `filters/<name>_ui.xcu`
UIName
+fragments**. (Type fragments embed `<prop oor:name="UIName">` inline, so types
were fine;
+filters keep the localized UIName in a sibling `_ui.xcu`.)
+**Symptom:** in Writer, *File ▸ Save As ▸ ODF Text Document ▸ Save* does
**not** write the
+file — the picker just reappears, indefinitely. (Not a crash, not a hang.)
+
+### 12.1 The loop mechanism (sfx2)
+
+`SfxStoringHelper::Execute`'s inner `while(!bExit)`
+([guisaveas.cxx:1497-1523](main/sfx2/source/doc/guisaveas.cxx#L1497)) only
sets `bExit`
+when `ModelData_Impl::CheckFilter` returns `STATUS_SAVE` (1). With an
**empty** filter name,
+`CheckFilter`
([guisaveas.cxx:716-768](main/sfx2/source/doc/guisaveas.cxx#L716)) returns
+`STATUS_SAVEAS_STANDARDNAME` (3) → set `bSetStandardName`, re-show → repeat
forever
+(`STATUS_SAVEAS`=2 would loop too — neither 2 nor 3 is handled as an exit).
`STATUS_*`
+values: NO_ACTION 0 / SAVE 1 / SAVEAS 2 / SAVEAS_STANDARDNAME 3.
+
+### 12.2 Where the empty name comes from (the file picker side)
+
+`FileDialogHelper_Impl::getRealFilter`
+([filedlghelper.cxx:1756-1768](main/sfx2/source/dialog/filedlghelper.cxx#L1756)):
+```cpp
+_rFilter = getCurrentFilterUIName(); // native Vista picker
getCurrentFilter() → ""
+if ( !_rFilter.Len() ) _rFilter = maCurFilter; // fallback = the filter's
UIName
+if ( _rFilter.Len() && mpMatcher ) {
+ pFilter = mpMatcher->GetFilter4UIName( _rFilter, m_nMustFlags,
m_nDontFlags );
+ _rFilter = pFilter ? pFilter->GetFilterName() : _rFilter.Erase(); //
NULL → ""
+}
+```
+The native `fps_office` Vista picker returns `""` for `getCurrentFilter()` (it
tracks the
+filter by *index*; `impl_sta_getCurrentFilter`
+[VistaFilePickerImpl.cxx:370](main/fpicker/source/win32/filepicker/VistaFilePickerImpl.cxx#L370)).
+The fallback `maCurFilter` holds the filter **UIName** — but because the
staged UIName is
+empty, the value is just the `" (.ext)"` annotation, and
+`SfxFilterMatcher::GetFilter4UIName(" (.odt)")` returns **NULL** → `.Erase()`
→ empty →
+the loop.
+
+### 12.3 cdb evidence
+```
+bp sfx!ModelData_Impl::CheckFilter
+ du poi(poi(@esp+4))+8 → "" ; aFilterName arg is EMPTY
+ pt; r al → al = 3 ; STATUS_SAVEAS_STANDARDNAME
+bp sfx!sfx2::FileDialogHelper_Impl::getCurrentFilterUIName
+ pt; du poi(@eax)+8 → "" ; native picker reports no current filter
+bp sfx!SfxFilterMatcher::GetFilter4UIName
+ du poi(poi(@esp+4))+8 → " (.odt)" ; looked-up UI name = empty + annotation
+ pt; r eax → 0 ; NULL → .Erase()
+```
+Save-dialog "File type" dropdown showed `(.odt)` with **no name** — consistent
with empty
+UIName. Confirmed in `bazel-bin/.../share/registry/writer.xcd`: the `writer8`
**filter**
+node has Flags/Type/DocumentService but **no `UIName` prop**, while the
`writer8` **type**
+node does (`Writer 8`).
+
+### 12.4 Fix (build-only, no source change)
+- [build/tools/fcfg_merge.pl](build/tools/fcfg_merge.pl): new `ui` manifest
section →
+ builds an `oor:name → <prop oor:name="UIName">` map from the `_ui.xcu`
fragments and
+ injects each into the filter node with the matching `oor:name` (before
`</node>`).
+ Mirrors what upstream FCFGMerge does when folding `_ui` into the filter.
+- [main/postprocess/postprocess.bzl](main/postprocess/postprocess.bzl): added
a `ui`
+ attribute to the `fcfg_merge` rule; threaded into the manifest + action
inputs.
+-
[main/filter/source/config/fragments/BUILD.bazel](main/filter/source/config/fragments/BUILD.bazel):
+ `_FILTER_UI = glob(["filters/*_ui.xcu"])` + `ui = _FILTER_UI` on all 18
`fcfg_*_filters`
+ targets. Injection is `oor:name`-matched, so passing the full `_ui` set to
every target
+ is harmless.
+
+**Verified:** after rebuild the dropdown reads "ODF Text Document (.odt)" and
the document
+saves as `.odt`.
+
+## 13. Startup FatalError "Failed to update/lastsynchronized" (FIXED)
+
+**Component:** brand bootstrap profiles (build); surfaces in `desktop`
extension manager.
+**Root cause (CONFIRMED):** the extension path macros
(`BUNDLED_EXTENSIONS_USER`,
+`BUNDLED_EXTENSIONS_PREREG`, `SHARED_EXTENSIONS_USER`, `UNO_*_PACKAGES_CACHE`,
+`TMP/BAK_EXTENSIONS`) were defined **only in `uno.ini`**, not in
`fundamental.ini`. The UNO
+component-context bootstrap reads `uno.ini` (so the PackageManager could still
create
+`user/extensions/*`), but bare `rtl::Bootstrap::expandMacros()` resolves
against the
+**`URE_BOOTSTRAP` file = `fundamental.ini`**. So `writeLastModified()`
+([dp_extensionmanager.cxx:116](main/desktop/source/deployment/manager/dp_extensionmanager.cxx#L116))
+expanded `"$BUNDLED_EXTENSIONS_USER/lastsynchronized"` to the bare
**`/lastsynchronized`**
+→ invalid `ucbhelper::Content` URL → `DeploymentException("Failed to update" +
url)` →
+caught at [app.cxx](main/desktop/source/app/app.cxx) outer handler →
+`FatalError(MakeStartupErrorMessage(...))`. Only seen when extension sync is
**not**
+disabled (`-env:DISABLE_EXTENSION_SYNCHRONIZATION=1` had been masking it).
+
+### 13.1 cdb evidence
+```
+bp sofficeapp!desktop::FatalError
+ du poi(poi(@esp+4))+8 → "The application cannot be started. \nFailed to
update/lastsynchronized"
+```
+The URL tail is just `/lastsynchronized` — the leading macro expanded to
empty. (Creating
+`share/prereg/bundled` + `share/extensions` dirs did **not** help — red
herring; the macro
+itself was empty.)
+
+### 13.2 Fix (build-only)
+[main/staging/fundamental.ini](main/staging/fundamental.ini): added the
extension path
+macros as cross-refs to `uno.ini`, e.g.
+`BUNDLED_EXTENSIONS_USER=${$ORIGIN/uno.ini:BUNDLED_EXTENSIONS_USER}` (+
`_PREREG`,
+`BUNDLED_EXTENSIONS`, `SHARED_EXTENSIONS_USER`, `TMP/BAK_EXTENSIONS`,
`UNO_*_PACKAGES_CACHE`).
+Upstream propagates these `fundamentalrc → fundamentalbasisrc → unorc` (scp2
+`common_brand.scp` gid_Brand_Profile_Fundamental_Ini items 999-1061); we have
no
+fundamentalbasis layer, so reference `uno.ini` directly.
`$OOO_BASE_DIR`/`$ORIGIN` are
+defined in `fundamental.ini`, so the imported values expand. Rejected
alternative
+(`DISABLE_EXTENSION_SYNCHRONIZATION=1`) — keeps sync working for future
extension modules.
+**Verified:** fatal gone; office boots into documents.
+
+## 14. Calc crash-on-open AV — debug-CRT-only latent UAF (NOT a migration bug)
+
+**Component:** `sc` view init — **stock AOO defect**, source byte-identical to
upstream.
+**Root cause (CONFIRMED):** `ScViewData::ReadUserDataSequence`
+([viewdata.cxx:2821](main/sc/source/ui/view/viewdata.cxx#L2821)) does
+`delete pTabData[nTab]; pTabData[nTab] = new ScViewDataTable;` per sheet but
**never
+refreshes `pThisTab`** (which pointed at `pTabData[nTabNo]`). Back in
+`ScTabView::SetTabNo`, line 1660 reads `aViewData.GetActivePart()` →
`pThisTab->eWhichActive`
+**before** line 1663 fixes `pThisTab` → use-after-free → AV
+`sc!ScTabView::SetTabNo` `mov ecx,[eax+edx*4+0x664]` with **edx=0xDDDDDDDD**
+(`pGridWin[0xdddddddd]`).
+
+**Why only in this build:** debug-CRT artifact, *not* a regression. Release
allocator reuses
+the just-freed same-size block, so the immediate `new` returns the **same**
address and
+`pThisTab` stays valid. The debug CRT (`MSVCR90D`) poison-fills freed blocks
with `0xDD`
+and **delays** their reuse, so `new` returns a *different* block → `pThisTab`
dangles.
+
+cdb proof (`.frame 0; dv /t` + `?? &this->aViewData`): `eOldActive =
0xDDDDDDDD`, but
+`this`/`pDoc`/`pViewShell` all valid, and crucially
+`pThisTab = 0x09a5f118` (old/low region, freed) **≠** `pTabData[nTabNo=0] =
0x13deca08`
+(fresh/valid) — the new table object is fine; only the stale pointer dangles.
**Contrast
+with §1 (ICU):** there, release *also* failed (missing data = real staging
gap); here
+release opens Calc fine.
+
+**Disposition:** out of migration scope ("source is not changed"). The 1-line
upstream fix
+would be `pThisTab = pTabData[nTabNo];` at the end of `ReadUserDataSequence`.
**Triage rule:**
+a debug-build `0xDD`/`0xFEEE` AV is a migration bug only if an upstream
*failure* feeds it
+(a throw, a missing staged file/data, as in §1); if every object is valid and
only one
+pointer dangles across a `delete`/`new`, it's a debug-CRT-exposed latent UAF →
confirm by
+opening the same document in the **release** build. Do feature testing in
release.
diff --git a/build/tools/fcfg_merge.pl b/build/tools/fcfg_merge.pl
index 5ff6565635..5d9c809dbc 100644
--- a/build/tools/fcfg_merge.pl
+++ b/build/tools/fcfg_merge.pl
@@ -8,6 +8,8 @@
# /abs/path/fragment.xcu
# filters
# /abs/path/fragment.xcu
+# ui
+# /abs/path/fragment_ui.xcu
# loaders
# handlers
# /abs/path/fragment.xcu
@@ -16,6 +18,17 @@
# Output wraps all non-empty sections in <oor:component-data oor:package=
# "org.openoffice.TypeDetection" oor:name="<xmlpackage>"> with
# <node oor:name="Types|Filters|FrameLoaders|ContentHandlers"> children.
+#
+# The "ui" section carries the filter UIName fragments (filters/<name>_ui.xcu).
+# Unlike type fragments (which embed <prop oor:name="UIName"> inline), filter
+# fragments keep the localized UIName in a SEPARATE <name>_ui.xcu file. The
+# upstream FCFGMerge tool folds those into the filter node; we do the same
here:
+# each ui fragment's <prop oor:name="UIName"> block is injected into the filter
+# node with the matching oor:name. Without this the filters' UIName is empty,
+# the Save dialog shows " (.ext)" with no name, and
+# FileDialogHelper::getRealFilter -> SfxFilterMatcher::GetFilter4UIName returns
+# NULL -> guisaveas CheckFilter never reaches STATUS_SAVE -> the Save dialog
+# loops forever (the file is never written).
use strict;
use warnings;
@@ -32,7 +45,8 @@ my %SETNAME = (
);
my @SECTIONS = qw(types filters loaders handlers);
-# Read manifest
+# Read manifest. "ui" is a pseudo-section: not emitted as its own <node>, but
+# used to inject UIName props into the filter nodes.
my %sections;
my $current;
open(my $mf, '<', $manifest) or die "Cannot read '$manifest': $!\n";
@@ -41,7 +55,7 @@ while (<$mf>) {
s{\\}{/}g;
s/^\s+|\s+$//g;
next unless length;
- if (exists $SETNAME{$_}) {
+ if (exists $SETNAME{$_} || $_ eq "ui") {
$current = $_;
} elsif (defined $current && /\S/) {
push @{$sections{$current}}, $_;
@@ -49,6 +63,18 @@ while (<$mf>) {
}
close($mf);
+# Build the UIName map: oor:name -> "<prop oor:name="UIName">...</prop>" block.
+my %uiname;
+for my $frag (@{$sections{ui} || []}) {
+ open(my $ff, '<', $frag) or die "Cannot read ui fragment '$frag': $!\n";
+ local $/ = undef;
+ my $txt = <$ff>;
+ close($ff);
+ my ($name) = $txt =~ m{<node\s+oor:name="([^"]+)"};
+ my ($block) = $txt =~ m{(<prop\s+oor:name="UIName".*?</prop>)}s;
+ $uiname{$name} = $block if defined $name && defined $block;
+}
+
open(my $fh, '>', $output) or die "Cannot write '$output': $!\n";
print $fh qq{<?xml version="1.0" encoding="UTF-8"?>\n};
print $fh qq{<oor:component-data
xmlns:oor="http://openoffice.org/2001/registry" };
@@ -61,8 +87,21 @@ for my $sec (@SECTIONS) {
print $fh "\t<node oor:name=\"$SETNAME{$sec}\">\n";
for my $frag (@$frags) {
open(my $ff, '<', $frag) or die "Cannot read fragment '$frag': $!\n";
- print $fh $_ while <$ff>;
+ local $/ = undef;
+ my $txt = <$ff>;
close($ff);
+
+ # For filter nodes, inject the matching UIName prop (if any) just
+ # before the node's closing </node>.
+ if ($sec eq "filters") {
+ my ($name) = $txt =~ m{<node\s+oor:name="([^"]+)"};
+ if (defined $name && exists $uiname{$name}) {
+ my $inject = "\t\t" . $uiname{$name} . "\n";
+ $txt =~ s{(\s*</node>)}{"\n" . $inject . $1}se;
+ }
+ }
+
+ print $fh $txt;
print $fh "\n";
}
print $fh "\t</node>\n";
diff --git a/main/filter/source/config/fragments/BUILD.bazel
b/main/filter/source/config/fragments/BUILD.bazel
index aefbce844b..92e912e2f3 100644
--- a/main/filter/source/config/fragments/BUILD.bazel
+++ b/main/filter/source/config/fragments/BUILD.bazel
@@ -10,6 +10,12 @@
load("//main/postprocess:postprocess.bzl", "fcfg_merge")
+# Filter UIName fragments (filters/<name>_ui.xcu). Filters keep their
+# localized UIName in a separate _ui.xcu (types embed it inline); these are
+# injected into the matching filter node by fcfg_merge.pl. Passing the full
+# set to every filter target is harmless: injection is matched by oor:name.
+_FILTER_UI = glob(["filters/*_ui.xcu"])
+
# ── fcfg_base
─────────────────────────────────────────────────────────────────
fcfg_merge(
@@ -27,6 +33,7 @@ fcfg_merge(
fcfg_merge(
name = "fcfg_base_filters",
+ ui = _FILTER_UI,
xmlpackage = "Filter",
filters = [
"filters/writer_web_HTML_help.xcu",
@@ -62,6 +69,7 @@ fcfg_merge(
fcfg_merge(
name = "fcfg_chart_filters",
+ ui = _FILTER_UI,
xmlpackage = "Filter",
filters = [
"filters/StarOffice_XML__Chart_.xcu",
@@ -92,6 +100,7 @@ fcfg_merge(
fcfg_merge(
name = "fcfg_database_filters",
+ ui = _FILTER_UI,
xmlpackage = "Filter",
filters = [
"filters/StarOffice_XML__Base_.xcu",
@@ -146,6 +155,7 @@ fcfg_merge(
fcfg_merge(
name = "fcfg_calc_filters",
+ ui = _FILTER_UI,
xmlpackage = "Filter",
filters = [
"filters/DIF.xcu",
@@ -196,6 +206,7 @@ fcfg_merge(
fcfg_merge(
name = "fcfg_draw_filters",
+ ui = _FILTER_UI,
xmlpackage = "Filter",
filters = [
"filters/StarOffice_XML__Draw_.xcu",
@@ -232,6 +243,7 @@ fcfg_merge(
fcfg_merge(
name = "fcfg_impress_filters",
+ ui = _FILTER_UI,
xmlpackage = "Filter",
filters = [
"filters/MS_PowerPoint_97.xcu",
@@ -268,6 +280,7 @@ fcfg_merge(
fcfg_merge(
name = "fcfg_math_filters",
+ ui = _FILTER_UI,
xmlpackage = "Filter",
filters = [
"filters/MathML_XML__Math_.xcu",
@@ -296,6 +309,7 @@ fcfg_merge(
fcfg_merge(
name = "fcfg_global_filters",
+ ui = _FILTER_UI,
xmlpackage = "Filter",
filters = [
"filters/Text__encoded___StarWriter_GlobalDocument_.xcu",
@@ -328,6 +342,7 @@ fcfg_merge(
fcfg_merge(
name = "fcfg_web_filters",
+ ui = _FILTER_UI,
xmlpackage = "Filter",
filters = [
"filters/HTML.xcu",
@@ -380,6 +395,7 @@ fcfg_merge(
fcfg_merge(
name = "fcfg_writer_filters",
+ ui = _FILTER_UI,
xmlpackage = "Filter",
filters = [
"filters/HTML__StarWriter_.xcu",
@@ -428,6 +444,7 @@ fcfg_merge(
fcfg_merge(
name = "fcfg_xslt_filters",
+ ui = _FILTER_UI,
xmlpackage = "Filter",
filters = [
"filters/DocBook_File.xcu",
@@ -455,6 +472,7 @@ fcfg_merge(
fcfg_merge(
name = "fcfg_palm_filters",
+ ui = _FILTER_UI,
xmlpackage = "Filter",
filters = [
"filters/AportisDoc_Palm_DB.xcu",
@@ -475,6 +493,7 @@ fcfg_merge(
fcfg_merge(
name = "fcfg_pocketexcel_filters",
+ ui = _FILTER_UI,
xmlpackage = "Filter",
filters = [
"filters/Pocket_Excel.xcu",
@@ -495,6 +514,7 @@ fcfg_merge(
fcfg_merge(
name = "fcfg_pocketword_filters",
+ ui = _FILTER_UI,
xmlpackage = "Filter",
filters = [
"filters/PocketWord_File.xcu",
@@ -543,6 +563,7 @@ fcfg_merge(
fcfg_merge(
name = "fcfg_drawgraphics_filters",
+ ui = _FILTER_UI,
xmlpackage = "Filter",
filters = [
"filters/BMP___MS_Windows.xcu",
@@ -627,6 +648,7 @@ fcfg_merge(
fcfg_merge(
name = "fcfg_impressgraphics_filters",
+ ui = _FILTER_UI,
xmlpackage = "Filter",
filters = [
"filters/CGM___Computer_Graphics_Metafile.xcu",
@@ -693,6 +715,7 @@ fcfg_merge(
fcfg_merge(
name = "fcfg_internalgraphics_filters",
+ ui = _FILTER_UI,
xmlpackage = "GraphicFilter",
filters = [
"internalgraphicfilters/bmp_Export.xcu",
@@ -864,6 +887,7 @@ fcfg_merge(
fcfg_merge(
name = "fcfg_w4w_filters",
+ ui = _FILTER_UI,
xmlpackage = "Filter",
filters = [
"filters/Ami_Pro_1_x_3_1__W4W_.xcu",
diff --git a/main/postprocess/postprocess.bzl b/main/postprocess/postprocess.bzl
index 554d33dcd5..8e2bf71132 100644
--- a/main/postprocess/postprocess.bzl
+++ b/main/postprocess/postprocess.bzl
@@ -265,6 +265,7 @@ def _fcfg_merge_impl(ctx):
for section, frags in [
("types", ctx.files.types),
("filters", ctx.files.filters),
+ ("ui", ctx.files.ui),
("loaders", ctx.files.loaders),
("handlers", ctx.files.handlers),
]:
@@ -277,7 +278,7 @@ def _fcfg_merge_impl(ctx):
content = "\n".join(lines) + "\n",
)
- all_frags = (ctx.files.types + ctx.files.filters +
+ all_frags = (ctx.files.types + ctx.files.filters + ctx.files.ui +
ctx.files.loaders + ctx.files.handlers)
ctx.actions.run(
@@ -307,6 +308,12 @@ fcfg_merge = rule(
allow_files = True,
doc = "filter fragment .xcu files (filters/ or
internalgraphicfilters/)",
),
+ "ui": attr.label_list(
+ allow_files = True,
+ doc = "filter UIName fragments (filters/<name>_ui.xcu); each <prop
" +
+ "oor:name=\"UIName\"> is injected into the filter node with
the " +
+ "matching oor:name. Filters (unlike types) keep UIName
separate.",
+ ),
"loaders": attr.label_list(
allow_files = True,
doc = "frame-loader fragment .xcu files (frameloaders/ subdir)",
diff --git a/main/staging/fundamental.ini b/main/staging/fundamental.ini
index 710c99b46a..95e80d6f43 100644
--- a/main/staging/fundamental.ini
+++ b/main/staging/fundamental.ini
@@ -10,3 +10,21 @@ UNO_SERVICES=${ORIGIN}/services.rdb
URE_MORE_TYPES=${ORIGIN}/oovbaapi.rdb
URE_MORE_SERVICES=
URE_MORE_JAVA_CLASSPATH_URLS=
+# Extension / deployment path macros. These are also defined in uno.ini, but
+# the UNO component-context bootstrap (which reads unorc/uno.ini) is NOT the
+# context that rtl::Bootstrap::expandMacros() resolves against -- that uses the
+# URE_BOOTSTRAP file, i.e. this fundamental.ini. Upstream propagates them
+# fundamentalrc -> fundamentalbasisrc -> unorc (scp2 common_brand.scp /
+# profileitem_ooo.scp); we have no fundamentalbasis layer, so reference uno.ini
+# directly. Without these here, desktop/.../dp_extensionmanager.cxx
+# writeLastModified() expands "$BUNDLED_EXTENSIONS_USER/lastsynchronized" to
the
+# bare "/lastsynchronized" (empty macro) -> invalid URL -> DeploymentException
+# "Failed to update/lastsynchronized" -> startup FatalError.
+BUNDLED_EXTENSIONS=${$ORIGIN/uno.ini:BUNDLED_EXTENSIONS}
+BUNDLED_EXTENSIONS_PREREG=${$ORIGIN/uno.ini:BUNDLED_EXTENSIONS_PREREG}
+BUNDLED_EXTENSIONS_USER=${$ORIGIN/uno.ini:BUNDLED_EXTENSIONS_USER}
+SHARED_EXTENSIONS_USER=${$ORIGIN/uno.ini:SHARED_EXTENSIONS_USER}
+TMP_EXTENSIONS=${$ORIGIN/uno.ini:TMP_EXTENSIONS}
+BAK_EXTENSIONS=${$ORIGIN/uno.ini:BAK_EXTENSIONS}
+UNO_SHARED_PACKAGES_CACHE=${$ORIGIN/uno.ini:UNO_SHARED_PACKAGES_CACHE}
+UNO_USER_PACKAGES_CACHE=${$ORIGIN/uno.ini:UNO_USER_PACKAGES_CACHE}