Version in base suite: 143.0.7499.169-1~deb13u1 Version in overlay suite: 145.0.7632.116-1~deb13u1 Base version: chromium_145.0.7632.116-1~deb13u1 Target version: chromium_145.0.7632.159-1~deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/c/chromium/chromium_145.0.7632.116-1~deb13u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/c/chromium/chromium_145.0.7632.159-1~deb13u1.dsc DEPS | 18 ash/strings/ash_strings_de.xtb | 4 ash/strings/ash_strings_pt-BR.xtb | 8 ash/strings/ash_strings_pt-PT.xtb | 2 ash/strings/ash_strings_sr-Latn.xtb | 2 ash/strings/ash_strings_sr.xtb | 2 ash/strings/ash_strings_zh-CN.xtb | 4 ash/webui/camera_app_ui/resources/strings/camera_strings_es-419.xtb | 2 ash/webui/camera_app_ui/resources/strings/camera_strings_fa.xtb | 2 build/util/LASTCHANGE | 2 build/util/LASTCHANGE.committime | 2 chrome/VERSION | 2 chrome/app/resources/chromium_strings_da.xtb | 2 chrome/app/resources/chromium_strings_el.xtb | 2 chrome/app/resources/chromium_strings_es-419.xtb | 2 chrome/app/resources/chromium_strings_es.xtb | 4 chrome/app/resources/generated_resources_ar.xtb | 2 chrome/app/resources/generated_resources_ca.xtb | 4 chrome/app/resources/generated_resources_cs.xtb | 4 chrome/app/resources/generated_resources_da.xtb | 6 chrome/app/resources/generated_resources_de.xtb | 20 chrome/app/resources/generated_resources_el.xtb | 4 chrome/app/resources/generated_resources_es-419.xtb | 6 chrome/app/resources/generated_resources_es.xtb | 8 chrome/app/resources/generated_resources_et.xtb | 2 chrome/app/resources/generated_resources_eu.xtb | 12 chrome/app/resources/generated_resources_fa.xtb | 16 chrome/app/resources/generated_resources_fi.xtb | 14 chrome/app/resources/generated_resources_fr.xtb | 20 chrome/app/resources/generated_resources_hr.xtb | 10 chrome/app/resources/generated_resources_is.xtb | 2 chrome/app/resources/generated_resources_it.xtb | 4 chrome/app/resources/generated_resources_ja.xtb | 4 chrome/app/resources/generated_resources_kk.xtb | 2 chrome/app/resources/generated_resources_ko.xtb | 2 chrome/app/resources/generated_resources_my.xtb | 6 chrome/app/resources/generated_resources_no.xtb | 2 chrome/app/resources/generated_resources_pt-BR.xtb | 6 chrome/app/resources/generated_resources_ro.xtb | 4 chrome/app/resources/generated_resources_sk.xtb | 2 chrome/app/resources/generated_resources_sl.xtb | 2 chrome/app/resources/generated_resources_sq.xtb | 2 chrome/app/resources/generated_resources_sr-Latn.xtb | 4 chrome/app/resources/generated_resources_sr.xtb | 4 chrome/app/resources/generated_resources_sw.xtb | 2 chrome/app/resources/generated_resources_te.xtb | 2 chrome/app/resources/generated_resources_tr.xtb | 2 chrome/app/resources/generated_resources_uk.xtb | 2 chrome/app/resources/generated_resources_vi.xtb | 4 chrome/app/resources/generated_resources_zh-CN.xtb | 10 chrome/app/resources/generated_resources_zh-TW.xtb | 2 chrome/app/resources/google_chrome_strings_ca.xtb | 2 chrome/app/resources/google_chrome_strings_da.xtb | 2 chrome/app/resources/google_chrome_strings_el.xtb | 2 chrome/app/resources/google_chrome_strings_es-419.xtb | 4 chrome/app/resources/google_chrome_strings_es.xtb | 4 chrome/app/resources/google_chrome_strings_fr.xtb | 2 chrome/app/resources/google_chrome_strings_hr.xtb | 4 chrome/app/resources/google_chrome_strings_vi.xtb | 2 chrome/app/resources/google_chrome_strings_zh-CN.xtb | 12 chrome/browser/glic/glic_profile_manager.cc | 14 chrome/browser/glic/glic_profile_manager.h | 2 chrome/browser/glic/glic_profile_manager_browsertest.cc | 25 chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_de.xtb | 18 chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_zh-CN.xtb | 2 chrome/browser/ui/android/strings/translations/android_chrome_strings_ca.xtb | 2 chrome/browser/ui/android/strings/translations/android_chrome_strings_da.xtb | 2 chrome/browser/ui/android/strings/translations/android_chrome_strings_de.xtb | 10 chrome/browser/ui/android/strings/translations/android_chrome_strings_my.xtb | 2 chrome/browser/ui/android/strings/translations/android_chrome_strings_no.xtb | 2 chrome/browser/ui/android/strings/translations/android_chrome_strings_sq.xtb | 2 chrome/browser/ui/android/strings/translations/android_chrome_strings_sr-Latn.xtb | 2 chrome/browser/ui/android/strings/translations/android_chrome_strings_sr.xtb | 2 chrome/browser/ui/android/strings/translations/android_chrome_strings_sw.xtb | 2 chrome/browser/ui/android/strings/translations/android_chrome_strings_zh-CN.xtb | 6 chrome/browser/ui/ash/network/mobile_data_notifications.cc | 2 chrome/browser/ui/views/infobars/infobar_container_view.cc | 61 chrome/browser/ui/views/infobars/infobar_container_view.h | 9 chrome/browser/ui/views/infobars/infobar_container_view_browsertest.cc | 88 chromeos/CHROMEOS_LKGM | 2 chromeos/profiles/arm.afdo.newest.txt | 2 chromeos/profiles/atom.afdo.newest.txt | 2 chromeos/profiles/bigcore.afdo.newest.txt | 2 chromeos/strings/chromeos_strings_de.xtb | 2 chromeos/strings/chromeos_strings_el.xtb | 2 chromeos/strings/chromeos_strings_fa.xtb | 4 chromeos/strings/chromeos_strings_pt-BR.xtb | 4 components/browser_ui/strings/android/translations/browser_ui_strings_fa.xtb | 8 components/browser_ui/strings/android/translations/browser_ui_strings_fi.xtb | 8 components/browser_ui/strings/android/translations/browser_ui_strings_no.xtb | 2 components/browser_ui/strings/android/translations/browser_ui_strings_sk.xtb | 2 components/browser_ui/strings/android/translations/browser_ui_strings_zh-CN.xtb | 2 components/certificate_transparency/data/log_list.json | 20 components/infobars/core/infobar_container.cc | 2 components/infobars/core/infobar_container.h | 2 components/infobars/core/infobar_container_with_priority.h | 2 components/policy/resources/policy_templates_de.xtb | 19 components/policy/resources/policy_templates_fr.xtb | 20 components/policy/resources/policy_templates_nl.xtb | 10 components/policy/resources/policy_templates_pt-BR.xtb | 8 components/policy/resources/policy_templates_ru.xtb | 2 components/strings/components_strings_ca.xtb | 4 components/strings/components_strings_de.xtb | 2 components/strings/components_strings_es-419.xtb | 2 components/strings/components_strings_es.xtb | 4 components/strings/components_strings_fa.xtb | 8 components/strings/components_strings_hi.xtb | 2 components/strings/components_strings_hu.xtb | 2 components/strings/components_strings_kn.xtb | 2 components/strings/components_strings_pt-BR.xtb | 2 components/strings/components_strings_ru.xtb | 2 components/strings/components_strings_sq.xtb | 2 components/strings/components_strings_sr-Latn.xtb | 6 components/strings/components_strings_sr.xtb | 6 components/strings/components_strings_sw.xtb | 4 components/strings/components_strings_zh-CN.xtb | 2 components/strings/components_strings_zh-TW.xtb | 2 content/browser/renderer_host/render_frame_host_impl.cc | 24 content/browser/security_exploit_browsertest.cc | 126 debian/changelog | 30 debian/clean | 1 debian/control | 1 debian/copyright | 1 debian/scripts/unbundle | 1 gpu/command_buffer/service/context_group.cc | 15 gpu/command_buffer/service/context_group.h | 5 gpu/command_buffer/service/decoder_context.h | 6 gpu/command_buffer/service/feature_info.cc | 40 gpu/command_buffer/service/feature_info.h | 10 gpu/command_buffer/service/gles2_cmd_copy_tex_image.cc | 4 gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc | 13 gpu/command_buffer/service/gles2_cmd_decoder.cc | 125 gpu/command_buffer/service/gles2_cmd_decoder_mock.h | 2 gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc | 5 gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h | 2 gpu/command_buffer/service/raster_decoder.cc | 6 gpu/command_buffer/service/renderbuffer_manager.cc | 4 gpu/command_buffer/service/renderbuffer_manager.h | 2 gpu/command_buffer/service/webgpu_decoder_impl.cc | 3 gpu/config/gpu_driver_bug_list.json | 11 gpu/config/gpu_lists_version.h | 2 gpu/config/gpu_workaround_list.txt | 1 infra/config/dev.star | 2 infra/config/generated/luci/cr-buildbucket.cfg | 56 infra/config/main.star | 2 net/data/ssl/chrome_root_store/root_store.certs | 562 net/data/ssl/chrome_root_store/root_store.md | 19 net/data/ssl/chrome_root_store/root_store.textproto | 69 net/http/transport_security_state_static.pins | 4 net/http/transport_security_state_static_pins.json | 2 remoting/resources/remoting_strings_el.xtb | 2 remoting/resources/remoting_strings_fa.xtb | 2 skia/ext/skia_commit_hash.h | 2 third_party/angle/src/libANGLE/renderer/vulkan/TextureVk.cpp | 13 third_party/blink/common/page_state/page_state_serialization.cc | 68 third_party/blink/public/common/page_state/page_state_serialization.h | 7 third_party/blink/renderer/core/css/css_math_expression_node.cc | 2 third_party/blink/renderer/core/css/cssom/css_unparsed_value.cc | 19 third_party/blink/renderer/core/css/parser/css_parser_token.h | 16 third_party/blink/renderer/core/inspector/devtools_session.cc | 1 third_party/blink/renderer/core/inspector/devtools_session.h | 10 third_party/blink/renderer/core/inspector/inspector_trace_events.cc | 2 third_party/blink/renderer/modules/clipboard/clipboard_change_event_controller.cc | 17 third_party/blink/renderer/modules/clipboard/clipboard_change_event_controller_unittest.cc | 100 third_party/blink/renderer/modules/webcodecs/background_readback.cc | 7 third_party/blink/renderer/platform/audio/mac/fft_frame_mac.cc | 12 third_party/blink/renderer/platform/audio/pffft/fft_frame_pffft.cc | 28 third_party/devtools-frontend/src/front_end/models/stack_trace/StackTraceImpl.test.ts | 4 third_party/devtools-frontend/src/front_end/models/stack_trace/StackTraceImpl.ts | 14 third_party/devtools-frontend/src/front_end/models/stack_trace/StackTraceModel.test.ts | 9 third_party/devtools-frontend/src/front_end/models/stack_trace/StackTraceModel.ts | 10 third_party/devtools-frontend/src/front_end/panels/timeline/BUILD.gn | 3 third_party/devtools-frontend/src/front_end/panels/timeline/TimelineUIUtils.ts | 83 third_party/devtools-frontend/src/front_end/ui/legacy/components/utils/JSPresentationUtils.test.ts | 2 third_party/devtools-frontend/src/front_end/ui/legacy/components/utils/JSPresentationUtils.ts | 11 third_party/libxslt/BUILD.gn | 113 third_party/libxslt/DIR_METADATA | 6 third_party/libxslt/OWNERS | 1 third_party/libxslt/README.chromium | 16 third_party/libxslt/chromium/0004-Use-a-dedicated-node-type-to-maintain-the-list-of-ca.patch | 707 third_party/libxslt/chromium/roll.py | 440 third_party/libxslt/chromium/xslt-locale.patch | 45 third_party/libxslt/linux/COPYING | 53 third_party/libxslt/linux/config.h | 225 third_party/libxslt/linux/libexslt/exsltconfig.h | 70 third_party/libxslt/linux/libxslt/xsltwin32config.h | 105 third_party/libxslt/mac/config.h | 225 third_party/libxslt/src/AUTHORS | 64 third_party/libxslt/src/Copyright | 53 third_party/libxslt/src/FEATURES | 242 third_party/libxslt/src/FindGcrypt.cmake | 40 third_party/libxslt/src/INSTALL | 50 third_party/libxslt/src/Makefile.am | 51 third_party/libxslt/src/README.md | 19 third_party/libxslt/src/TODO | 124 third_party/libxslt/src/config.h.cmake.in | 136 third_party/libxslt/src/config.h.in | 224 third_party/libxslt/src/libexslt.pc.in | 13 third_party/libxslt/src/libexslt/Makefile.am | 35 third_party/libxslt/src/libexslt/common.c | 124 third_party/libxslt/src/libexslt/crypto.c | 806 third_party/libxslt/src/libexslt/date.c | 3956 ++ third_party/libxslt/src/libexslt/dynamic.c | 296 third_party/libxslt/src/libexslt/exslt.c | 35 third_party/libxslt/src/libexslt/exslt.h | 108 third_party/libxslt/src/libexslt/exsltconfig.h.in | 70 third_party/libxslt/src/libexslt/exsltexports.h | 63 third_party/libxslt/src/libexslt/functions.c | 837 third_party/libxslt/src/libexslt/libexslt.3 | 270 third_party/libxslt/src/libexslt/libexslt.h | 35 third_party/libxslt/src/libexslt/math.c | 1173 third_party/libxslt/src/libexslt/saxon.c | 318 third_party/libxslt/src/libexslt/sets.c | 320 third_party/libxslt/src/libexslt/strings.c | 884 third_party/libxslt/src/libxslt-config.cmake.cmake.in | 107 third_party/libxslt/src/libxslt-config.cmake.in | 112 third_party/libxslt/src/libxslt.pc.in | 13 third_party/libxslt/src/libxslt/Makefile.am | 77 third_party/libxslt/src/libxslt/attributes.c | 1242 third_party/libxslt/src/libxslt/attributes.h | 39 third_party/libxslt/src/libxslt/attrvt.c | 405 third_party/libxslt/src/libxslt/documents.c | 442 third_party/libxslt/src/libxslt/documents.h | 93 third_party/libxslt/src/libxslt/extensions.c | 2403 + third_party/libxslt/src/libxslt/extensions.h | 262 third_party/libxslt/src/libxslt/extra.c | 197 third_party/libxslt/src/libxslt/extra.h | 72 third_party/libxslt/src/libxslt/functions.c | 1109 third_party/libxslt/src/libxslt/functions.h | 78 third_party/libxslt/src/libxslt/imports.c | 423 third_party/libxslt/src/libxslt/imports.h | 75 third_party/libxslt/src/libxslt/keys.c | 935 third_party/libxslt/src/libxslt/keys.h | 53 third_party/libxslt/src/libxslt/libxslt.3 | 31 third_party/libxslt/src/libxslt/libxslt.h | 55 third_party/libxslt/src/libxslt/namespaces.c | 835 third_party/libxslt/src/libxslt/namespaces.h | 68 third_party/libxslt/src/libxslt/numbers.c | 1412 + third_party/libxslt/src/libxslt/numbersInternals.h | 73 third_party/libxslt/src/libxslt/pattern.c | 2534 + third_party/libxslt/src/libxslt/pattern.h | 84 third_party/libxslt/src/libxslt/preproc.c | 2368 + third_party/libxslt/src/libxslt/preproc.h | 43 third_party/libxslt/src/libxslt/security.c | 479 third_party/libxslt/src/libxslt/security.h | 104 third_party/libxslt/src/libxslt/templates.c | 875 third_party/libxslt/src/libxslt/templates.h | 77 third_party/libxslt/src/libxslt/transform.c | 6472 ++++ third_party/libxslt/src/libxslt/transform.h | 207 third_party/libxslt/src/libxslt/transformInternals.h | 9 third_party/libxslt/src/libxslt/trio.h | 216 third_party/libxslt/src/libxslt/triodef.h | 220 third_party/libxslt/src/libxslt/variables.c | 2437 + third_party/libxslt/src/libxslt/variables.h | 118 third_party/libxslt/src/libxslt/win32config.h | 53 third_party/libxslt/src/libxslt/xslt.c | 7066 +++++ third_party/libxslt/src/libxslt/xslt.h | 110 third_party/libxslt/src/libxslt/xsltInternals.h | 2004 + third_party/libxslt/src/libxslt/xsltconfig.h | 146 third_party/libxslt/src/libxslt/xsltconfig.h.in | 146 third_party/libxslt/src/libxslt/xsltexports.h | 64 third_party/libxslt/src/libxslt/xsltlocale.c | 538 third_party/libxslt/src/libxslt/xsltlocale.h | 44 third_party/libxslt/src/libxslt/xsltutils.c | 2725 ++ third_party/libxslt/src/libxslt/xsltutils.h | 343 third_party/libxslt/src/m4/ax_append_link_flags.m4 | 44 third_party/libxslt/src/m4/ax_check_link_flag.m4 | 53 third_party/libxslt/src/m4/ax_require_defined.m4 | 37 third_party/libxslt/src/m4/libtool.m4 | 8513 ++++++ third_party/libxslt/src/m4/ltoptions.m4 | 467 third_party/libxslt/src/m4/ltsugar.m4 | 124 third_party/libxslt/src/m4/ltversion.m4 | 24 third_party/libxslt/src/m4/lt~obsolete.m4 | 99 third_party/libxslt/src/py-compile | 244 third_party/libxslt/src/win32/Makefile.mingw | 308 third_party/libxslt/src/win32/Readme.txt | 133 third_party/libxslt/src/win32/configure.js | 549 third_party/libxslt/src/win32/libxslt/libxslt.def | 149 third_party/libxslt/src/win32/libxslt/libxslt.dsw | 44 third_party/libxslt/src/win32/libxslt/libxslt_so.dsp | 247 third_party/libxslt/src/win32/libxslt/xsltproc.dsp | 102 third_party/libxslt/src/win32/runtests.py | 87 third_party/libxslt/src/xsltConf.sh.in | 8 third_party/libxslt/win32/config.h | 53 third_party/skia/src/gpu/ganesh/GrVertexChunkArray.cpp | 9 third_party/skia/src/gpu/ganesh/ops/AtlasRenderTask.cpp | 11 third_party/skia/src/gpu/ganesh/ops/AtlasRenderTask.h | 8 third_party/skia/src/gpu/ganesh/ops/PathTessellateOp.cpp | 6 third_party/skia/src/gpu/tessellate/FixedCountBufferUtils.h | 7 ui/accessibility/extensions/strings/accessibility_extensions_strings_de.xtb | 2 ui/accessibility/extensions/strings/accessibility_extensions_strings_zh-CN.xtb | 2 ui/strings/translations/ax_strings_de.xtb | 6 ui/strings/translations/ui_strings_de.xtb | 2 ui/strings/translations/ui_strings_sw.xtb | 2 v8/include/v8-inspector.h | 14 v8/include/v8-version.h | 2 v8/src/asmjs/asm-parser.cc | 3 v8/src/ast/ast-function-literal-id-reindexer.cc | 5 v8/src/ast/ast-traversal-visitor.h | 5 v8/src/debug/liveedit.cc | 8 v8/src/inspector/search-util.cc | 7 v8/src/inspector/search-util.h | 4 v8/src/inspector/v8-debugger-agent-impl.cc | 2 v8/src/inspector/v8-inspector-impl.cc | 45 v8/src/inspector/v8-inspector-impl.h | 6 v8/src/inspector/v8-inspector-session-impl.cc | 6 v8/src/inspector/v8-inspector-session-impl.h | 10 v8/src/parsing/parser.cc | 6 v8/src/regexp/regexp.cc | 5 v8/tools/builtins-pgo/profiles/meta.json | 2 v8/tools/builtins-pgo/profiles/x64-rl.profile | 3743 +- v8/tools/builtins-pgo/profiles/x64.profile | 2877 +- v8/tools/builtins-pgo/profiles/x86-rl.profile |12922 ++++----- v8/tools/builtins-pgo/profiles/x86.profile |13200 +++++----- 314 files changed, 82103 insertions(+), 16878 deletions(-) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp27r_6__k/chromium_145.0.7632.116-1~deb13u1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp27r_6__k/chromium_145.0.7632.159-1~deb13u1.dsc: no acceptable signature found diff -Nru chromium-145.0.7632.116/DEPS chromium-145.0.7632.159/DEPS --- chromium-145.0.7632.116/DEPS 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/DEPS 2026-03-02 23:00:09.000000000 +0000 @@ -312,15 +312,15 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '2ab8add5be2c46eb6238f4c217f6d6dbc9bccd23', + 'skia_revision': 'fba326b8829e469ac02e5a68a0d36982ef1975bc', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': 'ce21eb288e9b86bf6a294968a5113a2646d7b8dd', + 'v8_revision': '1e1e0c88c55414e3ab7f98629a0233d3dc77fca0', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': '4c0ae3917d4feab6ae1c99d7b750a69cdf3cc96c', + 'angle_revision': '2d051d9cef02bca69a97749a995b138e3dec0e1f', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -400,7 +400,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling devtools-frontend # and whatever else without interference from each other. - 'devtools_frontend_revision': '8eb35b80efbc72ffb3aff36c3c1106fe9269df88', + 'devtools_frontend_revision': 'b1eec47965f0f0bed968133496c5c097fb41cc0e', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libprotobuf-mutator # and whatever else without interference from each other. @@ -1206,7 +1206,7 @@ 'packages': [ { 'package': 'chromium/chrome/android/orderfiles/arm64', - 'version': 'iKZe8VLuAf1KG3cuNm3dp5oIv2BB2mjXoJTcsTQzQG4C', + 'version': '8Eq-PQRtQQ5mNczyxFgkEo4BeVLm-JJgKPzdDDJMYLcC', }, ], 'condition': 'checkout_android and non_git_source', @@ -1217,7 +1217,7 @@ 'packages': [ { 'package': 'chromium/android_webview/tools/orderfiles/arm', - 'version': 'BaIioIL8jGXNVPRz0IuD2HcFfek-aZs6UPa5QnWdhjcC', + 'version': 'zCa0x67uzpvnnTsvvzZfSMOCqjVtlfg5_xDn0O8VRwEC', }, ], 'condition': 'checkout_android and non_git_source', @@ -1228,7 +1228,7 @@ 'packages': [ { 'package': 'chromium/android_webview/tools/orderfiles/arm64', - 'version': 'kA7sSXzkhSV08mCQ_EJQ8D8PWBpvD3Q9yjdeMzOlhggC', + 'version': '4IMWgbPZ0sNU7XSU_U31e3c6HfYJU3J9YRLZpqBcoI8C', }, ], 'condition': 'checkout_android and non_git_source', @@ -1624,7 +1624,7 @@ 'src/clank': { 'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' + - '8fb16bd37d8d5afcd260df296d6bfefac4c21396', + 'fbe5dc3fce52e9301d4b88843f2e12928a5e8341', 'condition': 'checkout_android and checkout_src_internal', }, @@ -3769,7 +3769,7 @@ 'src/ios_internal': { 'url': Var('chrome_git') + '/chrome/ios_internal.git' + '@' + - 'da24730e14ce8740155049c2ed16ace480e2c5a4', + '780a275060655dc392f36ef313d39fd89681770a', 'condition': 'checkout_ios and checkout_src_internal', }, diff -Nru chromium-145.0.7632.116/ash/strings/ash_strings_de.xtb chromium-145.0.7632.159/ash/strings/ash_strings_de.xtb --- chromium-145.0.7632.116/ash/strings/ash_strings_de.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/ash/strings/ash_strings_de.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -1371,7 +1371,7 @@ Neu laden Hohe Sichtbarkeit bei Nearby Share aktivieren/deaktivieren Kreativität -Schaltfläche +Button Neuen Tab in neuem Inkognitofenster öffnen Bluetooth aktiviert Essentials @@ -2305,7 +2305,7 @@ Leistungsschwaches Ladegerät angeschlossen Einstellungen für den Konzentrationsmodus anzeigen. Konzentrationsmodus ist aktiviert, noch . Leistungsverfolgung ist aktiv -Aufnahme starten. Wenn die Aufnahme gestartet ist, kannst du Alt + Umschalttaste + L verwenden, um zur Ablage zu gehen – dort findest du die Schaltfläche zum Beenden der Aufnahme. +Aufnahme starten. Wenn die Aufnahme gestartet ist, kannst du Alt + Umschalttaste + L verwenden, um zur Ablage zu gehen – dort findest du den Button zum Beenden der Aufnahme. Fokus auf das Bild-im-Bild-Fenster verschieben Spracheingabe aktivieren/deaktivieren Optionen für das Dashboard für Spiele diff -Nru chromium-145.0.7632.116/ash/strings/ash_strings_pt-BR.xtb chromium-145.0.7632.159/ash/strings/ash_strings_pt-BR.xtb --- chromium-145.0.7632.116/ash/strings/ash_strings_pt-BR.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/ash/strings/ash_strings_pt-BR.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -221,7 +221,7 @@ Ativar o Sincronizar Wi-Fi O ponto de acesso está desativado Mudar para o usuário anterior -Escolha entre o tema claro ou escuro. Toque na área de trabalho e a mantenha pressionada. Depois, selecione a opção "Plano de fundo e estilo". +Escolha entre o tema claro ou escuro. Toque e mantenha pressionada a área de trabalho. Depois, selecione a opção "Plano de fundo e estilo". Área selecionada, use as teclas de seta para mover "" visível para dispositivos Bluetooth. Dispensar configuração de visualização de notificações do smartphone @@ -832,7 +832,7 @@ Não foi possível copiar com a formatação Essa ação libera o acesso à câmera para e todos os apps e sites com essa permissão. Talvez seja necessário atualizar a página da Web ou reiniciar o app. Usar senha -Modo de Economia de bateria ativado +Modo de economia de bateria ativado Sair da visualização do tutorial Mostrar configurações do teclado Excluir modelo? @@ -1906,7 +1906,7 @@ Algo deu errado VPN desconectada Mudar sua configuração de proteção de acesso a dados para periféricos pode otimizar o desempenho -Definir Estilo e fundo de tela +Definir plano de fundo e estilo Você precisa ter pelo menos 18 anos para usar os recursos Me ajude a ler, Me ajude a escrever e criar imagens com a IA. Gravar janela Memória disponível: de um total de @@ -1916,7 +1916,7 @@ Conectar com um código Arraste para selecionar uma área para a gravação Controles de mídia -Modo de Economia de bateria desativado +Modo de economia de bateria desativado Ativar Clique com o botão direito do mouse em qualquer lugar para reordenar os apps Alternar conexão de rede. . diff -Nru chromium-145.0.7632.116/ash/strings/ash_strings_pt-PT.xtb chromium-145.0.7632.159/ash/strings/ash_strings_pt-PT.xtb --- chromium-145.0.7632.116/ash/strings/ash_strings_pt-PT.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/ash/strings/ash_strings_pt-PT.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -1543,7 +1543,7 @@ Alterar utilização de letras maiúsculas Playlist: Desativado pelo administrador -Taxa de voz +Velocidade de voz Adicionar ligação a Editado no mês passado sistema diff -Nru chromium-145.0.7632.116/ash/strings/ash_strings_sr-Latn.xtb chromium-145.0.7632.159/ash/strings/ash_strings_sr-Latn.xtb --- chromium-145.0.7632.116/ash/strings/ash_strings_sr-Latn.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/ash/strings/ash_strings_sr-Latn.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -1738,7 +1738,7 @@ Izabrali ste marker na desnoj ivici, koristite tastere sa strelicama za pomeranje Tastatura za PIN Prevucite ili pritisnite taster za razmak da biste izabrali oblast za snimanje videa -Prethodno +Nazad Energija Prikaži šta je novo Povezano, nivo baterije je % diff -Nru chromium-145.0.7632.116/ash/strings/ash_strings_sr.xtb chromium-145.0.7632.159/ash/strings/ash_strings_sr.xtb --- chromium-145.0.7632.116/ash/strings/ash_strings_sr.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/ash/strings/ash_strings_sr.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -1738,7 +1738,7 @@ Изабрали сте маркер на десној ивици, користите тастере са стрелицама за померање Тастатура за PIN Превуците или притисните тастер за размак да бисте изабрали област за снимање видеа -Претходно +Назад Енергија Прикажи шта је ново Повезано, ниво батерије је % diff -Nru chromium-145.0.7632.116/ash/strings/ash_strings_zh-CN.xtb chromium-145.0.7632.159/ash/strings/ash_strings_zh-CN.xtb --- chromium-145.0.7632.116/ash/strings/ash_strings_zh-CN.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/ash/strings/ash_strings_zh-CN.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -190,7 +190,7 @@ 键 + 向下键 暂停媒体 取消设置查看手机中的应用 -“撤消” +“撤销” 开启 开启这些功能后,系统可能会将输入文本、文档内容和网页网址发送到 Google AI 服务器。系统会根据这些信息生成写作建议、总结内容、回答问题和改进产品,并遵守 。请勿包含任何个人、敏感或机密信息。 摄像头 @@ -315,7 +315,7 @@ 以摄氏度显示温度 键盘亮度 开启/关闭 -撤消 +撤销 打开表情符号选择器 游戏 Chromebook 版 Steam 资讯 diff -Nru chromium-145.0.7632.116/ash/webui/camera_app_ui/resources/strings/camera_strings_es-419.xtb chromium-145.0.7632.159/ash/webui/camera_app_ui/resources/strings/camera_strings_es-419.xtb --- chromium-145.0.7632.116/ash/webui/camera_app_ui/resources/strings/camera_strings_es-419.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/ash/webui/camera_app_ui/resources/strings/camera_strings_es-419.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -137,7 +137,7 @@ Tipo de grabación Resolución de video Errores en el sistema de archivos -Se copió el texto. +Se copió el texto Grabar video de GIF Muestra el texto y el botón para copiar Cambiar a la siguiente cámara diff -Nru chromium-145.0.7632.116/ash/webui/camera_app_ui/resources/strings/camera_strings_fa.xtb chromium-145.0.7632.159/ash/webui/camera_app_ui/resources/strings/camera_strings_fa.xtb --- chromium-145.0.7632.116/ash/webui/camera_app_ui/resources/strings/camera_strings_fa.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/ash/webui/camera_app_ui/resources/strings/camera_strings_fa.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -37,7 +37,7 @@ برای جزئیات، با سرپرست تماس بگیرید. برای درستی‌سنجی محتوا، آن را کپی کنید یا برای متوقف کردن اسکن، آن را ازهم باز کنید. جمع کردن کادر گفتگو و شروع کردن اسکن -بازگشت +برگشتن ضبط متوقف شد اسکن شروع ضبط diff -Nru chromium-145.0.7632.116/build/util/LASTCHANGE chromium-145.0.7632.159/build/util/LASTCHANGE --- chromium-145.0.7632.116/build/util/LASTCHANGE 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/build/util/LASTCHANGE 2026-03-02 23:00:09.000000000 +0000 @@ -1,2 +1,2 @@ -LASTCHANGE=7d28075c6a9ba147e6df449209001258bb82a122-refs/branch-heads/7632@{#3100} +LASTCHANGE=838c69b2e5b8cd00a916e35097249bc20eb25a0a-refs/branch-heads/7632@{#3673} LASTCHANGE_YEAR=2026 diff -Nru chromium-145.0.7632.116/build/util/LASTCHANGE.committime chromium-145.0.7632.159/build/util/LASTCHANGE.committime --- chromium-145.0.7632.116/build/util/LASTCHANGE.committime 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/build/util/LASTCHANGE.committime 2026-03-02 23:00:09.000000000 +0000 @@ -1 +1 @@ -1771618804 \ No newline at end of file +1772492409 \ No newline at end of file diff -Nru chromium-145.0.7632.116/chrome/VERSION chromium-145.0.7632.159/chrome/VERSION --- chromium-145.0.7632.116/chrome/VERSION 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/VERSION 2026-03-02 23:00:09.000000000 +0000 @@ -1,4 +1,4 @@ MAJOR=145 MINOR=0 BUILD=7632 -PATCH=116 +PATCH=159 diff -Nru chromium-145.0.7632.116/chrome/app/resources/chromium_strings_da.xtb chromium-145.0.7632.159/chrome/app/resources/chromium_strings_da.xtb --- chromium-145.0.7632.116/chrome/app/resources/chromium_strings_da.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/chromium_strings_da.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -304,7 +304,7 @@ Servicevilkår Installationen mislykkedes på grund af en ikke-specificeret fejl. Hvis Chromium kører, skal du lukke programmet og prøve igen. Eksportér adgangskoder fra Chromium -Adgangs­kode­admin­istrator +Adgangskode­administrator Søg i dette screenshot Download fuldført. kræver, at du læser og accepterer følgende servicevilkår, inden du bruger denne enhed. Disse vilkår udvider, ændrer eller begrænser på ingen måde vilkårene for Chromium OS. diff -Nru chromium-145.0.7632.116/chrome/app/resources/chromium_strings_el.xtb chromium-145.0.7632.159/chrome/app/resources/chromium_strings_el.xtb --- chromium-145.0.7632.116/chrome/app/resources/chromium_strings_el.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/chromium_strings_el.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -301,7 +301,7 @@ Σας προειδοποιεί για επικίνδυνους ιστοτόπους, ακόμα και για όσους δεν γνώριζε η Google στο παρελθόν, αναλύοντας περισσότερα δεδομένα από ιστοτόπους σε σχέση με την βασική προστασία. Μπορείτε να επιλέξετε να παραβλέψετε τις ειδοποιήσεις του Chromium. Αποσύνδεση από το Chromium Λήψη βοήθειας σχετικά με το Chromium -Όροι Παροχής Υπηρεσιών +Όροι παροχής υπηρεσιών Η εγκατάσταση απέτυχε λόγω απροσδιόριστου σφάλματος. Εάν το Chromium εκτελείται αυτήν τη στιγμή, κλείστε το και δοκιμάστε ξανά. Εξαγωγή κωδικών πρόσβασης από το Chromium Διαχείριση κωδικών πρόσβασης diff -Nru chromium-145.0.7632.116/chrome/app/resources/chromium_strings_es-419.xtb chromium-145.0.7632.159/chrome/app/resources/chromium_strings_es-419.xtb --- chromium-145.0.7632.116/chrome/app/resources/chromium_strings_es-419.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/chromium_strings_es-419.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -572,7 +572,7 @@ Retoma tu actividad desde donde la dejaste: Chromium restablece tus pestañas cada vez que reinicias. Para desactivar esta opción, ve a Importar contraseñas a Chromium : Chromium para desarrolladores -Se copió el texto. +Se copió el texto Chromium necesita permiso para acceder a tu cámara para este sitio Para usar el micrófono, otorga acceso a Chromium en la configuración del sistema Para obtener próximas actualizaciones de Chromium, necesitarás Windows 10 o versiones posteriores. Esta computadora usa Windows 7. diff -Nru chromium-145.0.7632.116/chrome/app/resources/chromium_strings_es.xtb chromium-145.0.7632.159/chrome/app/resources/chromium_strings_es.xtb --- chromium-145.0.7632.116/chrome/app/resources/chromium_strings_es.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/chromium_strings_es.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -42,7 +42,7 @@ Comparte tus ideas Para compartir tu ventana, permite la grabación de pantalla de Chromium en Ajustes del sistema Obtener ayuda con Chrome for Testing -Hola, ,¿en qué estás pensando hoy? +Hola, ,¿qué tienes en mente hoy? Error de instalación: Esta página está protegida Compartir una pestaña de Chromium @@ -366,7 +366,7 @@ Gemini en Chromium usa la navegación automática en tus pestañas para completar las tareas que le asignes. Más información Chromium necesita permiso para hacer seguimiento de tus manos No has visitado el sitio recientemente. Chromium ha eliminado , y . -¿En qué estás pensando hoy? +¿Qué tienes en mente hoy? Sueles bloquear las notificaciones. Para permitir que este sitio te envíe notificaciones, haz clic en el icono de notificación que aparece en la esquina derecha de la barra de direcciones. No hay suficiente espacio en disco. La cuenta de Chromium debe volver a autenticarse diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_ar.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_ar.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_ar.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_ar.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -8902,7 +8902,7 @@ تم حظر "" وبعض التطبيقات الأخرى على تُفتح صفحة إعدادات الأمان في علامة تبويب جديدة {NUM_PASSWORDS,plural, =1{هناك كلمة مرور جديدة لهذا الموقع الإلكتروني}zero{ما مِن كلمات مرور جديدة لهذا الموقع الإلكتروني}two{هناك كلمتا مرور جديدتان لهذا الموقع الإلكتروني}few{هناك كلمات مرور جديدة لهذا الموقع الإلكتروني}many{هناك كلمات مرور جديدة لهذا الموقع الإلكتروني}other{هناك كلمات مرور جديدة لهذا الموقع الإلكتروني}} -يمكن أن يؤدي ذلك إلى قراءة بيانات الموقع الإلكتروني وتغييرها +يمكن لهذه الإضافة قراءة بيانات الموقع الإلكتروني وتغييرها اسم الاختصار بإمكان التطبيقات والمواقع الإلكترونية التي لديها أذونات تحديد الموقع الجغرافي وكذلك خدمات النظام استخدام موقعك الجغرافي. مزيد من المعلومات مجموعة - diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_ca.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_ca.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_ca.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_ca.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -4916,7 +4916,7 @@ Noms d'emmagatzematge extraïble Finestra d'&incògnit nova Obre l'aplicació -Canvia per mi +Canvia-la per mi Aquesta pàgina té permís per editar fitxers {COUNT,plural, =1{# contacte no està disponible. Per fer servir amb aquesta persona, afegeix als teus contactes l'adreça electrònica associada al seu Compte de Google.}other{# contactes no estan disponibles. Per fer servir amb aquestes persones, afegeix als teus contactes les adreces electròniques associades als seus Comptes de Google.}} Configura un PIN nou per a la clau de seguretat @@ -10471,7 +10471,7 @@ Si ja esteu registrat en aquest dispositiu, podeu iniciar la sessió com a usuari existent. Afegeix i classifica els teus idiomes preferits. Quan sigui possible, els llocs web es mostraran en aquests idiomes. Aquestes preferències se sincronitzen amb la configuració del navegador. Més informació No s'ha pogut iniciar la sessió. Contacteu amb l'administrador o torneu-ho a provar. -Ajuda a millorar les funcions i el rendiment de Chrome i Chrome OS enviant automàticament informes d'error i dades de diagnòstic i d'ús a Google. +Ajuda a millorar les funcions i el rendiment de Chrome i ChromeOS enviant automàticament informes d'error i dades de diagnòstic i d'ús a Google. S'ha trobat  pestanya Més accions per als fitxers de Google Drive Limita l'inici de sessió diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_cs.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_cs.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_cs.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_cs.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -5163,7 +5163,7 @@ Stahování souborů k rozpoznávání řeči…  % Seskupit karty pomocí AI Můžete použít preferovaný jazyk účtu Google () -Pomoci s vylepšováním funkcí a výkonu prohlížeče Chrome +Pomáhat vylepšovat funkce a výkon Chromu Vygenerovaný obrázek  na téma ve stylu Začít Klikněte pravým tlačítkem na kartu a vyberte Přidat kartu do nové skupiny @@ -11778,7 +11778,7 @@ Odesílání této karty Poznámky k vydání Gemini momentálně není k dispozici. Zkuste to později. -Při pohybu myši posouvat obrazovku souvisle +Při pohybu myši se obrazovku souvisle posouvá Chrání před weby, soubory ke stažení a rozšířeními, o kterých je známo, že jsou nebezpečné. Pokud stránka provede něco podezřelého, odešlou se adresy URL a části obsahu stránky do Bezpečného prohlížení Google. K instalaci Linuxu je potřeba volného místa. Místo uvolníte smazáním souborů ze zařízení. Výukový program čtečky ChromeVox diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_da.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_da.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_da.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_da.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -4939,7 +4939,7 @@ {COUNT,plural, =1{# kontakt er ikke tilgængelig. Hvis du vil bruge med denne kontakt, skal du føje den mailadresse, der er tilknyttet vedkommendes Google-konto, til dine kontakter.}one{# kontakt er ikke tilgængelig. Hvis du vil bruge med denne kontakt, skal du føje den mailadresse, der er tilknyttet vedkommendes Google-konto, til dine kontakter.}other{# kontakter er ikke tilgængelige. Hvis du vil bruge med disse kontakter, skal du føje de mailadresser, der er tilknyttet deres Google-konti, til dine kontakter.}} Opret en ny pinkode til din sikkerhedsnøgle Flyt din adresselinje for at få en tilpasset browseroplevelse -Adgangs­kode­admin­istrator +Adgangskode­administrator Kopiér til Skift Apps skal downloades med indholdstypen "" @@ -5196,7 +5196,7 @@ Konfigurerer den virtuelle maskine. Dette kan tage et par minutter. scripttjeneste Fane, der blev lukket for nylig -Lokationsnøjagtighed +Lokations­nøjagtighed Chromebooks bruger apps i stedet for traditionel software. Få apps til produktivitet, underholdning og meget mere. Har tilladelse til at bruge dit kamera Udvidelser er ikke tilladt på dette website @@ -7717,7 +7717,7 @@ Serveren er utilgængelig Importér ONC-fil Du kan få adgang til den i Google Adgangs­kode­admin­istrator. -Google Adgangs­kode­admin­istrator +Google Adgangs­ko­de­administrator Der blev ikke fundet nogen apps % System: diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_de.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_de.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_de.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_de.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -498,7 +498,7 @@ Es konnte keine Verbindung zu hergestellt werden. Versuche es erneut. Synchronisierung pausiert Deine Dockingstation arbeitet im Modus für USB Typ-C-Kompatibilität. -Schaltfläche "Zurück" auf Unterseite "" +Button „Zurück“ auf Unterseite „ Gespeicherte Passwörter in meinem ansehen und verwalten Verwende „x“, um zwischen der linken, der rechten und beiden Maustasten gleichzeitig zu wechseln Besser schreiben @@ -1273,7 +1273,7 @@ Dürfen Ton abspielen Zum Ausführen von die Strg-Taste drücken und mit der Maus klicken Beim Zuklappen abmelden -Funktionsanfrage +Feature Request Alle HID-Geräte Dürfen deine Mauseingaben erfassen und verwenden Zum Anpinnen von Verknüpfungen gedrückt halten @@ -1302,7 +1302,7 @@ ist bereit, die Installation abzuschließen Die Passwortüberprüfung ist in Chromium nicht verfügbar Standortermittlung für Android-Apps und -Dienste nutzen. -Lesezeichen-Schaltfläche +Lesezeichen-Button In Chrome-Browser öffnen Vollständiger Downloadverlauf Weniger Apps @@ -3411,7 +3411,7 @@ Über das Kartenmenü kannst du die Einstellungen verwalten und unter „Chrome anpassen“ kannst du weitere Optionen aufrufen. -Schaltfläche ausblenden +Button ausblenden {GROUP_COUNT,plural, =1{Die Tabs bleiben auf diesem Gerät geöffnet, aber die Gruppe wird endgültig gelöscht.}other{Die Tabs bleiben auf diesem Gerät geöffnet, aber die Gruppen werden endgültig gelöscht.}} Google Assistant wird geladen... Bauwerke @@ -6446,7 +6446,7 @@ Wer Inhalte mit dir teilen kann Dieses Passwort wird nur auf diesem Gerät gespeichert. Wenn du es auf deinen anderen Geräten verwenden möchtest, speichere es in deinem Google-Konto. bearbeiten -Die Unternehmensrichtlinie hat sich geändert. Die Schaltfläche für Tests wurde zur Symbolleiste hinzugefügt. Klicke auf die Schaltfläche, um das Dialogfeld zum Aktivieren von Tests zu öffnen. +Die Unternehmensrichtlinie hat sich geändert. Der Button für Tests wurde zur Symbolleiste hinzugefügt. Klicke auf den Button, um das Dialogfeld zum Aktivieren von Tests zu öffnen. Apps und Websites mit Kameraberechtigung sowie Systemdienste können die Kamera verwenden. Möglicherweise musst du die App neu starten oder die Seite aktualisieren, damit die Kamera verwendet werden kann. {NUM_SITES,plural, =1{1 Website mit vielen Benachrichtigungen gefunden}other{{NUM_SITES} Websites mit vielen Benachrichtigungen gefunden}} Datei kann nicht hochgeladen werden. Die Bilddatei konnte nicht verarbeitet werden. @@ -8006,7 +8006,7 @@ Aufleuchten bei Benachrichtigungen Wenn du Tabs teilen und mit anderen zusammenarbeiten möchtest, melde dich in Chrome an und synchronisiere deinen Verlauf und deine Tabs. Du kannst dann auch auf allen deinen Geräten auf deine Passwörter und weitere Daten zugreifen. Benachrichtigungen stummschalten -Schaltfläche „Startseite“ anzeigen +Button „Startseite“ anzeigen Option auswählen Die Aufhebung der Freigabe ist nicht möglich, weil eine Anwendung diesen Ordner verwendet. Die Freigabe des Ordners wird aufgehoben, wenn Linux das nächste Mal heruntergefahren wird. Verbindung zu Google Drive-Konto aufheben @@ -8272,7 +8272,7 @@ Zwölf Boxkämpfer jagen Viktor quer über den großen Sylter Deich. Druckserver Mit dem Google Passwortmanager kannst du dich auf allen deinen Geräten schneller auf Websites anmelden -Die Unternehmensrichtlinie hat sich geändert. Die Schaltfläche für Tests wurde aus der Symbolleiste entfernt. +Die Unternehmensrichtlinie hat sich geändert. Der Button für Tests wurde aus der Symbolleiste entfernt. Führe Powerwash für dein aus und setze es auf die vorherige Version zurück. Beim Öffnen deines Profils ist ein Fehler aufgetreten. Melde dich bitte ab und dann wieder an. Wild @@ -9121,7 +9121,7 @@ Wenn du diese Daten löschen möchtest, ruf die entsprechenden Verwaltungseinstellungen auf &Weitere Informationen Soll "" wirklich im Diagnosemodus gestartet werden? -Lesezeichenordner-Schaltfläche +Lesezeichenordner-Button Übernehmen Die Website verwendet deine Kamera Mikrofon auf der Rückseite @@ -10651,7 +10651,7 @@ Ungültiges Clientzertifikat Drive Aktueller Downloadverlauf -Schaltfläche „Startseite“ anzeigen +Button „Startseite“ anzeigen Du kannst Definitionen oder Übersetzungen anzeigen oder Einheiten umrechnen lassen, indem du Text gedrückt hältst oder mit der rechten Maustaste darauf klickst. Unter Websitesprachen kannst du die Sprachen für die Übersetzung anpassen. Liebe Eltern, die nächsten Schritte müsst ihr ausführen. Ihr könnt das Gerät () nach der Kontoeinrichtung wieder eurem Kind geben. Bild herunterladen @@ -12167,7 +12167,7 @@ Anfängliche Punktbreite ist "Voll". Auf ein Element doppeltippen, es beim zweiten Tippen gedrückt halten und es dann an die gewünschte Position ziehen Dieses Fenster wird nach Abbruch der Installation geschlossen. -Dreipunkt-Menü-Schaltfläche +Dreipunkt-Menü-Button Offline Einschränkungen hinzufügen Hallo diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_el.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_el.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_el.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_el.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -4899,7 +4899,7 @@ Η συσκευή θα αποσυνδέεται αυτόματα μόλις απενεργοποιείται ή όταν δεν χρησιμοποιείται Οι ιστότοποι μπορούν να ζητούν άδεια για την εγκατάσταση εφαρμογών ιστού στη συσκευή σας Δημιουργία -Όροι Παροχής Υπηρεσιών +Όροι παροχής υπηρεσιών Προσαρμογή κουμπιών γραφίδας Το Smart Lock είναι ενεργοποιημένο Σύμπτυξη κατακόρυφων καρτελών @@ -5177,7 +5177,7 @@ Πραγματοποιείται λήψη των αρχείων αναγνώρισης ομιλίας… % Ομαδοποίηση καρτελών με AI Μπορείτε να χρησιμοποιήσετε τη γλώσσα του Λογαριασμού Google που προτιμάτε () -Συμβάλλετε στη βελτίωση των λειτουργιών και της απόδοσης του Chrome +Συμβάλετε στη βελτίωση των λειτουργιών και της απόδοσης του Chrome Δημιουργήθηκε εικόνα σχετικά με , σε στιλ Έναρξη Κάντε δεξί κλικ σε μια καρτέλα και επιλέξτε Προσθήκη καρτέλας σε νέα ομάδα diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_es-419.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_es-419.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_es-419.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_es-419.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -3598,7 +3598,7 @@ Seguridad Se agotó el papel Habilitar -Pregúntale al Modo IA +Preguntarle al Modo IA Administra tu actividad en las Apps con Gemini Consulta tus archivos de SharePoint y OneDrive, y el calendario de Outlook Ninja @@ -6723,7 +6723,7 @@ Detecta eventos peligrosos cuando ocurren y te advierte sobre ellos. Si deseas obtener más información, comunícate con tu administrador archivo local o compartido -Busca en Google o escribe una URL +Buscar en Google o escribir una URL ¿Quieres salir del grupo de pestañas? Activo No puedo acceder @@ -7538,7 +7538,7 @@ No pueden administrar las ventanas de todas tus pantallas retroceso Tu llave de seguridad no está protegida con un PIN. Para administrar las huellas dactilares, crea uno. -Agregar pestañas y otras cosas +Agregar pestañas y más Firma X9.62 ECDSA con SHA-384 Mostrar detalles Confirmar la descarga diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_es.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_es.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_es.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_es.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -202,7 +202,7 @@ Editar motor de búsqueda Cyberpunk Consulta las fotos y el contenido multimedia de tu teléfono -Gestionar apps +Gestionar aplicaciones Crear vista dividida {0,plural, =1{Cerrar ventana de Incógnito}other{Cerrar ventanas de Incógnito (# ventanas)}} Elige un nombre y un tema de color para diferenciar entre perfiles @@ -4913,7 +4913,7 @@ Se ha eliminado del historial de descargas, pero aún está en tu dispositivo Vuelve a iniciar sesión para confirmar que tu cuenta se puede usar con sitios web, aplicaciones y extensiones tanto en Chrome como en Google Play. También puedes quitar esta cuenta. Más información Aplicaciones instaladas y emitidas desde -Tu contraseña original de este sitio se ha encontrado en una brecha de seguridad de datos públicos. El pediste a que cambiara automáticamente tu contraseña. +Tu contraseña original de este sitio se ha encontrado en una brecha pública de seguridad de datos. El pediste a que cambiara automáticamente tu contraseña. Reiniciar y restablecer Rotación de pantalla Nombres de almacenamiento extraíble @@ -5553,7 +5553,7 @@ Ir al sitio Excel {NUM_TABS,plural, =1{Activar sonido del sitio}other{Activar sonido de los sitios}} -Tu contraseña se ha encontrado en una brecha de seguridad de datos públicos +Tu contraseña se ha encontrado en una brecha pública de seguridad de datos El administrador ha hecho un cambio que afecta a todo el sistema e inhabilita algunos perfiles antiguos. Ya no puedes acceder a este perfil, pero puedes quitarlo. Estás a punto de eliminar tus datos de guardados en este dispositivo Los sitios se suelen conectar a dispositivos HID para usarlos en funciones que utilizan teclados poco habituales, mandos de juegos y otros dispositivos @@ -8225,7 +8225,7 @@ Confirma el número PIN Mantén tus pestañas ordenadas con la IA Nombre del contenedor -Pregunta a Google o escribe una URL +Preguntar a Google o escribir una URL Para enviar esta pestaña a otro dispositivo, inicia sesión en Chrome en ambos dispositivos Seguir bloqueando imágenes En modo tablet, toca el botón del contador de pestañas situado en la barra de herramientas para abrir la nueva barra de pestañas donde se muestran miniaturas de cada pestaña. diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_et.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_et.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_et.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_et.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -368,7 +368,7 @@ Pealkirjata Taotluse lõpule viimiseks puudutage uuesti turvavõtit. Lokaat -{0,plural, =1{Salvesta üks kontol olev üksus}other{Salvesta # kontol olevat üksust}} +{0,plural, =1{Salvesta üks üksus kontole}other{Salvesta # üksust kontole}} Loo selle pildi jaoks QR-kood Service Workers Teadaolevad võrgud diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_eu.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_eu.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_eu.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_eu.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -260,7 +260,7 @@ lan-eremukoa da Kendu egin da txartela, azkenaldian erabili ez duzulako igarotakoan irekiko da… -Azkenaldiko AA bidez sortutako garren gaia, erakusten duena, estiloan, . +Azkenaldiko AA bidezko garren gaia, erakusten duena, estiloan, . Galdetu Google-ri aurreko orriari buruz Aldatu hizkuntza automatikoki, hautatutako edukiaren arabera Jokoak kontrolatzeko aukerak @@ -3052,7 +3052,7 @@ Eskuineko botoiarekin klik egiteko, erabili ukipen-panela eta teklatua Hautatu inportatu beharreko elementuak: Azpititulu automatikoak -Azkenaldiko AA bidez sortutako gaia () +Azkenaldiko AA bidezko gaia () Ezkutatu proiektuak Ez molestatzeko modua gaituta dago Kontrolatu datuak @@ -5268,7 +5268,7 @@ Segurtasun-giltzak ez dauka hatz-markarik gordeta Saiatu berriro minutu batzuk barru. Onartzen diren esteka batzuek aplikazioan irekitzen jarraituko dute. -AA bidez azkenaldian sortutako gaiak +Azkenaldiko AA bidezko gaiak Sakatu desegiteko Gailuaren hizkuntza aldatzeko, Chromebook berrabiarazi egin behar duzu. Lortu informazio gehiago Kanpoko luzapena lehendik dagoenaren bertsio berean edo zaharragoan dago. @@ -6346,7 +6346,7 @@ Gorde da pasahitza. Ikusi eta kudeatu gordetako pasahitzak hemen: . Hasi saioa webgunean Beste norbaitek pantailari begiratzen dionean, erakutsi Pribatutasun-begia ikonoa pantailaren behealdean, eskuinetara -Azkenaldiko AA bidez sortutako garren gaia, erakusten duena, estiloan +Azkenaldiko AA bidezko garren gaia, erakusten duena, estiloan Gaiaren sortzailea: Aurrera egin nahi duzu, eta software honi gailuan aldaketak egiteko baimena eman? Ez egin jarraipenik @@ -9173,7 +9173,7 @@ Leheneratu atzeko plano lehenetsia Aplikazioan gordetako datuak × dpi -Azkenaldiko AA bidez sortutako garren gaia, erakusten duena +Azkenaldiko AA bidezko garren gaia, erakusten duena Chrome-ren segurtasun sendoena daukazu Internetera konektatuta egon arren arazoak badirau, webgunean aurrera egiteko beste modu batzuk proba ditzakezu. . Baimena eskatu da. Erantzuteko, sakatu F6. @@ -9979,7 +9979,7 @@ Mendia Erabili oraingo orriak Fitxa taldeak -Azkenaldiko AA bidez sortutako garren gaia, erakusten duena, . +Azkenaldiko AA bidezko garren gaia, erakusten duena, . Arakatzaile zaharrekiko bateragarritasuna (LBS) - Barnekoak Desgaitu da ADB arazketa Gailu-identifikatzailea gatazkatsua da. diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_fa.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_fa.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_fa.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_fa.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -1110,7 +1110,7 @@ قلم ایتالیک ‏این برنامه صفحه‌ای را که هنگام جستجو از Omnibox نشان داده می‌شود، کنترل می‌کند. فراموشی گذرواژه قدیمی -برای حذف برنامه‌ها به «تنظیمات > فروشگاه Google Play > مدیریت اولویت‌های Android > برنامه‌ها یا مدیر برنامه» بروید. سپس روی برنامه‌ای که می‌خواهید حذف نصب شود تک‌ضرب بزنید (ممکن است برای پیدا کردن برنامه نیاز باشد صفحه را تند به‌راست یا چپ بکشید). سپس روی «حذف نصب» یا «غیرفعال کردن» تک‌ضرب بزنید. +برای برداشتن برنامه‌ها به «تنظیمات > فروشگاه Google Play > مدیریت اولویت‌های Android > برنامه‌ها یا مدیر برنامه» بروید. سپس روی برنامه‌ای که می‌خواهید حذف نصب شود تک‌ضرب بزنید (ممکن است برای پیدا کردن برنامه نیاز باشد صفحه را تند به‌راست یا چپ بکشید). سپس روی «حذف نصب» یا «غیرفعال کردن» تک‌ضرب بزنید. پیمایش به‌سمت آخرین زبانه ‏الگوی گواهینامه Microsoft در حال ارسال درخواست... @@ -2266,7 +2266,7 @@ بسیار بزرگ برای محافظت از حریم خصوصی‌تان مسدود شده است گواهی در انتظار -بازگشت +برگشتن تایپ کردن میان‌بر کلیدهای چسبان برداشتن ، از فهرست @@ -4643,7 +4643,7 @@ خطای شبکه رخ داد. ‏مجاز کردن حرکت‌گذاری انعطاف‌پذیر. برای مثال، می‌توانید با تایپ کردن «anhs» یا «asnh» به «ánh» برسید. فضای دستگاه خیلی کم است -محدودیت جدید مدت تماشای صفحه +حد جدید مدت تماشای صفحه ‏SSID پنهان دایره ساختن با لب‌ها ‏بازراه‌اندازی برای powerwash @@ -6934,7 +6934,7 @@ ‏محافظت هم‌زمان و پیش‌کنشی با ارسال اطلاعات بیشتر به «مرور ایمن Google» درحال همگام‌سازی در نمایش همیشگی گزینه‌های دسترس‌پذیری -برگشت +برگشتن سازمانتان، ، نمی‌تواند داده‌های موجود شما را ببیند یا مدیریت کند. این داده‌ها در نمایه فعلی باقی خواهد ماند. ‏نام اصلی Microsoft گزارش‌های سرویس @@ -8998,7 +8998,7 @@ ‏پرچم‌های ChromeOS اعلان‌ها روی صفحه نشان داده نمی‌شوند. با کلیک کردن روی نماد «مزاحم نشوید» در پایین سمت چپ صفحه، همچنان می‌توانید اعلان‌ها را ببینید. نصب -سعی مجدد +امتحان مجدد جلسه قبلی ازسر گرفته نشد ‏Microsoft 365 برای باز کردن و ویرایش فایل‌های Word،‏ Excel، و PowerPoint از OneDrive استفاده می‌کند. می‌توانید این فایل‌ها را در منو پیمایش کناری برنامه Files با برچسب «Microsoft OneDrive» پیدا کنید. باید با حساب Microsoft به سیستم وارد شوید. بیشتر بدانید سایت‌ها ممکن است مطابق انتظار شما عمل نکنند. اگر می‌خواهید اطلاعاتی درباره سایت‌هایی که بازدید می‌کنید در دستگاه باقی نگذارید، این گزینه را انتخاب کنید. @@ -11474,7 +11474,7 @@ {NUM_TABS,plural, =1{انتقال زبانه به پنجره‌ای دیگر}one{انتقال زبانه‌ها به پنجره‌ای دیگر}other{انتقال زبانه‌ها به پنجره‌ای دیگر}} برای شروع همگام‌سازی، تنظیمات همگام‌سازی را تأیید کنید. صرفه‌جویی‌های بسیار زیاد -مرور کردن سریع‌تر می‌شود زیرا احتمال کمتری وجود دارد که سایتی از شما بخواهد تأیید کنید شما شخص واقعی هستید +مرور کردن سریع‌تر می‌شود زیرا احتمال کمتری وجود دارد که سایتی از شما بخواهد درستی‌سنجی کنید شما شخصی حقیقی هستید وقتی که دستگاهی متصل نشده باشد پایدار Web Store @@ -11602,7 +11602,7 @@ وقتی ارتقا به پایان برسد، برنامه‌تان باز خواهد شد. ارتقا ممکن است چند دقیقه طول بکشد. برای دسترسی آسان، می‌توانید این پانل کناری را سنجاق کنید نمایش گزینه‌ها -‏همان‌طور که مرور می‌کنید، سایت‌ها می‌توانند ازطریق Chrome بررسی کنند و بااستفاده از سایت قبلی که بازدید کرده‌اید تأیید کنند که احتمالاً شما شخص واقعی هستید +‏همان‌طور که مرور می‌کنید، سایت‌ها می‌توانند ازطریق Chrome بررسی کنند و بااستفاده از سایت قبلی که بازدید کرده‌اید درستی‌سنجی کنند که احتمالاً شما شخص واقعی هستید می‌تواند این فایل‌ها و پوشه‌ها را ویرایش کند: ممکن است هزینه داده تلفن همراه اعمال شود منابع @@ -12138,7 +12138,7 @@ نمایان با نام ارسال بازخورد -سایت‌هایی که بازدید می‌کنید می‌توانند تأیید کنند که شما شخص واقعی هستید و روبات نیستید +سایت‌هایی که بازدید می‌کنید می‌توانند درستی‌سنجی کنند که شما شخص واقعی هستید و روبات نیستید &بازرسی عناصر پاسخ شما نمی‌تواند فایل‌های این پوشه را باز کند زیرا فایل‌های سیستم در آن وجود دارد diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_fi.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_fi.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_fi.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_fi.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -2328,7 +2328,7 @@ Tarkistetaan virtuaalikoneen kuvaa Kuka käyttää tätä laitetta: ? Synkronointi pois käytöstä -Videokehys kopioitu +Videon yksittäiskuva kopioitu Kuuntele laajennuksen toiminnot valitsemalla Aloita Jotain meni pieleen. Virhekoodi: . Optimoidaanko koko näytön suoratoisto? @@ -4767,7 +4767,7 @@ Jatka siitä, mihin jäit Lisää sivustoja Poista välilehti listasta -Kopio&i videokehys +Kopio&i videon yksittäiskehys Muokatut sanat Uusi &välilehti Voit valita synkronoitavan sisällön asetuksissa. @@ -6139,7 +6139,7 @@ Suositus Vahvista koodi seuraamalla puhelimen ohjeita Salasanan vähimmäispituus on kahdeksan merkkiä -Kopio&i videokehys +Kopio&i videon yksittäiskuva Netscape-varmenteen SSL-palvelimen nimi Vapauta levytilaa, tai tiettyjä tietoja voidaan poistaa automaattisesti. Ohjaa hiiren kohdistinta näppäimistöllä tai numeronäppäimistöllä @@ -6939,7 +6939,7 @@ Palvelulokit Avaaminen ei onnistu. Lisää salasana. Sivustot julkaisevat joskus PDF-tiedostoja, kuten asiakirjoja, sopimuksia ja lomakkeita -Sivustot voivat näyttää henkilöllisyyspalveluiden sisäänkirjautumiskehotteita +Sivustot voivat näyttää identiteettipalveluiden sisäänkirjautumiskehotteita Avataan edellisen laitteen ikkunoita Yhdistetty: Rajoita liikettä näytöllä @@ -7181,7 +7181,7 @@ Uusi välilehti oikealle Kanava vaihdettiin. Ota muutokset käyttöön käynnistämällä laite uudelleen. Valittu tulostin ei ole käytettävissä tai sitä ei ole asennettu oikein. Tarkista tulostin tai valitse toinen tulostin. -Estä henkilöllisyyspalveluiden sisäänkirjautumiskehotteet +Estä identiteettipalveluiden sisäänkirjautumiskehotteet Jos vaihdoit, päivitä muutos tallennettuihin salasanoihin (). Tunnetut verkot Estetty automaattisesti: , @@ -7392,7 +7392,7 @@ Lomittain Avaa koko ruudulla Verkkotunnuksen järjestelmänvalvoja on lukinnut laitteen (sarjanumero ) -&Hae videokehystä tällä: +&Hae videon yksittäiskuvaa tällä: Pinon jälki – USB-laite yhdistetty Kun esität historiaasi koskevia kysymyksiä, voit saada tiettyyn avaamasi sivun sisältöön liittyviä vastauksia @@ -11155,7 +11155,7 @@ Muokkaa pikanäppäintä… Siirrä ylös Kaikki linkin saaneet voivat muokata kaikkia välilehtiä, joten ne kannattaa jakaa harkiten. Linkki vanhenee 48 tunnin kuluttua. -&Hae videokehystä tällä: +&Hae videon yksittäiskuvaa tällä: Vain pieniä kirjaimia, numeroita, alaviivoja ja yhdysviivoja Kirjautumistavat Laajennusten käyttö kielletty diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_fr.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_fr.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_fr.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_fr.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -668,7 +668,7 @@ Impossible de charger "" pour le thème. Sélectionnez une action pour la touche Activer la &synchronisation… -Fiche d'aperçu du survol de l'onglet +Aperçu au survol de l'onglet Vous pouvez utiliser ce compte avec les applis Android. Pour ajouter le compte d'une autre personne, ajoutez plutôt un nouvel utilisateur à votre . Les autorisations que vous avez déjà accordées aux applis peuvent s'appliquer à ce compte. Vous pouvez contrôler les autorisations pour les applis Android dans Paramètres des applications. @@ -755,7 +755,7 @@ Épingler la vue fractionnée Les dossiers partagés sont disponibles sous Windows dans . d'exporter les mots de passe -Vous pouvez regrouper des onglets pour rassembler des pages similaires et les enregistrer sur vos différents appareils +Regroupez les onglets pour rassembler des pages similaires et les enregistrer sur vos différents appareils Moteur de recherche Lire un ton plus haut L'accès à votre caméra est bloqué pour cette page @@ -2484,7 +2484,7 @@ Conseil : De nombreuses applis Android sont disponibles sur le Web. Vérifiez leur disponibilité dans l'appli ou sur le site Web du développeur. Événement Impossible de se connecter à l'imprimante. Vérifiez qu'elle est sous tension et connectée à votre Chromebook par Wi-Fi ou USB. -Page de cache amélioré : +Page de cache back/forward : Naviguez plus rapidement et consommez moins de données en mode simplifié. Cliquez ici pour en savoir plus. Chrome Web Store Ajout du profil eSIM. Cela peut prendre quelques minutes. @@ -2683,7 +2683,7 @@ Google Pay Utilisez votre clé de sécurité avec Check-up Mots de passe -Apparence de la fiche d'aperçu du survol de l'onglet +Apparence de l'aperçu au survol de l'onglet Descripteurs de fichiers GTK @@ -4046,7 +4046,7 @@ Inspecter le pop-up Une seule fois Aucune remarque ajoutée -Sous-cadre en cache amélioré : +Sous-cadre en cache back/forward : Obtenir les clés d'accès Code incorrect. Réessayez. Pour utiliser le Gestionnaire de mots de passe de Google avec le trousseau macOS, relancez Chrome et autorisez l'accès au trousseau. Vos onglets s'ouvriront alors de nouveau. @@ -4312,7 +4312,7 @@ est configuré pour s'ouvrir dans un nouvel onglet de navigateur. Les liens compatibles s'ouvriront aussi dans le navigateur. En savoir plus Fenêtres redimensionnées en haut Paramètres du Partage à proximité pour l'appareil de dans le compte . -Choisissez d'afficher l'utilisation de la mémoire et les images dans la fiche d'aperçu du survol de l'onglet +Choisissez d'afficher l'utilisation de la mémoire et les images dans l'aperçu au survol de l'onglet Gestionnaire de téléchargement Certaines pages que vous consultez sont préchargées Le contenu Web disponible dans plusieurs langues vous sera proposé dans la première langue disponible de cette liste. Ces préférences sont synchronisées avec les paramètres de votre navigateur. En savoir plus @@ -5007,7 +5007,7 @@ partage une fenêtre. Afficher les notifications Nom à afficher -Afficher l'utilisation de la mémoire sur la fiche d'aperçu du survol de l'onglet +Afficher l'utilisation de la mémoire dans l'aperçu au survol de l'onglet Ne pas autoriser les sites à se connecter aux appareils sur votre réseau local Demande de site Web approuvée Activer/Désactiver la dictée @@ -6043,7 +6043,7 @@ Non autorisé à suivre la position de la caméra Afficher le code Liste des sites que vous avez bloqués et qui ne doivent pas suggérer d'annonces à d'autres sites -Sous-cadre de navigation privée en cache amélioré : +Sous-cadre de navigation privée en cache back/forward : Vous pouvez ouvrir et modifier les fichiers compatibles avec cette appli depuis l'appli Fichiers ou d'autres applis. Pour contrôler quels fichiers s'ouvrent dans cette appli par défaut, découvrez comment définir les applis par défaut sur votre appareil. Communiquer avec les applications natives associées Progression @@ -9808,7 +9808,7 @@ Cliquez sur "Mots de passe et saisie automatique" Impossible de vérifier si ce document est sûr, car il est trop volumineux. Vous ne pouvez pas imprimer de documents de plus de 50 Mo. Certains éléments sont bloqués -Ouvrez facilement Gemini avec +Ouvrez-le facilement avec Imprimantes et scanners Non, continuer à utiliser ce profil pour l'école Désactivé @@ -10308,7 +10308,7 @@ Délai dépassé L'optimisation V8 est désactivée Remplacer par la vue du haut -Page de navigation privée en cache amélioré : +Page de navigation privée en cache back/forward : Aidez-nous à améliorer la saisie automatique Phrase précédente Accéder à l'ensemble du texte énoncé à l'aide de la synthèse vocale diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_hr.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_hr.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_hr.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_hr.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -669,14 +669,14 @@ Nije uspjelo učitavanje putanje "" za temu. Odaberite radnju za tipku Uključite &sinkronizaciju... -Zadržavanje lebdeće kartice pregleda +Lebdeća kartica pregleda Ovaj račun možete koristiti s Android aplikacijama. Ako želite dodati račun za nekog drugog, umjesto toga dodajte novu osobu na svoj . Dopuštenja koja ste već dali aplikacijama mogu se primijeniti na ovaj račun. Dopuštenjima za Android aplikacije možete upravljati u postavkama aplikacija. Alat za kistove Žarišne točke vašeg uređaja Ponovno pritisnite tipku da biste potvrdili dodjelu i -Otvori profil gosta +Otvorite profil gosta Web-stranica, jedna datoteka Pošalji zapisnike o otklanjanju pogrešaka (preporučeno) I&zradi snimku zaslona @@ -2576,7 +2576,7 @@ Nadzirane korisnike onemogućio je administrator. Vaš će se uređaj isključiti za . Uklonite USB i ponovo uključite uređaj. Nakon toga možete upotrebljavati . ID: -Otvori profil gosta +Otvorite profil gosta Boja limuna Ograničenja WebRTC zapisnici @@ -4502,7 +4502,7 @@ USB-C uređaj (stražnji desni priključak) Reproduciraj animaciju Prikvači na alatnu traku -Prikaži slike pregleda kartice +Prikaži slike na pregledu kartice Upravljajte pisačima Nećete moći upotrebljavati Android aplikacije i Trgovinu Google Play Isticanje pokazivača miša prilikom kretanja @@ -7732,7 +7732,7 @@ Pitaj prije kopiranja ili premještanja Microsoftovih datoteka na Microsoft OneDrive Ukloni priključak Povezivanje s uređajem -Prilagodba profila +Prilagodite profil Odaberite certifikat za svoju autentikaciju na Otvori aplikacijom Kada zatvorite duplikate zadržava se najstarija kopija diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_is.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_is.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_is.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_is.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -3949,7 +3949,7 @@ Halda áfram að veita aðgang að hljóðnemanum Lesa aðgengisstillingar Gögn frá innfelldum vefsvæðum -Bendilshraði +Hraði bendils Bætir við seinkun á milli þess þegar þú ýtir á lykil og þess þegar hann virkjast TrackPoint-hröðun Bættu við flipa og fleiru diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_it.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_it.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_it.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_it.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -1200,7 +1200,7 @@ Sospendi alla chiusura dello schermo La pagina non risponde. Puoi aspettare oppure chiuderla. Lingua in cui tradurre -Reimposta +Riaddestra Fai clic per attivare Una scheda in secondo piano sta usando il microfono Esamina visualizzazioni @@ -3188,7 +3188,7 @@ Seleziona lo stato dell'esperimento . Descrizione dell'esperimento: Avatar giallo predefinito Apri comunque -In ascolto… +Sto ascoltando Nuovo gruppo Annulla sincronizzazione Riproduci dall'inizio diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_ja.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_ja.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_ja.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_ja.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -8543,7 +8543,7 @@ エラー にログインしているデバイスのみ 保存したパスワードに常にアクセスできるようにするには、本人確認を行ってください -現在のタブで新しい分割表示 +現在のタブで新しい分割ビュー XML サイトリストの前回のダウンロードは に行われました。 チャットアプリのステータスを設定するため、サイトでデバイスのアクティブ状態を検出する場合があります。 ネットワークのデバッグ @@ -9608,7 +9608,7 @@ Chrome アプリが開いている間 Chrome は実行され続けます。 Gemini によるログイン 候補の履歴 -現在のタブで新しい分割表示 +現在のタブで新しい分割ビュー データが失われる危険があります。 入力設定 一部 diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_kk.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_kk.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_kk.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_kk.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -5878,7 +5878,7 @@ Қонақ режимінде веб-қолданбалар орнатылмайды Аяқталғанда ашу Принтер ақпаратын өзгерту -Құпия сөз дұрыс емес +Құпия сөз қате. Сайттар виртуалдық шындық құрылғыларын және деректерді пайдалануға рұқсат сұрай алады. {NUM_TABS,plural, =1{Сайттың дыбысын өшіру}other{Сайттардың дыбысын өшіру}} Қауіпсіздік тексерісі жүргізілді. Құжатыңыз басып шығарылады. diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_ko.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_ko.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_ko.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_ko.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -7555,7 +7555,7 @@ 모든 디스플레이의 창 관리 허용 안함 백스페이스 보안 키가 PIN으로 보호되어 있지 않습니다. 지문을 관리하려면 먼저 PIN을 만드세요. -탭 등 추가 +탭 및 기타 정보 활용 SHA-384를 포함한 X9.62 ECDSA 서명 세부정보 표시 다운로드 확인 diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_my.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_my.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_my.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_my.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -6086,7 +6086,7 @@ ဝင်းဒိုးအသစ်တွင် အဖွဲ့ကို ဖွင့်ရန် သင်၏အရာများကို အရန်သိမ်းမလား။ ရုပ်ဖျက်မုဒ်မှ ထွက်ရန် -&စာညှပ် မန်နေဂျာ +&ဝဘ်လိပ်စာ စီမံစနစ် ဤစက်တွင် အတွက် လျှို့ဝှက်ကီး မရှိပါ ပြုစုသူ ကိရိယာများ {NUM_OF_FILES,plural, =1{ဖိုင် ၁ ဖိုင်ရွှေ့လိုက်သည်}other{ဖိုင် {NUM_OF_FILES} ဖိုင်ရွှေ့လိုက်သည်}} @@ -9544,7 +9544,7 @@ သင့်မိသားစုဝင်သည် စကားဝှက်များကို ယခု မရယူနိုင်ပါ။ Chrome အပ်ဒိတ်လုပ်ပြီး သူ၏စကားဝှက်များ စင့်ခ်လုပ်ခိုင်းပါ။ ဤရွေးချယ်စရာကို ယခုမရနိုင်ပါ။ ရုပ်ဖျက်ဌာန-: -ဖြတ်လမ်းလင့်ခ်များ ပြရန် +ဖြတ်လမ်းများ ပြရန် Microsoft 365 ဖိုင် စာလုံးကြီးများကို ဖတ်သည့်အခါ ပရိုဖိုင်ကို အမည်ပြောင်းရန် @@ -10438,7 +10438,7 @@ စာရင်းသွင်းမှုကို ဤစက်တွင်သာ ထည့်သွင်းထားပြီး သင့်အကောင့်အောက်ရှိ အခြားစက်များနှင့် စင့်ခ်လုပ်ထားခြင်း မရှိပါ။ ပိုမိုလေ့လာရန် အဆက်အသွယ် စာရင်းကို ဒေါင်းလုဒ်လုပ်နေသည်... မိုက်ခရိုဖုန်း ခွင့်ပြုချက် -&စာညှပ် မန်နေဂျာ +&ဝဘ်လိပ်စာ စီမံစနစ် က သင်လက်မှတ်ထိုးဝင်ပုံကို မှတ်ထားပြီး ရနိုင်တိုင်း အလိုအလျောက် လက်မှတ်ထိုးဝင်ပေးသည်။ ပိတ်ထားပါက အကြိမ်တိုင်း အတည်ပြုချက် တောင်းပါမည်။ Chrome ကပိတ်ထားသည်။ ဤနောက်ဆက်တွဲသည် လုံခြုံမှုမရှိနိုင်ပါ။ {EXTENSIONS_COUNT,plural, =1{လိပ်စာ # ခု}other{လိပ်စာ # ခု}} diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_no.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_no.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_no.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_no.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -4485,7 +4485,7 @@ Bluetooth i ChromeOS Blokker og forlat Fortsett å blokkere dette nettstedet fra å få tilgang til posisjonen din -Kopiér link +Kopier link Denne fanen er koblet til en USB-enhet Velg tidssone Logg av diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_pt-BR.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_pt-BR.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_pt-BR.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_pt-BR.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -2742,7 +2742,7 @@ Parar de carregar esta página Pasta de favoritos Para salvar senhas na Conta do Google, ative a sincronização. -Definir Estilo e fundo de tela +Definir plano de fundo e estilo Ativar a opção "Não rastrear" significa que uma solicitação será incluída no tráfego de navegação. Qualquer efeito depende de o website responder ou não à solicitação e de como ela é interpretada. Por exemplo, alguns websites podem reagir a esse pedido mostrando anúncios que não têm qualquer relação com os sites que você costuma visitar. Mesmo assim, alguns websites ainda vão coletar e usar seus dados de navegação para, por exemplo, melhorar a segurança, gerar conteúdo, anúncios, recomendações e relatórios de estatística. Detalhes da impressora Usar os tamanhos predefinidos para evitar problemas em smartphones, tablets ou janelas redimensionáveis @@ -8465,8 +8465,8 @@ Muito pequeno &Gerenciar mecanismos de pesquisa… Link do doodle -Os dados de apps podem ser quaisquer dados que um app tenha salvo (com base nas configurações do desenvolvedor), incluindo dados como contatos, mensagens e fotos. Os dados de backup não são contabilizados na cota de armazenamento no Google Drive da criança. - Você pode desativar esse serviço nas configurações. +Dados do app são as informações salvas pelo app (com base nas configurações do desenvolvedor), incluindo contatos, mensagens e fotos. Os dados de backup não são contabilizados na cota de armazenamento no Google Drive da criança. + Você pode desativar esse serviço nas Configurações. Backup do Linux cancelado PIN inválido Esquecer este dispositivo? diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_ro.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_ro.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_ro.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_ro.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -8560,7 +8560,7 @@ Erori Doar dispozitivele conectate la Confirmă-ți identitatea ca să te asiguri că ai în permanență acces la parolele salvate -Noua afișare împărțită cu fila actuală +Afișare împărțită nouă cu fila actuală Listele de site-uri XML au fost descărcate ultima dată pe . Site-urile detectează de obicei când folosești activ dispozitivul pentru a-ți seta disponibilitatea în aplicații de chat Remedierea erorilor de rețea @@ -9625,7 +9625,7 @@ Chrome va rula în continuare când sunt deschise aplicații Chrome. Gemini poate să se conecteze pentru tine Istoricul sugestiilor -Noua afișare împărțită cu fila actuală +Afișare împărțită nouă cu fila actuală Ușurel. Fiți atent(ă). Setări de introducere a textului Câteva diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_sk.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_sk.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_sk.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_sk.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -7172,7 +7172,7 @@ Nová karta vpravo Kanál sa zmenil. Ak chcete zmeny použiť, reštartujte zariadenie. Vybraná tlačiareň nie je k dispozícii alebo nie je správne nainštalovaná. Skontrolujte tlačiareň alebo skúste vybrať inú. -Blokovať výzvy na prihlásenie zo služieb identity +Blokovať výzvy na prihlásenie od služieb identity Ak áno, upravte svoje uložené heslo v službe tak, aby sa zhodovalo s týmto novým heslom. Známe siete Automaticky blokované: , diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_sl.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_sl.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_sl.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_sl.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -836,7 +836,7 @@ Dejavnost v ozadju in nekateri vizualni učinki (denimo gladko drsenje) bodo morda omejeni. Imenika razširitve ni bilo mogoče premakniti v profil. Ustvari profil -Daljši pritisk tipk +Počasne tipke Sledilna ploščica Nadaljuj predvajanje v napravi To omogoča dostop do lokacije za aplikacije, spletna mesta z dovoljenjem za lokacijo in sistemske storitve diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_sq.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_sq.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_sq.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_sq.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -10674,7 +10674,7 @@ Uebsajtet në gjuhët e tua Dallgë që përplasen në det, me një qytet dhe kështjellë imagjinare në sfond, me atmosferë të errët. Printerë të tjerë të disponueshëm -Kapërce +Anashkalo të gjitha faqet Titrat Llogaria jote diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_sr-Latn.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_sr-Latn.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_sr-Latn.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_sr-Latn.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -5162,7 +5162,7 @@ Preuzimaju se datoteke za prepoznavanje govora... % Grupišite kartice pomoću veštačke inteligencije Možete da koristite željeni jezik Google naloga () -Pomozite nam da poboljšamo Chrome-ove funkcije i učinak +Pomozite nam da poboljšamo Chrome-ove funkcije i performanse Generisana je . slika od , u stilu Započnimo Kliknite desnim tasterom na karticu i izaberite Dodaj karticu u novu grupu @@ -8350,7 +8350,7 @@ {NUM_PAGES,plural, =0{}=1{ i još 1 kartica}one{ i još # kartica}few{ i još # kartice}other{ i još # kartica}} Poveži se pomoću Podešavanja Google usluga -Prethodno +Nazad Proverite da li ima pravopisnih grešaka kada unosite tekst na veb-stranicama Pre Već ste sačuvali lozinku sa ovim korisničkim imenom za diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_sr.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_sr.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_sr.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_sr.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -5162,7 +5162,7 @@ Преузимају се датотеке за препознавање говора... % Групишите картице помоћу вештачке интелигенције Можете да користите жељени језик Google налога () -Помозите нам да побољшамо Chrome-ове функције и учинак +Помозите нам да побољшамо Chrome-ове функције и перформансе Генерисана је . слика од , у стилу Започнимо Кликните десним тастером на картицу и изаберите Додај картицу у нову групу @@ -8350,7 +8350,7 @@ {NUM_PAGES,plural, =0{}=1{ и још 1 картица}one{ и још # картица}few{ и још # картице}other{ и још # картица}} Повежи се помоћу Подешавања Google услуга -Претходно +Назад Проверите да ли има правописних грешака када уносите текст на веб-страницама Пре Већ сте сачували лозинку са овим корисничким именом за diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_sw.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_sw.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_sw.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_sw.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -2502,7 +2502,7 @@ Ongeza neno jipya Muda wake umekwisha Lo! Kulikuwa na hitilafu wakati wa uumbizaji. -Ya Juu +Juu Kiwango cha betri ya upande wa kushoto %. Programu zingine zimeruhusiwa kufungua viungo vinavyofunguliwa na . Hatua hii itazuia na zisifungue viungo vinavyoweza kutumika. Dhibiti kikagua maendelezo diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_te.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_te.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_te.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_te.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -11621,7 +11621,7 @@ మూలాధారాన్ని మార్చు దయచేసి దేశాన్ని ఎంచుకోండి సూచించబడిన గ్రూప్ నుండి ట్యాబ్‌ను మినహాయించండి - అన్ఇన్‌స్టాల్ చేయబడింది + అన్ఇన్‌స్టాల్ అయింది సైట్ మీ లొకేషన్‌ను ట్రాక్ చేస్తోంది మీ బుక్‌మార్క్‌లు, హిస్టరీ, పాస్‌వర్డ్‌లు, ఇతర సెట్టింగ్‌ల‌లో మార్పులు మీ Google ఖాతాకు ఇకపై సింక్ చేయ‌బడవు. అయినప్పటికీ, ఇప్పటికే ఉన్న మీ డేటా Google ఖాతాలో స్టోరేజ్‌ చేయబడుతుంది. Google డాష్‌బోర్డ్లో నిర్వహించబడుతుంది. పరికర లిస్ట్‌ను దాచండి diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_tr.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_tr.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_tr.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_tr.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -8766,7 +8766,7 @@ Yazıcılar Linux kapsayıcısı başlatılıyor Sekme, sekme şeridinin başına taşındı -Google Hesabınızı Yönetin +Google Hesabınızı yönetin Burada kal Bir hedef seç Gelişmiş yazım denetimini etkinleştirin diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_uk.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_uk.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_uk.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_uk.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -8156,7 +8156,7 @@ Переглянути сертифікати, імпортовані з Windows Пристрій не може підтримувати зв’язок із телефоном. Переконайтеся, що ваш телефон поблизу й розблокований, а Bluetooth і Wi-Fi увімкнено. Сайти можуть використовувати цю функцію, щоб шукати пристрої в локальній мережі й підключатися до них -Пошук вкладок +Пошук на вкладках Помірне заощадження Використовувати інший пристрій Потрібен дозвіл, щоб завантажити diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_vi.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_vi.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_vi.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_vi.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -1209,7 +1209,7 @@ Chuyển sang chế độ ngủ khi đóng nắp màn hình Trang không phản hồi. Bạn có thể chờ hoặc thoát khỏi trang này. Ngôn ngữ cần dịch sang -Đào tạo lại +Huấn luyện lại Nhấp để kích hoạt Thẻ nền đang sử dụng micrô Kiểm tra giao diện @@ -9523,7 +9523,7 @@ Có thể cuộn và thu phóng các thẻ được chia sẻ Hiệu ứng đánh dấu dòng Loại Chứng chỉ Netscape -Giúp tôi thay đổi +Giúp tôi đổi mật khẩu Khóa bảo mật sẽ lưu giữ bản ghi lượt truy cập của bạn vào trang web này. Âm thanh của thẻ này đang tắt Mở thư mục tệp đã tải xuống diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_zh-CN.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_zh-CN.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_zh-CN.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_zh-CN.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -226,7 +226,7 @@ 打印机已停止运行 {SELECTED_ITEMS,plural, =0{扩展程序}=1{扩展程序 ({SELECTED_ITEMS})}other{扩展程序 ({SELECTED_ITEMS})}} 头部指针 -在 Chrome 中畅享 Google 的智能技术 +在 Chrome 中畅享 Google 智能功能 现在轮到使用了 要申请访问权限,请与此设备的管理员联系。 允许运行用户脚本 @@ -1600,7 +1600,7 @@ 退出前先发提醒信息 () 如果您删除了自己的某个证书,则不能再用该证书标识自己的身份。 在新的标签页中打开链接 -撤消 +撤销 使用您的精确位置信息,而非基于 IP 地址的估计位置信息,以便获得最准确的 Gemini 结果。 更多设置 使用电池时让电源闲置 @@ -2496,7 +2496,7 @@ 如果 Chrome 发现您的密码在公开数据泄露事件中外泄,Google 密码管理工具可能会在您登录时建议更改密码。详细了解自动更改密码 经过简化的动画 不允许网站查看您剪贴板中的文字或图片 -分享组 +共享分组 您的书签和设置已就绪 crx 文件已损坏,未能成功解压。 您的标签页标题和网址会发送给 Google,并且可能由人工审核员查看,以改进此功能。 @@ -9078,7 +9078,7 @@ 填充密码时使用 Windows Hello 缺少网络类型 这款 AI 助理可为您提供要点总结、阐明概念、查找答案等 -管理分享设置 +管理共享设置 下列应用也能处理协议链接。其他应用会请求授权。 若要设置指纹,请让您的孩子轻触键盘右上角的指纹传感器。您孩子的指纹数据会安全地存储在此 上,绝不会外泄。 屏幕锁定和登录 @@ -9128,7 +9128,7 @@ 自助服务终端和数字标牌设备注册已完成 如果您降低阈值,就可以做出轻微的动作。如果您提高阈值,可能需要做出更夸张的动作。 按下“c”键表示松开鼠标按键 -分享分组 +共享分组 系统默认文字转语音声音 此登录服务由 托管 您的资料由 管理,管理方可以查看某些信息,包括: diff -Nru chromium-145.0.7632.116/chrome/app/resources/generated_resources_zh-TW.xtb chromium-145.0.7632.159/chrome/app/resources/generated_resources_zh-TW.xtb --- chromium-145.0.7632.116/chrome/app/resources/generated_resources_zh-TW.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/generated_resources_zh-TW.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -226,7 +226,7 @@ 印表機已停止運作 {SELECTED_ITEMS,plural, =0{擴充功能}=1{擴充功能 ({SELECTED_ITEMS})}other{擴充功能 ({SELECTED_ITEMS})}} 頭部指標 -在 Chrome 中體驗 Google 智慧功能 +在 Chrome 體驗 Google 智慧功能 現在可交由「」使用 如需要求存取權限,請與這個裝置的系統管理員聯絡。 允許使用者指令碼 diff -Nru chromium-145.0.7632.116/chrome/app/resources/google_chrome_strings_ca.xtb chromium-145.0.7632.159/chrome/app/resources/google_chrome_strings_ca.xtb --- chromium-145.0.7632.116/chrome/app/resources/google_chrome_strings_ca.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/google_chrome_strings_ca.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -395,7 +395,7 @@ Google Lens no està disponible. Torna-ho a provar més tard. Chrome OS no ha pogut sincronitzar les teves dades perquè la sincronització no està disponible per al teu domini. Chrome necessita permís d'accés a l'emmagatzematge per poder baixar fitxers -Opcional: ajuda a millorar les funcions i el rendiment de Chrome OS enviant automàticament dades de diagnòstic i d'ús a Google. +Opcional: ajuda a millorar les funcions i el rendiment de ChromeOS enviant automàticament dades de diagnòstic i d'ús a Google. Aprofundeix en la cerca afegint diverses pestanyes, fitxers i eines Exporteu contrasenyes de Chrome Codi addicional: . diff -Nru chromium-145.0.7632.116/chrome/app/resources/google_chrome_strings_da.xtb chromium-145.0.7632.159/chrome/app/resources/google_chrome_strings_da.xtb --- chromium-145.0.7632.116/chrome/app/resources/google_chrome_strings_da.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/google_chrome_strings_da.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -491,7 +491,7 @@ Indgående regel for Google Chrome om at tillade mDNS-trafik. Chrome lukkes snart -Google Adgangs­kode­admin­istrator +Google Adgangs­ko­de­administrator Advarer dig om skadelige websites – også websites, som Google ikke tidligere har kendt til – ved at analysere flere data fra websites end Standardbeskyttelse. Du kan vælge at springe Chrome-advarsler over. Din forælder har deaktiveret "Tilladelser for websites, apps og udvidelser" for Chrome Tilpas og styr Chrome. Angiv Chrome som din standardbrowser. diff -Nru chromium-145.0.7632.116/chrome/app/resources/google_chrome_strings_el.xtb chromium-145.0.7632.159/chrome/app/resources/google_chrome_strings_el.xtb --- chromium-145.0.7632.116/chrome/app/resources/google_chrome_strings_el.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/google_chrome_strings_el.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -307,7 +307,7 @@ Το Chrome χρειάζεται άδειες κάμερας και μικροφώνου για αυτόν τον ιστότοπο. Αποσύνδεση από το Chrome; Να συνδεθούν τα δεδομένα σας στο Chrome με αυτόν το λογαριασμό; -Όροι Παροχής Υπηρεσιών +Όροι παροχής υπηρεσιών Συνδεθείτε, για να συγχρονίσετε και να εξατομικεύσετε το Chrome στις συσκευές σας Να επιτρέπεται στην επέκταση να εμφανίζει αιτήματα πρόσβασης στη γραμμή εργαλείων του Chrome {NUM_TABS,plural, =1{Το Chrome συνιστά να θέσετε σε παύση την καρτέλα που επιβραδύνει το πρόγραμμα περιήγησης}other{Το Chrome συνιστά να θέσετε σε παύση τις καρτέλες που επιβραδύνουν το πρόγραμμα περιήγησης}} diff -Nru chromium-145.0.7632.116/chrome/app/resources/google_chrome_strings_es-419.xtb chromium-145.0.7632.159/chrome/app/resources/google_chrome_strings_es-419.xtb --- chromium-145.0.7632.116/chrome/app/resources/google_chrome_strings_es-419.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/google_chrome_strings_es-419.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -67,7 +67,7 @@ Abrir vínculo en una ventana de navegación de incó&gnito de Chrome Google Chrome no puede leer ni agregar datos al directorio de datos: Cuando escribes en la barra de direcciones o en el cuadro de búsqueda, Chrome envía lo que escribes a las herramientas de búsqueda, IA y agentes de tu organización para obtener sugerencias. -Google Chrome es un navegador web que ejecuta aplicaciones y páginas web a gran velocidad. Es rápido, estable y fácil de utilizar. Navega por la Web de forma más segura con protección contra suplantación de identidad y software malicioso integrada a Google Chrome. +Google Chrome es un navegador web que ejecuta aplicaciones y páginas web a gran velocidad. Es rápido, estable y fácil de utilizar. Navega por la Web de forma más segura con protección contra phishing y software malicioso integrada a Google Chrome. {0,plural, =1{Se reiniciará Chrome en una hora}other{Se reiniciará Chrome en # horas}} Esto te permitirá seleccionar dispositivos disponibles y mostrar contenido en ellos. Asegúrate de haber accedido a Chrome en tu y, luego, intenta enviarlo de nuevo. @@ -600,7 +600,7 @@ Es posible que Google Chrome no funcione correctamente porque ya no es compatible con esta distribución de Linux Salir de Chrome {COUNT,plural, =1{La organización cierra Chrome automáticamente si no lo usas durante 1 minuto.}other{La organización cierra Chrome automáticamente si no lo usas durante # minutos.}} -Se copió el texto. +Se copió el texto {COUNT,plural, =1{Tu organización borra automáticamente los datos de navegación si no usas Chrome durante 1 minuto. Esto puede incluir el historial, los datos de Autocompletar y las descargas. Las pestañas permanecerán abiertas.}other{Tu organización borra automáticamente los datos de navegación si no usas Chrome durante # minutos. Esto puede incluir el historial, los datos de Autocompletar y las descargas. Las pestañas permanecerán abiertas.}} Chrome te advertirá antes de que cargues un sitio con una conexión no segura Obtén la seguridad más sólida de Chrome diff -Nru chromium-145.0.7632.116/chrome/app/resources/google_chrome_strings_es.xtb chromium-145.0.7632.159/chrome/app/resources/google_chrome_strings_es.xtb --- chromium-145.0.7632.116/chrome/app/resources/google_chrome_strings_es.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/google_chrome_strings_es.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -48,7 +48,7 @@ ¿Iniciar sesión en Chrome? &Gestionar perfiles de Chrome Reinicia para finalizar la actualización de Chrome -Hola, ,¿en qué estás pensando hoy? +Hola, ,¿qué tienes en mente hoy? Error de instalación: Personaliza tu nuevo perfil de Chrome. Esta página está protegida @@ -382,7 +382,7 @@ Personalizar tu perfil de Chrome Te damos la bienvenida a Chrome. Se ha abierto una nueva ventana del navegador. Chrome necesita permiso para hacer seguimiento de tus manos -¿En qué estás pensando hoy? +¿Qué tienes en mente hoy? Usa tus contraseñas con Chrome en tu teléfono No se puede usar tu perfil porque se corresponde con una versión más reciente de Google Chrome. diff -Nru chromium-145.0.7632.116/chrome/app/resources/google_chrome_strings_fr.xtb chromium-145.0.7632.159/chrome/app/resources/google_chrome_strings_fr.xtb --- chromium-145.0.7632.116/chrome/app/resources/google_chrome_strings_fr.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/google_chrome_strings_fr.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -378,7 +378,7 @@ Chrome précharge davantage de pages susceptibles de vous intéresser afin qu'elles se chargent plus rapidement lorsque vous les consultez Gardez Chrome dans votre Dock pour y accéder rapidement à tout moment Découvrez des applications, des jeux, des extensions et des thèmes exceptionnels pour Google Chrome. -Personnalisez votre profil Chrome +Personnaliser votre profil Chrome Bienvenue dans Chrome, une nouvelle fenêtre du navigateur a été ouverte Chrome a besoin de l'autorisation de suivre vos mains À quoi pensez-vous aujourd'hui ? diff -Nru chromium-145.0.7632.116/chrome/app/resources/google_chrome_strings_hr.xtb chromium-145.0.7632.159/chrome/app/resources/google_chrome_strings_hr.xtb --- chromium-145.0.7632.116/chrome/app/resources/google_chrome_strings_hr.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/google_chrome_strings_hr.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -206,7 +206,7 @@ Chrome je blokirao ovo preuzimanje jer ta arhivska datoteka uključuje druge datoteke koje mogu skrivati zlonamjerni softver Prilagodite Chrome da biste svom pregledniku dali novi izgled Novo pretraživanje -Dodavanje profila u Chromeu +Dodajte profil u Chromeu Povucite za pretraživanje Vaše izmjene stupit će na snagu sljedeći put kada se ponovo pokrene Google Chrome. Aplikacije sustava Chrome @@ -215,7 +215,7 @@ Chrome je blokirao ovo preuzimanje jer je datoteka opasna Pretražite bilo što na ovoj stranici pomoću Google objektiva Ako oznake spremate i na Google račun, cijene proizvoda možete pratiti u Chromeu i primati obavijesti kad cijena padne -Dodavanje profila u Chromeu +Dodajte profil u Chromeu Ako dijelite i izvješća o upotrebi Chromea, ta izvješća uključuju URL-ove koje posjećujete Ponovo pokreni sad Tada ćete morati ponovo pokrenuti Chrome. diff -Nru chromium-145.0.7632.116/chrome/app/resources/google_chrome_strings_vi.xtb chromium-145.0.7632.159/chrome/app/resources/google_chrome_strings_vi.xtb --- chromium-145.0.7632.116/chrome/app/resources/google_chrome_strings_vi.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/google_chrome_strings_vi.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -557,7 +557,7 @@ góc dưới cùng bên phải của khu vực tìm kiếm: % từ bên phải sang, % từ dưới cùng lên Đang cập nhật Chrome Ứng dụng Chrome Beta -Loại bỏ tài khoản khỏi Chrome +Xoá tài khoản khỏi Chrome Sao chép Dịch vụ này giúp cập nhật phần mềm Google của bạn. Nếu dịch vụ này bị vô hiệu hoá hoặc bị dừng, phần mềm Google của bạn sẽ không được cập nhật. Điều này nghĩa là lỗ hổng bảo mật phát sinh sẽ không thể khắc phục được và các tính năng có thể không hoạt động. Dịch vụ này sẽ tự gỡ cài đặt khi không được phần mềm Google nào dùng. Hệ thống ChromeOS diff -Nru chromium-145.0.7632.116/chrome/app/resources/google_chrome_strings_zh-CN.xtb chromium-145.0.7632.159/chrome/app/resources/google_chrome_strings_zh-CN.xtb --- chromium-145.0.7632.116/chrome/app/resources/google_chrome_strings_zh-CN.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/app/resources/google_chrome_strings_zh-CN.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -48,7 +48,7 @@ 重新启动即可完成 Chrome 更新 ,您好!今天想聊点什么? 安装时出错: -自定义您的新 Chrome 个人资料 +自定义新的 Chrome 个人资料 此页面受保护 Chrome 操作系统是借助了其他开源软件才得以问世。 结束突出显示的任务。 @@ -237,7 +237,7 @@ 尚未保存任何密码。您需要先保存密码才能使用 Chrome 的密码检查功能。 Chrome 无法检查您的密码。请过 24 小时再试。 您的系统管理员已将 Google Chrome 配置为使用备用浏览器访问 -在您的所有设备上同步并个性化设置 Chrome +在所有设备上同步并设置个性化的 Chrome 您已在另一份 Chrome 个人资料中使用 登录 使用 Google 智能镜头搜索此页面 向 Google 智能镜头询问此页面 @@ -302,7 +302,7 @@ 已取消安装。 登录 Chrome 后可获享更多功能 Chrome 需要为此网站授予摄像头权限和麦克风权限 -退出 Chrome? +要在 Chrome 中退出账号吗? 是否将您的 Chrome 数据与此账号相关联? 服务条款 登录即可在您的所有设备上同步并个性化设置 Chrome @@ -374,7 +374,7 @@ Chrome 会预加载您可能会访问的更多网页,以便提高这些网页在您访问时的加载速度 将 Chrome 保留在程序坞中,即可随时快速访问 查找适用于Google Chrome的精彩应用、游戏、扩展程序和主题背景。 -自定义您的 Chrome 个人资料 +自定义 Chrome 个人资料 欢迎使用 Chrome;已打开新的浏览器窗口 Chrome 需要获得权限,才能跟踪您的手部动作 今天想聊点什么? @@ -597,7 +597,7 @@ 选择要使用 Google 智能镜头搜索的内容 {NUM_DEVICES,plural, =0{一个或多个 Chrome 扩展程序访问过 1 部 USB 设备}=1{一个或多个 Chrome 扩展程序正在访问 1 部 USB 设备}other{一个或多个 Chrome 扩展程序正在访问 # 部 USB 设备}} Google Chrome 可能无法正常运行,因为它不再支持此 Linux 发行版 -退出 Chrome +在 Chrome 中退出账号 {COUNT,plural, =1{您的组织会在 Chrome 闲置 1 分钟后自动关闭它。}other{您的组织会在 Chrome 闲置 # 分钟后自动关闭它。}} 已复制文字 {COUNT,plural, =1{您的组织会在 Chrome 闲置 1 分钟后自动删除浏览数据。这些数据可能包括历史记录、自动填充数据和下载内容。您的标签页将会保持打开状态。}other{您的组织会在 Chrome 闲置 # 分钟后自动删除浏览数据。这些数据可能包括历史记录、自动填充数据和下载内容。您的标签页将会保持打开状态。}} @@ -731,7 +731,7 @@ 它还能够控制Chrome启动后显示的页面。 知道了 离最新版本只有一步之遥了!重新启动 Chrome 即可完成更新。 -退出 Chrome +在 Chrome 中退出账号 向 Google 询问此视频 Google Chrome 无法确定或设置默认浏览器 搜索区域的左下角:左侧 %,底部 % diff -Nru chromium-145.0.7632.116/chrome/browser/glic/glic_profile_manager.cc chromium-145.0.7632.159/chrome/browser/glic/glic_profile_manager.cc --- chromium-145.0.7632.116/chrome/browser/glic/glic_profile_manager.cc 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/browser/glic/glic_profile_manager.cc 2026-03-02 23:00:09.000000000 +0000 @@ -28,9 +28,11 @@ #include "chrome/common/chrome_features.h" #include "chrome/common/chrome_switches.h" #include "content/public/browser/network_service_instance.h" +#include "url/gurl.h" #if !BUILDFLAG(IS_ANDROID) #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_tabstrip.h" #include "chrome/browser/ui/profiles/profile_picker.h" #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h" #endif @@ -310,6 +312,18 @@ #else NOTIMPLEMENTED() << "OpenFreDialogInNewTab"; #endif + } else if (GlicEnabling::IsTrustFirstOnboardingEnabledForProfile(profile)) { +#if !BUILDFLAG(IS_ANDROID) + // Open a browser and show the FRE in a new tab. + chrome::ScopedTabbedBrowserDisplayer displayer(profile); + Browser* browser = displayer.browser(); + chrome::AddAndReturnTabAt(browser, GURL(), /*index=*/-1, + /*foreground=*/true); + service->ToggleUI(browser, /*prevent_close=*/true, + mojom::InvocationSource::kProfilePicker); +#else + NOTIMPLEMENTED() << "ToggleUIOnNewTab"; +#endif } else { // Toggle glic but prevent close if it is already open for the selected // profile. diff -Nru chromium-145.0.7632.116/chrome/browser/glic/glic_profile_manager.h chromium-145.0.7632.159/chrome/browser/glic/glic_profile_manager.h --- chromium-145.0.7632.116/chrome/browser/glic/glic_profile_manager.h 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/browser/glic/glic_profile_manager.h 2026-03-02 23:00:09.000000000 +0000 @@ -110,6 +110,8 @@ private: FRIEND_TEST_ALL_PREFIXES(GlicProfileManagerDidSelectProfileTest, DidSelectProfile_NoConsent); + FRIEND_TEST_ALL_PREFIXES(GlicProfileManagerDidSelectProfileTest, + DidSelectProfile_Consented); // Callback from ProfilePicker::Show(). void DidSelectProfile(Profile* profile); diff -Nru chromium-145.0.7632.116/chrome/browser/glic/glic_profile_manager_browsertest.cc chromium-145.0.7632.159/chrome/browser/glic/glic_profile_manager_browsertest.cc --- chromium-145.0.7632.116/chrome/browser/glic/glic_profile_manager_browsertest.cc 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/browser/glic/glic_profile_manager_browsertest.cc 2026-03-02 23:00:09.000000000 +0000 @@ -604,7 +604,7 @@ auto* service = GetMockGlicKeyedService(profile); if (IsTrustFREOnboardingEnabled()) { - EXPECT_CALL(*service, ToggleUI(testing::IsNull(), true, + EXPECT_CALL(*service, ToggleUI(testing::NotNull(), true, mojom::InvocationSource::kProfilePicker, testing::Eq(std::nullopt), testing::_)); } else { @@ -615,6 +615,29 @@ GlicProfileManager::GetInstance()->DidSelectProfile(profile); } + +IN_PROC_BROWSER_TEST_P(GlicProfileManagerDidSelectProfileTest, + DidSelectProfile_Consented) { + // Create a profile that is eligible and has consented. + Profile* profile = +#if BUILDFLAG(IS_CHROMEOS) + CreateNewUserSessionAndProfile(kAccountId1, /*allow_glic=*/true); +#else + CreateNewProfile(/*signin_and_allow_glic=*/true); +#endif // BUILDFLAG(IS_CHROMEOS) + profile->GetPrefs()->SetInteger( + glic::prefs::kGlicCompletedFre, + static_cast(glic::prefs::FreStatus::kCompleted)); + ASSERT_TRUE(GlicEnabling::IsEnabledAndConsentForProfile(profile)); + + auto* service = GetMockGlicKeyedService(profile); + + EXPECT_CALL(*service, ToggleUI(testing::IsNull(), true, + mojom::InvocationSource::kProfilePicker, + testing::Eq(std::nullopt), testing::_)); + + GlicProfileManager::GetInstance()->DidSelectProfile(profile); +} INSTANTIATE_TEST_SUITE_P(All, GlicProfileManagerDidSelectProfileTest, diff -Nru chromium-145.0.7632.116/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_de.xtb chromium-145.0.7632.159/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_de.xtb --- chromium-145.0.7632.116/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_de.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_de.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -629,7 +629,7 @@ Textfeld ist leer Mind. Keine vorherige Schaltfläche -Vorherige Schaltfläche +Vorheriger Button nicht erkannte Eingabe Fangen wir mit ein paar Tasten an, die du regelmäßig verwenden wirst. Mit der Steuerung-Taste kannst du die Sprachausgabe anhalten. Du findest die Steuerung-Taste unten links auf deiner Tastatur. Drücke zum Fortfahren die Steuerung-Taste. Zum Seitenanfang @@ -661,7 +661,7 @@ Alle Lektionen Nach unten blicken Titelseite -Nutze „Bei Berühren vorlesen“, um die Schaltfläche „Nächste Lektion“ zu finden. Anschließend kannst du durch Doppeltippen fortfahren. +Nutze „Bei Berühren vorlesen“, um den Button „Nächste Lektion“ zu finden. Anschließend kannst du durch Doppeltippen fortfahren. Braille-Untertitel aktiviert Braille – vorherige Zeile Zeile @@ -713,7 +713,7 @@ Gainsboro Diktierfunktion ein-/ausschalten Akustisches Feedback (Earcons) aktivieren oder deaktivieren -Schaltfläche +Button Nächste Liste hdnggrp ChromeVox-Lernmodus @@ -751,7 +751,7 @@ Hierbei handelt es sich um die zweite Überschrift. Zum Springen drückst du entweder auf „Suche + H“ oder auf „Suche + Umschalttaste + H“. Vorherige Überschrift der Ebene 5 Anhang -Perfekt! Du kennst jetzt die Grundlagen von ChromeVox. Du kannst diese Anleitung noch einmal starten oder sie beenden, indem du unten auf die entsprechende Schaltfläche tippst. +Perfekt! Du kennst jetzt die Grundlagen von ChromeVox. Du kannst diese Anleitung noch einmal starten oder sie beenden, indem du unten auf den entsprechenden Button tippst. Erweiterung für die Sprachausgabe bei Google Enhanced Network Mit der Gesichtssteuerung kannst du den Cursor mithilfe von Gesichtsbewegungen steuern und Aktionen ausführen, z. B. die linke Maustaste mit einem Lächeln betätigen Mit zwei Fingern tippen @@ -848,7 +848,7 @@ Google Assistant Benachrichtigungsdialogfeld Inhaltsverzeichnis -Nächste Schaltfläche +Nächster Button Index Helligkeit verringern Türkis @@ -883,7 +883,7 @@ Ressourcen Violett Article-Element -Sobald du ein wenig Übung hast, suche die Schaltfläche „Nächste Lektion“ und wähle sie aus. Anschließend kannst du durch Doppeltippen fortfahren. +Sobald du ein wenig Übung hast, suche den Button „Nächste Lektion“ und wähle ihn aus. Anschließend kannst du durch Doppeltippen fortfahren. lstbx Chiffongelb Blasse Goldrutenfarbe @@ -943,7 +943,7 @@ Verbinden... Lavendel Zusammenfassung -Pop-up-Schaltfläche +Pop-up-Button Zeichenecho Mitternachtsblau () @@ -1013,7 +1013,7 @@ Pausiert alle momentan aktiven Medien-Widgets Nächste Tabelle (), Grad  -Drücke „Suchtaste plus Rechtspfeil“, um den Übungsbereich oder die Schaltfläche „Nächste Lektion“ zu markieren. Drücke dann „Suchtaste plus Leertaste“, um die Schaltfläche auszuwählen. +Drücke „Suchtaste plus Rechtspfeil“, um den Übungsbereich oder den Button „Nächste Lektion“ zu markieren. Drücke dann „Suchtaste plus Leertaste“, um den Button auszuwählen. Dunkelgrau Überschrift 2 .input {$$COUNT :number} .match $$COUNT 1{{Dollarzeichen}} *{{{$$COUNT} Dollarzeichen}} @@ -1150,7 +1150,7 @@ ChromeVox-Steuerfeld Steuerung für Datum Tomatencreme -Perfekt! Jetzt kennst du die Grundlagen von ChromeVox. Du kannst diese Anleitung noch einmal starten oder sie beenden, indem du auf die entsprechende Schaltfläche unten klickst. +Perfekt! Jetzt kennst du die Grundlagen von ChromeVox. Du kannst diese Anleitung noch einmal starten oder sie beenden, indem du auf den entsprechenden Button unten klickst. Keine nächste Überschrift der Ebene 6 Tomatenrot Koordinaten der aktuellen Zelle ansagen diff -Nru chromium-145.0.7632.116/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_zh-CN.xtb chromium-145.0.7632.159/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_zh-CN.xtb --- chromium-145.0.7632.116/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_zh-CN.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/browser/resources/chromeos/accessibility/strings/accessibility_strings_zh-CN.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -381,7 +381,7 @@ .input {$$COUNT :number} .match $$COUNT 1{{with {$$COUNT} item}} * {{with {$$COUNT} items}} 纵向 滑块 -撤消 +撤销 转到表格末尾 下一个访问过的链接 ChromeVox 辅助键 diff -Nru chromium-145.0.7632.116/chrome/browser/ui/android/strings/translations/android_chrome_strings_ca.xtb chromium-145.0.7632.159/chrome/browser/ui/android/strings/translations/android_chrome_strings_ca.xtb --- chromium-145.0.7632.116/chrome/browser/ui/android/strings/translations/android_chrome_strings_ca.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/browser/ui/android/strings/translations/android_chrome_strings_ca.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -1608,7 +1608,7 @@ El dispositiu no ha pogut obrir Chrome. Per resoldre el problema, baixa l'actualització més recent de Chrome de la botiga d'aplicacions. Explora contingut i segueix-lo Obre ràpidament al navegador. Mantén premuda aquesta drecera per editar-la. -Ansa per arrossegar +Ansa de posicionament Crea una adreça electrònica a Full inferior de l'activitat recent obert a alçada completa Utilitza dades mòbils diff -Nru chromium-145.0.7632.116/chrome/browser/ui/android/strings/translations/android_chrome_strings_da.xtb chromium-145.0.7632.159/chrome/browser/ui/android/strings/translations/android_chrome_strings_da.xtb --- chromium-145.0.7632.116/chrome/browser/ui/android/strings/translations/android_chrome_strings_da.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/browser/ui/android/strings/translations/android_chrome_strings_da.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -1218,7 +1218,7 @@ Nogle websites kan f.eks. reagere på denne anmodning ved at vise dig annoncer, som ikke er baseret på andre websites, du har besøgt. Mange websites vil fortsat indsamle og bruge browserdata til f.eks. at forbedre sikkerheden, til at levere indhold, annoncer og anbefalinger og til at generere rapporteringsstatistik. Læsetilstand -Google Adgangs­kode­admin­istrator +Google Adgangs­ko­de­administrator Søg i indstillinger , fastgjort inkognitofane med multivalg Se din Chrome-historik her diff -Nru chromium-145.0.7632.116/chrome/browser/ui/android/strings/translations/android_chrome_strings_de.xtb chromium-145.0.7632.159/chrome/browser/ui/android/strings/translations/android_chrome_strings_de.xtb --- chromium-145.0.7632.116/chrome/browser/ui/android/strings/translations/android_chrome_strings_de.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/browser/ui/android/strings/translations/android_chrome_strings_de.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -6,7 +6,7 @@ Hierhin verschieben Einstellungen für den Lesemodus sind vollständig geöffnet Für gibt es auf diesem Gerät keine Passkeys -Schnelle Sprachsuche verwenden. Zum Ändern Schaltfläche gedrückt halten. +Schnelle Sprachsuche verwenden. Zum Ändern Button gedrückt halten. Wird an gesendet… Auch Daten dieser Websites & Apps löschen? Fenster ist geöffnet @@ -284,7 +284,7 @@ Wähle einen Zeitraum aus und tippe dann auf „Daten löschen“ Datenschutz-Leitfaden Gruppe in ein anderes Fenster verschieben -Über die Schaltfläche "Optionen für Discover" kannst du festlegen, welche Meldungen dir angezeigt werden +Über den Button „Optionen für Discover“ kannst du festlegen, welche Meldungen dir angezeigt werden Karte abgelaufen Du kannst die Informationen anpassen, die von Websites verwendet werden, um dir Werbung zu präsentieren Neues Inkognitofenster @@ -1033,7 +1033,7 @@ Website funktioniert nicht? Drittanbieter-Cookies werden blockiert. In diese Sprache übersetzen Zurück zur Website -Auf die Schaltfläche "Tabs öffnen" tippen, um Tabs zu öffnen und mehrere Seiten gleichzeitig zu besuchen +Auf den Button „Tabs öffnen“ tippen, um Tabs zu öffnen und mehrere Seiten gleichzeitig zu besuchen Seite herunterladen Hier erscheinen Websites, denen du folgst Du kannst dich mit einem Textcursor auf den Seiten bewegen. Wenn du die Tastaturnavigation deaktivieren möchtest, drücke F7. @@ -1353,7 +1353,7 @@ Mono Kontodaten prüfen Wenn du auf allen deinen Geräten auf deine Passwörter und andere Daten zugreifen möchtest, melde dich als an. -Öffnet schnell einen neuen Tab. Zum Ändern Schaltfläche gedrückt halten. +Öffnet schnell einen neuen Tab. Zum Ändern Button gedrückt halten. Wenn du ein neues Fenster wiederherstellen möchtest, reduziere die Gesamtzahl der aktiven und inaktiven Fenster auf maximal . Inaktive Fenster werden nach 6 Monaten gelöscht. Neue Suche starten Feedback geben @@ -1374,7 +1374,7 @@ Seitenansicht bereit {FILE_COUNT,plural, =1{Bilder, 1 Bild in der Liste}other{Bilder, # Bilder in der Liste}} In Chrome anmelden, geöffnet. -Diese Seite schnell teilen. Zum Ändern Schaltfläche gedrückt halten. +Diese Seite schnell teilen. Zum Ändern Button gedrückt halten. CVC Update des Google Passwortmanagers geschlossen Ansicht mit den letzten Aktivitäten am unteren Rand geschlossen diff -Nru chromium-145.0.7632.116/chrome/browser/ui/android/strings/translations/android_chrome_strings_my.xtb chromium-145.0.7632.159/chrome/browser/ui/android/strings/translations/android_chrome_strings_my.xtb --- chromium-145.0.7632.116/chrome/browser/ui/android/strings/translations/android_chrome_strings_my.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/browser/ui/android/strings/translations/android_chrome_strings_my.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -1541,7 +1541,7 @@ သင်၏စီမံခန့်ခွဲသူက ပိတ်ထားသည် Chrome ထဲမှ ထွက်သွားရန် တဘ်ကို အုပ်စုသို့ ရွှေ့ရန် -စာညှပ် မန်နေဂျာ ဖွင့်ရန် +ဝဘ်လိပ်စာ စီမံစနစ် ဖွင့်ရန် ဘေးဘက်မြင်ကွင်းသို့ ချုံ့ရန် နေရာအလုံအလောက် မရှိပါ သင့်အဖွဲ့အစည်းက စကားဝှက်သိမ်းခြင်းကို ပိတ်ထားသည် diff -Nru chromium-145.0.7632.116/chrome/browser/ui/android/strings/translations/android_chrome_strings_no.xtb chromium-145.0.7632.159/chrome/browser/ui/android/strings/translations/android_chrome_strings_no.xtb --- chromium-145.0.7632.116/chrome/browser/ui/android/strings/translations/android_chrome_strings_no.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/browser/ui/android/strings/translations/android_chrome_strings_no.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -679,7 +679,7 @@ , festet fane Legg til et nettsted igjen hvis du vil ha det i gruppen med nettsteder som kan gjette hva du liker Vil du laste ned igjen? -Kopiér link +Kopier link Slå på mørkt tema når mørkt tema er påslått på enheten Hjem uten nett Tilpass og kontroller Google Chrome med et element som er uthevet diff -Nru chromium-145.0.7632.116/chrome/browser/ui/android/strings/translations/android_chrome_strings_sq.xtb chromium-145.0.7632.159/chrome/browser/ui/android/strings/translations/android_chrome_strings_sq.xtb --- chromium-145.0.7632.116/chrome/browser/ui/android/strings/translations/android_chrome_strings_sq.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/browser/ui/android/strings/translations/android_chrome_strings_sq.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -1759,7 +1759,7 @@ Raporto si përmbajtje të bezdisshme Fillo kërkimin Siguruar nga -Kapërce +Anashkalo Zbato temën e errët për sajtet Shko te cilësimet e sigurisë {NUM_WINDOWS,plural, =1{Mbyll 1 dritare të fshehtë}other{Mbyll # dritare të fshehta}} diff -Nru chromium-145.0.7632.116/chrome/browser/ui/android/strings/translations/android_chrome_strings_sr-Latn.xtb chromium-145.0.7632.159/chrome/browser/ui/android/strings/translations/android_chrome_strings_sr-Latn.xtb --- chromium-145.0.7632.116/chrome/browser/ui/android/strings/translations/android_chrome_strings_sr-Latn.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/browser/ui/android/strings/translations/android_chrome_strings_sr-Latn.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -1343,7 +1343,7 @@ Režim čitanja nije dostupan Izbori su sačuvani Provereno juče -Prethodno +Nazad Tajmer aplikacije je istekao. Počeće ponovo sutra. Da biste vratili novi prozor, smanjite ukupan broj aktivnih prozora na ili manje. Neaktivni prozori se brišu posle 6 meseci. Na Google nalogu diff -Nru chromium-145.0.7632.116/chrome/browser/ui/android/strings/translations/android_chrome_strings_sr.xtb chromium-145.0.7632.159/chrome/browser/ui/android/strings/translations/android_chrome_strings_sr.xtb --- chromium-145.0.7632.116/chrome/browser/ui/android/strings/translations/android_chrome_strings_sr.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/browser/ui/android/strings/translations/android_chrome_strings_sr.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -1343,7 +1343,7 @@ Режим читања није доступан Избори су сачувани Проверено јуче -Претходно +Назад Тајмер апликације је истекао. Почеће поново сутра. Да бисте вратили нови прозор, смањите укупан број активних прозора на или мање. Неактивни прозори се бришу после 6 месеци. На Google налогу diff -Nru chromium-145.0.7632.116/chrome/browser/ui/android/strings/translations/android_chrome_strings_sw.xtb chromium-145.0.7632.159/chrome/browser/ui/android/strings/translations/android_chrome_strings_sw.xtb --- chromium-145.0.7632.116/chrome/browser/ui/android/strings/translations/android_chrome_strings_sw.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/browser/ui/android/strings/translations/android_chrome_strings_sw.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -385,7 +385,7 @@ Upakiaji mapema wa kawaida Programu za wavuti Angalia tovuti -Ya Juu +Juu Mtu yeyote anayetumia kifaa hiki anaweza kuona faili zilizopakuliwa Ondoka Kimeacha kufanya kazi kwenye kifaa hiki diff -Nru chromium-145.0.7632.116/chrome/browser/ui/android/strings/translations/android_chrome_strings_zh-CN.xtb chromium-145.0.7632.159/chrome/browser/ui/android/strings/translations/android_chrome_strings_zh-CN.xtb --- chromium-145.0.7632.116/chrome/browser/ui/android/strings/translations/android_chrome_strings_zh-CN.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/browser/ui/android/strings/translations/android_chrome_strings_zh-CN.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -247,7 +247,7 @@ 您的组织已开启“增强型安全浏览”功能 {FILE_COUNT,plural, =1{1 项下载失败}other{# 项下载失败}} 文本 -撤消 +撤销 条结果,共 当前显示的是精简视图 过去 15 分钟 @@ -736,7 +736,7 @@ 工具栏中的快捷方式 密码和自动填充 打开“设置” -退出 Chrome? +要在 Chrome 中退出账号吗? 按新近度排序 根据系统向 Google 发送的浏览数据,实时提供 AI 赋能的保护,防范危险的网站、下载内容和扩展程序 开源许可 @@ -1538,7 +1538,7 @@ 一律使用安全连接 要退出标签页分组吗? 已被您的管理员关闭 -退出 Chrome +在 Chrome 中退出账号 将标签页移至分组 打开书签管理器 合拢为侧边视图 diff -Nru chromium-145.0.7632.116/chrome/browser/ui/ash/network/mobile_data_notifications.cc chromium-145.0.7632.159/chrome/browser/ui/ash/network/mobile_data_notifications.cc --- chromium-145.0.7632.116/chrome/browser/ui/ash/network/mobile_data_notifications.cc 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/browser/ui/ash/network/mobile_data_notifications.cc 2026-03-02 23:00:09.000000000 +0000 @@ -103,7 +103,7 @@ } void MobileDataNotifications::ShowOptionalMobileDataNotification() { - if (SessionManager::Get()->IsUserSessionBlocked()) { + if (SessionManager::Get()->IsUserSessionBlocked() || !NetworkHandler::IsInitialized()) { return; } diff -Nru chromium-145.0.7632.116/chrome/browser/ui/views/infobars/infobar_container_view.cc chromium-145.0.7632.159/chrome/browser/ui/views/infobars/infobar_container_view.cc --- chromium-145.0.7632.116/chrome/browser/ui/views/infobars/infobar_container_view.cc 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/browser/ui/views/infobars/infobar_container_view.cc 2026-03-02 23:00:09.000000000 +0000 @@ -160,5 +160,66 @@ RemoveChildView(static_cast(infobar)); } +void InfoBarContainerView::PlatformSpecificWillRemoveInfoBar( + infobars::InfoBar* infobar) { + // If there are no pending infobars to surface, there's no need to track + // focus for restoration, as no new infobar will immediately appear. + if (!HasPendingInfoBars()) { + restore_focus_on_next_shown_ = false; + return; + } + + auto* focus_manager = GetFocusManager(); + if (!focus_manager) { + restore_focus_on_next_shown_ = false; + return; + } + + // Determine the currently focused view. In environments where the window + // might not be fully active (e.g., Wayland during tests or under certain + // window manager states), `GetFocusedView()` returns null. In these cases, + // we must fall back to `GetStoredFocusView()` which tracks the view that + // *will* receive focus when the widget becomes active. + views::View* focused_view = focus_manager->GetFocusedView(); + if (!focused_view) { + focused_view = focus_manager->GetStoredFocusView(); + } + + // Only restore focus to the next infobar if the focus currently resides + // within the infobar being removed. This prevents stealing focus from + // unrelated UI elements when a background infobar is dismissed. + restore_focus_on_next_shown_ = + static_cast(infobar)->Contains(focused_view); +} + +void InfoBarContainerView::PlatformSpecificInfoBarShown( + infobars::InfoBar* infobar) { + auto* info_bar_view = static_cast(infobar); + CHECK(info_bar_view); + + if (!restore_focus_on_next_shown_) { + return; + } + + // Reset the flag to ensure focus is only restored once per removal event. + restore_focus_on_next_shown_ = false; + + // Prefer focusing the dismiss button if available, as it's the most common + // interactive element. If the infobar lacks a dismiss button, fall back to + // focusing the entire infobar view to maintain accessibility context. + views::View* view_to_focus = + info_bar_view->GetViewByElementId(InfoBarView::kDismissButtonElementId); + if (!view_to_focus) { + view_to_focus = info_bar_view; + } + + views::Widget* widget = GetWidget(); + if (widget && !widget->IsActive() && GetFocusManager()) { + GetFocusManager()->SetStoredFocusView(view_to_focus); + } else { + view_to_focus->RequestFocus(); + } +} + BEGIN_METADATA(InfoBarContainerView) END_METADATA diff -Nru chromium-145.0.7632.116/chrome/browser/ui/views/infobars/infobar_container_view.h chromium-145.0.7632.159/chrome/browser/ui/views/infobars/infobar_container_view.h --- chromium-145.0.7632.116/chrome/browser/ui/views/infobars/infobar_container_view.h 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/browser/ui/views/infobars/infobar_container_view.h 2026-03-02 23:00:09.000000000 +0000 @@ -36,12 +36,21 @@ void PlatformSpecificAddInfoBar(infobars::InfoBar* infobar, size_t position) override; void PlatformSpecificRemoveInfoBar(infobars::InfoBar* infobar) override; + void PlatformSpecificWillRemoveInfoBar(infobars::InfoBar* infobar) override; + void PlatformSpecificInfoBarShown(infobars::InfoBar* infobar) override; private: // This view draws the shadow over the web contents below the // lowest infobar. A separate view with a layer is used so it can // draw outside the bounds of |this|. raw_ptr content_shadow_; + + // True when the focused view was inside this container at the moment an + // infobar removal started. Used to restore focus back to the infobar region + // when the next infobar is shown (e.g. a queued infobar being promoted), so + // focus does not jump to page contents and screen reader users are made aware + // of the newly surfaced infobar. + bool restore_focus_on_next_shown_ = false; }; #endif // CHROME_BROWSER_UI_VIEWS_INFOBARS_INFOBAR_CONTAINER_VIEW_H_ diff -Nru chromium-145.0.7632.116/chrome/browser/ui/views/infobars/infobar_container_view_browsertest.cc chromium-145.0.7632.159/chrome/browser/ui/views/infobars/infobar_container_view_browsertest.cc --- chromium-145.0.7632.116/chrome/browser/ui/views/infobars/infobar_container_view_browsertest.cc 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chrome/browser/ui/views/infobars/infobar_container_view_browsertest.cc 2026-03-02 23:00:09.000000000 +0000 @@ -28,7 +28,9 @@ #include "components/infobars/core/infobar_manager.h" #include "content/public/test/browser_test.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/animation/animation_test_api.h" #include "ui/views/view_utils.h" +#include "url/gurl.h" namespace { @@ -61,7 +63,7 @@ } // namespace class InfoBarContainerViewBrowserTest : public InProcessBrowserTest { - public: + protected: InfoBarContainerViewBrowserTest() = default; InfoBarContainerView* GetInfoBarContainer() { @@ -108,7 +110,7 @@ // Tests for standard (non-prioritized) behavior. // class InfoBarContainerStandardTest : public InfoBarContainerViewBrowserTest { - public: + protected: InfoBarContainerStandardTest() { feature_list_.InitAndDisableFeature( infobars::features::kInfobarPrioritization); @@ -179,7 +181,7 @@ // Tests for priority-based behavior. // class InfoBarContainerPriorityTest : public InfoBarContainerViewBrowserTest { - public: + protected: InfoBarContainerPriorityTest() { // These caps match the design doc's defaults. feature_list_.InitAndEnableFeatureWithParameters( @@ -188,6 +190,13 @@ {"max_visible_default", "1"}, {"max_visible_low", "1"}}); } + + // Helper to get the currently focused or stored view. On Wayland, the focused + // view may be null. In that case, we return the stored view. + views::View* GetFocusedOrStoredView(views::FocusManager* focus_manager) { + views::View* focused_view = focus_manager->GetFocusedView(); + return focused_view ? focused_view : focus_manager->GetStoredFocusView(); + } }; IN_PROC_BROWSER_TEST_F(InfoBarContainerPriorityTest, CriticalStacksUpToCap) { @@ -309,13 +318,84 @@ EXPECT_EQ("Critical", GetVisibleInfoBarMessages()[0]); } +IN_PROC_BROWSER_TEST_F(InfoBarContainerPriorityTest, + PromotionRestoresFocusWhenFocusWasInInfobars) { + // Disable animations to avoid flaky tests related to focus management. + auto animation_mode_reset = gfx::AnimationTestApi::SetRichAnimationRenderMode( + gfx::Animation::RichAnimationRenderMode::FORCE_DISABLED); + + infobars::InfoBar* first = AddInfoBar( + infobars::InfoBarDelegate::InfobarPriority::kDefault, "Default 1"); + AddInfoBar(infobars::InfoBarDelegate::InfobarPriority::kDefault, + "Default 2 (Queued)"); + + views::FocusManager* focus_manager = GetInfoBarContainer()->GetFocusManager(); + ASSERT_TRUE(focus_manager); + + InfoBarContainerView* container = GetInfoBarContainer(); + + auto* close_button = static_cast(first)->GetViewByElementId( + InfoBarView::kDismissButtonElementId); + ASSERT_TRUE(close_button); + + close_button->RequestFocus(); + + focus_manager = close_button->GetFocusManager(); + ASSERT_TRUE(focus_manager); + + EXPECT_EQ(close_button, GetFocusedOrStoredView(focus_manager)); + ASSERT_TRUE(container->Contains(GetFocusedOrStoredView(focus_manager))); + + GetInfoBarManager()->RemoveInfoBar(first); + + std::vector visible = GetVisibleInfoBarMessages(); + ASSERT_EQ(1u, visible.size()); + EXPECT_EQ("Default 2 (Queued)", visible[0]); + + EXPECT_TRUE(container->Contains(GetFocusedOrStoredView(focus_manager))); +} + +IN_PROC_BROWSER_TEST_F(InfoBarContainerPriorityTest, + PromotionDoesNotStealFocusWhenFocusWasOutsideInfobars) { + infobars::InfoBar* first = AddInfoBar( + infobars::InfoBarDelegate::InfobarPriority::kDefault, "Default 1"); + AddInfoBar(infobars::InfoBarDelegate::InfobarPriority::kDefault, + "Default 2 (Queued)"); + + InfoBarContainerView* container = GetInfoBarContainer(); + ASSERT_TRUE(container); + + // Put focus in web contents (outside infobars). + content::WebContents* contents = + browser()->tab_strip_model()->GetActiveWebContents(); + ASSERT_TRUE(contents); + contents->Focus(); + + BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser()); + ASSERT_TRUE(browser_view); + views::FocusManager* focus_manager = + browser_view->GetWidget()->GetFocusManager(); + ASSERT_TRUE(focus_manager); + + EXPECT_FALSE(container->Contains(GetFocusedOrStoredView(focus_manager))); + + // Remove visible infobar -> queued one promoted. + GetInfoBarManager()->RemoveInfoBar(first); + + std::vector visible = GetVisibleInfoBarMessages(); + ASSERT_EQ(1u, visible.size()); + EXPECT_EQ("Default 2 (Queued)", visible[0]); + + EXPECT_FALSE(container->Contains(GetFocusedOrStoredView(focus_manager))); +} + // // Tests for split tab behavior, parameterized by whether prioritization is // enabled. // class InfoBarContainerSplitTabTest : public InfoBarContainerViewBrowserTest, public testing::WithParamInterface { - public: + protected: InfoBarContainerSplitTabTest() { std::vector enabled_features; std::vector disabled_features; diff -Nru chromium-145.0.7632.116/chromeos/CHROMEOS_LKGM chromium-145.0.7632.159/chromeos/CHROMEOS_LKGM --- chromium-145.0.7632.116/chromeos/CHROMEOS_LKGM 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chromeos/CHROMEOS_LKGM 2026-03-02 23:00:09.000000000 +0000 @@ -1 +1 @@ -16552.42.0 \ No newline at end of file +16552.50.0 \ No newline at end of file diff -Nru chromium-145.0.7632.116/chromeos/profiles/arm.afdo.newest.txt chromium-145.0.7632.159/chromeos/profiles/arm.afdo.newest.txt --- chromium-145.0.7632.116/chromeos/profiles/arm.afdo.newest.txt 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chromeos/profiles/arm.afdo.newest.txt 2026-03-02 23:00:09.000000000 +0000 @@ -1 +1 @@ -chromeos-chrome-arm-none-145-7632.38-1771211790-benchmark-145.0.7632.114-r1-redacted.afdo.xz +chromeos-chrome-arm-none-145-7632.66-1771816073-benchmark-145.0.7632.157-r1-redacted.afdo.xz diff -Nru chromium-145.0.7632.116/chromeos/profiles/atom.afdo.newest.txt chromium-145.0.7632.159/chromeos/profiles/atom.afdo.newest.txt --- chromium-145.0.7632.116/chromeos/profiles/atom.afdo.newest.txt 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chromeos/profiles/atom.afdo.newest.txt 2026-03-02 23:00:09.000000000 +0000 @@ -1 +1 @@ -chromeos-chrome-amd64-atom-145-7632.66-1771210491-benchmark-145.0.7632.107-r1-redacted.afdo.xz +chromeos-chrome-amd64-atom-145-7632.66-1771825912-benchmark-145.0.7632.157-r1-redacted.afdo.xz diff -Nru chromium-145.0.7632.116/chromeos/profiles/bigcore.afdo.newest.txt chromium-145.0.7632.159/chromeos/profiles/bigcore.afdo.newest.txt --- chromium-145.0.7632.116/chromeos/profiles/bigcore.afdo.newest.txt 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chromeos/profiles/bigcore.afdo.newest.txt 2026-03-02 23:00:09.000000000 +0000 @@ -1 +1 @@ -chromeos-chrome-amd64-bigcore-145-7632.66-1771209749-benchmark-145.0.7632.107-r1-redacted.afdo.xz +chromeos-chrome-amd64-bigcore-145-7632.66-1771819175-benchmark-145.0.7632.157-r1-redacted.afdo.xz diff -Nru chromium-145.0.7632.116/chromeos/strings/chromeos_strings_de.xtb chromium-145.0.7632.159/chromeos/strings/chromeos_strings_de.xtb --- chromium-145.0.7632.116/chromeos/strings/chromeos_strings_de.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chromeos/strings/chromeos_strings_de.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -1036,7 +1036,7 @@ GTC Dieses Update wird vom Hersteller des externen Geräts bereitgestellt und wurde nicht von Google überprüft. Dunkles Design bei Sonnenuntergang automatisch aktivieren -Schaltfläche +Button in den Farbtönen Scannen UMTS diff -Nru chromium-145.0.7632.116/chromeos/strings/chromeos_strings_el.xtb chromium-145.0.7632.159/chromeos/strings/chromeos_strings_el.xtb --- chromium-145.0.7632.116/chromeos/strings/chromeos_strings_el.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chromeos/strings/chromeos_strings_el.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -1414,7 +1414,7 @@ Κάντε κλικ σε οποιοδήποτε πλήκτρο για να προσαρμόσετε το κουμπί. Επανατοποθετήστε το πλήκτρο χρησιμοποιώντας το ποντίκι ή τα πλήκτρα βέλους. την Τετάρτη Επιλέξτε το μικρόφωνό σας -Όροι Παροχής Υπηρεσιών +Όροι παροχής υπηρεσιών κυανό Διαχείριση ρυθμίσεων APN δικτύου. Τα APN δημιουργούν μια σύνδεση μεταξύ ενός δικτύου κινητής τηλεφωνίας και του διαδικτύου. Μάθετε περισσότερα Ενημερώσεις υλικολογισμικού για εξωτερικές συσκευές diff -Nru chromium-145.0.7632.116/chromeos/strings/chromeos_strings_fa.xtb chromium-145.0.7632.159/chromeos/strings/chromeos_strings_fa.xtb --- chromium-145.0.7632.116/chromeos/strings/chromeos_strings_fa.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chromeos/strings/chromeos_strings_fa.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -376,7 +376,7 @@ بهترین عکس‌هایتان که به‌طور خودکار انتخاب شده‌اند · عقیق -بازگشت +برگشتن بازآوری کاغذدیواری کنونی بلندگو نمایش پنجره‌ها @@ -1397,7 +1397,7 @@ نوشتار ساده‌شده تعداد کلمات برای خلاصه کردن کافی نیست در حال اتصال -سعی مجدد +امتحان مجدد بتخانه با انتخاب کلید جدید، مجدداً تخصیص دهید ‏اتصال LAN diff -Nru chromium-145.0.7632.116/chromeos/strings/chromeos_strings_pt-BR.xtb chromium-145.0.7632.159/chromeos/strings/chromeos_strings_pt-BR.xtb --- chromium-145.0.7632.116/chromeos/strings/chromeos_strings_pt-BR.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/chromeos/strings/chromeos_strings_pt-BR.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -1006,7 +1006,7 @@ A rede Wi-Fi não é segura Modo claro automático Tipo de IP -Estilo e fundo de tela +Plano de fundo e estilo Arco-íris O dispositivo está conectando. Executar todas as rotinas @@ -1236,7 +1236,7 @@ Acessar as configurações da conta O botão "Adicionar APN" está ativado {PAGE_NUMBER,plural, =0{Digitalizar a página novamente?}=1{Digitalizar a página {PAGE_NUMBER} novamente?}one{Digitalizar a página {PAGE_NUMBER} novamente?}other{Digitalizar a página {PAGE_NUMBER} novamente?}} -Seus 3 comandos e saídas mais recentes. Você só poderá acessar esses itens enquanto estiver usando o Estilo e fundo de tela. +Seus 3 comandos e resultados mais recentes. Você só poderá acessar esses itens enquanto estiver usando o Plano de fundo e estilo. OTP barcos vermelho-escura diff -Nru chromium-145.0.7632.116/components/browser_ui/strings/android/translations/browser_ui_strings_fa.xtb chromium-145.0.7632.159/components/browser_ui/strings/android/translations/browser_ui_strings_fa.xtb --- chromium-145.0.7632.116/components/browser_ui/strings/android/translations/browser_ui_strings_fa.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/components/browser_ui/strings/android/translations/browser_ui_strings_fa.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -143,7 +143,7 @@ حذف نصب تحت مدیریت راهنمایی و بازخورد -بازگشت +برگشتن وقتی روشن باشد، سایت‌ها می‌توانند درخواست دهند به دستگاه‌های موجود در شبکه محلی شما متصل شوند. وقتی خاموش باشد، سایت‌ها نمی‌توانند به دستگاه‌های موجود در شبکه محلی شما متصل شوند. این بار اجازه هست • دقیق رنگ زمینه تیره @@ -725,11 +725,11 @@ مسدود کردن جاوااسکریپت برای سایتی خاص. ‏V8 موتور WebAssembly و جاوا اسکریپت Chrome است که از آن برای بهبود عملکرد سایت استفاده می‌شود وقتی روشن است -مرور کردن سریع‌تر می‌شود زیرا احتمال کمتری وجود دارد که سایتی از شما بخواهد تأیید کنید شما شخص واقعی هستید +مرور کردن سریع‌تر می‌شود زیرا احتمال کمتری وجود دارد که سایتی از شما بخواهد درستی‌سنجی کنید شما شخصی حقیقی هستید سایت‌ها نمی‌توانند به حسگرها دسترسی داشته باشند USB کوکی‌های طرف سوم را به‌طور موقت مجاز کنید. این کار به‌معنی محافظت کمتر هنگام مرور است اما ویژگی‌های سایت به احتمال زیاد عملکرد موردنظر را خواهد داشت. -‏همان‌طور که مرور می‌کنید، سایت‌ها می‌توانند ازطریق Chrome بررسی کنند و بااستفاده از سایت قبلی که بازدید کرده‌اید تأیید کنند که احتمالاً شما شخص واقعی هستید +‏همان‌طور که مرور می‌کنید، سایت‌ها می‌توانند ازطریق Chrome بررسی کنند و بااستفاده از سایت قبلی که بازدید کرده‌اید درستی‌سنجی کنند که احتمالاً شما شخص واقعی هستید آگهی‌های مزاحم بزرگ‌نمایی / @@ -757,7 +757,7 @@ ‏اجازه دهید Chrome برگه‌های اخیرتان را در فهرست برنامه‌ها و نتایج جستجوی دستگاهتان نشان دهد. هرزمان بخواهید می‌توانید این گزینه را در تنظیمات Chrome خاموش کنید. این صفحه خطرناک است به سایت‌ها اجازه داده نشود محتوای محافظت‌شده را پخش کنند -سایت‌هایی که بازدید می‌کنید می‌توانند تأیید کنند که شما شخص واقعی هستید و روبات نیستید +سایت‌هایی که بازدید می‌کنید می‌توانند درستی‌سنجی کنند که شما شخص واقعی هستید و روبات نیستید سازمان‌دهی شوید مکان این بار اجازه هست داده ذخیره شد diff -Nru chromium-145.0.7632.116/components/browser_ui/strings/android/translations/browser_ui_strings_fi.xtb chromium-145.0.7632.159/components/browser_ui/strings/android/translations/browser_ui_strings_fi.xtb --- chromium-145.0.7632.116/components/browser_ui/strings/android/translations/browser_ui_strings_fi.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/components/browser_ui/strings/android/translations/browser_ui_strings_fi.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -172,7 +172,7 @@ Sammuta kamera Sähköpostiosoitteet Käynnistä Chrome niin, että omniboxi on tarkennettuna, jolloin käynnistysaika on lyhyempi edullisemmilla laitteilla. -Sivustot voivat näyttää henkilöllisyyspalveluiden sisäänkirjautumiskehotteita. +Sivustot voivat näyttää identiteettipalveluiden sisäänkirjautumiskehotteita. Omniboxin pikakäynnistys Sivustot voivat pyytää lupaa luoda 3D-kartan ympäristöstäsi tai seurata kameran asentoa Kun tämä on päällä, äskettäin suljetut sivustot voivat viimeistellä datan lähettämistä tai vastaanottamista. Kun tämä ei ole päällä, äskettäin suljetut sivustot eivät voi viimeistellä datan lähettämistä tai vastaanottamista. @@ -437,7 +437,7 @@ Kamera laitettiin pois päältä Androidin asetuksista Kolmannen osapuolen evästeet sallittu Tämä poistaa evästeet ja muun sivustodatan täällä: -Sivustot voivat näyttää henkilöllisyyspalveluiden sisäänkirjautumiskehotteita +Sivustot voivat näyttää identiteettipalveluiden sisäänkirjautumiskehotteita Sivustot voivat tallentaa dataa laitteellesi Historia löytyy kaikilta laitteilta, joten voit helposti jatkaa siitä, mihin jäit Jatka tällä välilehdellä @@ -457,7 +457,7 @@ Ota käyttöön Keskeytä video Tiivistä kaikki pyynnöt -Estä henkilöllisyyspalveluiden sisäänkirjautumiskehotteet +Estä identiteettipalveluiden sisäänkirjautumiskehotteet Koko näyttö Sivustotoivomus Avattu viimeksi eilen @@ -535,7 +535,7 @@ Profiilikuvat Aktiiviset lataukset Kysy, saavatko sivustot seurata käsiäsi (suositus) -Estä henkilöllisyyspalveluiden sisäänkirjautumiskehotteet. +Estä identiteettipalveluiden sisäänkirjautumiskehotteet. Siirrä alas Nollataanko luvat? Sulje pyyhkäisemällä alas. diff -Nru chromium-145.0.7632.116/components/browser_ui/strings/android/translations/browser_ui_strings_no.xtb chromium-145.0.7632.159/components/browser_ui/strings/android/translations/browser_ui_strings_no.xtb --- chromium-145.0.7632.116/components/browser_ui/strings/android/translations/browser_ui_strings_no.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/components/browser_ui/strings/android/translations/browser_ui_strings_no.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -290,7 +290,7 @@ Nedlasting fullført Lokal nettverkstilgang Nettsteder viser vanligvis annonser for å kunne tilby innhold eller tjenester kostnadsfritt. Men noen nettsteder er kjent for å vise forstyrrende eller villedende annonser. -Kopiér link +Kopier link / ? kan bruke informasjonen din når du surfer Om denne siden diff -Nru chromium-145.0.7632.116/components/browser_ui/strings/android/translations/browser_ui_strings_sk.xtb chromium-145.0.7632.159/components/browser_ui/strings/android/translations/browser_ui_strings_sk.xtb --- chromium-145.0.7632.116/components/browser_ui/strings/android/translations/browser_ui_strings_sk.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/components/browser_ui/strings/android/translations/browser_ui_strings_sk.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -457,7 +457,7 @@ Zapnúť Pozastaviť video Zbaliť všetky požiadavky -Blokovať výzvy na prihlásenie zo služieb identity +Blokovať výzvy na prihlásenie od služieb identity Celá obrazovka Predvoľba webu Naposledy navštívený včera diff -Nru chromium-145.0.7632.116/components/browser_ui/strings/android/translations/browser_ui_strings_zh-CN.xtb chromium-145.0.7632.159/components/browser_ui/strings/android/translations/browser_ui_strings_zh-CN.xtb --- chromium-145.0.7632.116/components/browser_ui/strings/android/translations/browser_ui_strings_zh-CN.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/components/browser_ui/strings/android/translations/browser_ui_strings_zh-CN.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -94,7 +94,7 @@ 增强现实 所有需要使用移动传感器的功能都将无法正常运行 点按即可返回到 -撤消 +撤销 更多设置 声音 主题颜色:浅色 diff -Nru chromium-145.0.7632.116/components/certificate_transparency/data/log_list.json chromium-145.0.7632.159/components/certificate_transparency/data/log_list.json --- chromium-145.0.7632.116/components/certificate_transparency/data/log_list.json 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/components/certificate_transparency/data/log_list.json 2026-03-02 23:00:09.000000000 +0000 @@ -1,6 +1,6 @@ { - "version": "84.8", - "log_list_timestamp": "2026-02-20T12:57:40Z", + "version": "85.3", + "log_list_timestamp": "2026-03-02T12:53:38Z", "operators": [ { "name": "Google", @@ -515,12 +515,8 @@ "url": "https://oak.ct.letsencrypt.org/2026h1/", "mmd": 86400, "state": { - "readonly": { - "timestamp": "2025-12-12T22:30:00Z", - "final_tree_head": { - "sha256_root_hash": "deSRNfTNPgd9wfzoXIznvi+QUTxuK0R+daC6JGKGK3Q=", - "tree_size": 598614696 - } + "retired": { + "timestamp": "2026-02-28T00:00:00Z" } }, "temporal_interval": { @@ -535,12 +531,8 @@ "url": "https://oak.ct.letsencrypt.org/2026h2/", "mmd": 86400, "state": { - "readonly": { - "timestamp": "2025-12-12T22:30:00Z", - "final_tree_head": { - "sha256_root_hash": "uTgg1k3DUbSFFdXewyyxbsQuCc9RupplMphTwtXqvf4=", - "tree_size": 130815692 - } + "retired": { + "timestamp": "2026-02-28T00:00:00Z" } }, "temporal_interval": { diff -Nru chromium-145.0.7632.116/components/infobars/core/infobar_container.cc chromium-145.0.7632.159/components/infobars/core/infobar_container.cc --- chromium-145.0.7632.116/components/infobars/core/infobar_container.cc 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/components/infobars/core/infobar_container.cc 2026-03-02 23:00:09.000000000 +0000 @@ -102,6 +102,7 @@ void InfoBarContainer::OnInfoBarRemoved(InfoBar* infobar, bool animate) { CHECK(scoped_observation_.IsObserving()); + PlatformSpecificWillRemoveInfoBar(infobar); infobar->Hide(manager()->animations_enabled() && animate); } @@ -131,6 +132,7 @@ infobar->set_container(this); CHECK(manager()); infobar->Show(manager()->animations_enabled() && animate); + PlatformSpecificInfoBarShown(infobar); // Record the infobar being displayed. DCHECK_NE(InfoBarDelegate::INVALID, infobar->GetIdentifier()); diff -Nru chromium-145.0.7632.116/components/infobars/core/infobar_container.h chromium-145.0.7632.159/components/infobars/core/infobar_container.h --- chromium-145.0.7632.116/components/infobars/core/infobar_container.h 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/components/infobars/core/infobar_container.h 2026-03-02 23:00:09.000000000 +0000 @@ -94,6 +94,8 @@ InfoBar* new_infobar) {} virtual void PlatformSpecificRemoveInfoBar(InfoBar* infobar) = 0; virtual void PlatformSpecificInfoBarStateChanged(bool is_animating) {} + virtual void PlatformSpecificWillRemoveInfoBar(infobars::InfoBar* infobar) {} + virtual void PlatformSpecificInfoBarShown(infobars::InfoBar* infobar) {} // Adds |infobar| to this container before the existing infobar at position // |position| and calls Show() on it. |animate| is passed along to diff -Nru chromium-145.0.7632.116/components/infobars/core/infobar_container_with_priority.h chromium-145.0.7632.159/components/infobars/core/infobar_container_with_priority.h --- chromium-145.0.7632.116/components/infobars/core/infobar_container_with_priority.h 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/components/infobars/core/infobar_container_with_priority.h 2026-03-02 23:00:09.000000000 +0000 @@ -42,6 +42,8 @@ // InfoBarContainer overrides: void ChangeInfoBarManager(InfoBarManager* infobar_manager) override; + bool HasPendingInfoBars() const { return !pending_infobars_.empty(); } + protected: // InfoBarContainer overrides: void OnInfoBarAdded(InfoBar* infobar) override; diff -Nru chromium-145.0.7632.116/components/policy/resources/policy_templates_de.xtb chromium-145.0.7632.159/components/policy/resources/policy_templates_de.xtb --- chromium-145.0.7632.116/components/policy/resources/policy_templates_de.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/components/policy/resources/policy_templates_de.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -463,7 +463,7 @@ Wenn diese Richtlinie aktiviert ist, werden verbesserte internationale Tastenkürzel aktiviert. Ist die Richtlinie nicht konfiguriert, wird sie für verwaltete und nutzereigene Geräte aktiviert. Beachte, dass es sich hierbei um eine vorübergehende Richtlinie handelt, die dafür sorgt, dass alte Tastenkürzel weiterhin von verwalteten Nutzern verwendet werden können. Diese Richtlinie wird verworfen, sobald benutzerdefinierte Tastenkürzel verfügbar sind. -„Home“-Schaltfläche in der Symbolleiste anzeigen +„Home“-Button in der Symbolleiste anzeigen Abfragen an Quirks-Server für Hardwareprofile aktivieren Wenn die Richtlinie aktiviert oder nicht konfiguriert ist, wird die LPAC-Sandbox für Druckdienste aktiviert, sofern dies von der Systemkonfiguration unterstützt wird. @@ -1833,9 +1833,9 @@ Ist diese Richtlinie nicht konfiguriert, können Nutzer die im Launcher angepinnten Apps ändern. Gruppen aus Einzelrichtlinien aktivieren -Wenn die Richtlinie auf "True" gesetzt ist, wird während aktiver Sitzungen in der Taskleiste eine große rote Schaltfläche zum Abmelden angezeigt, solange das Display nicht gesperrt ist. +Wenn die Richtlinie auf „True“ gesetzt ist, wird während aktiver Sitzungen in der Taskleiste ein großer roter Button zum Abmelden angezeigt, solange das Display nicht gesperrt ist. - Ist sie auf "False" gesetzt oder nicht konfiguriert, wird keine Schaltfläche angezeigt. + Ist sie auf „False“ gesetzt oder nicht konfiguriert, wird kein Button angezeigt. Das Abspielen von Videos in Android-Apps wird nicht berücksichtigt, auch wenn diese Richtlinie auf gesetzt ist. Liste der aktivierten Plug-ins angeben Keine weitergeleiteten Suchen mit erhöhter Sicherheit zulassen @@ -2199,7 +2199,7 @@ Nutzer können nicht ändern, in welchem Ordner die Lesezeichen abgelegt werden. Aber sie haben die Möglichkeit, den Ordner in der Lesezeichenleiste auszublenden. Der Standardname des Ordners für verwaltete Lesezeichen lautet "Verwaltete Lesezeichen", kann jedoch angepasst werden. Dazu muss der Richtlinie ein neues untergeordnetes Wörterbuch mit einem einfachen Schlüssel namens "" hinzugefügt werden, wobei der gewünschte Ordnername der Wert ist. Verwaltete Lesezeichen werden nicht mit dem Nutzerkonto synchronisiert und können nicht von Erweiterungen geändert werden. Zeitzone -„Home“-Schaltfläche in der Symbolleiste ausblenden +„Home“-Button in der Symbolleiste ausblenden Ermöglicht die Bereitstellung von Clientzertifikaten für verwaltete Nutzer und Profile Post-Quanten-Algorithmus für Schlüsselvereinbarungen mit WebRTC deaktivieren Zulassen, dass veraltete -Plug-ins als normale -Plug-ins verwendet werden @@ -7606,7 +7606,7 @@ Einstellungen zum Teilen von Tabgruppen SHA-256-Hash der Desktopvorlage. Websites nicht erlauben, um Schreibzugriff auf Dateien und Verzeichnisse zu bitten -Wert der Schaltfläche zum Umschalten der App-Aktivitätserfassung. Wenn diese Option auf „true“ gesetzt ist, werden die App-Aktivitäten von Nutzern an den Server gesendet, damit sie in der -App des Kindes und des Elternteils angezeigt werden können. Ist sie auf „false“ gesetzt, funktionieren App-spezifische Zeitlimits zwar weiterhin, es werden jedoch keine Daten an den Server gesendet, sodass sie nicht in angezeigt werden können. +Wert des Buttons zum Umschalten der App-Aktivitätserfassung. Wenn diese Option auf „true“ gesetzt ist, werden die App-Aktivitäten von Nutzern an den Server gesendet, damit sie in der -App des Kindes und des Elternteils angezeigt werden können. Ist sie auf „false“ gesetzt, funktionieren App-spezifische Zeitlimits zwar weiterhin, es werden jedoch keine Daten an den Server gesendet, sodass sie nicht in angezeigt werden können. HTTPS-Upgrades deaktivieren. Automatische Wiedergabe von Medien in Chrome zulassen Mit dieser Richtlinie wird festgelegt, ob dem Nutzer beim ersten Anmeldungsvorgang der Einführungsbildschirm für KI-Funktionen während der Sitzung angezeigt wird. @@ -7845,9 +7845,8 @@ Sie kann den Nutzer vor dem Zugriff auf eingeschränkte Inhalte schützen, die sich auf Web-Properties von Google befinden. Wenn diese Richtlinie auf "true" gesetzt wird, wird der Nutzer abgemeldet, sobald sein Authentifizierungstoken ungültig wird und das Token nicht wiederhergestellt werden kann. Wird sie auf "false" gesetzt oder nicht konfiguriert, kann der Nutzer in einem nicht authentifizierten Zustand fortfahren. -Wenn diese Funktion aktiviert ist, erscheint auf dem Start- und Sperrbildschirm eine Schaltfläche zum Anzeigen des Passworts. - Sie wird im Textfeld für das Passwort als Augensymbol dargestellt. Die Schaltfläche wird nicht angezeigt, wenn die Funktion deaktiviert ist. - +Wenn diese Funktion aktiviert ist, erscheint auf dem Start- und Sperrbildschirm ein Button zum Anzeigen des Passworts. + Sie wird im Textfeld für das Passwort als Augensymbol dargestellt. Der Button wird nicht angezeigt, wenn die Funktion deaktiviert ist. Über diese Richtlinie wird festgelegt, ob die Hauptversion im User-Agent-String als „99“ festgeschrieben wird. Anhand des User-Agent-Anfrageheaders können Websites die Anwendung, das Betriebssystem, den Anbieter und/oder die Version des anfragenden User-Agents identifizieren. @@ -8462,7 +8461,7 @@ Cloud-Berichterstellung über verwaltete Profile aktivieren Erweitertes Autofill zulassen, ohne KI‑Modelle zu verbessern. Festlegen, wie oft der Nutzer das Passwort eingeben muss, um das schnelle Entsperren zu verwenden -Schaltfläche zum Anzeigen des Passworts auf dem Start- oder Sperrbildschirm anzeigen +Button zum Anzeigen des Passworts auf dem Start- oder Sperrbildschirm anzeigen Mit dieser Richtlinie kann das alte Verhalten für den Cookie-Bereich wiederhergestellt werden. Das bedeutet, dass auf Cookies, die über ein bestimmtes Protokoll (z. B. HTTPS) oder einen bestimmten Port festgelegt wurden, über ein anderes Protokoll oder einen anderen Port zugegriffen werden kann. @@ -12127,7 +12126,7 @@ Wenn die Richtlinie auf „false“ gesetzt oder nicht konfiguriert ist, werden keine Informationen ausgegeben. Wenn sie auf „true“ gesetzt wird, werden die Anmelde-/Abmeldeereignisse auf den Geräten gemeldet. Konfigurationsrichtlinie für den Chrome Enterprise Connector „OnFileTransfer” -Wenn diese Richtlinie nicht konfiguriert oder auf „Enabled“ gesetzt wird, können Nutzer mit ihre Kamera für die Suche verwenden. Ist die Richtlinie auf „Disabled“ gesetzt, wird Nutzern die Schaltfläche „“ im Suchfeld nicht angezeigt, wenn die kameragestützte Suche mit verfügbar ist. +Wenn diese Richtlinie nicht konfiguriert oder auf „Enabled“ gesetzt wird, können Nutzer mit ihre Kamera für die Suche verwenden. Ist die Richtlinie auf „Disabled“ gesetzt, wird Nutzern der Button „“ im Suchfeld nicht angezeigt, wenn die kameragestützte Suche mit verfügbar ist. Contentanbieter für betreute Nutzer aktivieren Methode für die automatische Erkennung der Zeitzone konfigurieren Tab Compare nicht zulassen. diff -Nru chromium-145.0.7632.116/components/policy/resources/policy_templates_fr.xtb chromium-145.0.7632.159/components/policy/resources/policy_templates_fr.xtb --- chromium-145.0.7632.116/components/policy/resources/policy_templates_fr.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/components/policy/resources/policy_templates_fr.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -546,11 +546,11 @@ Si cette règle est désactivée, l'appli n'utilisera pas les notifications temporaires. Autoriser les utilisateurs non affiliés à utiliser Crostini -Cette règle détermine si une page avec un en-tête peut être stockée dans le cache amélioré. Le paramètre de site Web défini pour cet en-tête ne prévoit peut-être pas que la page soit restaurée à partir du cache amélioré, car certaines informations sensibles peuvent rester affichées après la restauration, même si elles ne sont plus accessibles. +Cette règle détermine si une page avec un en-tête peut être stockée dans le cache back/forward. Le paramètre de site Web défini pour cet en-tête ne prévoit peut-être pas que la page soit restaurée à partir du cache back/forward, car certaines informations sensibles peuvent rester affichées après la restauration, même si elles ne sont plus accessibles. -Si cette règle est activée ou n'est pas configurée, la page avec un en-tête pourrait être restaurée à partir du cache amélioré, sauf si l'éviction du cache est déclenchée (par exemple, en cas de modification du cookie HttpOnly sur le site). +Si cette règle est activée ou n'est pas configurée, la page avec un en-tête pourrait être restaurée à partir du cache back/forward, sauf si l'éviction du cache est déclenchée (par exemple, en cas de modification du cookie HttpOnly sur le site). -Si cette règle est désactivée, la page avec un en-tête ne sera pas stockée dans le cache amélioré. +Si cette règle est désactivée, la page avec un en-tête ne sera pas stockée dans le cache back/forward. Empêche les utilisateurs de cet appareil de recourir au téléchargement indépendant adb, mais sans imposer la réinitialisation Powerwash. Cela peut remettre en question la sécurité de l'appareil. Définir un délai en jours pour le stockage des métadonnées liées aux tâches d'impression Oui @@ -903,7 +903,7 @@ Désactiver les rapports sur l'état du stockage de l'appareil Autoriser l'organiseur d'onglets et améliorer les modèles d'IA. Autoriser à se connecter aux appareils sur toutes les adresses IP -Autoriser l'utilisation du cache amélioré +Autoriser l'utilisation du cache back/forward Fiches non affichées sur la page Nouvel onglet Les formats de cette liste seront mis en correspondance avec la source de sécurité de l'URL à l'origine de la demande. En cas de correspondance, @@ -1887,7 +1887,7 @@ Désactiver l'accès au menu contextuel du moteur de recherche par défaut Paramètres des groupes suggérés -Ne pas autoriser l'utilisation du cache amélioré +Ne pas autoriser l'utilisation du cache back/forward Si cette règle est activée ou qu'elle n'est pas configurée, les utilisateurs peuvent choisir d'associer les clients et les hôtes au moment de la connexion, ce qui évite d'avoir à saisir systématiquement un code. Si cette règle est désactivée, cette fonctionnalité n'est pas disponible. @@ -2984,7 +2984,7 @@ Cette règle ne peut être configurée que comme règle relative aux utilisateurs du cloud. Ne pas autoriser la fonctionnalité Désactiver l'enregistreur d'écran -Interdire le stockage des pages avec un en-tête dans le cache amélioré. +Interdire le stockage des pages avec un en-tête dans le cache back/forward. Utiliser la consultation CNAME lors de l'authentification Kerberos Permet aux utilisateurs affiliés de cet appareil d'utiliser le téléchargement indépendant adb Laisser l'utilisateur décider si l'appareil doit se verrouiller quand il est arrêté provisoirement ou que son écran est rabattu @@ -6446,9 +6446,9 @@ Si la règle n'est pas définie, l'utilisateur peut choisir l'image de l'avatar qui le représente dans l'écran de connexion. Contrôles des paramètres de Privacy Sandbox Le nouveau comportement de l'analyseur HTML, permettant d'utiliser plus de balises, sera activé. -Lorsque cette règle est activée, la fonctionnalité permet d'utiliser le cache amélioré. Si l'utilisateur change de page, celle qui est quittée peut être conservée en l'état (arborescence de documents, script, etc.) dans le cache amélioré. Par exemple, si l'utilisateur retourne sur cette page, celle-ci peut ainsi être restaurée à partir de ce cache et affichée telle qu'elle était avant sa mise en cache. +Lorsque cette règle est activée, la fonctionnalité permet d'utiliser le cache back/forward. Si l'utilisateur change de page, celle qui est quittée peut être conservée en l'état (arborescence de documents, script, etc.) dans le cache back/forward. Par exemple, si l'utilisateur retourne sur cette page, celle-ci peut ainsi être restaurée à partir de ce cache et affichée telle qu'elle était avant sa mise en cache. - Toutefois, cette fonctionnalité peut entraîner des dysfonctionnements pour certains sites Web qui ne s'attendent pas à ce que leurs pages soient mises en cache, en particulier ceux qui reposent sur le déclenchement de l'événement "" en cas de changement de page. L'événement "" ne se déclenche pas si la page concernée est stockée dans le cache amélioré. + Toutefois, cette fonctionnalité peut entraîner des dysfonctionnements pour certains sites Web qui ne s'attendent pas à ce que leurs pages soient mises en cache, en particulier ceux qui reposent sur le déclenchement de l'événement "" en cas de changement de page. L'événement "" ne se déclenche pas si la page concernée est stockée dans le cache back/forward. Si cette règle est activée ou qu'elle n'est pas configurée, @@ -7422,7 +7422,7 @@ Si elle est désactivée, ils ne peuvent pas en bénéficier. Google Sheets (compatible depuis la version 135) -Autoriser les pages avec un en-tête à accéder au cache amélioré +Autoriser les pages avec un en-tête à accéder au cache back/forward Désactiver le transfert de fichiers dans les connexions d'assistance à distance avec les administrateurs de l'entreprise La collecte de métriques avec clé d'URL n'est pas autorisée Ne pas autoriser les contrôles de rapports précis @@ -10654,7 +10654,7 @@ Si cette règle est activée ou si elle n'est pas configurée, les sites Web sont autorisés à vérifier si l'utilisateur possède des modes de paiement enregistrés. Définir la taille du cache disque de support -Autoriser le stockage des pages avec un en-tête dans le cache amélioré. +Autoriser le stockage des pages avec un en-tête dans le cache back/forward. Autoriser les utilisateurs à lancer des mises à jour du micrologiciel Règle d'accès à la configuration des imprimantes d'appareils. URL pour lesquelles la règle AutoOpenFileTypes peut s'appliquer diff -Nru chromium-145.0.7632.116/components/policy/resources/policy_templates_nl.xtb chromium-145.0.7632.159/components/policy/resources/policy_templates_nl.xtb --- chromium-145.0.7632.116/components/policy/resources/policy_templates_nl.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/components/policy/resources/policy_templates_nl.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -3857,11 +3857,11 @@ Als je het beleid niet toepast of niet instelt, rapporteren ingeschreven apparaten de statistieken niet. Dit beleid is beëindigd in M70. Gebruik in plaats hiervan en . -Hiermee wordt de functie Automatisch aanvullen van geactiveerd en wordt gebruikers toegestaan webformulieren automatisch in te vullen met eerder opgeslagen informatie zoals adres- of creditcardgegevens. +Hiermee wordt de functie Automatisch invullen van geactiveerd en wordt gebruikers toegestaan webformulieren automatisch in te vullen met eerder opgeslagen informatie zoals adres- of creditcardgegevens. -Als je deze instelling uitzet, kunnen gebruikers de functie Automatisch aanvullen niet gebruiken. +Als je deze instelling uitzet, kunnen gebruikers de functie Automatisch invullen niet gebruiken. -Als je de instelling activeert of geen waarde instelt, kunnen gebruikers de opties voor Automatisch aanvullen zelf beheren. Zo kunnen ze profielen voor Automatisch aanvullen instellen en de functie naar wens aan- of uitzetten. +Als je de instelling activeert of geen waarde instelt, kunnen gebruikers de opties voor Automatisch invullen zelf beheren. Zo kunnen ze profielen voor Automatisch invullen instellen en de functie naar wens aan- of uitzetten. Dag van de week voor het interval. 'Persoon toevoegen' aanzetten in gebruikersbeheer Toestaan dat een nieuwe decoder gebruikt voor videodecodering met hardwareversnelling. @@ -7334,8 +7334,8 @@ Als je dit beleid instelt op False of niet instelt, kunnen sites alleen WebAssembly-modules naar vensters en werkrollen in dezelfde oorsprong sturen. Lijst met geblokkeerde domeinen voor zwevende SSO-service Dit beleid bepaalt hoe er wordt omgegaan met onveilige formulieren (formulieren die gegevens sturen via HTTP) die zijn ingesloten in beveiligde sites (HTTPS) in de browser. - Als je het beleid toepast of niet instelt, wordt er een waarschuwingsbericht op de volledige pagina weergegeven als er een onveilig formulier wordt gestuurd. Daarnaast wordt er een waarschuwingsballon naast de formuliervelden weergegeven als de focus erop wordt geplaatst en wordt automatisch aanvullen uitgezet voor deze formulieren. - Als je het beleid niet toepast, worden er geen waarschuwingen weergegeven voor onveilige formulieren en werkt automatisch aanvullen normaal. + Als je het beleid toepast of niet instelt, wordt er een waarschuwingsbericht op de volledige pagina weergegeven als er een onveilig formulier wordt gestuurd. Daarnaast wordt er een waarschuwingsballon naast de formuliervelden weergegeven als de focus erop wordt geplaatst en wordt automatisch invullen uitgezet voor deze formulieren. + Als je het beleid niet toepast, worden er geen waarschuwingen weergegeven voor onveilige formulieren en werkt automatisch invullen normaal. Dit beleid wordt verwijderd in Chrome 130. Vingerafdruk diff -Nru chromium-145.0.7632.116/components/policy/resources/policy_templates_pt-BR.xtb chromium-145.0.7632.159/components/policy/resources/policy_templates_pt-BR.xtb --- chromium-145.0.7632.116/components/policy/resources/policy_templates_pt-BR.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/components/policy/resources/policy_templates_pt-BR.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -586,7 +586,7 @@ No ChromeOS, essa configuração faz com que o frame rate e a frequência da CPU sejam limitados, as luzes de fundo fiquem esmaecidas e o Android seja colocado no modo de economia de bateria. Em dispositivos com várias CPUs, algumas delas serão desativadas. Os diferentes níveis são: (0): o modo de economia de bateria será desativado. - (1): o modo economia de bateria será ativado quando o dispositivo estiver usando a energia da bateria e o nível dela estiver baixo. + (1): o modo de economia de bateria será ativado quando o dispositivo estiver usando a energia da bateria e o nível dela estiver baixo. (2): esse valor foi descontinuado na versão M121. Na versão M121 e mais recentes, os valores serão tratados como EnabledBelowThreshold. Desativar verificação ortográfica @@ -4375,7 +4375,7 @@ Se a política for definida como falsa, o preenchimento automático nunca fará sugestões ou preencherá informações de cartão de crédito nem salvará outros dados desse tipo que os usuários enviarem ao navegar na Web. Sair Bloquear pontos de extensão legados do navegador -O modo Economia de bateria vai ser desativado. +O modo de economia de bateria vai ser desativado. Não aplicar o cancelamento de eco do áudio do sistema Mostrar o aviso abaixo da caixa de pesquisa na página "Nova guia" Não disponibilizar o Modo área de trabalho unificada para o usuário @@ -10081,7 +10081,7 @@ Se você definir a política, os usuários não poderão mudá-la. Se ela não for definida, a previsão de rede será ativada, mas os usuários poderão mudar a configuração. Permitir o backup de dados do -Ativar o modo Economia de bateria +Ativar o modo de economia de bateria Permitir que a execute solicitações de API do WebAuthn transmitidas por proxy de um host remoto. Ativar acesso a dados de periféricos Thunderbolt/USB4 Não tenho preferência. @@ -11369,7 +11369,7 @@ Definir se a configuração do para temas de anúncios pode ser desativada Lupa de tela inteira ativada Ativar o Serviço de Localização do Google para Android -O modo Economia de bateria vai ser ativado quando o dispositivo estiver usando a energia da bateria e o nível dela estiver baixo. +O modo de economia de bateria vai ser ativado quando o dispositivo estiver usando a energia da bateria e o nível dela estiver baixo. Ativar o recurso de acessibilidade de ditado. Se esta política for definida como ativada, o ditado ficará sempre ativado. diff -Nru chromium-145.0.7632.116/components/policy/resources/policy_templates_ru.xtb chromium-145.0.7632.159/components/policy/resources/policy_templates_ru.xtb --- chromium-145.0.7632.116/components/policy/resources/policy_templates_ru.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/components/policy/resources/policy_templates_ru.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -3653,7 +3653,7 @@ Настройки для сайтов с навязчивой рекламой Использовать no-referrer-when-downgrade в качестве правила по умолчанию в отношении URL перехода Если правило включено, доступны инструменты устранения неполадок для режима киоска: -– Инструменты разработчика в Chrome; +– инструменты разработчика в Chrome; – окно браузера Chrome; – диспетчер задач. Если правило отключено или не настроено, инструменты устранения неполадок для режима киоска недоступны. diff -Nru chromium-145.0.7632.116/components/strings/components_strings_ca.xtb chromium-145.0.7632.159/components/strings/components_strings_ca.xtb --- chromium-145.0.7632.116/components/strings/components_strings_ca.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/components/strings/components_strings_ca.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -364,7 +364,7 @@ Google Chrome està provant d'activar Windows Hello per emplenar contrasenyes. x polzades S'està verificant la forma de pagament -Shopping Insights +Estadístiques de compra La teva organització ha bloquejat aquest lloc web CVC Hi ha hagut un error en mostrar aquesta pàgina web. @@ -4297,7 +4297,7 @@ És possible que la xarxa Wi-Fi () que esteu fent servir requereixi que visiteu la seva pàgina d'inici de sessió. Què és la llista de la compra? La captura de pantalla s'ha iniciat -Shopping Insights +Estadístiques de compra Formes de pagament disponibles per seleccionar i continuar el pagament. El teclat està amagat. Som-hi Historial agrupat diff -Nru chromium-145.0.7632.116/components/strings/components_strings_de.xtb chromium-145.0.7632.159/components/strings/components_strings_de.xtb --- chromium-145.0.7632.116/components/strings/components_strings_de.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/components/strings/components_strings_de.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -1393,7 +1393,7 @@ Ladesymbol beim Starten der App Standortermittlung nicht zulässig Der Server hat ein Zertifikat übermittelt, das nicht mit den integrierten Erwartungen übereinstimmt. Diese Erwartungen sind zu deinem Schutz in bestimmten Websites mit hohen Sicherheitsstandards enthalten. -Klicke auf die Schaltfläche zum erneuten Laden, um die für das Laden der Seite erforderlichen Daten noch einmal zu senden. +Klicke auf den Button zum erneuten Laden, um die für das Laden der Seite erforderlichen Daten noch einmal zu senden. Miniaturansichten Mikrofon Versionsinformationen zu deinem Gerät und Browser diff -Nru chromium-145.0.7632.116/components/strings/components_strings_es-419.xtb chromium-145.0.7632.159/components/strings/components_strings_es-419.xtb --- chromium-145.0.7632.116/components/strings/components_strings_es-419.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/components/strings/components_strings_es-419.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -4525,7 +4525,7 @@ Para obtener información adicional y conocer las políticas que pueden aplicarse, abre chrome://management en tu navegador.  ×  mm , -VIN (número de identificación del vehículo) +VIN (número de identificación vehicular) Temperatura de la plataforma Preparando archivo Para habilitar estos parámetros de configuración y usar la información de pago de tu Cuenta de Google, visita la configuración de los servicios de autocompletado. diff -Nru chromium-145.0.7632.116/components/strings/components_strings_es.xtb chromium-145.0.7632.159/components/strings/components_strings_es.xtb --- chromium-145.0.7632.116/components/strings/components_strings_es.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/components/strings/components_strings_es.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -1756,7 +1756,7 @@ ( x in) Películas de culto e independientes La cantidad y las causas de los bloqueos que han ocurrido recientemente -Hace poco has cambiado una contraseña que se ha encontrado en una brecha de seguridad de datos públicos. Si tienes problemas, el Gestor de contraseñas de Google puede ayudarte a iniciar sesión. +Hace poco has cambiado una contraseña que se ha encontrado en una brecha pública de seguridad de datos. Si tienes problemas, el Gestor de contraseñas de Google puede ayudarte a iniciar sesión. Fuente solicitada De Lo visitas a menudo @@ -5087,7 +5087,7 @@ Periféricos de audio conectados Revistas Configurando... -Hace poco has cambiado una contraseña que se ha encontrado en una brecha de seguridad de datos públicos. Si tienes problemas, el Gestor de contraseñas puede ayudarte a iniciar sesión. +Hace poco has cambiado una contraseña que se ha encontrado en una brecha pública de seguridad de datos. Si tienes problemas, el Gestor de contraseñas puede ayudarte a iniciar sesión. {0,plural, =1{Es posible que incluya contenido sensible}other{Es posible que archivos incluyan contenido sensible}} : para salir de pantalla completa, pulsa || Mensaje de Slack diff -Nru chromium-145.0.7632.116/components/strings/components_strings_fa.xtb chromium-145.0.7632.159/components/strings/components_strings_fa.xtb --- chromium-145.0.7632.116/components/strings/components_strings_fa.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/components/strings/components_strings_fa.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -954,7 +954,7 @@ می‌توانید در انتخاب کنید از اثر انگشت شما برای تکمیل گذرواژه‌ها استفاده شود یا نه اسکن کارت جدید برچسب (ساتن) -بازگشت +برگشتن کاغذ (جوهرافشان) اطلاعات کارت ذخیره شد محافظت از حساب @@ -3089,7 +3089,7 @@ نمی‌توان با حساب مصرف‌کننده ثبت‌نام کرد (مجوز بسته‌بندی دردسترس است). نوع «زیرنویس زنده ناشنوایان» برای این رسانه دردسترس نیست. برای دریافت زیرنویس ناشنوایان، را برای این سایت مسدود کنید. -راستی‌آزمایی +درستی‌سنجی بخش محتوای جاسازی‌شده ۴۸ × ۳۶ اینچ @@ -3745,7 +3745,7 @@ ‏هم سرورهای پروکسی ثابت و هم آدرس اسکریپت pac. مشخص شده‌اند. ۵ × ۳٫۵ اینچ موتورهای جستجو -درهرصورت هم‌رسانی شود +به‌هرحال هم‌رسانی شود Google Drive صامت (پیش‌فرض) پاکت (روکش‌دار) @@ -3849,7 +3849,7 @@ دکمه «جستجوی زبانه‌ها»، برای جستجوی زبانه‌ها، فعال کنید فایل‌های دوربین، بارگیری‌ها، و نماگرفت‌ها PRC 32K -سعی مجدد +امتحان مجدد آخرین بازدید {PAYMENT_METHOD,plural, =0{}=1{ و روش دیگر}one{ و روش دیگر}other{ و روش دیگر}} diff -Nru chromium-145.0.7632.116/components/strings/components_strings_hi.xtb chromium-145.0.7632.159/components/strings/components_strings_hi.xtb --- chromium-145.0.7632.116/components/strings/components_strings_hi.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/components/strings/components_strings_hi.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -4429,7 +4429,7 @@ "" सही तरीके से कॉन्फ़िगर नहीं किया गया है. आमतौर पर "" को अनइंस्टॉल करने से समस्या ठीक हो जाती है. सहमति लेना ज़रूरी नहीं है मेकअप और कॉस्मेटिक -सेव करें और कीमत ट्रैक करें +कीमत सेव करके उसे ट्रैक करें इस नीति में ऐसे डेटा टाइप दिए गए हैं जो आपके मौजूदा प्लैटफ़ॉर्म पर काम नहीं करते: . कुकी सेटिंग मैनेज करती है आपने अभी-अभी जिस साइट पर अपना पासवर्ड डाला है वह सुरक्षित नहीं है. क्रोमियम इसमें आपकी मदद कर सकता है. अपना पासवर्ड बदलने और Google को यह बताने के लिए कि आपका खाता सुरक्षित नहीं है, 'खाता सुरक्षित करें' पर क्लिक करें. diff -Nru chromium-145.0.7632.116/components/strings/components_strings_hu.xtb chromium-145.0.7632.159/components/strings/components_strings_hu.xtb --- chromium-145.0.7632.116/components/strings/components_strings_hu.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/components/strings/components_strings_hu.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -4099,7 +4099,7 @@ Eltávolítja az otthoni címet a Chrome automatikus kitöltés funkciójából? Jelentkezzen be a fotó mentéséhez Kötelező -Kérd a szülő segítségét +Kérd a szülőd segítségét A(z) elindul… A kapcsolódási hibák elhárítása Ez a weboldal korábban megadott adatokat kér ahhoz, hogy megfelelően jelenjen meg. Az adatokat újra elküldheti, de ezzel meg fog ismételni minden olyan műveletet, amelyet ez az oldal korábban végrehajtott. diff -Nru chromium-145.0.7632.116/components/strings/components_strings_kn.xtb chromium-145.0.7632.159/components/strings/components_strings_kn.xtb --- chromium-145.0.7632.116/components/strings/components_strings_kn.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/components/strings/components_strings_kn.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -1711,7 +1711,7 @@ ವೆಬ್ ಕ್ಯಾಲೆಂಡರ್ ಮೊಬೈಲ್ ಡೇಟಾ ಅಥವಾ ವೈ-ಫೈ ಆನ್ ಮಾಡಲಾಗುತ್ತಿದೆ {0,plural, =1{ಫೈಲ್ ಅನ್ನು ಅಪ್‌ಲೋಡ್ ಮಾಡದಂತೆ ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ}one{ ಫೈಲ್‌ಗಳನ್ನು ಅಪ್‌ಲೋಡ್ ಮಾಡದಂತೆ ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ}other{ ಫೈಲ್‌ಗಳನ್ನು ಅಪ್‌ಲೋಡ್ ಮಾಡದಂತೆ ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ}} -ವೈ-ಫೈಗೆ ಸಂಪರ್ಕಿಸಿ +ವೈ-ಫೈಗೆ ಕನೆಕ್ಟ್ ಮಾಡಿ ಪ್ರಾಕ್ಸಿ, ಫೈರ್‌ವಾಲ್ ಮತ್ತು DNS ಕಾನ್ಫಿಗರೇಶನ್‌‌ ಪರಿಶೀಲಿಸಲಾಗುತ್ತಿದೆ ಐಬಾನ್‌ ಅಪ್‌ಡೇಟ್‌ ಸಮಯದಲ್ಲಿ ನಿಮ್ಮ ಸಾಧನವನ್ನು 10 ನಿಮಿಷಗಳವರೆಗೆ ಬಳಸಲು ನಿಮಗೆ ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ. diff -Nru chromium-145.0.7632.116/components/strings/components_strings_pt-BR.xtb chromium-145.0.7632.159/components/strings/components_strings_pt-BR.xtb --- chromium-145.0.7632.116/components/strings/components_strings_pt-BR.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/components/strings/components_strings_pt-BR.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -4524,7 +4524,7 @@ Para ver mais informações e políticas que podem ser aplicadas, abra chrome://management no navegador. x mm , -Chassi (número de identificação do veículo) +NIV (número de identificação do veículo) Temperatura da plataforma Preparando o arquivo Para ativar essas configurações e usar as informações de pagamento da sua Conta do Google, acesse as configurações do preenchimento automático. diff -Nru chromium-145.0.7632.116/components/strings/components_strings_ru.xtb chromium-145.0.7632.159/components/strings/components_strings_ru.xtb --- chromium-145.0.7632.116/components/strings/components_strings_ru.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/components/strings/components_strings_ru.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -2593,7 +2593,7 @@ Блокировка клавиатуры разрешена Цветы Окно подтверждения -Польский +Доработать Управление адресами… Неверный код. Приложение запрашивает разрешение на установку учетных данных Wi-Fi. Это позволит устройству автоматически подключаться к связанным сетям Wi-Fi. Чтобы стереть эти учетные данные, удалите приложение. diff -Nru chromium-145.0.7632.116/components/strings/components_strings_sq.xtb chromium-145.0.7632.159/components/strings/components_strings_sq.xtb --- chromium-145.0.7632.116/components/strings/components_strings_sq.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/components/strings/components_strings_sq.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -4561,7 +4561,7 @@ Fshi skedarët pas orësh Tabakaja 11 Tani ofrohen veçori të tjera të privatësisë së reklamave -Kapërce +Anashkalo Fshi lejen e drejtimit Mirëmbajtje kopshti Njihu me identifikuesin unik të pajisjes tënde diff -Nru chromium-145.0.7632.116/components/strings/components_strings_sr-Latn.xtb chromium-145.0.7632.159/components/strings/components_strings_sr-Latn.xtb --- chromium-145.0.7632.116/components/strings/components_strings_sr-Latn.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/components/strings/components_strings_sr-Latn.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -364,7 +364,7 @@ Google Chrome pokušava da uključi Windows Hello za popunjavanje lozinki. x in Verifikuje se način plaćanja -Uvid u kupovinu +Uvid za kupovinu Vaša organizacija je blokirala ovaj sajt CVC Došlo je do greške pri prikazivanju ove veb-stranice. @@ -3576,7 +3576,7 @@ Ovaj IBAN nije sačuvan na Google nalogu. Umesto toga, sačuvan je u Chrome-u na ovom uređaju. Da biste dobili ovu adresu na svim uređajima, potvrdite svoj identitet Vesti -Prethodno +Nazad <Unesite termin za pretragu> Token za registraciju: Došlo je do greške sa proksi serverom ili je adresa netačna. @@ -4296,7 +4296,7 @@ WiFi mreža koju koristite () će možda zahtevati da posetite stranicu za prijavljivanje. Šta je to lista za kupovinu? Snimanje ekrana je počelo -Uvid u kupovinu +Uvid za kupovinu Načini plaćanja dostupni za izbor da bi se nastavilo sa plaćanjem. Tastatura je sakrivena. Idemo Grupisana istorija diff -Nru chromium-145.0.7632.116/components/strings/components_strings_sr.xtb chromium-145.0.7632.159/components/strings/components_strings_sr.xtb --- chromium-145.0.7632.116/components/strings/components_strings_sr.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/components/strings/components_strings_sr.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -364,7 +364,7 @@ Google Chrome покушава да укључи Windows Hello за попуњавање лозинки. x in Верификује се начин плаћања -Увид у куповину +Увид за куповину Ваша организација је блокирала овај сајт CVC Дошло је до грешке при приказивању ове веб-странице. @@ -3576,7 +3576,7 @@ Овај IBAN није сачуван на Google налогу. Уместо тога, сачуван је у Chrome-у на овом уређају. Да бисте добили ову адресу на свим уређајима, потврдите свој идентитет Вести -Претходно +Назад <Унесите термин за претрагу> Токен за регистрацију: Дошло је до грешке са прокси сервером или је адреса нетачна. @@ -4296,7 +4296,7 @@ WiFi мрежа коју користите () ће можда захтевати да посетите страницу за пријављивање. Шта је то листа за куповину? Снимање екрана је почело -Увид у куповину +Увид за куповину Начини плаћања доступни за избор да би се наставило са плаћањем. Тастатура је сакривена. Идемо Груписана историја diff -Nru chromium-145.0.7632.116/components/strings/components_strings_sw.xtb chromium-145.0.7632.159/components/strings/components_strings_sw.xtb --- chromium-145.0.7632.116/components/strings/components_strings_sw.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/components/strings/components_strings_sw.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -1052,7 +1052,7 @@ Sheria ya Ajira na Kazi Tukio {COUNT,plural, =0{Hamna}=1{Nenosiri 1 (la )}=2{Manenosiri 2 (ya )}other{Manenosiri # (ya )}} -Ya Juu +Juu Funga vichupo au programu nyingine Tembelea tovuti Kivinjari chako hakidhibitiwi. @@ -1714,7 +1714,7 @@ kalenda ya wavuti Kuwasha data ya simu au Wi-Fi {0,plural, =1{Faili imezuiwa ili isipakiwe}other{Faili zimezuiwa ili zisipakiwe}} -Unganisha kwenye Wi-Fi +Unganisha Wi-Fi Kuangalia seva mbadala, kingamtandao na mipangilio ya DNS Iban Wakati wa kusasisha hutaweza kutumia kifaa chako kwa hadi dakika 10. diff -Nru chromium-145.0.7632.116/components/strings/components_strings_zh-CN.xtb chromium-145.0.7632.159/components/strings/components_strings_zh-CN.xtb --- chromium-145.0.7632.116/components/strings/components_strings_zh-CN.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/components/strings/components_strings_zh-CN.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -660,7 +660,7 @@ 取消屏蔽“ 上次访问时间: 音乐与舞蹈游戏 -撤消 +撤销 此政策最多只能包含 个条目。 已选择“门牌号”选项 已设置为使用系统代理设置,但同时指定了一个明确的代理配置。 diff -Nru chromium-145.0.7632.116/components/strings/components_strings_zh-TW.xtb chromium-145.0.7632.159/components/strings/components_strings_zh-TW.xtb --- chromium-145.0.7632.116/components/strings/components_strings_zh-TW.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/components/strings/components_strings_zh-TW.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -3548,7 +3548,7 @@ 切換至這個分頁 Chrome 瀏覽器正嘗試在 中填入密碼。 影片已儲存至 Google 雲端硬碟 -信用卡驗證碼已儲存 +信用卡安全碼已儲存 耳罩式耳機 信封 (普通紙) 要求的字型大小 diff -Nru chromium-145.0.7632.116/content/browser/renderer_host/render_frame_host_impl.cc chromium-145.0.7632.159/content/browser/renderer_host/render_frame_host_impl.cc --- chromium-145.0.7632.116/content/browser/renderer_host/render_frame_host_impl.cc 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/content/browser/renderer_host/render_frame_host_impl.cc 2026-03-02 23:00:09.000000000 +0000 @@ -276,6 +276,7 @@ #include "third_party/blink/public/common/loader/resource_type_util.h" #include "third_party/blink/public/common/messaging/transferable_message.h" #include "third_party/blink/public/common/navigation/navigation_params_mojom_traits.h" +#include "third_party/blink/public/common/page_state/page_state_serialization.h" #include "third_party/blink/public/common/permissions/permission_utils.h" #include "third_party/blink/public/common/permissions_policy/document_policy.h" #include "third_party/blink/public/common/runtime_feature_state/runtime_feature_state_context.h" @@ -13652,8 +13653,29 @@ bool RenderFrameHostImpl::CanAccessFilesOfPageState( const blink::PageState& state) { + // Ensure that all of the files in the PageState were actually listed in the + // GetReferencedFiles list, using a set to prune duplicates. + // See https://crbug.com/487383169. + std::vector all_files; + if (!blink::GetAllFilesInPageState(state.ToEncodedData(), &all_files)) { + // All files in the PageState weren't recovered due to parsing failures. + // The renderer should be killed instead of proceeding with a PageState that + // might still contain files that could be used without being validated. + return false; + } + std::vector referenced_files = state.GetReferencedFiles(); + std::set referenced_file_set(referenced_files.begin(), + referenced_files.end()); + for (const base::FilePath& file : all_files) { + if (!referenced_file_set.contains(file)) { + // Found a file that was not in the list to be validated, so the renderer + // should be killed. + return false; + } + } + return ChildProcessSecurityPolicyImpl::GetInstance()->CanReadAllFiles( - GetProcess()->GetDeprecatedID(), state.GetReferencedFiles()); + GetProcess()->GetDeprecatedID(), referenced_files); } void RenderFrameHostImpl::GrantFileAccessFromPageState( diff -Nru chromium-145.0.7632.116/content/browser/security_exploit_browsertest.cc chromium-145.0.7632.159/content/browser/security_exploit_browsertest.cc --- chromium-145.0.7632.116/content/browser/security_exploit_browsertest.cc 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/content/browser/security_exploit_browsertest.cc 2026-03-02 23:00:09.000000000 +0000 @@ -90,6 +90,7 @@ #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "services/network/public/cpp/network_switches.h" #include "services/network/public/cpp/resource_request.h" +#include "services/network/public/cpp/resource_request_body.h" #include "services/network/public/mojom/fetch_api.mojom.h" #include "services/network/public/mojom/trust_tokens.mojom.h" #include "services/network/public/mojom/url_loader.mojom.h" @@ -102,6 +103,7 @@ #include "third_party/blink/public/common/fenced_frame/fenced_frame_utils.h" #include "third_party/blink/public/common/frame/fenced_frame_sandbox_flags.h" #include "third_party/blink/public/common/navigation/navigation_policy.h" +#include "third_party/blink/public/common/page_state/page_state_serialization.h" #include "third_party/blink/public/mojom/blob/blob_url_store.mojom.h" #include "third_party/blink/public/mojom/choosers/file_chooser.mojom.h" #include "third_party/blink/public/mojom/fenced_frame/fenced_frame.mojom.h" @@ -1592,6 +1594,130 @@ EXPECT_EQ(bad_message::RFH_INVALID_WEB_UI_CONTROLLER, kill_waiter.Wait()); } +namespace { + +// An interceptor class that allows replacing the PageState of the DidCommit IPC +// from the renderer process to the browser process. +class DidCommitPageStateReplacer : public DidCommitNavigationInterceptor { + public: + DidCommitPageStateReplacer(WebContents* web_contents, + const blink::PageState& page_state) + : DidCommitNavigationInterceptor(web_contents), + replacement_page_state_(page_state) {} + + DidCommitPageStateReplacer(const DidCommitPageStateReplacer&) = delete; + DidCommitPageStateReplacer& operator=(const DidCommitPageStateReplacer&) = + delete; + + ~DidCommitPageStateReplacer() override = default; + + protected: + bool WillProcessDidCommitNavigation( + RenderFrameHost* render_frame_host, + NavigationRequest* navigation_request, + mojom::DidCommitProvisionalLoadParamsPtr* params, + mojom::DidCommitProvisionalLoadInterfaceParamsPtr* interface_params) + override { + (**params).page_state = replacement_page_state_; + return true; + } + + private: + blink::PageState replacement_page_state_; +}; + +} // namespace + +// Test that committing a navigation with a PageState that does not list all of +// its file paths in GetReferencedFiles will cause a renderer kill. +IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, PageStateWithUnlistedFile) { + // Navigate to foo.com initially. + GURL foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html")); + EXPECT_TRUE(NavigateToURL(shell(), foo_url)); + + // Create a PageState that contains a file path which isn't in the list of + // referenced files which are validated. + GURL foo_url2(embedded_test_server()->GetURL("foo.com", "/title2.html")); + blink::ExplodedPageState exploded_page_state; + ASSERT_TRUE(blink::DecodePageState( + blink::PageState::CreateFromURL(foo_url2).ToEncodedData(), + &exploded_page_state)); + scoped_refptr request_body = + new network::ResourceRequestBody(); + base::FilePath bad_file = base::FilePath::FromUTF8Unsafe("/tmp/offlimits"); + request_body->AppendFileRange( + bad_file, 0, std::numeric_limits::max(), base::Time()); + exploded_page_state.top.http_body.request_body = request_body; + exploded_page_state.top.http_body.http_content_type = u"text/plain"; + std::string encoded_page_state; + blink::EncodePageState(exploded_page_state, &encoded_page_state); + blink::PageState page_state = + blink::PageState::CreateFromEncodedData(encoded_page_state); + + // Create an interceptor which will put the modified PageState into the next + // navigation's DidCommit message. + DidCommitPageStateReplacer page_state_replacer(shell()->web_contents(), + page_state); + + // Navigate in the same renderer process to send the bad PageState. + RenderFrameHostImpl* rfh = static_cast( + shell()->web_contents()->GetPrimaryMainFrame()); + RenderProcessHostBadIpcMessageWaiter kill_waiter(rfh->GetProcess()); + EXPECT_TRUE(NavigateToURLAndExpectNoCommit(shell(), foo_url2)); + + // Verify that the malicious renderer was killed, for the right reason. + EXPECT_EQ(bad_message::RFH_CAN_ACCESS_FILES_OF_PAGE_STATE_AT_COMMIT, + kill_waiter.Wait()); +} + +// Similar to the test above, but also uses a malformed DocumentState within the +// corrupted PageState, to make it harder to find file paths that are present. +IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest, + PageStateWithUnlistedFileAndBadDocumentState) { + // Navigate to foo.com initially. + GURL foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html")); + EXPECT_TRUE(NavigateToURL(shell(), foo_url)); + + // Create a PageState that contains a file path which isn't in the list of + // referenced files which are validated. + GURL foo_url2(embedded_test_server()->GetURL("foo.com", "/title2.html")); + blink::ExplodedPageState exploded_page_state; + ASSERT_TRUE(blink::DecodePageState( + blink::PageState::CreateFromURL(foo_url2).ToEncodedData(), + &exploded_page_state)); + scoped_refptr request_body = + new network::ResourceRequestBody(); + base::FilePath bad_file = base::FilePath::FromUTF8Unsafe("/tmp/offlimits"); + request_body->AppendFileRange( + bad_file, 0, std::numeric_limits::max(), base::Time()); + exploded_page_state.top.http_body.request_body = request_body; + exploded_page_state.top.http_body.http_content_type = u"text/plain"; + + // Also modify the DocumentState to force RecursivelyAppendReferencedFiles to + // return false. + exploded_page_state.top.document_state = {u"one", u"two"}; + + std::string encoded_page_state; + blink::EncodePageState(exploded_page_state, &encoded_page_state); + blink::PageState page_state = + blink::PageState::CreateFromEncodedData(encoded_page_state); + + // Create an interceptor which will put the modified PageState into the next + // navigation's DidCommit message. + DidCommitPageStateReplacer page_state_replacer(shell()->web_contents(), + page_state); + + // Navigate in the same renderer process to send the bad PageState. + RenderFrameHostImpl* rfh = static_cast( + shell()->web_contents()->GetPrimaryMainFrame()); + RenderProcessHostBadIpcMessageWaiter kill_waiter(rfh->GetProcess()); + EXPECT_TRUE(NavigateToURLAndExpectNoCommit(shell(), foo_url2)); + + // Verify that the malicious renderer was killed, for the right reason. + EXPECT_EQ(bad_message::RFH_CAN_ACCESS_FILES_OF_PAGE_STATE_AT_COMMIT, + kill_waiter.Wait()); +} + class BeginNavigationTransitionReplacer : public FrameHostInterceptor { public: BeginNavigationTransitionReplacer(WebContents* web_contents, diff -Nru chromium-145.0.7632.116/debian/changelog chromium-145.0.7632.159/debian/changelog --- chromium-145.0.7632.116/debian/changelog 2026-02-26 03:14:31.000000000 +0000 +++ chromium-145.0.7632.159/debian/changelog 2026-03-04 23:24:02.000000000 +0000 @@ -1,3 +1,33 @@ +chromium (145.0.7632.159-1~deb13u1) trixie-security; urgency=high + + [ Andres Salomon ] + * New upstream security release. + - CVE-2026-3536: Integer overflow in ANGLE. Reported by cinzinga. + - CVE-2026-3537: Object lifecycle issue in PowerVR. + Reported by Zhihua Yao of KunLun Lab. + - CVE-2026-3538: Integer overflow in Skia. + Reported by Symeon Paraschoudis. + - CVE-2026-3539: Object lifecycle issue in DevTools. + Reported by Zhenpeng (Leo) Lin at depthfirst. + - CVE-2026-3540: Inappropriate implementation in WebAudio. + Reported by Davi Antônio Cruz. + - CVE-2026-3541: Inappropriate implementation in CSS. Reported by Syn4pse. + - CVE-2026-3542: Inappropriate implementation in WebAssembly. + Reported by qymag1c. + - CVE-2026-3543: Inappropriate implementation in V8. Reported by qymag1c. + - CVE-2026-3544: Heap buffer overflow in WebCodecs. + Reported by c6eed09fc8b174b0f3eebedcceb1e792. + - CVE-2026-3545: Insufficient data validation in Navigation. + Reported by Google. + + [ Daniel Richard G. ] + * Re-bundle libxslt, to fix crashes due to an ABI incompatibility between + the bundled libxml2 and the system libxml2 used by the system libxslt. + - d/clean, d/control, d/copyright: Remove libxslt references. + - d/scripts/unbundle: Add entry for libxslt. + + -- Andres Salomon Wed, 04 Mar 2026 18:24:02 -0500 + chromium (145.0.7632.116-1~deb13u1) trixie-security; urgency=high * New upstream security release. diff -Nru chromium-145.0.7632.116/debian/clean chromium-145.0.7632.159/debian/clean --- chromium-145.0.7632.116/debian/clean 2026-01-21 10:06:03.000000000 +0000 +++ chromium-145.0.7632.159/debian/clean 2026-03-04 19:10:49.000000000 +0000 @@ -13,7 +13,6 @@ third_party/opus/BUILD.gn third_party/libpng/BUILD.gn third_party/libjpeg/BUILD.gn -third_party/libxslt/BUILD.gn third_party/openh264/BUILD.gn third_party/freetype/BUILD.gn third_party/fontconfig/BUILD.gn diff -Nru chromium-145.0.7632.116/debian/control chromium-145.0.7632.159/debian/control --- chromium-145.0.7632.116/debian/control 2026-02-11 22:40:35.000000000 +0000 +++ chromium-145.0.7632.159/debian/control 2026-03-04 19:10:49.000000000 +0000 @@ -72,7 +72,6 @@ libxtst-dev, libjpeg-dev, libgtk-3-dev, - libxslt1-dev, liblcms2-dev, libpulse-dev, libpam0g-dev, diff -Nru chromium-145.0.7632.116/debian/copyright chromium-145.0.7632.159/debian/copyright --- chromium-145.0.7632.116/debian/copyright 2026-02-11 22:40:35.000000000 +0000 +++ chromium-145.0.7632.159/debian/copyright 2026-03-04 19:10:49.000000000 +0000 @@ -131,7 +131,6 @@ third_party/libusb third_party/libxml/mac third_party/libxml/win32 - third_party/libxslt third_party/litert/src third_party/llvm* third_party/lzma_sdk/bin diff -Nru chromium-145.0.7632.116/debian/scripts/unbundle chromium-145.0.7632.159/debian/scripts/unbundle --- chromium-145.0.7632.116/debian/scripts/unbundle 2026-01-21 10:06:03.000000000 +0000 +++ chromium-145.0.7632.159/debian/scripts/unbundle 2026-03-04 19:10:49.000000000 +0000 @@ -50,6 +50,7 @@ 'libyuv' , 'libwebp', # libavif depends on libsharpyuv-dev; only in libwebp 1.3 (trixie) 'libxml', # trixie includes libxml2 2.9, which lacks security feature XML_PARSE_NO_XXE + 'libxslt', # avoid mismatched libxml2 via transitive dependency 're2', # experienced crashes Aug 2023 w/ 20230301-3; try >= 20240401. 'simdutf', # not packaged in debian 'snappy', diff -Nru chromium-145.0.7632.116/gpu/command_buffer/service/context_group.cc chromium-145.0.7632.159/gpu/command_buffer/service/context_group.cc --- chromium-145.0.7632.116/gpu/command_buffer/service/context_group.cc 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/gpu/command_buffer/service/context_group.cc 2026-03-02 23:00:09.000000000 +0000 @@ -120,9 +120,17 @@ use_passthrough_cmd_decoder_ = gpu_preferences_.use_passthrough_cmd_decoder; } - gpu::ContextResult ContextGroup::Initialize(DecoderContext* decoder, ContextType context_type) { + return InitializeWithCompleteFramebufferForWorkarounds(decoder, context_type, + 0); +} + +gpu::ContextResult +ContextGroup::InitializeWithCompleteFramebufferForWorkarounds( + DecoderContext* decoder, + ContextType context_type, + uint32_t complete_fbo_for_workarounds) { switch (context_type) { case CONTEXT_TYPE_WEBGL1: if (kGpuFeatureStatusBlocklisted == @@ -156,8 +164,9 @@ DisallowedFeatures adjusted_disallowed_features = GetDisallowedFeatures(context_type); - feature_info_->Initialize(context_type, use_passthrough_cmd_decoder_, - adjusted_disallowed_features); + feature_info_->InitializeWithCompleteFramebufferForWorkarounds( + context_type, use_passthrough_cmd_decoder_, adjusted_disallowed_features, + complete_fbo_for_workarounds); // Fail early if ES3 is requested and driver does not support it. if ((context_type == CONTEXT_TYPE_WEBGL2 || diff -Nru chromium-145.0.7632.116/gpu/command_buffer/service/context_group.h chromium-145.0.7632.159/gpu/command_buffer/service/context_group.h --- chromium-145.0.7632.116/gpu/command_buffer/service/context_group.h 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/gpu/command_buffer/service/context_group.h 2026-03-02 23:00:09.000000000 +0000 @@ -72,7 +72,10 @@ // call to destroy if it succeeds. gpu::ContextResult Initialize(DecoderContext* decoder, ContextType context_type); - + gpu::ContextResult InitializeWithCompleteFramebufferForWorkarounds( + DecoderContext* decoder, + ContextType context_type, + uint32_t complete_fbo_for_workarounds); // Destroys all the resources when called for the last context in the group. // It should only be called by DecoderContext. void Destroy(DecoderContext* decoder, bool have_context); diff -Nru chromium-145.0.7632.116/gpu/command_buffer/service/decoder_context.h chromium-145.0.7632.159/gpu/command_buffer/service/decoder_context.h --- chromium-145.0.7632.116/gpu/command_buffer/service/decoder_context.h 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/gpu/command_buffer/service/decoder_context.h 2026-03-02 23:00:09.000000000 +0000 @@ -140,6 +140,12 @@ virtual gles2::ErrorState* GetErrorState() = 0; // + // Methods required by GLES2 Decoder helpers + // + // Bind the framebuffer `service_id` and perform any workarounds needed. + virtual void BindFramebuffer(unsigned target, uint32_t service_id) const = 0; + + // // Methods required by Texture. // // Indicates whether a given internal format is one for a compressed diff -Nru chromium-145.0.7632.116/gpu/command_buffer/service/feature_info.cc chromium-145.0.7632.159/gpu/command_buffer/service/feature_info.cc --- chromium-145.0.7632.116/gpu/command_buffer/service/feature_info.cc 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/gpu/command_buffer/service/feature_info.cc 2026-03-02 23:00:09.000000000 +0000 @@ -63,7 +63,8 @@ bool IsWebGLDrawBuffersSupported(bool webglCompatibilityContext, GLenum depth_texture_internal_format, - GLenum depth_stencil_texture_internal_format) { + GLenum depth_stencil_texture_internal_format, + GLuint complete_fbo_for_workarounds) { // This is called after we make sure GL_EXT_draw_buffers is supported. GLint max_draw_buffers = 0; GLint max_color_attachments = 0; @@ -80,6 +81,9 @@ GLuint fbo; glGenFramebuffersEXT(1, &fbo); + if (complete_fbo_for_workarounds) { + glBindFramebufferEXT(GL_FRAMEBUFFER, complete_fbo_for_workarounds); + } glBindFramebufferEXT(GL_FRAMEBUFFER, fbo); GLuint depth_stencil_texture = 0; @@ -156,6 +160,9 @@ } } + if (complete_fbo_for_workarounds) { + glBindFramebufferEXT(GL_FRAMEBUFFER, complete_fbo_for_workarounds); + } glBindFramebufferEXT(GL_FRAMEBUFFER, static_cast(fb_binding)); glDeleteFramebuffersEXT(1, &fbo); @@ -235,6 +242,15 @@ void FeatureInfo::Initialize(ContextType context_type, bool is_passthrough_cmd_decoder, const DisallowedFeatures& disallowed_features) { + InitializeWithCompleteFramebufferForWorkarounds( + context_type, is_passthrough_cmd_decoder, disallowed_features, 0); +} + +void FeatureInfo::InitializeWithCompleteFramebufferForWorkarounds( + ContextType context_type, + bool is_passthrough_cmd_decoder, + const DisallowedFeatures& disallowed_features, + unsigned complete_fbo_for_workarounds) { if (initialized_) { DCHECK_EQ(context_type, context_type_); DCHECK_EQ(is_passthrough_cmd_decoder, is_passthrough_cmd_decoder_); @@ -245,14 +261,14 @@ disallowed_features_ = disallowed_features; context_type_ = context_type; is_passthrough_cmd_decoder_ = is_passthrough_cmd_decoder; - InitializeFeatures(); + InitializeFeatures(complete_fbo_for_workarounds); initialized_ = true; } void FeatureInfo::ForceReinitialize() { CHECK(initialized_); CHECK(is_passthrough_cmd_decoder_); - InitializeFeatures(); + InitializeFeatures(0); } void FeatureInfo::InitializeForTesting( @@ -274,7 +290,7 @@ DisallowedFeatures()); } -bool IsGL_REDSupportedOnFBOs() { +bool IsGL_REDSupportedOnFBOs(uint32_t complete_fbo_for_workarounds) { #if BUILDFLAG(IS_MAC) // The glTexImage2D call below can hang on Mac so skip this since it's only // really needed to workaround a Mesa issue. See https://crbug.com/1158744. @@ -308,6 +324,9 @@ GL_UNSIGNED_BYTE, nullptr); GLuint textureFBOID = 0; glGenFramebuffersEXT(1, &textureFBOID); + if (complete_fbo_for_workarounds) { + glBindFramebufferEXT(GL_FRAMEBUFFER, complete_fbo_for_workarounds); + } glBindFramebufferEXT(GL_FRAMEBUFFER, textureFBOID); glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0); @@ -316,6 +335,9 @@ glDeleteFramebuffersEXT(1, &textureFBOID); glDeleteTextures(1, &textureId); + if (complete_fbo_for_workarounds) { + glBindFramebufferEXT(GL_FRAMEBUFFER, complete_fbo_for_workarounds); + } glBindFramebufferEXT(GL_FRAMEBUFFER, static_cast(fb_binding)); glBindTexture(GL_TEXTURE_2D, static_cast(tex_binding)); @@ -473,7 +495,7 @@ } } -void FeatureInfo::InitializeFeatures() { +void FeatureInfo::InitializeFeatures(uint32_t complete_fbo_for_workarounds) { // Figure out what extensions to turn on. std::string extensions_string(gl::GetGLExtensionsFromCurrentContext()); gfx::ExtensionSet extensions(gfx::MakeExtensionSet(extensions_string)); @@ -1261,9 +1283,9 @@ can_emulate_es2_draw_buffers_on_es3_nv) && (context_type_ == CONTEXT_TYPE_OPENGLES2 || (context_type_ == CONTEXT_TYPE_WEBGL1 && - IsWebGLDrawBuffersSupported(is_webgl_compatibility_context, - depth_texture_format, - depth_stencil_texture_format))); + IsWebGLDrawBuffersSupported( + is_webgl_compatibility_context, depth_texture_format, + depth_stencil_texture_format, complete_fbo_for_workarounds))); if (have_es2_draw_buffers) { AddExtensionString("GL_EXT_draw_buffers"); feature_flags_.ext_draw_buffers = true; @@ -1384,7 +1406,7 @@ if ((gl_version_info_->is_es3 || gfx::HasExtension(extensions, "GL_EXT_texture_rg")) && - IsGL_REDSupportedOnFBOs()) { + IsGL_REDSupportedOnFBOs(complete_fbo_for_workarounds)) { feature_flags_.ext_texture_rg = true; AddExtensionString("GL_EXT_texture_rg"); diff -Nru chromium-145.0.7632.116/gpu/command_buffer/service/feature_info.h chromium-145.0.7632.159/gpu/command_buffer/service/feature_info.h --- chromium-145.0.7632.116/gpu/command_buffer/service/feature_info.h 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/gpu/command_buffer/service/feature_info.h 2026-03-02 23:00:09.000000000 +0000 @@ -163,6 +163,14 @@ bool is_passthrough_cmd_decoder, const DisallowedFeatures& disallowed_features); + // Same as initialize but with a provided `complete_fbo_for_workarounds` to + // use with the ensure_previous_framebuffer_not_deleted driver bug workaround. + void InitializeWithCompleteFramebufferForWorkarounds( + ContextType context_type, + bool is_passthrough_cmd_decoder, + const DisallowedFeatures& disallowed_features, + uint32_t complete_fbo_for_workarounds); + // Same as above, but allows reinitialization. void ForceReinitialize(); @@ -250,7 +258,7 @@ void AddExtensionString(std::string_view s); void InitializeBasicState(const base::CommandLine* command_line); - void InitializeFeatures(); + void InitializeFeatures(uint32_t complete_fbo_for_workarounds); void InitializeFloatAndHalfFloatFeatures(const gfx::ExtensionSet& extensions); void EnableANGLEInstancedArrayIfPossible(const gfx::ExtensionSet& extensions); diff -Nru chromium-145.0.7632.116/gpu/command_buffer/service/gles2_cmd_copy_tex_image.cc chromium-145.0.7632.159/gpu/command_buffer/service/gles2_cmd_copy_tex_image.cc --- chromium-145.0.7632.116/gpu/command_buffer/service/gles2_cmd_copy_tex_image.cc 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/gpu/command_buffer/service/gles2_cmd_copy_tex_image.cc 2026-03-02 23:00:09.000000000 +0000 @@ -185,7 +185,7 @@ // framebuffer is copying from a texture and sample directly from that texture // instead of doing an extra copy - glBindFramebufferEXT(GL_FRAMEBUFFER, source_framebuffer); + decoder->BindFramebuffer(GL_FRAMEBUFFER, source_framebuffer); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, scratch_textures_[0]); glCopyTexImage2D(GL_TEXTURE_2D, 0, source_framebuffer_internal_format, x, y, @@ -217,7 +217,7 @@ glTexImage2D(GL_TEXTURE_2D, 0, compatability_format, width, height, 0, compatability_format, luma_type, nullptr); - glBindFramebufferEXT(GL_FRAMEBUFFER, scratch_fbo_); + decoder->BindFramebuffer(GL_FRAMEBUFFER, scratch_fbo_); glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, scratch_textures_[1], 0); diff -Nru chromium-145.0.7632.116/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc chromium-145.0.7632.159/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc --- chromium-145.0.7632.116/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc 2026-03-02 23:00:09.000000000 +0000 @@ -492,7 +492,8 @@ glDeleteShader(shader); } -bool BindFramebufferTexture2D(GLenum target, +bool BindFramebufferTexture2D(DecoderContext* decoder, + GLenum target, GLuint texture_id, GLint level, GLuint framebuffer) { @@ -512,7 +513,7 @@ glTexParameterf(binding_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(binding_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(binding_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glBindFramebufferEXT(GL_FRAMEBUFFER, framebuffer); + decoder->BindFramebuffer(GL_FRAMEBUFFER, framebuffer); glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, texture_id, level); @@ -546,7 +547,7 @@ DCHECK(dest_binding_target == GL_TEXTURE_2D || dest_binding_target == GL_TEXTURE_CUBE_MAP); DCHECK(source_level == 0 || decoder->GetFeatureInfo()->IsES3Capable()); - if (BindFramebufferTexture2D(source_target, source_id, source_level, + if (BindFramebufferTexture2D(decoder, source_target, source_id, source_level, framebuffer)) { glBindTexture(dest_binding_target, dest_id); glTexParameterf(dest_binding_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -604,7 +605,7 @@ DCHECK(dest_binding_target == GL_TEXTURE_2D || dest_binding_target == GL_TEXTURE_CUBE_MAP); DCHECK(source_level == 0 || decoder->GetFeatureInfo()->IsES3Capable()); - if (BindFramebufferTexture2D(source_target, source_id, source_level, + if (BindFramebufferTexture2D(decoder, source_target, source_id, source_level, framebuffer)) { glBindTexture(dest_binding_target, dest_id); glTexParameterf(dest_binding_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -769,7 +770,7 @@ DCHECK(dest_binding_target == GL_TEXTURE_2D || dest_binding_target == GL_TEXTURE_CUBE_MAP); DCHECK(source_level == 0 || decoder->GetFeatureInfo()->IsES3Capable()); - if (BindFramebufferTexture2D(source_target, source_id, source_level, + if (BindFramebufferTexture2D(decoder, source_target, source_id, source_level, framebuffer)) { glBindTexture(dest_binding_target, dest_id); glTexParameterf(dest_binding_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -1343,7 +1344,7 @@ (y + height / 2.f) * m_y / source_height); DCHECK(dest_level == 0 || decoder->GetFeatureInfo()->IsES3Capable()); - if (BindFramebufferTexture2D(dest_target, dest_id, dest_level, + if (BindFramebufferTexture2D(decoder, dest_target, dest_id, dest_level, framebuffer_)) { #ifndef NDEBUG // glValidateProgram of MACOSX validates FBO unlike other platforms, so diff -Nru chromium-145.0.7632.116/gpu/command_buffer/service/gles2_cmd_decoder.cc chromium-145.0.7632.159/gpu/command_buffer/service/gles2_cmd_decoder.cc --- chromium-145.0.7632.116/gpu/command_buffer/service/gles2_cmd_decoder.cc 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/gpu/command_buffer/service/gles2_cmd_decoder.cc 2026-03-02 23:00:09.000000000 +0000 @@ -674,6 +674,9 @@ // Implements GpuSwitchingObserver. void OnGpuSwitched() override; + // Bind the framebuffer `fbo` and perform any workarounds needed. + void BindFramebuffer(unsigned target, uint32_t service_id) const override; + // Restores the current state to the user's settings. void RestoreCurrentFramebufferBindings(); @@ -2417,6 +2420,10 @@ // Backbuffer attachments that are currently undefined. uint32_t backbuffer_needs_clear_bits_; + // An always-complete FBO to use for workarounds + GLuint complete_fbo_ = 0; + GLuint complete_fbo_color_texture_ = 0; + // The current decoder error communicates the decoder error through command // processing functions that do not return the error value. Should be set only // if not returning an error. @@ -2593,7 +2600,7 @@ : decoder_(decoder) { ScopedGLErrorSuppressor suppressor("ScopedFramebufferBinder::ctor", decoder_->error_state_.get()); - decoder->api()->glBindFramebufferEXTFn(GL_FRAMEBUFFER, id); + decoder->BindFramebuffer(GL_FRAMEBUFFER, id); decoder->OnFboChanged(); } @@ -2979,7 +2986,27 @@ return gpu::ContextResult::kFatalFailure; } - auto result = group_->Initialize(this, context_type); + if (workarounds().ensure_previous_framebuffer_not_deleted) { + // Use a 1x1 RGBA8 framebuffer as the "always complete" framebuffer to bind + // before binding other framebuffers + api()->glGenTexturesFn(1, &complete_fbo_color_texture_); + api()->glBindTextureFn(GL_TEXTURE_2D, complete_fbo_color_texture_); + api()->glTexImage2DFn(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, + GL_UNSIGNED_BYTE, nullptr); + + api()->glGenFramebuffersEXTFn(1, &complete_fbo_); + api()->glBindFramebufferEXTFn(GL_FRAMEBUFFER, complete_fbo_); + api()->glFramebufferTexture2DEXTFn(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + complete_fbo_color_texture_, 0); + CHECK_EQ(api()->glCheckFramebufferStatusEXTFn(GL_FRAMEBUFFER), + static_cast(GL_FRAMEBUFFER_COMPLETE)); + } + CHECK_GL_ERROR(); + + auto result = group_->InitializeWithCompleteFramebufferForWorkarounds( + this, context_type, complete_fbo_); + if (result != gpu::ContextResult::kSuccess) { // Must not destroy ContextGroup if it is not initialized. group_ = nullptr; @@ -3115,7 +3142,7 @@ state_.viewport_width = initial_size.width(); state_.viewport_height = initial_size.height(); } else { - api()->glBindFramebufferEXTFn(GL_FRAMEBUFFER, GetBackbufferServiceId()); + BindFramebuffer(GL_FRAMEBUFFER, GetBackbufferServiceId()); // These are NOT if the back buffer has these proprorties. They are // if we want the command buffer to enforce them regardless of what // the real backbuffer is assuming the real back buffer gives us more than @@ -3807,7 +3834,7 @@ if (workarounds().unbind_attachments_on_bound_render_fbo_delete) framebuffer->DoUnbindGLAttachmentsForWorkaround(target); - api()->glBindFramebufferEXTFn(target, GetBackbufferServiceId()); + BindFramebuffer(target, GetBackbufferServiceId()); state_.UpdateWindowRectanglesForBoundDrawFramebufferClientID(0); framebuffer_state_.bound_draw_framebuffer = nullptr; framebuffer_state_.clear_state_dirty = true; @@ -3815,7 +3842,7 @@ if (framebuffer == framebuffer_state_.bound_read_framebuffer.get()) { framebuffer_state_.bound_read_framebuffer = nullptr; GLenum target = GetReadFramebufferTarget(); - api()->glBindFramebufferEXTFn(target, GetBackbufferServiceId()); + BindFramebuffer(target, GetBackbufferServiceId()); } OnFboChanged(); RemoveFramebuffer(client_id); @@ -3963,33 +3990,32 @@ ProcessPendingReadPixels(false); } -static void RebindCurrentFramebuffer(gl::GLApi* api, - GLenum target, - Framebuffer* framebuffer, - GLuint back_buffer_service_id) { - GLuint framebuffer_id = framebuffer ? framebuffer->service_id() : 0; +void GLES2DecoderImpl::RestoreCurrentFramebufferBindings() { + framebuffer_state_.clear_state_dirty = true; - if (framebuffer_id == 0) { - framebuffer_id = back_buffer_service_id; - } + auto rebind_current_framebuffer = [this](GLenum target, + Framebuffer* framebuffer, + GLuint back_buffer_service_id) { + GLuint framebuffer_id = framebuffer ? framebuffer->service_id() : 0; - api->glBindFramebufferEXTFn(target, framebuffer_id); -} + if (framebuffer_id == 0) { + framebuffer_id = back_buffer_service_id; + } -void GLES2DecoderImpl::RestoreCurrentFramebufferBindings() { - framebuffer_state_.clear_state_dirty = true; + BindFramebuffer(target, framebuffer_id); + }; if (!SupportsSeparateFramebufferBinds()) { - RebindCurrentFramebuffer(api(), GL_FRAMEBUFFER, - framebuffer_state_.bound_draw_framebuffer.get(), - GetBackbufferServiceId()); - } else { - RebindCurrentFramebuffer(api(), GL_READ_FRAMEBUFFER, - framebuffer_state_.bound_read_framebuffer.get(), - GetBackbufferServiceId()); - RebindCurrentFramebuffer(api(), GL_DRAW_FRAMEBUFFER, - framebuffer_state_.bound_draw_framebuffer.get(), - GetBackbufferServiceId()); + rebind_current_framebuffer(GL_FRAMEBUFFER, + framebuffer_state_.bound_draw_framebuffer.get(), + GetBackbufferServiceId()); + } else { + rebind_current_framebuffer(GL_READ_FRAMEBUFFER, + framebuffer_state_.bound_read_framebuffer.get(), + GetBackbufferServiceId()); + rebind_current_framebuffer(GL_DRAW_FRAMEBUFFER, + framebuffer_state_.bound_draw_framebuffer.get(), + GetBackbufferServiceId()); } OnFboChanged(); } @@ -4378,6 +4404,16 @@ client()->OnGpuSwitched(); } +void GLES2DecoderImpl::BindFramebuffer(unsigned target, + uint32_t service_id) const { + if (workarounds().ensure_previous_framebuffer_not_deleted) { + DCHECK(complete_fbo_); + api()->glBindFramebufferEXTFn(target, complete_fbo_); + } + + api()->glBindFramebufferEXTFn(target, service_id); +} + void GLES2DecoderImpl::Destroy(bool have_context) { if (!initialized()) return; @@ -4427,6 +4463,13 @@ offscreen_target_frame_buffer_->Destroy(); if (offscreen_target_color_texture_.get()) offscreen_target_color_texture_->Destroy(); + + if (complete_fbo_color_texture_) { + api()->glDeleteTexturesFn(1, &complete_fbo_color_texture_); + } + if (complete_fbo_) { + api()->glDeleteFramebuffersEXTFn(1, &complete_fbo_); + } } else { if (offscreen_target_frame_buffer_.get()) offscreen_target_frame_buffer_->Invalidate(); @@ -5056,13 +5099,13 @@ ? framebuffer_state_.bound_draw_framebuffer->service_id() : GetBackbufferServiceId(); if (!SupportsSeparateFramebufferBinds()) { - api()->glBindFramebufferEXTFn(GL_FRAMEBUFFER, service_id); + BindFramebuffer(GL_FRAMEBUFFER, service_id); } else { - api()->glBindFramebufferEXTFn(GL_DRAW_FRAMEBUFFER, service_id); + BindFramebuffer(GL_DRAW_FRAMEBUFFER, service_id); service_id = framebuffer_state_.bound_read_framebuffer.get() ? framebuffer_state_.bound_read_framebuffer->service_id() : GetBackbufferServiceId(); - api()->glBindFramebufferEXTFn(GL_READ_FRAMEBUFFER, service_id); + BindFramebuffer(GL_READ_FRAMEBUFFER, service_id); } OnFboChanged(); } @@ -5203,7 +5246,7 @@ service_id = GetBackbufferServiceId(); } - api()->glBindFramebufferEXTFn(target, service_id); + BindFramebuffer(target, service_id); OnFboChanged(); } @@ -6978,8 +7021,7 @@ if (target == GL_READ_FRAMEBUFFER && draw_framebuffer != framebuffer) { // TODO(zmo): There is no guarantee that an FBO that is complete on the // READ attachment will be complete as a DRAW attachment. - api()->glBindFramebufferEXTFn(GL_DRAW_FRAMEBUFFER, - framebuffer->service_id()); + BindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer->service_id()); } state_.SetDeviceColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); state_.SetDeviceCapabilityState(GL_SCISSOR_TEST, false); @@ -7026,8 +7068,7 @@ target == GL_READ_FRAMEBUFFER && draw_framebuffer != framebuffer) { // TODO(zmo): There is no guarantee that an FBO that is complete on the // READ attachment will be complete as a DRAW attachment. - api()->glBindFramebufferEXTFn(GL_DRAW_FRAMEBUFFER, - framebuffer->service_id()); + BindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer->service_id()); } state_.SetDeviceCapabilityState(GL_SCISSOR_TEST, false); ClearDeviceWindowRectangles(); @@ -7045,7 +7086,7 @@ if (target == GL_READ_FRAMEBUFFER && draw_framebuffer != framebuffer) { GLuint service_id = draw_framebuffer ? draw_framebuffer->service_id() : GetBackbufferServiceId(); - api()->glBindFramebufferEXTFn(GL_DRAW_FRAMEBUFFER, service_id); + BindFramebuffer(GL_DRAW_FRAMEBUFFER, service_id); } } @@ -7902,7 +7943,8 @@ bool GLES2DecoderImpl::RegenerateRenderbufferIfNeeded( Renderbuffer* renderbuffer) { - if (!renderbuffer->RegenerateAndBindBackingObjectIfNeeded(workarounds())) { + if (!renderbuffer->RegenerateAndBindBackingObjectIfNeeded(this, + workarounds())) { return false; } @@ -12060,7 +12102,7 @@ GLenum fb_target = GetDrawFramebufferTarget(); GLuint fb = 0; api()->glGenFramebuffersEXTFn(1, &fb); - api()->glBindFramebufferEXTFn(fb_target, fb); + BindFramebuffer(fb_target, fb); bool have_color = (channels & GLES2Util::kRGBA) != 0; if (have_color) { @@ -12103,7 +12145,7 @@ Framebuffer* framebuffer = GetFramebufferInfoForTarget(fb_target); GLuint fb_service_id = framebuffer ? framebuffer->service_id() : GetBackbufferServiceId(); - api()->glBindFramebufferEXTFn(fb_target, fb_service_id); + BindFramebuffer(fb_target, fb_service_id); return result; } @@ -14582,8 +14624,9 @@ new FeatureInfo(workarounds(), group_->gpu_feature_info())); DisallowedFeatures disallowed_features = feature_info_->disallowed_features(); disallowed_features.AllowExtensions(); - info->Initialize(feature_info_->context_type(), - false /* is_passthrough_cmd_decoder */, disallowed_features); + info->InitializeWithCompleteFramebufferForWorkarounds( + feature_info_->context_type(), false /* is_passthrough_cmd_decoder */, + disallowed_features, complete_fbo_); bucket->SetFromString(gfx::MakeExtensionString(info->extensions()).c_str()); return error::kNoError; } diff -Nru chromium-145.0.7632.116/gpu/command_buffer/service/gles2_cmd_decoder_mock.h chromium-145.0.7632.159/gpu/command_buffer/service/gles2_cmd_decoder_mock.h --- chromium-145.0.7632.116/gpu/command_buffer/service/gles2_cmd_decoder_mock.h 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/gpu/command_buffer/service/gles2_cmd_decoder_mock.h 2026-03-02 23:00:09.000000000 +0000 @@ -147,6 +147,8 @@ int height, int depth)); MOCK_METHOD0(GetErrorState, ErrorState *()); + MOCK_CONST_METHOD2(BindFramebuffer, + void(unsigned target, uint32_t service_id)); MOCK_METHOD0(GetLogger, Logger*()); diff -Nru chromium-145.0.7632.116/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc chromium-145.0.7632.159/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc --- chromium-145.0.7632.116/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc 2026-03-02 23:00:09.000000000 +0000 @@ -1541,6 +1541,11 @@ return nullptr; } +void GLES2DecoderPassthroughImpl::BindFramebuffer(unsigned target, + uint32_t service_id) const { + NOTREACHED(); +} + void GLES2DecoderPassthroughImpl::WaitForReadPixels( base::OnceClosure callback) {} diff -Nru chromium-145.0.7632.116/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h chromium-145.0.7632.159/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h --- chromium-145.0.7632.116/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h 2026-03-02 23:00:09.000000000 +0000 @@ -315,6 +315,8 @@ ErrorState* GetErrorState() override; + void BindFramebuffer(unsigned target, uint32_t service_id) const override; + void WaitForReadPixels(base::OnceClosure callback) override; // Returns true if the context was lost either by GL_ARB_robustness, forced diff -Nru chromium-145.0.7632.116/gpu/command_buffer/service/raster_decoder.cc chromium-145.0.7632.159/gpu/command_buffer/service/raster_decoder.cc --- chromium-145.0.7632.116/gpu/command_buffer/service/raster_decoder.cc 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/gpu/command_buffer/service/raster_decoder.cc 2026-03-02 23:00:09.000000000 +0000 @@ -559,6 +559,7 @@ gles2::ContextGroup* GetContextGroup() override; gles2::ErrorState* GetErrorState() override; + void BindFramebuffer(unsigned target, uint32_t service_id) const override; bool IsCompressedTextureFormat(unsigned format) override; bool ClearLevel(gles2::Texture* texture, @@ -1596,6 +1597,11 @@ return error_state_.get(); } +void RasterDecoderImpl::BindFramebuffer(unsigned target, + uint32_t service_id) const { + NOTREACHED(); +} + bool RasterDecoderImpl::IsCompressedTextureFormat(unsigned format) { return feature_info()->validators()->compressed_texture_format.IsValid( format); diff -Nru chromium-145.0.7632.116/gpu/command_buffer/service/renderbuffer_manager.cc chromium-145.0.7632.159/gpu/command_buffer/service/renderbuffer_manager.cc --- chromium-145.0.7632.116/gpu/command_buffer/service/renderbuffer_manager.cc 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/gpu/command_buffer/service/renderbuffer_manager.cc 2026-03-02 23:00:09.000000000 +0000 @@ -15,6 +15,7 @@ #include "base/trace_event/memory_dump_manager.h" #include "base/trace_event/trace_event.h" #include "gpu/command_buffer/common/gles2_cmd_utils.h" +#include "gpu/command_buffer/service/decoder_context.h" #include "gpu/command_buffer/service/feature_info.h" #include "gpu/command_buffer/service/framebuffer_manager.h" #include "gpu/command_buffer/service/gles2_cmd_decoder.h" @@ -141,6 +142,7 @@ } bool Renderbuffer::RegenerateAndBindBackingObjectIfNeeded( + const DecoderContext* decoder, const GpuDriverBugWorkarounds& workarounds) { bool multisample_workaround = workarounds.multisample_renderbuffer_resize_emulation; @@ -167,7 +169,7 @@ // Attach new renderbuffer to all framebuffers for (auto& point : framebuffer_attachment_points_) { - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, point.first->service_id()); + decoder->BindFramebuffer(GL_DRAW_FRAMEBUFFER, point.first->service_id()); glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER, point.second, GL_RENDERBUFFER, service_id_); } diff -Nru chromium-145.0.7632.116/gpu/command_buffer/service/renderbuffer_manager.h chromium-145.0.7632.159/gpu/command_buffer/service/renderbuffer_manager.h --- chromium-145.0.7632.116/gpu/command_buffer/service/renderbuffer_manager.h 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/gpu/command_buffer/service/renderbuffer_manager.h 2026-03-02 23:00:09.000000000 +0000 @@ -22,6 +22,7 @@ namespace gpu { class GpuDriverBugWorkarounds; +class DecoderContext; namespace gles2 { @@ -79,6 +80,7 @@ // Regenerates the object backing this client_id, creating a new service_id. // Also reattaches any framebuffers using this renderbuffer. bool RegenerateAndBindBackingObjectIfNeeded( + const DecoderContext* decoder, const GpuDriverBugWorkarounds& workarounds); void AddFramebufferAttachmentPoint(Framebuffer* framebuffer, diff -Nru chromium-145.0.7632.116/gpu/command_buffer/service/webgpu_decoder_impl.cc chromium-145.0.7632.159/gpu/command_buffer/service/webgpu_decoder_impl.cc --- chromium-145.0.7632.116/gpu/command_buffer/service/webgpu_decoder_impl.cc 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/gpu/command_buffer/service/webgpu_decoder_impl.cc 2026-03-02 23:00:09.000000000 +0000 @@ -306,6 +306,9 @@ std::string_view GetLogPrefix() override { return "WebGPUDecoderImpl"; } gles2::ContextGroup* GetContextGroup() override { return nullptr; } gles2::ErrorState* GetErrorState() override { NOTREACHED(); } + void BindFramebuffer(unsigned target, uint32_t service_id) const override { + NOTREACHED(); + } bool IsCompressedTextureFormat(unsigned format) override { NOTREACHED(); } bool ClearLevel(gles2::Texture* texture, unsigned target, diff -Nru chromium-145.0.7632.116/gpu/config/gpu_driver_bug_list.json chromium-145.0.7632.159/gpu/config/gpu_driver_bug_list.json --- chromium-145.0.7632.116/gpu/config/gpu_driver_bug_list.json 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/gpu/config/gpu_driver_bug_list.json 2026-03-02 23:00:09.000000000 +0000 @@ -3817,6 +3817,17 @@ "features": [ "disable_d3d12_video_encoder" ] + }, + { + "id": 471, + "description": "IMG drivers can sometimes reference previously bound complete framebuffers.", + "os": { + "type": "android" + }, + "gl_vendor": "Imagination.*", + "features": [ + "ensure_previous_framebuffer_not_deleted" + ] } ] } diff -Nru chromium-145.0.7632.116/gpu/config/gpu_lists_version.h chromium-145.0.7632.159/gpu/config/gpu_lists_version.h --- chromium-145.0.7632.116/gpu/config/gpu_lists_version.h 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/gpu/config/gpu_lists_version.h 2026-03-02 23:00:09.000000000 +0000 @@ -3,6 +3,6 @@ #ifndef GPU_CONFIG_GPU_LISTS_VERSION_H_ #define GPU_CONFIG_GPU_LISTS_VERSION_H_ -#define GPU_LISTS_VERSION "7d28075c6a9ba147e6df449209001258bb82a122" +#define GPU_LISTS_VERSION "838c69b2e5b8cd00a916e35097249bc20eb25a0a" #endif // GPU_CONFIG_GPU_LISTS_VERSION_H_ diff -Nru chromium-145.0.7632.116/gpu/config/gpu_workaround_list.txt chromium-145.0.7632.159/gpu/config/gpu_workaround_list.txt --- chromium-145.0.7632.116/gpu/config/gpu_workaround_list.txt 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/gpu/config/gpu_workaround_list.txt 2026-03-02 23:00:09.000000000 +0000 @@ -77,6 +77,7 @@ dont_use_loops_to_initialize_variables enable_bgra8_overlays_with_yuv_overlay_support enable_webgl_timer_query_extensions +ensure_previous_framebuffer_not_deleted etc1_power_of_two_only exit_on_context_lost flush_before_create_fence diff -Nru chromium-145.0.7632.116/infra/config/dev.star chromium-145.0.7632.159/infra/config/dev.star --- chromium-145.0.7632.116/infra/config/dev.star 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/infra/config/dev.star 2026-03-02 23:00:09.000000000 +0000 @@ -77,7 +77,7 @@ default = os.LINUX_JAMMY, overrides = json.decode(io.read_file("//lib/linux-default.json")), ), - os.MAC_DEFAULT: os.MAC_15, + os.MAC_DEFAULT: "Mac-15|Mac-26", os.MAC_BETA: "Mac-15|Mac-26", os.WINDOWS_DEFAULT: os.WINDOWS_10, }, diff -Nru chromium-145.0.7632.116/infra/config/generated/luci/cr-buildbucket.cfg chromium-145.0.7632.159/infra/config/generated/luci/cr-buildbucket.cfg --- chromium-145.0.7632.116/infra/config/generated/luci/cr-buildbucket.cfg 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/infra/config/generated/luci/cr-buildbucket.cfg 2026-03-02 23:00:09.000000000 +0000 @@ -4876,7 +4876,7 @@ swarming_host: "chromium-swarm.appspot.com" dimensions: "builder:Mac Builder" dimensions: "cpu:arm64" - dimensions: "os:Mac-15" + dimensions: "os:Mac-15|Mac-26" dimensions: "pool:luci.chromium.ci" exe { cipd_package: "infra/chromium/bootstrapper/${platform}" @@ -10882,7 +10882,7 @@ swarming_host: "chromium-swarm.appspot.com" dimensions: "builder:ios-simulator" dimensions: "cpu:arm64" - dimensions: "os:Mac-15" + dimensions: "os:Mac-15|Mac-26" dimensions: "pool:luci.chromium.ci" exe { cipd_package: "infra/chromium/bootstrapper/${platform}" @@ -11002,7 +11002,7 @@ swarming_host: "chromium-swarm.appspot.com" dimensions: "builder:ios-simulator-full-configs" dimensions: "cpu:arm64" - dimensions: "os:Mac-15" + dimensions: "os:Mac-15|Mac-26" dimensions: "pool:luci.chromium.ci" exe { cipd_package: "infra/chromium/bootstrapper/${platform}" @@ -12177,7 +12177,7 @@ dimensions: "builderless:1" dimensions: "cpu:arm64" dimensions: "free_space:standard" - dimensions: "os:Mac-15" + dimensions: "os:Mac-15|Mac-26" dimensions: "pool:luci.chromium.ci" exe { cipd_package: "infra/chromium/bootstrapper/${platform}" @@ -12293,7 +12293,7 @@ swarming_host: "chromium-swarm.appspot.com" dimensions: "builder:mac-arm64-rel" dimensions: "cpu:arm64" - dimensions: "os:Mac-15" + dimensions: "os:Mac-15|Mac-26" dimensions: "pool:luci.chromium.ci" exe { cipd_package: "infra/chromium/bootstrapper/${platform}" @@ -20951,7 +20951,7 @@ swarming_host: "chromium-swarm.appspot.com" dimensions: "builderless:1" dimensions: "cpu:arm64" - dimensions: "os:Mac-15" + dimensions: "os:Mac-15|Mac-26" dimensions: "pool:luci.chromium.gpu.try" exe { cipd_package: "infra/chromium/bootstrapper/${platform}" @@ -21184,7 +21184,7 @@ swarming_host: "chromium-swarm.appspot.com" dimensions: "builder:ios-simulator-compilator" dimensions: "cpu:arm64" - dimensions: "os:Mac-15" + dimensions: "os:Mac-15|Mac-26" dimensions: "pool:luci.chromium.try" exe { cipd_package: "infra/chromium/bootstrapper/${platform}" @@ -21292,7 +21292,7 @@ swarming_host: "chromium-swarm.appspot.com" dimensions: "builder:ios-simulator-full-configs" dimensions: "cpu:arm64" - dimensions: "os:Mac-15" + dimensions: "os:Mac-15|Mac-26" dimensions: "pool:luci.chromium.try" exe { cipd_package: "infra/chromium/bootstrapper/${platform}" @@ -24502,7 +24502,7 @@ dimensions: "builderless:1" dimensions: "cpu:arm64" dimensions: "free_space:standard" - dimensions: "os:Mac-15" + dimensions: "os:Mac-15|Mac-26" dimensions: "pool:luci.chromium.try" dimensions: "ssd:1" exe { @@ -24608,7 +24608,7 @@ dimensions: "builderless:1" dimensions: "cpu:arm64" dimensions: "free_space:standard" - dimensions: "os:Mac-15" + dimensions: "os:Mac-15|Mac-26" dimensions: "pool:luci.chromium.try" dimensions: "ssd:1" exe { @@ -24725,7 +24725,7 @@ dimensions: "builderless:1" dimensions: "cpu:arm64" dimensions: "free_space:standard" - dimensions: "os:Mac-15" + dimensions: "os:Mac-15|Mac-26" dimensions: "pool:luci.chromium.try" dimensions: "ssd:1" exe { @@ -24837,7 +24837,7 @@ dimensions: "builderless:1" dimensions: "cpu:arm64" dimensions: "free_space:standard" - dimensions: "os:Mac-15" + dimensions: "os:Mac-15|Mac-26" dimensions: "pool:luci.chromium.try" dimensions: "ssd:1" exe { @@ -24949,7 +24949,7 @@ dimensions: "builderless:1" dimensions: "cpu:arm64" dimensions: "free_space:standard" - dimensions: "os:Mac-15" + dimensions: "os:Mac-15|Mac-26" dimensions: "pool:luci.chromium.try" dimensions: "ssd:1" exe { @@ -25056,7 +25056,7 @@ dimensions: "builderless:1" dimensions: "cpu:arm64" dimensions: "free_space:standard" - dimensions: "os:Mac-15" + dimensions: "os:Mac-15|Mac-26" dimensions: "pool:luci.chromium.try" dimensions: "ssd:1" exe { @@ -25163,7 +25163,7 @@ dimensions: "builderless:1" dimensions: "cpu:arm64" dimensions: "free_space:standard" - dimensions: "os:Mac-15" + dimensions: "os:Mac-15|Mac-26" dimensions: "pool:luci.chromium.try" dimensions: "ssd:1" exe { @@ -25275,7 +25275,7 @@ dimensions: "builderless:1" dimensions: "cpu:arm64" dimensions: "free_space:standard" - dimensions: "os:Mac-15" + dimensions: "os:Mac-15|Mac-26" dimensions: "pool:luci.chromium.try" dimensions: "ssd:1" exe { @@ -25382,7 +25382,7 @@ dimensions: "builderless:1" dimensions: "cpu:arm64" dimensions: "free_space:standard" - dimensions: "os:Mac-15" + dimensions: "os:Mac-15|Mac-26" dimensions: "pool:luci.chromium.try" dimensions: "ssd:1" exe { @@ -25494,7 +25494,7 @@ dimensions: "builderless:1" dimensions: "cpu:arm64" dimensions: "free_space:standard" - dimensions: "os:Mac-15" + dimensions: "os:Mac-15|Mac-26" dimensions: "pool:luci.chromium.try" dimensions: "ssd:1" exe { @@ -25601,7 +25601,7 @@ dimensions: "builderless:1" dimensions: "cpu:arm64" dimensions: "free_space:standard" - dimensions: "os:Mac-15" + dimensions: "os:Mac-15|Mac-26" dimensions: "pool:luci.chromium.try" dimensions: "ssd:1" exe { @@ -25714,7 +25714,7 @@ dimensions: "builderless:1" dimensions: "cpu:arm64" dimensions: "free_space:standard" - dimensions: "os:Mac-15" + dimensions: "os:Mac-15|Mac-26" dimensions: "pool:luci.chromium.try" dimensions: "ssd:1" exe { @@ -25821,7 +25821,7 @@ dimensions: "builderless:1" dimensions: "cpu:arm64" dimensions: "free_space:standard" - dimensions: "os:Mac-15" + dimensions: "os:Mac-15|Mac-26" dimensions: "pool:luci.chromium.try" dimensions: "ssd:1" exe { @@ -25934,7 +25934,7 @@ dimensions: "builderless:1" dimensions: "cpu:arm64" dimensions: "free_space:standard" - dimensions: "os:Mac-15" + dimensions: "os:Mac-15|Mac-26" dimensions: "pool:luci.chromium.try" dimensions: "ssd:1" exe { @@ -26159,7 +26159,7 @@ dimensions: "builderless:1" dimensions: "cpu:arm64" dimensions: "free_space:standard" - dimensions: "os:Mac-15" + dimensions: "os:Mac-15|Mac-26" dimensions: "pool:luci.chromium.try" dimensions: "ssd:1" exe { @@ -26266,7 +26266,7 @@ dimensions: "builderless:1" dimensions: "cpu:arm64" dimensions: "free_space:standard" - dimensions: "os:Mac-15" + dimensions: "os:Mac-15|Mac-26" dimensions: "pool:luci.chromium.try" dimensions: "ssd:1" exe { @@ -26373,7 +26373,7 @@ dimensions: "builderless:1" dimensions: "cpu:arm64" dimensions: "free_space:standard" - dimensions: "os:Mac-15" + dimensions: "os:Mac-15|Mac-26" dimensions: "pool:luci.chromium.try" dimensions: "ssd:1" exe { @@ -26486,7 +26486,7 @@ dimensions: "builderless:1" dimensions: "cpu:arm64" dimensions: "free_space:standard" - dimensions: "os:Mac-15" + dimensions: "os:Mac-15|Mac-26" dimensions: "pool:luci.chromium.try" dimensions: "ssd:1" exe { @@ -26593,7 +26593,7 @@ dimensions: "builderless:1" dimensions: "cpu:arm64" dimensions: "free_space:standard" - dimensions: "os:Mac-15" + dimensions: "os:Mac-15|Mac-26" dimensions: "pool:luci.chromium.try" dimensions: "ssd:1" exe { @@ -26709,7 +26709,7 @@ swarming_host: "chromium-swarm.appspot.com" dimensions: "builderless:1" dimensions: "cpu:arm64" - dimensions: "os:Mac-15" + dimensions: "os:Mac-15|Mac-26" dimensions: "pool:luci.chromium.gpu.try" exe { cipd_package: "infra/chromium/bootstrapper/${platform}" diff -Nru chromium-145.0.7632.116/infra/config/main.star chromium-145.0.7632.159/infra/config/main.star --- chromium-145.0.7632.116/infra/config/main.star 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/infra/config/main.star 2026-03-02 23:00:09.000000000 +0000 @@ -203,7 +203,7 @@ default = os.LINUX_JAMMY, overrides = json.decode(io.read_file("//lib/linux-default.json")), ), - os.MAC_DEFAULT: os.MAC_15, + os.MAC_DEFAULT: "Mac-15|Mac-26", os.MAC_BETA: "Mac-15|Mac-26", os.WINDOWS_DEFAULT: os.WINDOWS_10, }, diff -Nru chromium-145.0.7632.116/net/data/ssl/chrome_root_store/root_store.certs chromium-145.0.7632.159/net/data/ssl/chrome_root_store/root_store.certs --- chromium-145.0.7632.116/net/data/ssl/chrome_root_store/root_store.certs 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/net/data/ssl/chrome_root_store/root_store.certs 2026-03-02 23:00:09.000000000 +0000 @@ -509,130 +509,6 @@ 03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= -----END CERTIFICATE----- -# b676f2eddae8775cd36cb0f63cd1d4603961f49e6265ba013a2f0307b6d0b804 -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 21:d6:d0:4a:4f:25:0f:c9:32:37:fc:aa:5e:12:8d:e9 - Signature Algorithm: sha512WithRSAEncryption - Issuer: C = PL, O = Unizeto Technologies S.A., OU = Certum Certification Authority, CN = Certum Trusted Network CA 2 - Validity - Not Before: Oct 6 08:39:56 2011 GMT - Not After : Oct 6 08:39:56 2046 GMT - Subject: C = PL, O = Unizeto Technologies S.A., OU = Certum Certification Authority, CN = Certum Trusted Network CA 2 - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public-Key: (4096 bit) - Modulus: - 00:bd:f9:78:f8:e6:d5:80:0c:64:9d:86:1b:96:64: - 67:3f:22:3a:1e:75:01:7d:ef:fb:5c:67:8c:c9:cc: - 5c:6b:a9:91:e6:b9:42:e5:20:4b:9b:da:9b:7b:b9: - 99:5d:d9:9b:80:4b:d7:84:40:2b:27:d3:e8:ba:30: - bb:3e:09:1a:a7:49:95:ef:2b:40:24:c2:97:c7:a7: - ee:9b:25:ef:a8:0a:00:97:85:5a:aa:9d:dc:29:c9: - e2:35:07:eb:70:4d:4a:d6:c1:b3:56:b8:a1:41:38: - 9b:d1:fb:31:7f:8f:e0:5f:e1:b1:3f:0f:8e:16:49: - 60:d7:06:8d:18:f9:aa:26:10:ab:2a:d3:d0:d1:67: - 8d:1b:46:be:47:30:d5:2e:72:d1:c5:63:da:e7:63: - 79:44:7e:4b:63:24:89:86:2e:34:3f:29:4c:52:8b: - 2a:a7:c0:e2:91:28:89:b9:c0:5b:f9:1d:d9:e7:27: - ad:ff:9a:02:97:c1:c6:50:92:9b:02:2c:bd:a9:b9: - 34:59:0a:bf:84:4a:ff:df:fe:b3:9f:eb:d9:9e:e0: - 98:23:ec:a6:6b:77:16:2a:db:cc:ad:3b:1c:a4:87: - dc:46:73:5e:19:62:68:45:57:e4:90:82:42:bb:42: - d6:f0:61:e0:c1:a3:3d:66:a3:5d:f4:18:ee:88:c9: - 8d:17:45:29:99:32:75:02:31:ee:29:26:c8:6b:02: - e6:b5:62:45:7f:37:15:5a:23:68:89:d4:3e:de:4e: - 27:b0:f0:40:0c:bc:4d:17:cb:4d:a2:b3:1e:d0:06: - 5a:dd:f6:93:cf:57:75:99:f5:fa:86:1a:67:78:b3: - bf:96:fe:34:dc:bd:e7:52:56:e5:b3:e5:75:7b:d7: - 41:91:05:dc:5d:69:e3:95:0d:43:b9:fc:83:96:39: - 95:7b:6c:80:5a:4f:13:72:c6:d7:7d:29:7a:44:ba: - 52:a4:2a:d5:41:46:09:20:fe:22:a0:b6:5b:30:8d: - bc:89:0c:d5:d7:70:f8:87:52:fd:da:ef:ac:51:2e: - 07:b3:4e:fe:d0:09:da:70:ef:98:fa:56:e6:6d:db: - b5:57:4b:dc:e5:2c:25:15:c8:9e:2e:78:4e:f8:da: - 9c:9e:86:2c:ca:57:f3:1a:e5:c8:92:8b:1a:82:96: - 7a:c3:bc:50:12:69:d8:0e:5a:46:8b:3a:eb:26:fa: - 23:c9:b6:b0:81:be:42:00:a4:f8:d6:fe:30:2e:c7: - d2:46:f6:e5:8e:75:fd:f2:cc:b9:d0:87:5b:cc:06: - 10:60:bb:83:35:b7:5e:67:de:47:ec:99:48:f1:a4: - a1:15:fe:ad:8c:62:8e:39:55:4f:39:16:b9:b1:63: - 9d:ff:b7 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: critical - CA:TRUE - X509v3 Subject Key Identifier: - B6:A1:54:39:02:C3:A0:3F:8E:8A:BC:FA:D4:F8:1C:A6:D1:3A:0E:FD - X509v3 Key Usage: critical - Certificate Sign, CRL Sign - Signature Algorithm: sha512WithRSAEncryption - 71:a5:0e:ce:e4:e9:bf:3f:38:d5:89:5a:c4:02:61:fb:4c:c5: - 14:17:2d:8b:4f:53:6b:10:17:fc:65:84:c7:10:49:90:de:db: - c7:26:93:88:26:6f:70:d6:02:5e:39:a0:f7:8f:ab:96:b5:a5: - 13:5c:81:14:6d:0e:81:82:11:1b:8a:4e:c6:4f:a5:dd:62:1e: - 44:df:09:59:f4:5b:77:0b:37:e9:8b:20:c6:f8:0a:4e:2e:58: - 1c:eb:33:d0:cf:86:60:c9:da:fb:80:2f:9e:4c:60:84:78:3d: - 21:64:d6:fb:41:1f:18:0f:e7:c9:75:71:bd:bd:5c:de:34:87: - 3e:41:b0:0e:f6:b9:d6:3f:09:13:96:14:2f:de:9a:1d:5a:b9: - 56:ce:35:3a:b0:5f:70:4d:5e:e3:29:f1:23:28:72:59:b6:ab: - c2:8c:66:26:1c:77:2c:26:76:35:8b:28:a7:69:a0:f9:3b:f5: - 23:dd:85:10:74:c9:90:03:56:91:e7:af:ba:47:d4:12:97:11: - 22:e3:a2:49:94:6c:e7:b7:94:4b:ba:2d:a4:da:33:8b:4c:a6: - 44:ff:5a:3c:c6:1d:64:d8:b5:31:e4:a6:3c:7a:a8:57:0b:db: - ed:61:1a:cb:f1:ce:73:77:63:a4:87:6f:4c:51:38:d6:e4:5f: - c7:9f:b6:81:2a:e4:85:48:79:58:5e:3b:f8:db:02:82:67:c1: - 39:db:c3:74:4b:3d:36:1e:f9:29:93:88:68:5b:a8:44:19:21: - f0:a7:e8:81:0d:2c:e8:93:36:b4:37:b2:ca:b0:1b:26:7a:9a: - 25:1f:9a:9a:80:9e:4b:2a:3f:fb:a3:9a:fe:73:32:71:c2:9e: - c6:72:e1:8a:68:27:f1:e4:0f:b4:c4:4c:a5:61:93:f8:97:10: - 07:2a:30:25:a9:b9:c8:71:b8:ef:68:cc:2d:7e:f5:e0:7e:0f: - 82:a8:6f:b6:ba:6c:83:43:77:cd:8a:92:17:a1:9e:5b:78:16: - 3d:45:e2:33:72:dd:e1:66:ca:99:d3:c9:c5:26:fd:0d:68:04: - 46:ae:b6:d9:9b:8c:be:19:be:b1:c6:f2:19:e3:5c:02:ca:2c: - d8:6f:4a:07:d9:c9:35:da:40:75:f2:c4:a7:19:6f:9e:42:10: - 98:75:e6:95:8b:60:bc:ed:c5:12:d7:8a:ce:d5:98:5c:56:96: - 03:c5:ee:77:06:35:ff:cf:e4:ee:3f:13:61:ee:db:da:2d:85: - f0:cd:ae:9d:b2:18:09:45:c3:92:a1:72:17:fc:47:b6:a0:0b: - 2c:f1:c4:de:43:68:08:6a:5f:3b:f0:76:63:fb:cc:06:2c:a6: - c6:e2:0e:b5:b9:be:24:8f ------BEGIN CERTIFICATE----- -MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCB -gDELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu -QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIG -A1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAyMCIYDzIwMTExMDA2MDgz -OTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZ -VW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRp -ZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3 -b3JrIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWA -DGSdhhuWZGc/IjoedQF97/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn -0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+oCgCXhVqqndwpyeI1B+twTUrWwbNWuKFB -OJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40bRr5HMNUuctHFY9rnY3lE -fktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2puTRZCr+E -Sv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1m -o130GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02i -sx7QBlrd9pPPV3WZ9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOW -OZV7bIBaTxNyxtd9KXpEulKkKtVBRgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgez -Tv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pyehizKV/Ma5ciSixqClnrDvFAS -adgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vMBhBgu4M1t15n -3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD -AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMC -AQYwDQYJKoZIhvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQ -F/xlhMcQSZDe28cmk4gmb3DWAl45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTf -CVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuAL55MYIR4PSFk1vtBHxgP58l1cb29 -XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMoclm2q8KMZiYcdywm -djWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tMpkT/ -WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jb -AoJnwTnbw3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksq -P/ujmv5zMnHCnsZy4YpoJ/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Ko -b7a6bINDd82Kkhehnlt4Fj1F4jNy3eFmypnTycUm/Q1oBEauttmbjL4ZvrHG8hnj -XALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLXis7VmFxWlgPF7ncGNf/P -5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7zAYspsbi -DrW5viSP ------END CERTIFICATE----- - # f356bea244b7a91eb35d53ca9ad7864ace018e2d35d5f8f96ddf68a6f41aa474 Certificate: Data: @@ -10565,4 +10441,442 @@ Ao9QAwKxuDdollDruF/UKIqlIgyKhPBZLtU30WHlQnNYKoH3dtvi4k0NX/a3vgW0 rk4N3hY9A4GzJl5LuEsAz/+MF7psYC0nhzck5npgL7XTgwSqT0N1osGDsieYK7EO gLrAhV5Cud+xYJHT6xh+cHiudoO+cVrQkOPKwRYlZ0rwtnu64ZzZ +-----END CERTIFICATE----- + +# 0552e6f83fdf65e8fa9670e666df28a4e21340b510cbe52566f97c4fb94b2bd1 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 73:3b:30:04:48:5b:d9:4d:78:2e:73:4b:c9:a1:dc:66 + Signature Algorithm: sha512WithRSAEncryption + Issuer: C=DE, O=D-Trust GmbH, CN=D-TRUST BR Root CA 2 2023 + Validity + Not Before: May 9 08:56:31 2023 GMT + Not After : May 9 08:56:30 2038 GMT + Subject: C=DE, O=D-Trust GmbH, CN=D-TRUST BR Root CA 2 2023 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:ae:ff:09:59:91:80:0a:4a:68:e6:24:3f:b8:a7: + e4:c8:3a:0a:3a:16:cd:c9:23:61:a0:93:71:f2:ab: + 8b:73:8f:a0:67:65:60:d2:54:6b:63:51:6f:49:33: + e0:72:07:13:7d:38:cd:06:92:07:29:52:6b:4e:77: + 6c:04:d3:95:fa:dd:4c:8c:d9:5d:c1:61:7d:4b:e7: + 28:b3:44:81:7b:51:af:dd:33:b1:68:7c:d6:4e:4c: + fe:2b:68:b9:ca:66:69:c4:ec:5e:57:7f:f7:0d:c7: + 9c:36:36:e5:07:60:ac:c0:4c:ea:08:6c:ef:06:7c: + 4f:5b:28:7a:08:fc:93:5d:9b:f6:9c:b4:8b:86:ba: + 21:b9:f4:f0:e8:59:5a:28:a1:34:84:1a:25:91:b6: + b5:8f:ef:b2:f9:80:fa:f9:3d:3c:11:72:d8:e3:2f: + 86:76:c5:79:2c:c1:a9:90:93:46:98:67:cb:83:6a: + a0:50:23:a7:3b:f6:81:39:e0:ed:f0:b9:bf:65:f1: + d8:cb:7a:fb:ef:73:03:ce:00:f4:7d:d7:e0:5d:3b: + 66:b8:dc:8e:ba:83:cb:87:76:03:fc:25:d9:e7:23: + 6f:06:fd:67:f3:e0:ff:84:bc:47:bf:b5:16:18:46: + 69:14:cc:05:f7:db:d3:49:ac:6b:cc:ab:e4:b5:0b: + 43:24:5e:4b:6b:4d:67:df:d6:b5:3e:4f:78:1f:94: + 71:24:ea:de:70:fc:f1:93:fe:9e:93:5a:e4:94:5a: + 97:54:0c:35:7b:5f:6c:ee:00:1f:24:ec:03:ba:02: + f5:76:f4:9f:d4:9a:ed:85:2c:38:22:2f:c7:d8:2f: + 76:11:4f:fd:6c:5c:e8:f5:8e:27:87:7f:19:4a:21: + 47:90:1d:79:8d:1c:5b:f8:cf:4a:85:e4:ed:b3:5b: + 8d:be:c4:64:28:5d:41:c4:6e:ac:38:5a:4f:23:74: + 74:a9:12:c3:f6:d2:b9:11:15:33:07:91:d8:3b:37: + 3a:63:30:06:d1:c5:22:36:28:62:23:10:e0:46:cc: + 97:ac:d6:2b:5d:64:24:d5:ee:1c:0e:de:fb:08:5a: + 75:2a:f6:63:6d:ce:0b:42:be:d1:ba:70:1c:9c:21: + e5:0f:31:69:17:d7:fc:0a:b4:de:ed:80:9c:cb:92: + b4:8b:f5:de:59:a2:58:09:a5:63:47:0b:e1:41:32: + 34:41:d9:9a:b1:d9:a8:b0:1b:5a:de:0d:0d:f4:e2: + b2:5d:35:80:b9:81:d4:84:69:91:02:cb:75:d0:8d: + c5:b5:3d:09:91:09:8f:14:a1:14:74:79:3e:d6:c9: + 15:1d:a4:59:59:22:dc:f6:8a:45:3d:3c:12:d6:3e: + 5d:32:2f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + 67:90:F0:D6:DE:B5:18:D5:46:29:7E:5C:AB:F8:9E:08:BC:64:95:10 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 CRL Distribution Points: + Full Name: + URI:http://crl.d-trust.net/crl/d-trust_br_root_ca_2_2023.crl + + Signature Algorithm: sha512WithRSAEncryption + Signature Value: + 34:f7:b3:77:53:db:30:16:b9:2d:a5:21:f1:40:21:75:eb:eb: + 48:16:81:3d:73:e0:9e:27:2a:eb:77:a9:13:a4:6a:0a:5a:5a: + 14:33:3d:68:1f:81:ae:69:fd:8c:9f:65:6c:34:42:d9:2d:d0: + 7f:78:16:b1:3a:ac:23:31:ad:5e:7f:ae:e7:ae:2b:fa:ba:fc: + 3c:97:95:40:93:5f:c3:2d:03:a3:ed:a4:6f:53:d7:fa:40:0e: + 30:f5:00:20:2c:00:4c:8c:3b:b4:a3:1f:b6:bf:91:32:ab:af: + 92:98:d3:16:e6:d4:d1:54:5c:43:5b:2e:ae:ef:57:2a:a8:b4: + 6f:a4:ef:0d:56:14:da:21:ab:20:76:9e:03:fc:26:b8:9e:3f: + 3e:03:26:e6:4c:db:9d:5f:42:84:3d:45:03:03:1c:59:88:ca: + dc:2e:61:24:5a:a4:ea:27:0b:73:12:be:52:b3:0a:cf:32:17: + e2:1e:87:1a:16:95:48:6d:5a:e0:d0:cf:09:92:26:66:91:d8: + a3:61:0e:aa:81:81:7f:e8:52:82:d1:42:e7:e0:1d:18:fa:a4: + 85:36:e7:86:e0:0d:eb:bc:d4:c9:d6:3c:43:f1:5d:49:6e:7e: + 81:9b:69:b5:89:62:8f:88:52:d8:d7:fe:27:c1:23:c5:cb:2b: + 02:bb:b1:5f:fe:fb:43:85:03:46:be:5d:c6:ca:21:26:ff:d7: + 02:9e:74:4a:dc:f8:13:15:b1:81:57:36:cb:65:5c:d1:1d:31: + 77:e9:25:c3:c3:b2:32:37:d5:f1:98:09:e4:6d:63:80:08:ab: + 06:92:81:d4:e9:70:8f:a7:3f:b2:ed:86:8c:82:6a:35:c8:42: + 5a:82:d1:52:1a:45:0f:15:a5:00:f0:94:7b:65:27:57:39:43: + cf:7c:7f:e6:bd:35:b3:7b:f1:19:4c:de:3a:96:cf:e9:76:ee: + 03:e7:c2:43:52:3c:6a:81:e8:c1:5a:80:bd:11:5d:93:6b:fb: + c7:e6:64:3f:bb:69:1c:e9:dd:25:8b:af:74:c9:54:40:ca:cb: + 93:13:0a:ed:fb:66:92:11:ca:f5:c0:fa:d8:83:55:03:7c:d3: + c5:22:46:75:70:6b:79:48:06:2a:82:9a:bf:e6:eb:16:0e:22: + 45:01:bc:dd:36:94:34:a9:35:26:8a:d7:97:b9:ee:08:72:bf: + 34:92:70:83:80:ab:38:aa:59:68:dd:40:a4:18:90:b2:f3:d5: + 03:ca:26:ca:ef:d5:c7:e0:8f:53:8e:f0:00:e3:a8:ed:9f:f9: + ad:77:e0:2b:63:4f:9e:c3:ee:37:bb:78:09:84:9e:b9:6e:fb: + 29:99:90:e8:80:d3:9f:24 +-----BEGIN CERTIFICATE----- +MIIFqTCCA5GgAwIBAgIQczswBEhb2U14LnNLyaHcZjANBgkqhkiG9w0BAQ0FADBI +MQswCQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlE +LVRSVVNUIEJSIFJvb3QgQ0EgMiAyMDIzMB4XDTIzMDUwOTA4NTYzMVoXDTM4MDUw +OTA4NTYzMFowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEi +MCAGA1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDIgMjAyMzCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAK7/CVmRgApKaOYkP7in5Mg6CjoWzckjYaCTcfKr +i3OPoGdlYNJUa2NRb0kz4HIHE304zQaSBylSa053bATTlfrdTIzZXcFhfUvnKLNE +gXtRr90zsWh81k5M/itoucpmacTsXld/9w3HnDY25QdgrMBM6ghs7wZ8T1soegj8 +k12b9py0i4a6Ibn08OhZWiihNIQaJZG2tY/vsvmA+vk9PBFy2OMvhnbFeSzBqZCT +Rphny4NqoFAjpzv2gTng7fC5v2Xx2Mt6++9zA84A9H3X4F07ZrjcjrqDy4d2A/wl +2ecjbwb9Z/Pg/4S8R7+1FhhGaRTMBffb00msa8yr5LULQyReS2tNZ9/WtT5PeB+U +cSTq3nD88ZP+npNa5JRal1QMNXtfbO4AHyTsA7oC9Xb0n9Sa7YUsOCIvx9gvdhFP +/Wxc6PWOJ4d/GUohR5AdeY0cW/jPSoXk7bNbjb7EZChdQcRurDhaTyN0dKkSw/bS +uREVMweR2Ds3OmMwBtHFIjYoYiMQ4EbMl6zWK11kJNXuHA7e+whadSr2Y23OC0K+ +0bpwHJwh5Q8xaRfX/Aq03u2AnMuStIv13lmiWAmlY0cL4UEyNEHZmrHZqLAbWt4N +DfTisl01gLmB1IRpkQLLddCNxbU9CZEJjxShFHR5PtbJFR2kWVki3PaKRT08EtY+ +XTIvAgMBAAGjgY4wgYswDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUZ5Dw1t61 +GNVGKX5cq/ieCLxklRAwDgYDVR0PAQH/BAQDAgEGMEkGA1UdHwRCMEAwPqA8oDqG +OGh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3RfYnJfcm9vdF9jYV8y +XzIwMjMuY3JsMA0GCSqGSIb3DQEBDQUAA4ICAQA097N3U9swFrktpSHxQCF16+tI +FoE9c+CeJyrrd6kTpGoKWloUMz1oH4Guaf2Mn2VsNELZLdB/eBaxOqwjMa1ef67n +riv6uvw8l5VAk1/DLQOj7aRvU9f6QA4w9QAgLABMjDu0ox+2v5Eyq6+SmNMW5tTR +VFxDWy6u71cqqLRvpO8NVhTaIasgdp4D/Ca4nj8+AybmTNudX0KEPUUDAxxZiMrc +LmEkWqTqJwtzEr5SswrPMhfiHocaFpVIbVrg0M8JkiZmkdijYQ6qgYF/6FKC0ULn +4B0Y+qSFNueG4A3rvNTJ1jxD8V1Jbn6Bm2m1iWKPiFLY1/4nwSPFyysCu7Ff/vtD +hQNGvl3GyiEm/9cCnnRK3PgTFbGBVzbLZVzRHTF36SXDw7IyN9XxmAnkbWOACKsG +koHU6XCPpz+y7YaMgmo1yEJagtFSGkUPFaUA8JR7ZSdXOUPPfH/mvTWze/EZTN46 +ls/pdu4D58JDUjxqgejBWoC9EV2Ta/vH5mQ/u2kc6d0li690yVRAysuTEwrt+2aS +Ecr1wPrYg1UDfNPFIkZ1cGt5SAYqgpq/5usWDiJFAbzdNpQ0qTUmiteXue4Icr80 +knCDgKs4qllo3UCkGJCy89UDyibK79XH4I9TjvAA46jtn/mtd+ArY0+ew+43u3gJ +hJ65bvspmZDogNOfJA== +-----END CERTIFICATE----- + +# 8e8221b2e7d4007836a1672f0dcc299c33bc07d316f132fa1a206d587150f1ce +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 69:26:09:7e:80:4b:4c:a0:a7:8c:78:62:53:5f:5a:6f + Signature Algorithm: sha512WithRSAEncryption + Issuer: C=DE, O=D-Trust GmbH, CN=D-TRUST EV Root CA 2 2023 + Validity + Not Before: May 9 09:10:33 2023 GMT + Not After : May 9 09:10:32 2038 GMT + Subject: C=DE, O=D-Trust GmbH, CN=D-TRUST EV Root CA 2 2023 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:d8:8e:a3:89:80:0b:b2:57:52:dc:a9:53:4c:37: + b9:7f:63:17:13:ef:a7:5b:23:5b:69:75:b0:99:0a: + 17:c1:8b:c4:db:a8:e0:cc:31:ba:c2:f2:cd:5d:e9: + b7:f8:1d:af:6a:c4:95:87:d7:47:c9:95:d8:82:04: + 50:3d:81:08:ff:e4:3d:b3:b1:d6:c5:b2:fd:88:09: + db:9c:84:ec:25:17:14:87:7f:30:78:9b:6a:58:c9: + b6:73:28:3c:34:f7:99:f7:7f:d3:a6:f8:1c:45:7c: + ad:2c:8c:94:3f:d8:67:10:53:7e:22:cd:4e:25:51: + f0:25:24:35:11:5e:10:c6:ec:87:66:89:81:68:ba: + cc:2b:9d:47:73:1f:bd:cd:91:a4:72:6a:9c:a2:1b: + 18:a0:6f:ec:50:f4:7d:40:c2:a8:30:cf:bd:73:c8: + 13:2b:10:13:1e:8b:9a:a8:3a:94:73:d3:18:69:0a: + 4a:ff:c1:01:03:ff:79:7f:b5:48:7f:7b:ee:e8:29: + 6f:36:4c:95:61:86:d8:f9:a2:73:8a:ee:ae:2f:96: + ee:68:cd:3d:4d:28:42:f9:45:2b:32:1b:46:55:16: + 6a:a6:4b:29:f9:bb:95:56:bf:46:1d:ec:1d:93:1d: + c0:65:b2:1f:a1:43:ae:56:9e:a0:b1:8f:6b:12:b7: + 60:6d:78:0b:ca:8a:5c:ed:1e:96:0e:83:a6:48:95: + 8d:3b:a3:21:c4:ae:58:c6:00:b2:84:b4:23:a4:96: + 86:35:b8:d8:9e:d8:ac:34:49:98:63:95:c5:cb:6d: + 48:47:e2:f2:2e:18:1e:d0:31:ab:dd:74:ec:f9:dc: + 8c:b8:1c:8e:68:23:ba:d0:f3:50:dc:cf:65:8f:73: + 3a:32:c7:7c:fe:ca:82:22:4f:be:8e:62:47:66:e5: + cd:87:e2:e8:d5:0f:18:9f:e5:04:72:4b:46:3c:10: + f2:44:c2:64:56:71:4e:75:e8:9c:c9:26:74:c5:7d: + 59:d1:0a:5b:0f:6d:fe:9e:75:1c:18:c6:1a:3a:7c: + d8:0d:04:cc:cd:b7:45:65:7a:b1:8f:b8:ae:84:48: + 3e:b3:7a:4d:a8:03:e2:e2:7e:01:16:59:68:18:43: + 33:b0:d2:dc:b0:1a:43:35:ee:a5:da:a9:46:5c:ae: + 86:81:41:01:4a:74:26:ec:9f:06:bf:c2:05:37:64: + 75:78:29:68:fd:c5:f5:eb:fe:47:f9:e4:85:b0:e1: + 7b:31:9d:a6:7f:72:a3:b9:c4:2c:2e:cc:99:57:0e: + 21:0c:45:01:94:65:eb:65:09:c6:63:22:0b:33:49: + 92:48:3c:fc:cd:ce:b0:3e:8e:9e:8b:f8:fe:49:c5: + 35:72:47 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Subject Key Identifier: + AA:FC:91:10:1B:87:91:5F:16:B9:BF:4F:4B:91:5E:00:1C:B1:32:80 + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 CRL Distribution Points: + Full Name: + URI:http://crl.d-trust.net/crl/d-trust_ev_root_ca_2_2023.crl + + Signature Algorithm: sha512WithRSAEncryption + Signature Value: + 93:cb:a5:1f:99:11:ec:9a:0d:5f:2c:15:93:c6:3f:be:10:8d: + 78:42:f0:6e:90:47:47:8e:a3:92:32:8d:70:8f:f6:5b:8d:be: + 89:ce:47:01:6a:1b:20:20:89:5b:c8:82:10:6c:e0:e7:99:aa: + 6b:c6:2a:a0:63:35:91:6a:85:25:ad:17:38:a5:9b:7e:50:f2: + 76:ea:85:05:2a:27:41:2b:b1:81:d1:a2:f6:40:75:a9:0e:cb: + f1:55:48:d8:ec:d1:ec:b3:e8:ce:14:a1:35:ec:c2:5e:35:1a: + ab:a6:16:01:06:8e:ea:dc:2f:a3:8a:ca:2c:91:eb:52:8e:5f: + 0c:9b:17:cf:cb:73:07:19:c4:6a:c2:73:54:ef:7c:43:52:63: + c1:11:ca:c2:45:b1:f4:3b:53:f5:69:ae:3c:e3:a5:de:ac:e8: + 54:b7:b2:91:fd:ac:a9:1f:f2:87:e4:17:c6:49:a8:7c:d8:0a: + 41:f4:f2:3e:e7:77:34:04:52:dd:e8:81:f2:4d:2f:54:45:9d: + 15:e1:4f:cc:e5:de:34:57:10:c9:23:72:17:70:8d:50:70:1f: + 56:6c:cc:b9:ff:3a:5a:4f:63:7a:c3:6e:65:07:1d:84:a1:ff: + a9:0c:63:89:6d:b2:40:88:39:d7:1f:77:68:b5:fc:9c:d5:d6: + 67:69:5b:a8:74:db:fc:89:f6:1b:32:f7:a4:24:a6:76:b7:47: + 53:ef:8d:49:8f:a9:b6:83:5a:a5:96:90:45:61:f5:de:03:4f: + 26:0f:a8:8b:f0:03:96:b0:ac:15:d0:71:5a:6a:7b:94:e6:70: + 93:da:f1:69:e0:b2:62:4d:9e:8f:ff:89:9d:9b:5d:cd:45:e9: + 94:02:22:8d:e0:35:7f:e8:f1:04:79:71:6c:54:83:f8:33:b9: + 05:32:1b:58:55:11:4f:d0:e5:27:47:71:ec:ed:da:67:d6:62: + a6:4b:4d:0f:69:a2:c9:bc:ec:22:4b:94:c7:68:94:17:7e:e2: + 8e:28:3e:b6:c6:ea:f5:34:6c:9f:37:88:07:38:db:86:71:fa: + cd:95:48:43:6e:a3:4f:82:87:d7:34:98:6e:4b:93:79:60:75: + 69:0f:f0:1a:d5:53:fa:21:0c:c2:3f:e9:3f:1f:18:8c:92:5d: + 78:a7:76:67:19:bb:b2:ea:7f:e9:70:09:56:56:a3:b0:0c:0b: + 2d:36:5e:c5:e9:c4:d5:83:cb:86:17:97:2c:6c:13:6f:87:5a: + af:49:a6:1d:db:cd:38:04:2e:5f:e2:4a:35:0e:2d:4b:f8:a2: + 24:04:8d:d8:e1:63:5e:02:92:34:da:98:61:5c:1c:6f:58:76: + 64:b3:fc:02:b8:f5:9d:0a +-----BEGIN CERTIFICATE----- +MIIFqTCCA5GgAwIBAgIQaSYJfoBLTKCnjHhiU19abzANBgkqhkiG9w0BAQ0FADBI +MQswCQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlE +LVRSVVNUIEVWIFJvb3QgQ0EgMiAyMDIzMB4XDTIzMDUwOTA5MTAzM1oXDTM4MDUw +OTA5MTAzMlowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEi +MCAGA1UEAxMZRC1UUlVTVCBFViBSb290IENBIDIgMjAyMzCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBANiOo4mAC7JXUtypU0w3uX9jFxPvp1sjW2l1sJkK +F8GLxNuo4MwxusLyzV3pt/gdr2rElYfXR8mV2IIEUD2BCP/kPbOx1sWy/YgJ25yE +7CUXFId/MHibaljJtnMoPDT3mfd/06b4HEV8rSyMlD/YZxBTfiLNTiVR8CUkNRFe +EMbsh2aJgWi6zCudR3Mfvc2RpHJqnKIbGKBv7FD0fUDCqDDPvXPIEysQEx6Lmqg6 +lHPTGGkKSv/BAQP/eX+1SH977ugpbzZMlWGG2Pmic4ruri+W7mjNPU0oQvlFKzIb +RlUWaqZLKfm7lVa/Rh3sHZMdwGWyH6FDrlaeoLGPaxK3YG14C8qKXO0elg6DpkiV +jTujIcSuWMYAsoS0I6SWhjW42J7YrDRJmGOVxcttSEfi8i4YHtAxq9107PncjLgc +jmgjutDzUNzPZY9zOjLHfP7KgiJPvo5iR2blzYfi6NUPGJ/lBHJLRjwQ8kTCZFZx +TnXonMkmdMV9WdEKWw9t/p51HBjGGjp82A0EzM23RWV6sY+4roRIPrN6TagD4uJ+ +ARZZaBhDM7DS3LAaQzXupdqpRlyuhoFBAUp0JuyfBr/CBTdkdXgpaP3F9ev+R/nk +hbDhezGdpn9yo7nELC7MmVcOIQxFAZRl62UJxmMiCzNJkkg8/M3OsD6Onov4/knF +NXJHAgMBAAGjgY4wgYswDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUqvyREBuH +kV8Wub9PS5FeAByxMoAwDgYDVR0PAQH/BAQDAgEGMEkGA1UdHwRCMEAwPqA8oDqG +OGh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3RfZXZfcm9vdF9jYV8y +XzIwMjMuY3JsMA0GCSqGSIb3DQEBDQUAA4ICAQCTy6UfmRHsmg1fLBWTxj++EI14 +QvBukEdHjqOSMo1wj/Zbjb6JzkcBahsgIIlbyIIQbODnmaprxiqgYzWRaoUlrRc4 +pZt+UPJ26oUFKidBK7GB0aL2QHWpDsvxVUjY7NHss+jOFKE17MJeNRqrphYBBo7q +3C+jisosketSjl8MmxfPy3MHGcRqwnNU73xDUmPBEcrCRbH0O1P1aa4846XerOhU +t7KR/aypH/KH5BfGSah82ApB9PI+53c0BFLd6IHyTS9URZ0V4U/M5d40VxDJI3IX +cI1QcB9WbMy5/zpaT2N6w25lBx2Eof+pDGOJbbJAiDnXH3dotfyc1dZnaVuodNv8 +ifYbMvekJKZ2t0dT741Jj6m2g1qllpBFYfXeA08mD6iL8AOWsKwV0HFaanuU5nCT +2vFp4LJiTZ6P/4mdm13NRemUAiKN4DV/6PEEeXFsVIP4M7kFMhtYVRFP0OUnR3Hs +7dpn1mKmS00PaaLJvOwiS5THaJQXfuKOKD62xur1NGyfN4gHONuGcfrNlUhDbqNP +gofXNJhuS5N5YHVpD/Aa1VP6IQzCP+k/HxiMkl14p3ZnGbuy6n/pcAlWVqOwDAst +Nl7F6cTVg8uGF5csbBNvh1qvSaYd2804BC5f4ko1Di1L+KIkBI3Y4WNeApI02phh +XBxvWHZks/wCuPWdCg== +-----END CERTIFICATE----- + +# 578af4ded0853f4e5998db4aeaf9cbea8d945f60b620a38d1a3c13b2bc7ba8e1 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 36:3a:96:8c:c9:5c:b2:58:cd:d0:01:5d:c5:e5:57:00 + Signature Algorithm: ecdsa-with-SHA384 + Issuer: C=DE, O=Deutsche Telekom Security GmbH, CN=Telekom Security TLS ECC Root 2020 + Validity + Not Before: Aug 25 07:48:20 2020 GMT + Not After : Aug 25 23:59:59 2045 GMT + Subject: C=DE, O=Deutsche Telekom Security GmbH, CN=Telekom Security TLS ECC Root 2020 + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:ce:bf:fe:57:a8:bf:d5:aa:f7:10:9a:cd:bc:d1: + 11:a2:bd:67:42:cc:90:eb:15:18:90:d9:a2:cd:0c: + 2a:25:eb:3e:4f:ce:b5:d2:8f:0f:f3:35:da:43:8b: + 02:80:be:6f:51:24:1d:0f:6b:2b:ca:9f:c2:6f:50: + 32:e5:37:20:b6:20:ff:88:0d:0f:6d:49:bb:db:06: + a4:87:90:92:94:f4:09:d0:cf:7f:c8:80:0b:c1:97: + b3:bb:35:27:c9:c2:1b + ASN1 OID: secp384r1 + NIST CURVE: P-384 + X509v3 extensions: + X509v3 Subject Key Identifier: + E3:72:CC:6E:95:99:47:B1:E6:B3:61:4C:D1:CB:AB:E3:BA:CD:DE:9F + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + Signature Algorithm: ecdsa-with-SHA384 + Signature Value: + 30:64:02:30:75:52:8b:b7:a4:10:4f:ae:4a:10:8b:b2:84:5b: + 42:e1:e6:2a:36:02:da:a0:6e:19:3f:25:bf:da:59:32:8e:e4: + fb:90:dc:93:64:ce:ad:b4:41:47:60:e2:cf:a7:cb:1e:02:30: + 37:41:8c:66:df:41:6b:d6:83:00:41:fd:2f:5a:f7:50:b4:67: + d1:2c:a8:71:d7:43:ca:9c:27:24:91:83:48:0d:cf:cd:f7:54: + 81:af:ec:7f:e4:67:db:b8:90:ee:dd:25 +-----BEGIN CERTIFICATE----- +MIICQjCCAcmgAwIBAgIQNjqWjMlcsljN0AFdxeVXADAKBggqhkjOPQQDAzBjMQsw +CQYDVQQGEwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBH +bWJIMSswKQYDVQQDDCJUZWxla29tIFNlY3VyaXR5IFRMUyBFQ0MgUm9vdCAyMDIw +MB4XDTIwMDgyNTA3NDgyMFoXDTQ1MDgyNTIzNTk1OVowYzELMAkGA1UEBhMCREUx +JzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkgR21iSDErMCkGA1UE +AwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgRUNDIFJvb3QgMjAyMDB2MBAGByqGSM49 +AgEGBSuBBAAiA2IABM6//leov9Wq9xCazbzREaK9Z0LMkOsVGJDZos0MKiXrPk/O +tdKPD/M12kOLAoC+b1EkHQ9rK8qfwm9QMuU3ILYg/4gND21Ju9sGpIeQkpT0CdDP +f8iAC8GXs7s1J8nCG6NCMEAwHQYDVR0OBBYEFONyzG6VmUex5rNhTNHLq+O6zd6f +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2cA +MGQCMHVSi7ekEE+uShCLsoRbQuHmKjYC2qBuGT8lv9pZMo7k+5Dck2TOrbRBR2Di +z6fLHgIwN0GMZt9Ba9aDAEH9L1r3ULRn0SyocddDypwnJJGDSA3PzfdUga/sf+Rn +27iQ7t0l +-----END CERTIFICATE----- + +# efc65cadbb59adb6efe84da22311b35624b71b3b1ea0da8b6655174ec8978646 +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 21:9c:54:2d:e8:f6:ec:71:77:fa:4e:e8:c3:70:57:97 + Signature Algorithm: sha384WithRSAEncryption + Issuer: C=DE, O=Deutsche Telekom Security GmbH, CN=Telekom Security TLS RSA Root 2023 + Validity + Not Before: Mar 28 12:16:45 2023 GMT + Not After : Mar 27 23:59:59 2048 GMT + Subject: C=DE, O=Deutsche Telekom Security GmbH, CN=Telekom Security TLS RSA Root 2023 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + 00:ed:35:a1:81:80:f3:cb:4a:69:5b:c2:fb:51:83: + ae:26:fd:e1:6e:f3:81:12:7d:71:40:ff:87:75:42: + 29:21:ed:81:52:2c:df:12:c1:19:84:89:c1:bd:c5: + 28:d5:d5:4b:6c:44:d6:4c:db:07:96:4a:55:7a:ca: + 36:82:04:36:a8:a5:fc:27:f6:49:f1:d5:72:9e:91: + f9:23:d6:70:7b:bb:f5:9b:c1:ec:93:cf:19:ea:65: + 7e:88:70:a0:73:fc:f6:ff:b5:56:62:e1:73:6a:34: + 98:3e:82:b8:ac:95:53:f4:01:a0:27:07:72:a3:00: + 53:a0:e4:b2:ab:83:38:57:33:25:94:9f:be:48:1d: + 98:e1:a3:ba:9e:5c:cd:04:71:51:7d:75:78:ab:f3: + 59:aa:c4:e0:60:be:8f:83:52:b8:75:1a:41:35:ed: + bc:f3:3a:63:e9:a9:14:45:d7:e6:52:d1:6e:d2:de: + bc:e3:f5:0b:3b:e6:e0:c4:bd:43:64:13:a6:ce:f4: + 98:37:6c:8a:95:a8:97:c8:47:0f:f0:5e:10:8b:e7: + 1d:1c:fe:b1:3b:a0:05:33:68:05:41:82:c1:03:2b: + 01:c8:e7:8f:4d:ab:e8:b5:f6:cd:6b:44:b5:e7:dd: + 8b:ec:ea:25:b4:00:22:57:4d:b0:b1:b2:31:c1:16: + ce:ff:fd:14:84:b7:47:fa:b2:f1:70:de:db:8b:6c: + 36:58:a4:7c:b3:11:d1:c3:77:7f:5f:b6:25:e0:0d: + c5:d2:b3:f9:b8:b8:77:db:37:71:71:47:e3:60:18: + 4f:24:b6:75:37:78:b9:a3:62:af:bd:c9:72:8e:2f: + cc:bb:ae:db:e4:15:52:19:07:33:fb:6a:b7:2d:4b: + 90:28:82:73:fe:18:8b:35:8d:db:a7:04:6a:be:ea: + c1:4d:36:3b:16:36:91:32:ef:b6:40:89:91:43:e0: + f2:a2:ab:04:2e:e6:f2:4c:0e:16:34:20:ac:87:c1: + 2d:7e:c9:66:47:17:14:11:a4:f3:f7:a1:24:89:ab: + d8:1a:c8:a1:5c:b1:a3:f7:8c:6d:c8:01:c9:4f:c9: + ec:c4:fc:ac:51:33:d1:c8:83:d1:c9:9f:1d:d4:47: + 34:29:3e:cb:b0:0e:fa:83:0b:28:58:e5:29:dc:3f: + 7c:a8:9f:c9:b6:0a:bb:a6:e8:46:16:0f:96:e5:7b: + e4:6a:7a:48:6d:76:98:05:a5:dc:6d:1e:42:1e:42: + da:1a:e0:52:f7:b5:83:c0:1a:7b:78:35:2c:38:f5: + 1f:fd:49:a3:2e:d2:59:63:bf:80:b0:8c:93:73:cb: + 35:a6:99:95:22:61:65:03:60:fb:2f:93:4b:fa:9a: + 9c:80:3b + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Subject Key Identifier: + B6:A7:97:82:3D:74:85:9B:F7:3C:9F:93:9A:95:79:75:52:8C:6D:47 + X509v3 Basic Constraints: critical + CA:TRUE + X509v3 Authority Key Identifier: + B6:A7:97:82:3D:74:85:9B:F7:3C:9F:93:9A:95:79:75:52:8C:6D:47 + Signature Algorithm: sha384WithRSAEncryption + Signature Value: + a8:cc:61:a6:be:75:9e:15:50:a4:6b:fb:a8:70:45:7c:ba:7e: + b1:5a:fc:5b:23:fa:0a:77:f8:98:71:82:0c:6d:e0:5e:46:aa: + 93:f4:1e:a0:c3:e1:93:db:4b:ad:b2:a6:5d:ab:b0:d4:62:cb: + 5e:bb:66:f5:2d:ee:97:40:3c:62:eb:5e:d6:14:d6:8c:e2:96: + 8b:41:69:93:35:e6:b9:99:6b:62:b4:a1:17:66:34:a6:6b:63: + c6:b9:4e:f2:22:e9:58:0d:56:41:d1:fa:0c:4a:f0:33:cd:3b: + bb:6d:21:3a:ae:8e:72:b5:c3:4a:fb:e9:7d:e5:b1:9b:86:ee: + e2:e0:7d:b4:f7:32:fd:22:84:f1:85:c9:37:79:e9:b5:3f:bf: + 5c:e4:74:b2:8f:11:62:00:dd:18:66:a1:d9:7b:23:5f:f1:8e: + d5:67:e8:54:da:5b:3a:6b:36:6f:f9:81:b1:33:47:33:77:40: + f9:52:aa:dd:d4:83:cf:85:78:99:9a:93:b9:73:67:42:46:11: + 21:ea:fe:0a:a9:1b:1a:65:69:b3:8f:ae:16:b6:f6:4b:56:b2: + 2d:f9:a5:c8:ec:3b:62:a3:ed:6b:d0:4e:d5:40:09:a4:1f:98: + d7:3a:a5:92:59:20:e4:b0:7d:cd:5b:73:68:bd:6d:c4:a2:13: + 0e:67:19:b8:8d:42:7e:6c:0c:9a:6e:a0:24:2d:d5:45:1b:dc: + c4:02:14:fe:85:5b:65:97:ca:4e:90:50:08:7a:42:35:f9:ea: + c2:66:d4:f8:01:ae:1e:b4:be:c3:a8:ef:fe:76:9a:a2:a6:1f: + 46:f6:84:ed:fc:db:ce:c4:02:ce:77:48:2c:8c:b2:ec:c3:00: + a3:ec:2c:55:18:c1:7e:19:ee:e1:2f:f2:ad:83:9b:9e:ab:19: + df:c6:8a:2f:8c:77:e5:b7:05:ec:3b:c1:ec:be:86:b3:86:bc: + c0:f7:dc:e7:ea:5b:ae:b2:cc:b5:35:86:4b:d0:e2:3f:b6:d8: + f8:0e:00:ee:5d:e3:f7:8d:58:ff:cf:8b:37:e9:63:5f:6e:f7: + 09:71:36:c2:12:5d:57:f2:c8:b4:cd:f3:ee:02:df:11:dc:6a: + b9:57:84:1d:59:4d:8c:ce:c8:0e:23:c2:b7:26:9a:10:14:71: + fe:93:b2:8a:b8:80:f0:0e:10:9e:d3:a8:50:0c:37:82:2f:ea: + e0:8a:9d:e1:2c:39:ff:b5:b4:73:00:e4:f7:48:a6:73:ac:bf: + b2:de:77:04:87:b4:a3:cd:9b:35:24:37:fa:90:93:13:81:42: + c6:98:26:75:37:66:41:10:ac:bb:f5:94:e3:c2:31:2b:ad:e7: + 23:56:cc:35:25:92:b3:50 +-----BEGIN CERTIFICATE----- +MIIFszCCA5ugAwIBAgIQIZxULej27HF3+k7ow3BXlzANBgkqhkiG9w0BAQwFADBj +MQswCQYDVQQGEwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0 +eSBHbWJIMSswKQYDVQQDDCJUZWxla29tIFNlY3VyaXR5IFRMUyBSU0EgUm9vdCAy +MDIzMB4XDTIzMDMyODEyMTY0NVoXDTQ4MDMyNzIzNTk1OVowYzELMAkGA1UEBhMC +REUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkgR21iSDErMCkG +A1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgUlNBIFJvb3QgMjAyMzCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAO01oYGA88tKaVvC+1GDrib94W7zgRJ9 +cUD/h3VCKSHtgVIs3xLBGYSJwb3FKNXVS2xE1kzbB5ZKVXrKNoIENqil/Cf2SfHV +cp6R+SPWcHu79ZvB7JPPGeplfohwoHP89v+1VmLhc2o0mD6CuKyVU/QBoCcHcqMA +U6DksquDOFczJZSfvkgdmOGjup5czQRxUX11eKvzWarE4GC+j4NSuHUaQTXtvPM6 +Y+mpFEXX5lLRbtLevOP1Czvm4MS9Q2QTps70mDdsipWol8hHD/BeEIvnHRz+sTug +BTNoBUGCwQMrAcjnj02r6LX2zWtEtefdi+zqJbQAIldNsLGyMcEWzv/9FIS3R/qy +8XDe24tsNlikfLMR0cN3f1+2JeANxdKz+bi4d9s3cXFH42AYTyS2dTd4uaNir73J +co4vzLuu2+QVUhkHM/tqty1LkCiCc/4YizWN26cEar7qwU02OxY2kTLvtkCJkUPg +8qKrBC7m8kwOFjQgrIfBLX7JZkcXFBGk8/ehJImr2BrIoVyxo/eMbcgByU/J7MT8 +rFEz0ciD0cmfHdRHNCk+y7AO+oMLKFjlKdw/fKifybYKu6boRhYPluV75Gp6SG12 +mAWl3G0eQh5C2hrgUve1g8Aae3g1LDj1H/1Joy7SWWO/gLCMk3PLNaaZlSJhZQNg ++y+TS/qanIA7AgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtqeX +gj10hZv3PJ+TmpV5dVKMbUcwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS2 +p5eCPXSFm/c8n5OalXl1UoxtRzANBgkqhkiG9w0BAQwFAAOCAgEAqMxhpr51nhVQ +pGv7qHBFfLp+sVr8WyP6Cnf4mHGCDG3gXkaqk/QeoMPhk9tLrbKmXauw1GLLXrtm +9S3ul0A8Yute1hTWjOKWi0FpkzXmuZlrYrShF2Y0pmtjxrlO8iLpWA1WQdH6DErw +M807u20hOq6OcrXDSvvpfeWxm4bu4uB9tPcy/SKE8YXJN3nptT+/XOR0so8RYgDd +GGah2XsjX/GO1WfoVNpbOms2b/mBsTNHM3dA+VKq3dSDz4V4mZqTuXNnQkYRIer+ +CqkbGmVps4+uFrb2S1ayLfmlyOw7YqPta9BO1UAJpB+Y1zqlklkg5LB9zVtzaL1t +xKITDmcZuI1CfmwMmm6gJC3VRRvcxAIU/oVbZZfKTpBQCHpCNfnqwmbU+AGuHrS+ +w6jv/naaoqYfRvaE7fzbzsQCzndILIyy7MMAo+wsVRjBfhnu4S/yrYObnqsZ38aK +L4x35bcF7DvB7L6Gs4a8wPfc5+pbrrLMtTWGS9DiP7bY+A4A7l3j941Y/8+LN+lj +X273CXE2whJdV/LItM3z7gLfEdxquVeEHVlNjM7IDiPCtyaaEBRx/pOyiriA8A4Q +ntOoUAw3gi/q4Iqd4Sw5/7W0cwDk90imc6y/st53BIe0o82bNSQ3+pCTE4FCxpgm +dTdmQRCsu/WU48IxK63nI1bMNSWSs1A= -----END CERTIFICATE----- \ No newline at end of file diff -Nru chromium-145.0.7632.116/net/data/ssl/chrome_root_store/root_store.md chromium-145.0.7632.159/net/data/ssl/chrome_root_store/root_store.md --- chromium-145.0.7632.116/net/data/ssl/chrome_root_store/root_store.md 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/net/data/ssl/chrome_root_store/root_store.md 2026-03-02 23:00:09.000000000 +0000 @@ -1,7 +1,7 @@ # Chrome Root Store -Version: 29 +Version: 30 [TOC] @@ -14,7 +14,6 @@ 8ecde6884f3d87b1125ba31ac3fcb13d7016de7f57cc904fe1cb97c6ae98196e | CN=Amazon Root CA 1,O=Amazon,C=US | 2015-05-26 | 2038-01-17 e35d28419ed02025cfa69038cd623962458da5c695fbdea3c22b0bfb25897092 | CN=Amazon Root CA 4,O=Amazon,C=US | 2015-05-26 | 2040-05-26 5c58468d55f58e497e743982d2b50010b6d165374acf83a7d4a32db768c4408e | CN=Certum Trusted Network CA,OU=Certum Certification Authority,O=Unizeto Technologies S.A.,C=PL | 2008-10-22 | 2029-12-31 -b676f2eddae8775cd36cb0f63cd1d4603961f49e6265ba013a2f0307b6d0b804 | CN=Certum Trusted Network CA 2,OU=Certum Certification Authority,O=Unizeto Technologies S.A.,C=PL | 2011-10-06 | 2046-10-06 f356bea244b7a91eb35d53ca9ad7864ace018e2d35d5f8f96ddf68a6f41aa474 | CN=Atos TrustedRoot 2011,O=Atos,C=DE | 2011-07-07 | 2030-12-31 57de0583efd2b26e0361da99da9df4648def7ee8441c3b728afa9bcde0f9b26a | CN=Autoridad de Certificacion Firmaprofesional CIF A62634068,C=ES | 2014-09-23 | 2036-05-05 657cfe2fa73faa38462571f332a2363a46fce7020951710702cdfbb6eeda3305 | OU=certSIGN ROOT CA G2,O=CERTSIGN SA,C=RO | 2017-02-06 | 2042-02-06 @@ -24,7 +23,6 @@ eec5496b988ce98625b934092eec2908bed0b0f316c2d4730c84eaf1f3d34881 | CN=D-TRUST Root Class 3 CA 2 EV 2009,O=D-Trust GmbH,C=DE | 2009-11-05 | 2029-11-05 91e2f5788d5810eba7ba58737de1548a8ecacd014598bc0b143e041b17052552 | CN=T-TeleSec GlobalRoot Class 2,OU=T-Systems Trust Center,O=T-Systems Enterprise Services GmbH,C=DE | 2008-10-01 | 2033-10-01 fd73dad31c644ff1b43bef0ccdda96710b9cd9875eca7e31707af3e96d522bbd | CN=T-TeleSec GlobalRoot Class 3,OU=T-Systems Trust Center,O=T-Systems Enterprise Services GmbH,C=DE | 2008-10-01 | 2033-10-01 -d48d3d23eedb50a459e55197601c27774b9d7b18c94d5a059511a10250b93168 | CN=Certigna Root CA,OU=0002 48146308100036,O=Dhimyotis,C=FR | 2013-10-01 | 2033-10-01 e3b6a2db2ed7ce48842f7ac53241c7b71d54144bfb40c11f3f1d0b42f5eea12d | CN=Certigna,O=Dhimyotis,C=FR | 2007-06-29 | 2027-06-29 31ad6648f8104138c738f39ea4320133393e3a18cc02296ef97c2ac9ef6731d0 | CN=DigiCert Global Root G3,OU=www.digicert.com,O=DigiCert Inc,C=US | 2013-08-01 | 2038-01-15 3e9099b5015e8f486c00bcea9d111ee721faba355a89bcf1df69561e3dc6325c | CN=DigiCert Assured ID Root CA,OU=www.digicert.com,O=DigiCert Inc,C=US | 2006-11-10 | 2031-11-10 @@ -77,12 +75,7 @@ f1c1b50ae5a20dd8030ec9f6bc24823dd367b5255759b4e71b61fce9f7375d73 | CN=SecureTrust CA,O=SecureTrust Corporation,C=US | 2006-11-07 | 2029-12-31 9bea11c976fe014764c1be56a6f914b5a560317abd9988393382e5161aa0493c | CN=UCA Global G2 Root,O=UniTrust,C=CN | 2016-03-11 | 2040-12-31 d43af9b35473755c9684fc06d7d8cb70ee5c28e773fb294eb41ee71722924d24 | CN=UCA Extended Validation Root,O=UniTrust,C=CN | 2015-03-13 | 2038-12-31 -22a2c1f7bded704cc1e701b5f408c310880fe956b5de2a4a44f99c873a25a7c8 | CN=SSL.com EV Root Certification Authority ECC,O=SSL Corporation,L=Houston,ST=Texas,C=US | 2016-02-12 | 2041-02-12 -2e7bf16cc22485a7bbe2aa8696750761b0ae39be3b2fe9d0cc6d4ef73491425c | CN=SSL.com EV Root Certification Authority RSA R2,O=SSL Corporation,L=Houston,ST=Texas,C=US | 2017-05-31 | 2042-05-30 -3417bb06cc6007da1b961c920b8ab4ce3fad820e4aa30b9acbc4a74ebdcebc65 | CN=SSL.com Root Certification Authority ECC,O=SSL Corporation,L=Houston,ST=Texas,C=US | 2016-02-12 | 2041-02-12 -85666a562ee0be5ce925c1d8890a6f76a87ec16d4d7d5f29ea7419cf20123b69 | CN=SSL.com Root Certification Authority RSA,O=SSL Corporation,L=Houston,ST=Texas,C=US | 2016-02-12 | 2041-02-12 62dd0be9b9f50a163ea0f8e75c053b1eca57ea55c8688f647c6881f2c8357b95 | CN=SwissSign Gold CA - G2,O=SwissSign AG,C=CH | 2006-10-25 | 2036-10-25 -59769007f7685d0fcd50872f9f95d5755a5b2b457d81f3692b610a98672f0e1b | CN=TWCA Global Root CA,OU=Root CA,O=TAIWAN-CA,C=TW | 2012-06-27 | 2030-12-31 dd6936fe21f8f077c123a1a521c12224f72255b73e03a7260693e8a24b0fa389 | CN=TeliaSonera Root CA v1,O=TeliaSonera | 2007-10-18 | 2032-10-18 6b328085625318aa50d173c98d8bda09d57e27413d114cf787a0f5d06c030cf6 | CN=Certum EC-384 CA,OU=Certum Certification Authority,O=Asseco Data Systems S.A.,C=PL | 2018-03-26 | 2043-03-26 fe7696573855773e37a95e7ad4d9cc96c30157c15d31765ba9b15704e1ae78fd | CN=Certum Trusted Root CA,OU=Certum Certification Authority,O=Asseco Data Systems S.A.,C=PL | 2018-03-16 | 2043-03-16 @@ -122,6 +115,16 @@ 9a114025197c5bb95d94e63d55cd43790847b646b23cdf11ada4a00eff15fb48 | CN=Buypass Class 2 Root CA,O=Buypass AS-983163327,C=NO | 2010-10-26 | 2040-10-26 edf7ebbca27a2a384d387b7d4010c666e2edb4843e4c29b4ae1d5b9332e6b24d | CN=Buypass Class 3 Root CA,O=Buypass AS-983163327,C=NO | 2010-10-26 | 2040-10-26 c0a6f4dc63a24bfdcf54ef2a6a082a0a72de35803e2ff5ff527ae5d87206dfd5 | OU=ePKI Root Certification Authority,O=Chunghwa Telecom Co.\, Ltd.,C=TW | 2004-12-20 | 2034-12-20 +d48d3d23eedb50a459e55197601c27774b9d7b18c94d5a059511a10250b93168 | CN=Certigna Root CA,OU=0002 48146308100036,O=Dhimyotis,C=FR | 2013-10-01 | 2033-10-01 6c61dac3a2def031506be036d2a6fe401994fbd13df9c8d466599274c446ec98 | CN=NetLock Arany (Class Gold) Főtanúsítvány,OU=Tanúsítványkiadók (Certification Services),O=NetLock Kft.,L=Budapest,C=HU | 2008-12-11 | 2028-12-06 +22a2c1f7bded704cc1e701b5f408c310880fe956b5de2a4a44f99c873a25a7c8 | CN=SSL.com EV Root Certification Authority ECC,O=SSL Corporation,L=Houston,ST=Texas,C=US | 2016-02-12 | 2041-02-12 +2e7bf16cc22485a7bbe2aa8696750761b0ae39be3b2fe9d0cc6d4ef73491425c | CN=SSL.com EV Root Certification Authority RSA R2,O=SSL Corporation,L=Houston,ST=Texas,C=US | 2017-05-31 | 2042-05-30 +3417bb06cc6007da1b961c920b8ab4ce3fad820e4aa30b9acbc4a74ebdcebc65 | CN=SSL.com Root Certification Authority ECC,O=SSL Corporation,L=Houston,ST=Texas,C=US | 2016-02-12 | 2041-02-12 +85666a562ee0be5ce925c1d8890a6f76a87ec16d4d7d5f29ea7419cf20123b69 | CN=SSL.com Root Certification Authority RSA,O=SSL Corporation,L=Houston,ST=Texas,C=US | 2016-02-12 | 2041-02-12 +59769007f7685d0fcd50872f9f95d5755a5b2b457d81f3692b610a98672f0e1b | CN=TWCA Global Root CA,OU=Root CA,O=TAIWAN-CA,C=TW | 2012-06-27 | 2030-12-31 f015ce3cc239bfef064be9f1d2c417e1a0264a0a94be1f0c8d121864eb6949cc | CN=HiPKI Root CA - G1,O=Chunghwa Telecom Co.\, Ltd.,C=TW | 2019-02-22 | 2037-12-31 193144f431e0fddb740717d4de926a571133884b4360d30e272913cbe660ce41 | CN=SwissSign RSA TLS Root CA 2022 - 1,O=SwissSign AG,C=CH | 2022-06-08 | 2047-06-08 +0552e6f83fdf65e8fa9670e666df28a4e21340b510cbe52566f97c4fb94b2bd1 | CN=D-TRUST BR Root CA 2 2023,O=D-Trust GmbH,C=DE | 2023-05-09 | 2038-05-09 +8e8221b2e7d4007836a1672f0dcc299c33bc07d316f132fa1a206d587150f1ce | CN=D-TRUST EV Root CA 2 2023,O=D-Trust GmbH,C=DE | 2023-05-09 | 2038-05-09 +578af4ded0853f4e5998db4aeaf9cbea8d945f60b620a38d1a3c13b2bc7ba8e1 | CN=Telekom Security TLS ECC Root 2020,O=Deutsche Telekom Security GmbH,C=DE | 2020-08-25 | 2045-08-25 +efc65cadbb59adb6efe84da22311b35624b71b3b1ea0da8b6655174ec8978646 | CN=Telekom Security TLS RSA Root 2023,O=Deutsche Telekom Security GmbH,C=DE | 2023-03-28 | 2048-03-27 diff -Nru chromium-145.0.7632.116/net/data/ssl/chrome_root_store/root_store.textproto chromium-145.0.7632.159/net/data/ssl/chrome_root_store/root_store.textproto --- chromium-145.0.7632.116/net/data/ssl/chrome_root_store/root_store.textproto 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/net/data/ssl/chrome_root_store/root_store.textproto 2026-03-02 23:00:09.000000000 +0000 @@ -8,7 +8,7 @@ # Version # should always be incremented up whenever this (or any pem file that # it references) is changed. -version_major: 29 +version_major: 30 # CN=Actalis Authentication Root CA, O=Actalis S.p.A./03358520967, L=Milan, C=IT # https://ssltest-a.actalis.it:8443 @@ -53,11 +53,6 @@ ev_policy_oids: "2.23.140.1.1" } -# CN=Certum Trusted Network CA 2, OU=Certum Certification Authority, O=Unizeto Technologies S.A., C=PL -trust_anchors { - sha256_hex: "b676f2eddae8775cd36cb0f63cd1d4603961f49e6265ba013a2f0307b6d0b804" -} - # C=DE, O=Atos, CN=Atos TrustedRoot 2011 trust_anchors { sha256_hex: "f356bea244b7a91eb35d53ca9ad7864ace018e2d35d5f8f96ddf68a6f41aa474" @@ -149,8 +144,12 @@ } # CN=Certigna Root CA, OU=0002 48146308100036, O=Dhimyotis, C=FR +# Constraint date: Sun, Jun 14, 2026 23:59:59 GMT+0000 trust_anchors { sha256_hex: "d48d3d23eedb50a459e55197601c27774b9d7b18c94d5a059511a10250b93168" + constraints: { + sct_not_after_sec: 1781481599 + } } # CN=Certigna, O=Dhimyotis, C=FR @@ -506,26 +505,42 @@ # CN=SSL.com EV Root Certification Authority ECC, O=SSL Corporation, L=Houston, ST=Texas, C=US # https://test-ev-ecc.ssl.com/ +# Constraint date: Sun, Jun 14, 2026 23:59:59 GMT+0000 trust_anchors { sha256_hex: "22a2c1f7bded704cc1e701b5f408c310880fe956b5de2a4a44f99c873a25a7c8" ev_policy_oids: "2.23.140.1.1" + constraints: { + sct_not_after_sec: 1781481599 + } } # CN=SSL.com EV Root Certification Authority RSA R2, O=SSL Corporation, L=Houston, ST=Texas, C=US # https://test-ev-rsa.ssl.com/ +# Constraint date: Sun, Jun 14, 2026 23:59:59 GMT+0000 trust_anchors { sha256_hex: "2e7bf16cc22485a7bbe2aa8696750761b0ae39be3b2fe9d0cc6d4ef73491425c" ev_policy_oids: "2.23.140.1.1" + constraints: { + sct_not_after_sec: 1781481599 + } } # CN=SSL.com Root Certification Authority ECC, O=SSL Corporation, L=Houston, ST=Texas, C=US +# Constraint date: Sun, Jun 14, 2026 23:59:59 GMT+0000 trust_anchors { sha256_hex: "3417bb06cc6007da1b961c920b8ab4ce3fad820e4aa30b9acbc4a74ebdcebc65" + constraints: { + sct_not_after_sec: 1781481599 + } } # CN=SSL.com Root Certification Authority RSA, O=SSL Corporation, L=Houston, ST=Texas, C=US +# Constraint date: Sun, Jun 14, 2026 23:59:59 GMT+0000 trust_anchors { sha256_hex: "85666a562ee0be5ce925c1d8890a6f76a87ec16d4d7d5f29ea7419cf20123b69" + constraints: { + sct_not_after_sec: 1781481599 + } } # CN=SwissSign Gold CA - G2, O=SwissSign AG, C=CH @@ -537,9 +552,13 @@ # CN=TWCA Global Root CA, OU=Root CA, O=TAIWAN-CA, C=TW # https://evssldemo3.twca.com.tw/index.html +# Constraint date: Mon, Sep 14, 2026 23:59:59 GMT+0000 trust_anchors { sha256_hex: "59769007f7685d0fcd50872f9f95d5755a5b2b457d81f3692b610a98672f0e1b" ev_policy_oids: "2.23.140.1.1" + constraints: { + sct_not_after_sec: 1789430399 + } } # CN=TeliaSonera Root CA v1, O=TeliaSonera @@ -751,6 +770,44 @@ } } +# CN=D-TRUST BR Root CA 2 2023, O=D-Trust GmbH, C=DE +# Constraint date: Mon Aug 30, 2027 23:59:59 GMT+0000 +trust_anchors { + sha256_hex: "0552e6f83fdf65e8fa9670e666df28a4e21340b510cbe52566f97c4fb94b2bd1" + constraints: { + sct_not_after_sec: 1819670399 + } +} + +# CN=D-TRUST EV Root CA 2 2023, O=D-Trust GmbH, C=DE +# https://certdemo-ev-valid-rsa.tls.d-trust.net/ +# Constraint date: Mon Aug 30, 2027 23:59:59 GMT+0000 +trust_anchors { + sha256_hex: "8e8221b2e7d4007836a1672f0dcc299c33bc07d316f132fa1a206d587150f1ce" + ev_policy_oids: "2.23.140.1.1" + constraints: { + sct_not_after_sec: 1819670399 + } +} + +# CN=Telekom Security TLS ECC Root 2020, O=Deutsche Telekom Security GmbH, C=DE +# Constraint date: Mon Aug 30, 2027 23:59:59 GMT+0000 +trust_anchors { + sha256_hex: "578af4ded0853f4e5998db4aeaf9cbea8d945f60b620a38d1a3c13b2bc7ba8e1" + constraints: { + sct_not_after_sec: 1819670399 + } +} + +# CN=Telekom Security TLS RSA Root 2023, O=Deutsche Telekom Security GmbH, C=DE +# Constraint date: Mon Aug 30, 2027 23:59:59 GMT+0000 +trust_anchors { + sha256_hex: "efc65cadbb59adb6efe84da22311b35624b71b3b1ea0da8b6655174ec8978646" + constraints: { + sct_not_after_sec: 1819670399 + } +} + # Cloudflare MTC experiment log shard3. # See https://bootstrap-mtca.cloudflareresearch.com/logs/shard3/metadata mtc_anchors { diff -Nru chromium-145.0.7632.116/net/http/transport_security_state_static.pins chromium-145.0.7632.159/net/http/transport_security_state_static.pins --- chromium-145.0.7632.116/net/http/transport_security_state_static.pins 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/net/http/transport_security_state_static.pins 2026-03-02 23:00:09.000000000 +0000 @@ -43,9 +43,9 @@ # hash function for preloaded entries again (we have already done so once). # -# Last updated: 2026-02-20 12:57 UTC +# Last updated: 2026-03-02 12:53 UTC PinsListTimestamp -1771592260 +1772456018 TestSPKI sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= diff -Nru chromium-145.0.7632.116/net/http/transport_security_state_static_pins.json chromium-145.0.7632.159/net/http/transport_security_state_static_pins.json --- chromium-145.0.7632.116/net/http/transport_security_state_static_pins.json 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/net/http/transport_security_state_static_pins.json 2026-03-02 23:00:09.000000000 +0000 @@ -31,7 +31,7 @@ // the 'static_spki_hashes' and 'bad_static_spki_hashes' fields in 'pinsets' // refer to, and the timestamp at which the pins list was last updated. // -// Last updated: 2026-02-20 12:57 UTC +// Last updated: 2026-03-02 12:53 UTC // { "pinsets": [ diff -Nru chromium-145.0.7632.116/remoting/resources/remoting_strings_el.xtb chromium-145.0.7632.159/remoting/resources/remoting_strings_el.xtb --- chromium-145.0.7632.116/remoting/resources/remoting_strings_el.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/remoting/resources/remoting_strings_el.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -71,7 +71,7 @@ Πρόγραμμα απεγκατάστασης κεντρικού υπολογιστή Chromoting Εφαρμογή προώθησης URL Ο κωδικός πρόσβασης δεν είναι έγκυρος. Δοκιμάστε ξανά. -Όροι Παροχής Υπηρεσιών +Όροι παροχής υπηρεσιών Βασική βιβλιοθήκη Άνοιγμα προτιμήσεων προσβασιμότητας Να μην εμφανιστεί ξανά diff -Nru chromium-145.0.7632.116/remoting/resources/remoting_strings_fa.xtb chromium-145.0.7632.159/remoting/resources/remoting_strings_fa.xtb --- chromium-145.0.7632.116/remoting/resources/remoting_strings_fa.xtb 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/remoting/resources/remoting_strings_fa.xtb 2026-03-02 23:00:09.000000000 +0000 @@ -137,7 +137,7 @@ با دنبال کردن دستورالعمل‌ها، رایانه‌تان را برای دسترسی از راه دور تنظیم کنید صفحه نمایش مانند صفحه لمسی عمل می‌کند ‏به «کنترل رایانه ازراه‌دور Chrome» خوش‌آمدید -سعی مجدد +امتحان مجدد ‏حق نشر ۲۰۲۵ Chromium Authors. کلیه حقوق محفوظ است. میزبان آفلاین است. توقف هم‌رسانی diff -Nru chromium-145.0.7632.116/skia/ext/skia_commit_hash.h chromium-145.0.7632.159/skia/ext/skia_commit_hash.h --- chromium-145.0.7632.116/skia/ext/skia_commit_hash.h 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/skia/ext/skia_commit_hash.h 2026-03-02 23:00:09.000000000 +0000 @@ -3,6 +3,6 @@ #ifndef SKIA_EXT_SKIA_COMMIT_HASH_H_ #define SKIA_EXT_SKIA_COMMIT_HASH_H_ -#define SKIA_COMMIT_HASH "2ab8add5be2c46eb6238f4c217f6d6dbc9bccd23" +#define SKIA_COMMIT_HASH "fba326b8829e469ac02e5a68a0d36982ef1975bc" #endif // SKIA_EXT_SKIA_COMMIT_HASH_H_ diff -Nru chromium-145.0.7632.116/third_party/angle/src/libANGLE/renderer/vulkan/TextureVk.cpp chromium-145.0.7632.159/third_party/angle/src/libANGLE/renderer/vulkan/TextureVk.cpp --- chromium-145.0.7632.116/third_party/angle/src/libANGLE/renderer/vulkan/TextureVk.cpp 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/third_party/angle/src/libANGLE/renderer/vulkan/TextureVk.cpp 2026-03-02 23:00:09.000000000 +0000 @@ -3156,8 +3156,17 @@ // invalidate must be called after wait for finish. ANGLE_TRY(srcBuffer->invalidate(renderer)); - size_t dstBufferSize = sourceBox.width * sourceBox.height * sourceBox.depth * - dstFormat.pixelBytes * layerCount; + // Use size_t calculations to avoid 32-bit overflows. Note that the dimensions are bound by + // the maximums specified in Constants.h, and that gl::Box members are signed 32-bit + // integers. + static_assert(gl::IMPLEMENTATION_MAX_2D_TEXTURE_SIZE * + gl::IMPLEMENTATION_MAX_2D_TEXTURE_SIZE < + std::numeric_limits::max()); + size_t dstBufferSize = sourceBox.width * sourceBox.height; + static_assert(gl::IMPLEMENTATION_MAX_3D_TEXTURE_SIZE * + gl::IMPLEMENTATION_MAX_2D_ARRAY_TEXTURE_LAYERS * 16 < + std::numeric_limits::max()); + dstBufferSize *= sourceBox.depth * dstFormat.pixelBytes * layerCount; // Allocate memory in the destination texture for the copy/conversion. uint8_t *dstData = nullptr; diff -Nru chromium-145.0.7632.116/third_party/blink/common/page_state/page_state_serialization.cc chromium-145.0.7632.159/third_party/blink/common/page_state/page_state_serialization.cc --- chromium-145.0.7632.116/third_party/blink/common/page_state/page_state_serialization.cc 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/third_party/blink/common/page_state/page_state_serialization.cc 2026-03-02 23:00:09.000000000 +0000 @@ -83,6 +83,9 @@ // // For reference, see FormController::formStatesFromStateVector in // third_party/WebKit/Source/core/html/forms/FormController.cpp. + // + // Support for PageState version 14 was added to allow validation of the file + // list. size_t index = 0; @@ -117,11 +120,37 @@ return false; if (type && base::EqualsASCII(*type, "file")) { - if (value_size != 2) + // `value_size` is expected to be either: + // - 0 for an empty file form field + // - 2 for legacy PageState versions that only contain file path and + // display name. + // - A multiple of 3 for modern PageStates, which contain a list of + // (file path, name, relative path) triples within a single item. + // (See File::AppendToControlState.) + // + // Extract the file path(s) for sizes 2 and 3, and continue with + // validation for the zero-size empty file case. Any other values of + // `value_size` should be considered invalid. + if (value_size == 2) { + // PageState version < 14. + referenced_files->emplace_back(document_state[index++]); + index++; // Skip over display name. + } else if (value_size > 2 && value_size % 3 == 0) { + // PageState version >= 14. + // Add the file path from each group of three. + for (size_t i = 0; i < value_size / 3; ++i) { + // Double-check bounds for the 3 elements we will look at. + if (index + 2 >= document_state.size()) { + return false; + } + referenced_files->emplace_back(document_state[index++]); + index++; // Skip over name. + index++; // Skip over relative path. + } + } else if (value_size != 0) { return false; - - referenced_files->emplace_back(document_state[index++]); - index++; // Skip over display name. + } + // If value_size is 0, the file form field is empty, so continue. } else { index += value_size; } @@ -1033,6 +1062,37 @@ *encoded = obj.GetAsString(); } +bool GetAllFilesInPageState(const std::string& encoded, + std::vector* files) { + ExplodedPageState exploded; + if (!DecodePageState(encoded, &exploded)) { + // If the PageState can't be decoded at all, then there are no usable files + // in it and it is safe to leave the `files` set empty and return true. + return true; + } + + // TODO(crbug.com/40241973): Refactor to avoid sending PageState objects to + // the browser process, so that this use of RecursivelyAppendReferencedFiles + // is not needed. + std::vector> referenced_files; + if (!RecursivelyAppendReferencedFiles(exploded.top, &referenced_files)) { + // If the PageState can be decoded but this function failed due to an issue + // parsing the DocumentState, it is important to return false to indicate + // that the PageState is not safe to use. Some files could otherwise be + // present and usable without showing up in the list. + return false; + } + + // Copy all of the files found into the output parameter. + files->reserve(referenced_files.size()); + for (const auto& file : referenced_files) { + if (file) { + files->push_back(base::FilePath::FromUTF16Unsafe(*file)); + } + } + return true; +} + #if BUILDFLAG(IS_ANDROID) bool DecodePageStateWithDeviceScaleFactorForTesting( const std::string& encoded, diff -Nru chromium-145.0.7632.116/third_party/blink/public/common/page_state/page_state_serialization.h chromium-145.0.7632.159/third_party/blink/public/common/page_state/page_state_serialization.h --- chromium-145.0.7632.116/third_party/blink/public/common/page_state/page_state_serialization.h 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/third_party/blink/public/common/page_state/page_state_serialization.h 2026-03-02 23:00:09.000000000 +0000 @@ -96,6 +96,13 @@ int version, std::string* encoded); +// Similar to `PageState::GetReferencedFiles`, but returns all FilePaths within +// the entire PageState by traversing its frame tree. Used to validate that the +// list returned by `GetReferencedFiles` is complete. +BLINK_COMMON_EXPORT bool GetAllFilesInPageState( + const std::string& encoded, + std::vector* files); + #if BUILDFLAG(IS_ANDROID) BLINK_COMMON_EXPORT bool DecodePageStateWithDeviceScaleFactorForTesting( const std::string& encoded, diff -Nru chromium-145.0.7632.116/third_party/blink/renderer/core/css/css_math_expression_node.cc chromium-145.0.7632.159/third_party/blink/renderer/core/css/css_math_expression_node.cc --- chromium-145.0.7632.116/third_party/blink/renderer/core/css/css_math_expression_node.cc 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/third_party/blink/renderer/core/css/css_math_expression_node.cc 2026-03-02 23:00:09.000000000 +0000 @@ -2108,7 +2108,7 @@ CSSValueID function_id) { const CSSMathExpressionNode* operand = operands.front(); - if (operand->IsCalcSize()) { + if (operand->IsCalcSize() || CSSMathType(*operand).IsIntermediateResult()) { return nullptr; } diff -Nru chromium-145.0.7632.116/third_party/blink/renderer/core/css/cssom/css_unparsed_value.cc chromium-145.0.7632.159/third_party/blink/renderer/core/css/cssom/css_unparsed_value.cc --- chromium-145.0.7632.116/third_party/blink/renderer/core/css/cssom/css_unparsed_value.cc 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/third_party/blink/renderer/core/css/cssom/css_unparsed_value.cc 2026-03-02 23:00:09.000000000 +0000 @@ -19,7 +19,11 @@ String FindVariableName(CSSParserTokenStream& stream) { stream.ConsumeWhitespace(); - return stream.Consume().Value().ToString(); + if (stream.Peek().GetType() == CSSParserTokenType::kIdentToken) { + return stream.Consume().Value().ToString(); + } else { + return {}; + } } V8CSSUnparsedSegment* VariableReferenceValue( @@ -35,6 +39,11 @@ CSSStyleVariableReferenceValue* variable_reference = CSSStyleVariableReferenceValue::Create(variable_name.ToString(), unparsed_value); + if (!variable_reference) { + // TODO(sesse): Plumb the ExceptionState here so that we can use + // the Create() variant that properly throws an exception. + return nullptr; + } return MakeGarbageCollected(variable_reference); } @@ -57,8 +66,12 @@ if (stream.Peek().GetType() == CSSParserTokenType::kCommaToken) { stream.Consume(); } - tokens.push_back(VariableReferenceValue( - variable_name, ParserTokenStreamToTokens(stream))); + V8CSSUnparsedSegment* ref = VariableReferenceValue( + variable_name, ParserTokenStreamToTokens(stream)); + if (!ref) { + break; + } + tokens.push_back(ref); } else { if (stream.Peek().GetBlockType() == CSSParserToken::kBlockStart) { ++nesting_level; diff -Nru chromium-145.0.7632.116/third_party/blink/renderer/core/css/parser/css_parser_token.h chromium-145.0.7632.159/third_party/blink/renderer/core/css/parser/css_parser_token.h --- chromium-145.0.7632.116/third_party/blink/renderer/core/css/parser/css_parser_token.h 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/third_party/blink/renderer/core/css/parser/css_parser_token.h 2026-03-02 23:00:09.000000000 +0000 @@ -93,7 +93,8 @@ unit_(0), // Don't care. value_is_inline_(false), value_is_8bit_(false), // Don't care. - padding_(0) // Don't care. + padding_(0), // Don't care. + value_length_(0) // For security. {} // The resulting CSSParserToken may hold a reference to the data in value. @@ -128,6 +129,9 @@ return static_cast(type_); } StringView Value() const { +#if DCHECK_IS_ON() + DCHECK(has_value_); +#endif return value_is_8bit_ ? StringView(Span8()) : StringView(Span16()); } @@ -221,6 +225,9 @@ value_data_char_raw_ = string.Bytes(); value_is_inline_ = false; } +#if DCHECK_IS_ON() + has_value_ = true; +#endif } bool ValueDataCharRawEqual(const CSSParserToken& other) const; const void* ValueDataCharRaw() const { @@ -268,8 +275,15 @@ // tightly with the rest of this object for a smaller object size. unsigned value_is_8bit_ : 1; +#if DCHECK_IS_ON() + unsigned has_value_ : 1 = false; + + // These are free bits. You may take from them if you need. + [[maybe_unused]] unsigned padding_ : 11; +#else // These are free bits. You may take from them if you need. [[maybe_unused]] unsigned padding_ : 12; +#endif unsigned value_length_; union { diff -Nru chromium-145.0.7632.116/third_party/blink/renderer/core/inspector/devtools_session.cc chromium-145.0.7632.159/third_party/blink/renderer/core/inspector/devtools_session.cc --- chromium-145.0.7632.116/third_party/blink/renderer/core/inspector/devtools_session.cc 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/third_party/blink/renderer/core/inspector/devtools_session.cc 2026-03-02 23:00:09.000000000 +0000 @@ -401,6 +401,7 @@ } void DevToolsSession::Trace(Visitor* visitor) const { + v8_inspector::V8Inspector::ManagedChannel::Trace(visitor); visitor->Trace(receiver_); visitor->Trace(host_remote_); visitor->Trace(agent_); diff -Nru chromium-145.0.7632.116/third_party/blink/renderer/core/inspector/devtools_session.h chromium-145.0.7632.159/third_party/blink/renderer/core/inspector/devtools_session.h --- chromium-145.0.7632.116/third_party/blink/renderer/core/inspector/devtools_session.h 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/third_party/blink/renderer/core/inspector/devtools_session.h 2026-03-02 23:00:09.000000000 +0000 @@ -50,10 +50,10 @@ class InspectorPerformanceAgent; class InspectorWebAudioAgent; -class CORE_EXPORT DevToolsSession : public GarbageCollected, - public mojom::blink::DevToolsSession, - public protocol::FrontendChannel, - public v8_inspector::V8Inspector::Channel { +class CORE_EXPORT DevToolsSession + : public v8_inspector::V8Inspector::ManagedChannel, + public mojom::blink::DevToolsSession, + public protocol::FrontendChannel { public: DevToolsSession( DevToolsAgent*, @@ -87,7 +87,7 @@ } void Detach(); void DetachFromV8(); - void Trace(Visitor*) const; + void Trace(Visitor*) const override; // protocol::FrontendChannel implementation. void FlushProtocolNotifications() override; diff -Nru chromium-145.0.7632.116/third_party/blink/renderer/core/inspector/inspector_trace_events.cc chromium-145.0.7632.159/third_party/blink/renderer/core/inspector/inspector_trace_events.cc --- chromium-145.0.7632.116/third_party/blink/renderer/core/inspector/inspector_trace_events.cc 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/third_party/blink/renderer/core/inspector/inspector_trace_events.cc 2026-03-02 23:00:09.000000000 +0000 @@ -1321,6 +1321,7 @@ ExecutionContext* context, const v8::Local& function) { auto dict = std::move(trace_context).WriteDictionary(); + if (LocalFrame* frame = FrameForExecutionContext(context)) dict.Add("frame", IdentifiersFactory::FrameId(frame)); @@ -1348,6 +1349,7 @@ dict.Add("columnNumber", location->ColumnNumber()); uint64_t sample_trace_id = InspectorTraceEvents::GetNextSampleTraceId(); dict.Add("sampleTraceId", sample_trace_id); + v8::CpuProfiler::CollectSample(context->GetIsolate(), sample_trace_id); } void inspector_paint_image_event::Data(perfetto::TracedValue context, diff -Nru chromium-145.0.7632.116/third_party/blink/renderer/modules/clipboard/clipboard_change_event_controller.cc chromium-145.0.7632.159/third_party/blink/renderer/modules/clipboard/clipboard_change_event_controller.cc --- chromium-145.0.7632.116/third_party/blink/renderer/modules/clipboard/clipboard_change_event_controller.cc 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/third_party/blink/renderer/modules/clipboard/clipboard_change_event_controller.cc 2026-03-02 23:00:09.000000000 +0000 @@ -26,6 +26,9 @@ void ClipboardChangeEventController::FocusedFrameChanged() { if (fire_clipboardchange_on_focus_) { + if (!GetExecutionContext()) { + return; + } UseCounter::Count(GetExecutionContext(), WebFeature::kClipboardChangeEventFiredAfterFocusGain); fire_clipboardchange_on_focus_ = false; @@ -61,7 +64,13 @@ SystemClipboard* ClipboardChangeEventController::GetSystemClipboard() const { ExecutionContext* context = GetExecutionContext(); + if (!context) { + return nullptr; + } LocalFrame* local_frame = To(context)->GetFrame(); + if (!local_frame) { + return nullptr; + } return local_frame->GetSystemClipboard(); } @@ -74,7 +83,6 @@ void ClipboardChangeEventController::OnClipboardChanged() { ExecutionContext* context = GetExecutionContext(); - // TODO(roraja): revisit if this null check is really required if (!context) { return; } @@ -101,6 +109,9 @@ void ClipboardChangeEventController::MaybeDispatchClipboardChangeEvent() { ExecutionContext* context = GetExecutionContext(); + if (!context) { + return; + } LocalDOMWindow& window = *To(context); // Check if document has focus @@ -114,6 +125,9 @@ // Check for sticky activation first LocalFrame* frame = window.GetFrame(); + if (!frame) { + return; + } if (frame->HasStickyUserActivation()) { DispatchClipboardChangeEvent(); return; @@ -136,7 +150,6 @@ void ClipboardChangeEventController::DispatchClipboardChangeEvent() { SystemClipboard* clipboard = GetSystemClipboard(); - // TODO(roraja): revisit if this null check if (!clipboard) { return; } diff -Nru chromium-145.0.7632.116/third_party/blink/renderer/modules/clipboard/clipboard_change_event_controller_unittest.cc chromium-145.0.7632.159/third_party/blink/renderer/modules/clipboard/clipboard_change_event_controller_unittest.cc --- chromium-145.0.7632.116/third_party/blink/renderer/modules/clipboard/clipboard_change_event_controller_unittest.cc 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/third_party/blink/renderer/modules/clipboard/clipboard_change_event_controller_unittest.cc 2026-03-02 23:00:09.000000000 +0000 @@ -246,4 +246,104 @@ clipboard_change_event_handler, false); } +// Regression test: FocusedFrameChanged() must not crash when the execution +// context has been destroyed (e.g. during frame detachment). This reproduces +// the null dereference crash in MaybeDispatchClipboardChangeEvent() reported +// in crbug.com/1771962050. +// +// The real crash path is: Frame::Detach() -> DomWindow()->FrameDestroyed() +// (which calls NotifyContextDestroyed(), making GetExecutionContext() return +// null) -> FocusController::FrameDetached() -> SetFocusedFrame(nullptr) -> +// NotifyFocusChangedObservers() -> FocusedFrameChanged() -> +// MaybeDispatchClipboardChangeEvent() -> null dereference. +TEST_F(ClipboardChangeEventTest, NoCrashWhenFocusChangedAfterContextDestroyed) { + ExecutionContext* execution_context = GetFrame().DomWindow(); + GetFrame().GetSystemClipboard()->OnClipboardDataChanged({"text/plain"}, 1); + + SetSecureOrigin(execution_context); + // Page is not focused so that DidUpdateData() sets + // fire_clipboardchange_on_focus_ = true. + SetPageFocus(false); + + auto* clipboard_change_event_controller = + MakeGarbageCollected( + *GetFrame().DomWindow()->navigator(), &GetDocument()); + + // Trigger clipboard change while unfocused. OnClipboardChanged() calls + // MaybeDispatchClipboardChangeEvent() which sees no focus and sets + // fire_clipboardchange_on_focus_ = true. + clipboard_change_event_controller->DidUpdateData(); + test::RunPendingTasks(); + + // Simulate frame detachment by calling FrameDestroyed() directly on the + // DomWindow. This calls NotifyContextDestroyed(), making + // GetExecutionContext() return null (unit tests may call FrameDestroyed() + // manually per the code comments in LocalDOMWindow). + GetFrame().DomWindow()->FrameDestroyed(); + + // Calling FocusedFrameChanged() with a destroyed context must not crash. + // Before the fix: null dereference at *To(context) in + // MaybeDispatchClipboardChangeEvent() because fire_clipboardchange_on_focus_ + // is true and GetExecutionContext() returns null. + clipboard_change_event_controller->FocusedFrameChanged(); +} + +// Regression test: DidUpdateData() (via OnClipboardChanged) must not crash +// when the execution context has been destroyed during frame detachment. +TEST_F(ClipboardChangeEventTest, + NoCrashWhenClipboardChangedAfterContextDestroyed) { + ExecutionContext* execution_context = GetFrame().DomWindow(); + GetFrame().GetSystemClipboard()->OnClipboardDataChanged({"text/plain"}, 1); + + SetSecureOrigin(execution_context); + SetPageFocus(true); + + auto* clipboard_change_event_controller = + MakeGarbageCollected( + *GetFrame().DomWindow()->navigator(), &GetDocument()); + + // Simulate frame detachment. + GetFrame().DomWindow()->FrameDestroyed(); + + // OnClipboardChanged() already has a null check, so this should not crash. + clipboard_change_event_controller->DidUpdateData(); + test::RunPendingTasks(); +} + +// Regression test: MaybeDispatchClipboardChangeEvent must not crash during +// page teardown when fire_clipboardchange_on_focus_ is true. This simulates +// the exact crash path through Page::WillBeDestroyed() -> Frame::Detach() -> +// FocusController::FrameDetached() -> NotifyFocusChangedObservers(). +TEST_F(ClipboardChangeEventTest, + NoCrashDuringTeardownWithPendingFocusDispatch) { + ExecutionContext* execution_context = GetFrame().DomWindow(); + GetFrame().GetSystemClipboard()->OnClipboardDataChanged({"text/plain"}, 1); + + SetSecureOrigin(execution_context); + // First set page focused to establish the focused frame in FocusController + // (FocusHasChanged sets focused_frame_ = main_frame when focused is true). + SetPageFocus(true); + + auto* clipboard_change_event_controller = + MakeGarbageCollected( + *GetFrame().DomWindow()->navigator(), &GetDocument()); + + // Unfocus the page. This does NOT clear focused_frame_ (only updates + // is_active_ and is_focused_ flags). hasFocus() will now return false. + SetPageFocus(false); + + // Trigger clipboard change while unfocused to set + // fire_clipboardchange_on_focus_ = true. + clipboard_change_event_controller->DidUpdateData(); + test::RunPendingTasks(); + + // Do NOT call FrameDestroyed() — let PageTestBase::TearDown() destroy the + // page naturally. During teardown: Page::WillBeDestroyed() -> Frame::Detach() + // -> DomWindow()->FrameDestroyed() (context destroyed) -> + // FocusController::FrameDetached() -> SetFocusedFrame(nullptr) (because + // focused_frame_ == main_frame) -> NotifyFocusChangedObservers() -> + // FocusedFrameChanged() -> MaybeDispatchClipboardChangeEvent(). + // Before the fix: crashes with null dereference. +} + } // namespace blink diff -Nru chromium-145.0.7632.116/third_party/blink/renderer/modules/webcodecs/background_readback.cc chromium-145.0.7632.159/third_party/blink/renderer/modules/webcodecs/background_readback.cc --- chromium-145.0.7632.116/third_party/blink/renderer/modules/webcodecs/background_readback.cc 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/third_party/blink/renderer/modules/webcodecs/background_readback.cc 2026-03-02 23:00:09.000000000 +0000 @@ -164,7 +164,8 @@ ReadbackToFrameDoneCallback result_cb) { DCHECK(CanUseRgbReadback(*txt_frame)); - SkImageInfo info = GetImageInfoForFrame(*txt_frame, txt_frame->coded_size()); + SkImageInfo info = + GetImageInfoForFrame(*txt_frame, txt_frame->visible_rect().size()); const auto format = media::VideoPixelFormatFromSkColorType( info.colorType(), media::IsOpaque(txt_frame->format())); @@ -188,7 +189,7 @@ int rgba_stide = result->stride(media::VideoFrame::Plane::kARGB); DCHECK_GT(rgba_stide, 0); - gfx::Point src_point; + gfx::Point src_point = txt_frame->visible_rect().origin(); auto shared_image = txt_frame->shared_image(); auto origin = shared_image->surface_origin(); std::unique_ptr ri_access = @@ -250,7 +251,7 @@ base::span dst_pixels = dest_buffer.subspan(offset); size_t max_bytes_written = stride * src_rect.height(); - if (stride <= 0 || max_bytes_written > dest_buffer.size()) { + if (stride <= 0 || max_bytes_written > dst_pixels.size()) { DLOG(ERROR) << "Buffer is not sufficiently large for readback"; base::BindPostTaskToCurrentDefault(std::move(std::move(done_cb))) .Run(false); diff -Nru chromium-145.0.7632.116/third_party/blink/renderer/platform/audio/mac/fft_frame_mac.cc chromium-145.0.7632.159/third_party/blink/renderer/platform/audio/mac/fft_frame_mac.cc --- chromium-145.0.7632.116/third_party/blink/renderer/platform/audio/mac/fft_frame_mac.cc 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/third_party/blink/renderer/platform/audio/mac/fft_frame_mac.cc 2026-03-02 23:00:09.000000000 +0000 @@ -46,11 +46,11 @@ FFTFrame::FFTSetupDatum::FFTSetupDatum(unsigned log2fft_size) { // We only need power-of-two sized FFTS, so FFT_RADIX2. setup_ = vDSP_create_fftsetup(log2fft_size, FFT_RADIX2); - DCHECK(setup_); + CHECK(setup_); } FFTFrame::FFTSetupDatum::~FFTSetupDatum() { - DCHECK(setup_); + CHECK(setup_); vDSP_destroy_fftsetup(setup_); } @@ -63,7 +63,7 @@ if (first_call) { // Make sure we construct the fft_setups vector below on the main thread. // Once constructed, we can access it from any thread. - DCHECK(IsMainThread()); + CHECK(IsMainThread()); first_call = false; } @@ -82,7 +82,7 @@ // Make sure allocation of a new setup only occurs on the main thread so we // don't have a race condition with multiple threads trying to write to the // same element of the vector. - DCHECK(IsMainThread()); + CHECK(IsMainThread()); setup[log2fft_size] = std::make_unique(log2fft_size); } @@ -94,8 +94,10 @@ log2fft_size_(static_cast(log2(fft_size))), real_data_(fft_size), imag_data_(fft_size) { + CHECK_GE(fft_size, MinFFTSize()); + CHECK_LE(fft_size, MaxFFTSize()); // We only allow power of two - DCHECK_EQ(1UL << log2fft_size_, fft_size_); + CHECK_EQ(1UL << log2fft_size_, fft_size_); // Initialize the PFFFT_Setup object here so that it will be ready when we // compute FFTs. diff -Nru chromium-145.0.7632.116/third_party/blink/renderer/platform/audio/pffft/fft_frame_pffft.cc chromium-145.0.7632.159/third_party/blink/renderer/platform/audio/pffft/fft_frame_pffft.cc --- chromium-145.0.7632.116/third_party/blink/renderer/platform/audio/pffft/fft_frame_pffft.cc 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/third_party/blink/renderer/platform/audio/pffft/fft_frame_pffft.cc 2026-03-02 23:00:09.000000000 +0000 @@ -24,17 +24,17 @@ const unsigned kMinFFTPow2Size = 5; FFTFrame::FFTSetup::FFTSetup(unsigned fft_size) { - DCHECK_LE(fft_size, 1U << kMaxFFTPow2Size); - DCHECK_GE(fft_size, 1U << kMinFFTPow2Size); + CHECK_LE(fft_size, 1U << kMaxFFTPow2Size); + CHECK_GE(fft_size, 1U << kMinFFTPow2Size); // All FFTs we need are FFTs of real signals, and the inverse FFTs produce // real signals. Hence |PFFFT_REAL|. setup_ = pffft_new_setup(fft_size, PFFFT_REAL); - DCHECK(setup_); + CHECK(setup_); } FFTFrame::FFTSetup::~FFTSetup() { - DCHECK(setup_); + CHECK(setup_); pffft_destroy_setup(setup_); } @@ -56,14 +56,14 @@ // Make sure we construct the fft_setups vector below on the main thread. // Once constructed, we can access it from any thread. - DCHECK(IsMainThread()); + CHECK(IsMainThread()); first_call = false; base::AutoLock locker(setup_lock); // Initialize the hash map with all the possible keys (FFT sizes), with a // value of nullptr because we want to initialize the setup data lazily. The - // set of valid FFT sizes for PFFFT are of the form 2^k*3^m*5*n where k >= + // set of valid FFT sizes for PFFFT are of the form 2^k*3^m*5^n where k >= // 5, m >= 0, n >= 0. We only go up to a max size of 32768, because we need // at least an FFT size of 32768 for the convolver node. @@ -82,7 +82,7 @@ } // There should be 87 entries when we're done. - DCHECK_EQ(fft_setups.size(), 87u); + CHECK_EQ(fft_setups.size(), 87u); } return fft_setups; @@ -91,7 +91,7 @@ void FFTFrame::InitializeFFTSetupForSize(wtf_size_t fft_size) { auto& setup = FFTSetups(); - DCHECK(setup.Contains(fft_size)); + CHECK(setup.Contains(fft_size)); if (setup.find(fft_size)->value == nullptr) { DEFINE_STATIC_LOCAL(base::Lock, setup_lock, ()); @@ -99,7 +99,7 @@ // Make sure allocation of a new setup only occurs on the main thread so we // don't have a race condition with multiple threads trying to write to the // same element of the vector. - DCHECK(IsMainThread()); + CHECK(IsMainThread()); auto fft_data = std::make_unique(fft_size); base::AutoLock locker(setup_lock); @@ -110,8 +110,8 @@ PFFFT_Setup* FFTFrame::FFTSetupForSize(wtf_size_t fft_size) { auto& setup = FFTSetups(); - DCHECK(setup.Contains(fft_size)); - DCHECK(setup.find(fft_size)->value); + CHECK(setup.Contains(fft_size)); + CHECK(setup.find(fft_size)->value); return setup.find(fft_size)->value->GetSetup(); } @@ -123,6 +123,8 @@ imag_data_(fft_size / 2), complex_data_(fft_size), pffft_work_(fft_size) { + CHECK_GE(fft_size, MinFFTSize()); + CHECK_LE(fft_size, MaxFFTSize()); // Initialize the PFFFT_Setup object here so that it will be ready when we // compute FFTs. @@ -172,8 +174,8 @@ unsigned hrtf_fft_size = static_cast(HRTFPanner::FftSizeForSampleRate(sample_rate)); - DCHECK_GT(hrtf_fft_size, 1U << kMinFFTPow2Size); - DCHECK_LE(hrtf_fft_size, 1U << kMaxFFTPow2Size); + CHECK_GT(hrtf_fft_size, 1U << kMinFFTPow2Size); + CHECK_LE(hrtf_fft_size, 1U << kMaxFFTPow2Size); InitializeFFTSetupForSize(hrtf_fft_size); InitializeFFTSetupForSize(hrtf_fft_size / 2); diff -Nru chromium-145.0.7632.116/third_party/devtools-frontend/src/front_end/models/stack_trace/StackTraceImpl.test.ts chromium-145.0.7632.159/third_party/devtools-frontend/src/front_end/models/stack_trace/StackTraceImpl.test.ts --- chromium-145.0.7632.116/third_party/devtools-frontend/src/front_end/models/stack_trace/StackTraceImpl.test.ts 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/third_party/devtools-frontend/src/front_end/models/stack_trace/StackTraceImpl.test.ts 2026-03-02 23:00:09.000000000 +0000 @@ -72,5 +72,9 @@ assert.strictEqual(stringifyFragment(fragment), 'at foo (foo.ts:1:0)'); }); + + it('handles empty fragments correctly', () => { + assert.lengthOf(FragmentImpl.EMPTY_FRAGMENT.frames, 0); + }); }); }); diff -Nru chromium-145.0.7632.116/third_party/devtools-frontend/src/front_end/models/stack_trace/StackTraceImpl.ts chromium-145.0.7632.159/third_party/devtools-frontend/src/front_end/models/stack_trace/StackTraceImpl.ts --- chromium-145.0.7632.116/third_party/devtools-frontend/src/front_end/models/stack_trace/StackTraceImpl.ts 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/third_party/devtools-frontend/src/front_end/models/stack_trace/StackTraceImpl.ts 2026-03-02 23:00:09.000000000 +0000 @@ -31,7 +31,9 @@ } export class FragmentImpl implements StackTrace.StackTrace.Fragment { - readonly node: FrameNode; + static readonly EMPTY_FRAGMENT = new FragmentImpl(); + + readonly node?: FrameNode; readonly stackTraces = new Set(); /** @@ -46,11 +48,15 @@ return node.fragment; } - private constructor(node: FrameNode) { + private constructor(node?: FrameNode) { this.node = node; } get frames(): FrameImpl[] { + if (!this.node) { + return []; + } + const frames: FrameImpl[] = []; for (const node of this.node.getCallStack()) { @@ -101,6 +107,10 @@ } get frames(): DebuggableFrameImpl[] { + if (!this.fragment.node) { + return []; + } + const frames: DebuggableFrameImpl[] = []; let index = 0; diff -Nru chromium-145.0.7632.116/third_party/devtools-frontend/src/front_end/models/stack_trace/StackTraceModel.test.ts chromium-145.0.7632.159/third_party/devtools-frontend/src/front_end/models/stack_trace/StackTraceModel.test.ts --- chromium-145.0.7632.116/third_party/devtools-frontend/src/front_end/models/stack_trace/StackTraceModel.test.ts 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/third_party/devtools-frontend/src/front_end/models/stack_trace/StackTraceModel.test.ts 2026-03-02 23:00:09.000000000 +0000 @@ -177,6 +177,15 @@ ].join('\n')); }); + it('allows empty sync fragments', async () => { + const {model} = setup(); + + const stackTrace = await model.createFromProtocolRuntime({callFrames: []}, identityTranslateFn); + + assert.lengthOf(stackTrace.syncFragment.frames, 0); + assert.lengthOf(stackTrace.asyncFragments, 0); + }); + it('calls the translate function with the correct raw frames', async () => { const {model, translateSpy} = setup(); const callFrames = [ diff -Nru chromium-145.0.7632.116/third_party/devtools-frontend/src/front_end/models/stack_trace/StackTraceModel.ts chromium-145.0.7632.159/third_party/devtools-frontend/src/front_end/models/stack_trace/StackTraceModel.ts --- chromium-145.0.7632.116/third_party/devtools-frontend/src/front_end/models/stack_trace/StackTraceModel.ts 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/third_party/devtools-frontend/src/front_end/models/stack_trace/StackTraceModel.ts 2026-03-02 23:00:09.000000000 +0000 @@ -77,7 +77,7 @@ // is re-translated as a side-effect. // We just need to remember the stack traces of the skipped over fragments, so we can send the // UPDATED event also to them. - if (fragment.node.children.length === 0) { + if (fragment.node?.children.length === 0) { translatePromises.push(this.#translateFragment(fragment, translateRawFrames)); } stackTracesToUpdate = stackTracesToUpdate.union(fragment.stackTraces); @@ -133,6 +133,10 @@ } async #createFragment(frames: RawFrame[], rawFramesToUIFrames: TranslateRawFrames): Promise { + if (frames.length === 0) { + return FragmentImpl.EMPTY_FRAGMENT; + } + const release = await this.#mutex.acquire(); try { const node = this.#trie.insert(frames); @@ -150,6 +154,10 @@ } async #translateFragment(fragment: FragmentImpl, rawFramesToUIFrames: TranslateRawFrames): Promise { + if (!fragment.node) { + return; + } + const rawFrames = fragment.node.getCallStack().map(node => node.rawFrame).toArray(); const uiFrames = await rawFramesToUIFrames(rawFrames, this.target()); console.assert(rawFrames.length === uiFrames.length, 'Broken rawFramesToUIFrames implementation'); diff -Nru chromium-145.0.7632.116/third_party/devtools-frontend/src/front_end/panels/timeline/BUILD.gn chromium-145.0.7632.159/third_party/devtools-frontend/src/front_end/panels/timeline/BUILD.gn --- chromium-145.0.7632.116/third_party/devtools-frontend/src/front_end/panels/timeline/BUILD.gn 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/third_party/devtools-frontend/src/front_end/panels/timeline/BUILD.gn 2026-03-02 23:00:09.000000000 +0000 @@ -230,8 +230,11 @@ "../../core/sdk:bundle", "../../models/bindings:bundle", "../../models/trace:bundle", + "../../models/trace_source_maps_resolver:bundle", "../../models/workspace:bundle", "../../testing", + "../../ui/legacy/components/utils:bundle", + "../../ui/legacy/theme_support:bundle", "./components:bundle", ] } diff -Nru chromium-145.0.7632.116/third_party/devtools-frontend/src/front_end/panels/timeline/TimelineUIUtils.ts chromium-145.0.7632.159/third_party/devtools-frontend/src/front_end/panels/timeline/TimelineUIUtils.ts --- chromium-145.0.7632.116/third_party/devtools-frontend/src/front_end/panels/timeline/TimelineUIUtils.ts 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/third_party/devtools-frontend/src/front_end/panels/timeline/TimelineUIUtils.ts 2026-03-02 23:00:09.000000000 +0000 @@ -313,18 +313,10 @@ */ idleCallbackRequested: 'Idle callback requested', /** - * @description Stack label in Timeline UIUtils of the Performance panel - */ - recalculationForced: 'Recalculation forced', - /** * @description Call site stack label in Timeline UIUtils of the Performance panel */ firstLayoutInvalidation: 'First layout invalidation', /** - * @description Stack label in Timeline UIUtils of the Performance panel - */ - layoutForced: 'Layout forced', - /** * @description Label in front of CSS property (eg `opacity`) being animated or a CSS animation name (eg `layer-4-fade-in-out`) */ animating: 'Animating', @@ -1725,20 +1717,8 @@ parsedTrace: Trace.TraceModel.ParsedTrace): Promise { const {startTime} = Trace.Helpers.Timing.eventTimingsMilliSeconds(event); let initiatorStackLabel = i18nString(UIStrings.initiatorStackTrace); - let stackLabel = i18nString(UIStrings.functionStack); - const stackTraceForEvent = Trace.Extras.StackTraceForEvent.get(event, parsedTrace.data); - if (stackTraceForEvent?.callFrames.length || stackTraceForEvent?.description || stackTraceForEvent?.parent) { - contentHelper.addSection(i18nString(UIStrings.functionStack)); - await contentHelper.createChildStackTraceElement(stackTraceForEvent); - // TODO(andoli): also build stack trace component for other events - // that have a stack trace using the StackTraceForEvent helper. - } else { - const stackTrace = Trace.Helpers.Trace.getZeroIndexedStackTraceInEventPayload(event); - if (stackTrace?.length) { - contentHelper.addSection(stackLabel); - await contentHelper.createChildStackTraceElement(TimelineUIUtils.stackTraceFromCallFrames(stackTrace)); - } - } + await contentHelper.appendFunctionStackTraceSection(event, parsedTrace); + switch (event.name) { case Trace.Types.Events.Name.TIMER_FIRE: initiatorStackLabel = i18nString(UIStrings.timerInstalled); @@ -1751,11 +1731,9 @@ break; case Trace.Types.Events.Name.RECALC_STYLE: initiatorStackLabel = i18nString(UIStrings.firstInvalidated); - stackLabel = i18nString(UIStrings.recalculationForced); break; case Trace.Types.Events.Name.LAYOUT: initiatorStackLabel = i18nString(UIStrings.firstLayoutInvalidation); - stackLabel = i18nString(UIStrings.layoutForced); break; } @@ -1768,8 +1746,9 @@ // and the time since the initiator (Pending For). const stackTrace = Trace.Helpers.Trace.getZeroIndexedStackTraceInEventPayload(initiator); if (stackTrace) { - contentHelper.addSection(initiatorStackLabel); - await contentHelper.createChildStackTraceElement(TimelineUIUtils.stackTraceFromCallFrames(stackTrace)); + const traceElement = + await contentHelper.createChildStackTraceElement(TimelineUIUtils.stackTraceFromCallFrames(stackTrace)); + contentHelper.appendSectionWithBodyIfExists(initiatorStackLabel, {body: traceElement}); } const link = this.createEntryLink(initiator); @@ -2414,6 +2393,39 @@ this.fragment.appendChild(this.element); } + /** + * Creates a new section, but only if the provided `body` element is present, + * otherwise it does nothing. + */ + appendSectionWithBodyIfExists(title: string, options: { + body: HTMLElement|null, + swatchColor?: string, + event?: Trace.Types.Events.Event, + }): void { + if (!options.body) { + return; + } + this.addSection(title, options.swatchColor, options.event); + this.tableElement.appendChild(options.body); + } + + /** + * Generates a stack trace for the given event. If there is no stack data, + * nothing is appended; you can safely call this without fearing that it will + * create an empty section. + */ + async appendFunctionStackTraceSection( + event: Trace.Types.Events.Event, + parsedTrace: Trace.TraceModel.ParsedTrace, + ): Promise { + const stackTraceForEvent = Trace.Extras.StackTraceForEvent.get(event, parsedTrace.data); + if (!stackTraceForEvent) { + return; + } + const traceElement = await this.createChildStackTraceElement(stackTraceForEvent); + this.appendSectionWithBodyIfExists(i18nString(UIStrings.functionStack), {body: traceElement}); + } + linkifier(): LegacyComponents.Linkifier.Linkifier|null { return this.#linkifier; } @@ -2481,9 +2493,13 @@ this.appendElementRow(title, locationContent); } - async createChildStackTraceElement(runtimeStackTrace: Protocol.Runtime.StackTrace): Promise { + /** + * Creates a stack trace element for the given trace, but checks if it + * contains any entries, and discards it if it's empty. + */ + async createChildStackTraceElement(runtimeStackTrace: Protocol.Runtime.StackTrace): Promise { if (!this.#linkifier) { - return; + return null; } let callFrameContents; @@ -2493,7 +2509,6 @@ callFrameContents = new LegacyComponents.JSPresentationUtils.StackTracePreviewContent( undefined, this.target ?? undefined, this.#linkifier, {tabStops: true, showColumnNumber: true}); callFrameContents.stackTrace = stackTrace; - await callFrameContents.updateComplete; } else { // I _think_ this only happens during tests. // See "TimelineFlameChartView > shows the details for a selected main thread event". @@ -2505,10 +2520,16 @@ {runtimeStackTrace, tabStops: true, showColumnNumber: true}); } - const stackTraceElement = - this.tableElement.createChild('div', 'timeline-details-view-row timeline-details-stack-values'); + await callFrameContents.updateComplete; + if (!callFrameContents.hasContent()) { + return null; + } + + const stackTraceElement = document.createElement('div'); + stackTraceElement.classList.add('timeline-details-view-row', 'timeline-details-stack-values'); callFrameContents.markAsRoot(); callFrameContents.show(stackTraceElement); + return stackTraceElement; } } diff -Nru chromium-145.0.7632.116/third_party/devtools-frontend/src/front_end/ui/legacy/components/utils/JSPresentationUtils.test.ts chromium-145.0.7632.159/third_party/devtools-frontend/src/front_end/ui/legacy/components/utils/JSPresentationUtils.test.ts --- chromium-145.0.7632.116/third_party/devtools-frontend/src/front_end/ui/legacy/components/utils/JSPresentationUtils.test.ts 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/third_party/devtools-frontend/src/front_end/ui/legacy/components/utils/JSPresentationUtils.test.ts 2026-03-02 23:00:09.000000000 +0000 @@ -126,6 +126,7 @@ const component = new Components.JSPresentationUtils.StackTracePreviewContent(undefined, target, linkifier, options); renderElementIntoDOM(component); + assert.isFalse(component.hasContent()); component.stackTrace = stackTrace; await component.updateComplete; assert.deepEqual(component.contentElement.deepInnerText().split('\n'), ['\tfoo\t@\twww.google.com/script.js:1']); @@ -133,6 +134,7 @@ assert.exists(expandButton); expandButton.click(); await component.updateComplete; + assert.isTrue(component.hasContent()); assert.deepEqual(component.contentElement.deepInnerText().split('\n'), [ '\tfoo\t@\twww.google.com/script.js:1', '\tbar\t@\tbar.js:2', diff -Nru chromium-145.0.7632.116/third_party/devtools-frontend/src/front_end/ui/legacy/components/utils/JSPresentationUtils.ts chromium-145.0.7632.159/third_party/devtools-frontend/src/front_end/ui/legacy/components/utils/JSPresentationUtils.ts --- chromium-145.0.7632.116/third_party/devtools-frontend/src/front_end/ui/legacy/components/utils/JSPresentationUtils.ts 2026-02-20 20:20:04.000000000 +0000 +++ chromium-145.0.7632.159/third_party/devtools-frontend/src/front_end/ui/legacy/components/utils/JSPresentationUtils.ts 2026-03-02 23:00:09.000000000 +0000 @@ -324,6 +324,11 @@ #links: HTMLElement[] = []; readonly #table: HTMLElement; + /** + * Updated when we update to define if we have any rows for the StackTrace; + * allowing the caller to know if this element is empty or not. + */ + #hasRows = false; constructor(element?: HTMLElement, target?: SDK.Target.Target, linkifier?: Linkifier, options?: Options) { super(element, {useShadowDom: true}); @@ -353,6 +358,10 @@ this.performUpdate(); } + hasContent(): boolean { + return this.#hasRows; + } + override performUpdate(): void { if (!this.#linkifier) { return; @@ -363,6 +372,7 @@ if (this.#stackTrace) { const stackTraceRows = buildStackTraceRows( this.#stackTrace, this.#target ?? null, this.#linkifier, tabStops, this.#options.showColumnNumber); + this.#hasRows = stackTraceRows.length > 0; this.#links = renderStackTraceTable(this.#table, this.element, this.#options.expandable ?? false, stackTraceRows); return; } @@ -373,6 +383,7 @@ const stackTraceRows = buildStackTraceRowsForLegacyRuntimeStackTrace( runtimeStackTrace ?? {callFrames: []}, this.#target ?? null, this.#linkifier, tabStops, updateCallback, this.#options.showColumnNumber); + this.#hasRows = stackTraceRows.length > 0; this.#links = renderStackTraceTable(this.#table, this.element, this.#options.expandable ?? false, stackTraceRows); } diff -Nru chromium-145.0.7632.116/third_party/libxslt/BUILD.gn chromium-145.0.7632.159/third_party/libxslt/BUILD.gn --- chromium-145.0.7632.116/third_party/libxslt/BUILD.gn 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/BUILD.gn 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,113 @@ +# Copyright 2014 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +config("libxslt_config") { + defines = [ "LIBXSLT_STATIC" ] + + # TODO(crbug.com/364568421): Consdier removing "src/libxslt" from this list + # if we can remove win32config.h + include_dirs = [ + "src", + "src/libxslt", + ] +} + +config("libxslt_warnings") { + if (is_clang) { + cflags = [ + # libxslt stores a char[3] in a `const unsigned char*`. + "-Wno-pointer-sign", + + # xsltDefaultRegion and xsltCalibrateTimestamps are only + # used with certain preprocessor defines set. + "-Wno-unused-function", + ] + } +} + +static_library("libxslt") { + sources = [ + "src/libxslt/attributes.c", + "src/libxslt/attributes.h", + "src/libxslt/attrvt.c", + "src/libxslt/documents.c", + "src/libxslt/documents.h", + "src/libxslt/extensions.c", + "src/libxslt/extensions.h", + "src/libxslt/extra.c", + "src/libxslt/extra.h", + "src/libxslt/functions.c", + "src/libxslt/functions.h", + "src/libxslt/imports.c", + "src/libxslt/imports.h", + "src/libxslt/keys.c", + "src/libxslt/keys.h", + "src/libxslt/libxslt.h", + "src/libxslt/namespaces.c", + "src/libxslt/namespaces.h", + "src/libxslt/numbers.c", + "src/libxslt/numbersInternals.h", + "src/libxslt/pattern.c", + "src/libxslt/pattern.h", + "src/libxslt/preproc.c", + "src/libxslt/preproc.h", + "src/libxslt/security.c", + "src/libxslt/security.h", + "src/libxslt/templates.c", + "src/libxslt/templates.h", + "src/libxslt/transform.c", + "src/libxslt/transform.h", + "src/libxslt/trio.h", + "src/libxslt/triodef.h", + "src/libxslt/variables.c", + "src/libxslt/variables.h", + "src/libxslt/win32config.h", + "src/libxslt/xslt.c", + "src/libxslt/xslt.h", + "src/libxslt/xsltInternals.h", + "src/libxslt/xsltconfig.h", + "src/libxslt/xsltexports.h", + "src/libxslt/xsltlocale.c", + "src/libxslt/xsltlocale.h", + "src/libxslt/xsltutils.c", + "src/libxslt/xsltutils.h", + "win32/config.h", + ] + + configs -= [ "//build/config/compiler:chromium_code" ] + configs += [ + "//build/config/compiler:no_chromium_code", + + # Must be after no_chromium_code for warning flags to be ordered correctly. + ":libxslt_warnings", + ] + public_configs = [ ":libxslt_config" ] + + if (is_linux || is_chromeos) { + sources += [ "linux/config.h" ] + } + if (is_apple) { + sources += [ "mac/config.h" ] + } + + cflags = [] + if (is_linux || is_chromeos || is_android || is_fuchsia) { + include_dirs = [ "linux" ] + } else if (is_win) { + include_dirs = [ "win32" ] + cflags += [ + "/wd4267", # size_t to int. + + # TODO(brucedawson): http://crbug.com/554200 4311 is a VS + # 2015 64-bit warning for pointer truncation + "/wd4311", + ] + } else if (is_apple) { + include_dirs = [ "mac" ] + } + + deps = [ "//third_party/libxml" ] + + visibility = [ "//third_party/blink/renderer/*" ] +} diff -Nru chromium-145.0.7632.116/third_party/libxslt/DIR_METADATA chromium-145.0.7632.159/third_party/libxslt/DIR_METADATA --- chromium-145.0.7632.116/third_party/libxslt/DIR_METADATA 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/DIR_METADATA 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,6 @@ +monorail: { + component: "Blink>XML" +} +buganizer_public: { + component_id: 1456730 +} diff -Nru chromium-145.0.7632.116/third_party/libxslt/OWNERS chromium-145.0.7632.159/third_party/libxslt/OWNERS --- chromium-145.0.7632.116/third_party/libxslt/OWNERS 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/OWNERS 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1 @@ +file://third_party/libxml/OWNERS diff -Nru chromium-145.0.7632.116/third_party/libxslt/README.chromium chromium-145.0.7632.159/third_party/libxslt/README.chromium --- chromium-145.0.7632.116/third_party/libxslt/README.chromium 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/README.chromium 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,16 @@ +Name: libxslt +URL: http://xmlsoft.org/XSLT +Revision: 35323d6a15f6e63c9919ddbc0abe64c90a0dd88a +Update Mechanism: Manual +Version: 35323d6a15f6e63c9919ddbc0abe64c90a0dd88a +CPEPrefix: cpe:/a:xmlsoft:libxslt:1.1.45 +Security Critical: yes +Shipped: yes +License: X11 +License File: src/Copyright + +Description: + +libxslt from libxml.org. + +Modifications: Apply the patches in chromium/*.patch diff -Nru chromium-145.0.7632.116/third_party/libxslt/chromium/0004-Use-a-dedicated-node-type-to-maintain-the-list-of-ca.patch chromium-145.0.7632.159/third_party/libxslt/chromium/0004-Use-a-dedicated-node-type-to-maintain-the-list-of-ca.patch --- chromium-145.0.7632.116/third_party/libxslt/chromium/0004-Use-a-dedicated-node-type-to-maintain-the-list-of-ca.patch 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/chromium/0004-Use-a-dedicated-node-type-to-maintain-the-list-of-ca.patch 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,707 @@ +From 6ce8f3bf2b51befcea2af489bc859d690888981f Mon Sep 17 00:00:00 2001 +From: Daniel Cheng +Date: Wed, 4 Jun 2025 12:19:14 -0700 +Subject: [PATCH] Use a dedicated node type to maintain the list of cached RVTs + +While evaluating a stylesheet, result value trees (result tree fragments +in the XSLT spec) are represented as xmlDocs and cached on the transform +context in a linked list, using xmlDoc's prev and next pointers to +maintain the list. + +However, XPath evaluations can inadvertently traverse these links, which +are an implementation detail and do not reflect the actual document +structure. Using a dedicated node type avoids these unintended +traversals. + +Bug: 416535738 +Change-Id: Iaacbe617905a3f844367cc56b2cbcf525d4818b6 +--- + third_party/libxslt/src/libxslt/transform.c | 87 ++++--- + third_party/libxslt/src/libxslt/variables.c | 219 +++++++++++------- + .../libxslt/src/libxslt/xsltInternals.h | 23 +- + 3 files changed, 199 insertions(+), 130 deletions(-) + +diff --git a/third_party/libxslt/src/libxslt/transform.c b/third_party/libxslt/src/libxslt/transform.c +index 6ce73d2526e32..ac89c9b96bac4 100644 +--- a/libxslt/transform.c ++++ b/libxslt/transform.c +@@ -518,19 +518,20 @@ xsltTransformCacheFree(xsltTransformCachePtr cache) + /* + * Free tree fragments. + */ +- if (cache->RVT) { +- xmlDocPtr tmp, cur = cache->RVT; ++ if (cache->rvtList) { ++ xsltRVTListPtr tmp, cur = cache->rvtList; + while (cur) { + tmp = cur; +- cur = (xmlDocPtr) cur->next; +- if (tmp->_private != NULL) { ++ cur = cur->next; ++ if (tmp->RVT->_private != NULL) { + /* +- * Tree the document info. ++ * Free the document info. + */ +- xsltFreeDocumentKeys((xsltDocumentPtr) tmp->_private); +- xmlFree(tmp->_private); ++ xsltFreeDocumentKeys((xsltDocumentPtr) tmp->RVT->_private); ++ xmlFree(tmp->RVT->_private); + } +- xmlFreeDoc(tmp); ++ xmlFreeDoc(tmp->RVT); ++ xmlFree(tmp); + } + } + /* +@@ -2263,38 +2264,36 @@ xsltLocalVariablePush(xsltTransformContextPtr ctxt, + * are preserved; all other fragments are freed/cached. + */ + static void +-xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt, xmlDocPtr base) ++xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt, xsltRVTListPtr base) + { +- xmlDocPtr cur = ctxt->localRVT, tmp; ++ xsltRVTListPtr cur = ctxt->localRVTList, tmp; + + if (cur == base) + return; +- if (cur->prev != NULL) +- xsltTransformError(ctxt, NULL, NULL, "localRVT not head of list\n"); + +- /* Reset localRVT early because some RVTs might be registered again. */ +- ctxt->localRVT = base; +- if (base != NULL) +- base->prev = NULL; ++ /* Reset localRVTList early because some RVTs might be registered again. */ ++ ctxt->localRVTList = base; + + do { + tmp = cur; +- cur = (xmlDocPtr) cur->next; +- if (tmp->compression == XSLT_RVT_LOCAL) { +- xsltReleaseRVT(ctxt, tmp); +- } else if (tmp->compression == XSLT_RVT_GLOBAL) { +- xsltRegisterPersistRVT(ctxt, tmp); +- } else if (tmp->compression == XSLT_RVT_FUNC_RESULT) { ++ cur = cur->next; ++ if (tmp->RVT->compression == XSLT_RVT_LOCAL) { ++ xsltReleaseRVTList(ctxt, tmp); ++ } else if (tmp->RVT->compression == XSLT_RVT_GLOBAL) { ++ xsltRegisterPersistRVT(ctxt, tmp->RVT); ++ xmlFree(tmp); ++ } else if (tmp->RVT->compression == XSLT_RVT_FUNC_RESULT) { + /* + * This will either register the RVT again or move it to the + * context variable. + */ +- xsltRegisterLocalRVT(ctxt, tmp); +- tmp->compression = XSLT_RVT_FUNC_RESULT; ++ xsltRegisterLocalRVT(ctxt, tmp->RVT); ++ tmp->RVT->compression = XSLT_RVT_FUNC_RESULT; ++ xmlFree(tmp); + } else { + xmlGenericError(xmlGenericErrorContext, +- "xsltReleaseLocalRVTs: Unexpected RVT flag %p\n", +- tmp->psvi); ++ "xsltReleaseLocalRVTs: Unexpected RVT flag %d\n", ++ tmp->RVT->compression); + } + } while (cur != base); + } +@@ -2322,7 +2321,7 @@ xsltApplySequenceConstructor(xsltTransformContextPtr ctxt, + xmlNodePtr oldInsert, oldInst, oldCurInst, oldContextNode; + xmlNodePtr cur, insert, copy = NULL; + int level = 0, oldVarsNr; +- xmlDocPtr oldLocalFragmentTop; ++ xsltRVTListPtr oldLocalFragmentTop; + + #ifdef XSLT_REFACTORED + xsltStylePreCompPtr info; +@@ -2368,7 +2367,7 @@ xsltApplySequenceConstructor(xsltTransformContextPtr ctxt, + } + ctxt->depth++; + +- oldLocalFragmentTop = ctxt->localRVT; ++ oldLocalFragmentTop = ctxt->localRVTList; + oldInsert = insert = ctxt->insert; + oldInst = oldCurInst = ctxt->inst; + oldContextNode = ctxt->node; +@@ -2602,7 +2601,7 @@ xsltApplySequenceConstructor(xsltTransformContextPtr ctxt, + /* + * Cleanup temporary tree fragments. + */ +- if (oldLocalFragmentTop != ctxt->localRVT) ++ if (oldLocalFragmentTop != ctxt->localRVTList) + xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); + + ctxt->insert = oldInsert; +@@ -2697,7 +2696,7 @@ xsltApplySequenceConstructor(xsltTransformContextPtr ctxt, + /* + * Cleanup temporary tree fragments. + */ +- if (oldLocalFragmentTop != ctxt->localRVT) ++ if (oldLocalFragmentTop != ctxt->localRVTList) + xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); + + ctxt->insert = oldInsert; +@@ -2763,7 +2762,7 @@ xsltApplySequenceConstructor(xsltTransformContextPtr ctxt, + /* + * Cleanup temporary tree fragments. + */ +- if (oldLocalFragmentTop != ctxt->localRVT) ++ if (oldLocalFragmentTop != ctxt->localRVTList) + xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); + + ctxt->insert = oldInsert; +@@ -2893,7 +2892,7 @@ xsltApplySequenceConstructor(xsltTransformContextPtr ctxt, + /* + * Cleanup temporary tree fragments. + */ +- if (oldLocalFragmentTop != ctxt->localRVT) ++ if (oldLocalFragmentTop != ctxt->localRVTList) + xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); + + ctxt->insert = oldInsert; +@@ -3072,7 +3071,7 @@ xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt, + int oldVarsBase = 0; + xmlNodePtr cur; + xsltStackElemPtr tmpParam = NULL; +- xmlDocPtr oldUserFragmentTop; ++ xsltRVTListPtr oldUserFragmentTop; + #ifdef WITH_PROFILER + long start = 0; + #endif +@@ -3120,8 +3119,8 @@ xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt, + return; + } + +- oldUserFragmentTop = ctxt->tmpRVT; +- ctxt->tmpRVT = NULL; ++ oldUserFragmentTop = ctxt->tmpRVTList; ++ ctxt->tmpRVTList = NULL; + + /* + * Initiate a distinct scope of local params/variables. +@@ -3232,16 +3231,16 @@ xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt, + * user code should now use xsltRegisterLocalRVT() instead + * of the obsolete xsltRegisterTmpRVT(). + */ +- if (ctxt->tmpRVT) { +- xmlDocPtr curdoc = ctxt->tmpRVT, tmp; ++ if (ctxt->tmpRVTList) { ++ xsltRVTListPtr curRVTList = ctxt->tmpRVTList, tmp; + +- while (curdoc != NULL) { +- tmp = curdoc; +- curdoc = (xmlDocPtr) curdoc->next; +- xsltReleaseRVT(ctxt, tmp); ++ while (curRVTList != NULL) { ++ tmp = curRVTList; ++ curRVTList = curRVTList->next; ++ xsltReleaseRVTList(ctxt, tmp); + } + } +- ctxt->tmpRVT = oldUserFragmentTop; ++ ctxt->tmpRVTList = oldUserFragmentTop; + + /* + * Pop the xsl:template declaration from the stack. +@@ -5319,7 +5318,7 @@ xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, + + #ifdef XSLT_FAST_IF + { +- xmlDocPtr oldLocalFragmentTop = ctxt->localRVT; ++ xsltRVTListPtr oldLocalFragmentTop = ctxt->localRVTList; + + res = xsltPreCompEvalToBoolean(ctxt, contextNode, comp); + +@@ -5327,7 +5326,7 @@ xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, + * Cleanup fragments created during evaluation of the + * "select" expression. + */ +- if (oldLocalFragmentTop != ctxt->localRVT) ++ if (oldLocalFragmentTop != ctxt->localRVTList) + xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); + } + +diff --git a/libxslt/variables.c b/libxslt/variables.c +index eb98aab2fdc90..6696d9a1315c8 100644 +--- a/libxslt/variables.c ++++ b/libxslt/variables.c +@@ -47,6 +47,21 @@ static const xmlChar *xsltComputingGlobalVarMarker = + #define XSLT_VAR_IN_SELECT (1<<1) + #define XSLT_TCTXT_VARIABLE(c) ((xsltStackElemPtr) (c)->contextVariable) + ++static xsltRVTListPtr ++xsltRVTListCreate(void) ++{ ++ xsltRVTListPtr ret; ++ ++ ret = (xsltRVTListPtr) xmlMalloc(sizeof(xsltRVTList)); ++ if (ret == NULL) { ++ xsltTransformError(NULL, NULL, NULL, ++ "xsltRVTListCreate: malloc failed\n"); ++ return(NULL); ++ } ++ memset(ret, 0, sizeof(xsltRVTList)); ++ return(ret); ++} ++ + /************************************************************************ + * * + * Result Value Tree (Result Tree Fragment) interfaces * +@@ -64,6 +79,7 @@ static const xmlChar *xsltComputingGlobalVarMarker = + xmlDocPtr + xsltCreateRVT(xsltTransformContextPtr ctxt) + { ++ xsltRVTListPtr rvtList; + xmlDocPtr container; + + /* +@@ -76,12 +92,11 @@ xsltCreateRVT(xsltTransformContextPtr ctxt) + /* + * Reuse a RTF from the cache if available. + */ +- if (ctxt->cache->RVT) { +- container = ctxt->cache->RVT; +- ctxt->cache->RVT = (xmlDocPtr) container->next; +- /* clear the internal pointers */ +- container->next = NULL; +- container->prev = NULL; ++ if (ctxt->cache->rvtList) { ++ rvtList = ctxt->cache->rvtList; ++ container = ctxt->cache->rvtList->RVT; ++ ctxt->cache->rvtList = rvtList->next; ++ xmlFree(rvtList); + if (ctxt->cache->nbRVT > 0) + ctxt->cache->nbRVT--; + #ifdef XSLT_DEBUG_PROFILE_CACHE +@@ -119,11 +134,16 @@ xsltCreateRVT(xsltTransformContextPtr ctxt) + int + xsltRegisterTmpRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) + { ++ xsltRVTListPtr list; ++ + if ((ctxt == NULL) || (RVT == NULL)) + return(-1); + +- RVT->prev = NULL; ++ list = xsltRVTListCreate(); ++ if (list == NULL) return(-1); ++ + RVT->compression = XSLT_RVT_LOCAL; ++ list->RVT = RVT; + + /* + * We'll restrict the lifetime of user-created fragments +@@ -131,15 +151,13 @@ xsltRegisterTmpRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) + * var/param itself. + */ + if (ctxt->contextVariable != NULL) { +- RVT->next = (xmlNodePtr) XSLT_TCTXT_VARIABLE(ctxt)->fragment; +- XSLT_TCTXT_VARIABLE(ctxt)->fragment = RVT; ++ list->next = XSLT_TCTXT_VARIABLE(ctxt)->fragment; ++ XSLT_TCTXT_VARIABLE(ctxt)->fragment = list; + return(0); + } + +- RVT->next = (xmlNodePtr) ctxt->tmpRVT; +- if (ctxt->tmpRVT != NULL) +- ctxt->tmpRVT->prev = (xmlNodePtr) RVT; +- ctxt->tmpRVT = RVT; ++ list->next = ctxt->tmpRVTList; ++ ctxt->tmpRVTList = list; + return(0); + } + +@@ -159,11 +177,16 @@ int + xsltRegisterLocalRVT(xsltTransformContextPtr ctxt, + xmlDocPtr RVT) + { ++ xsltRVTListPtr list; ++ + if ((ctxt == NULL) || (RVT == NULL)) + return(-1); + +- RVT->prev = NULL; ++ list = xsltRVTListCreate(); ++ if (list == NULL) return(-1); ++ + RVT->compression = XSLT_RVT_LOCAL; ++ list->RVT = RVT; + + /* + * When evaluating "select" expressions of xsl:variable +@@ -174,8 +197,8 @@ xsltRegisterLocalRVT(xsltTransformContextPtr ctxt, + if ((ctxt->contextVariable != NULL) && + (XSLT_TCTXT_VARIABLE(ctxt)->flags & XSLT_VAR_IN_SELECT)) + { +- RVT->next = (xmlNodePtr) XSLT_TCTXT_VARIABLE(ctxt)->fragment; +- XSLT_TCTXT_VARIABLE(ctxt)->fragment = RVT; ++ list->next = XSLT_TCTXT_VARIABLE(ctxt)->fragment; ++ XSLT_TCTXT_VARIABLE(ctxt)->fragment = list; + return(0); + } + /* +@@ -183,10 +206,8 @@ xsltRegisterLocalRVT(xsltTransformContextPtr ctxt, + * If not reference by a returning instruction (like EXSLT's function), + * then this fragment will be freed, when the instruction exits. + */ +- RVT->next = (xmlNodePtr) ctxt->localRVT; +- if (ctxt->localRVT != NULL) +- ctxt->localRVT->prev = (xmlNodePtr) RVT; +- ctxt->localRVT = RVT; ++ list->next = ctxt->localRVTList; ++ ctxt->localRVTList = list; + return(0); + } + +@@ -344,8 +365,9 @@ xsltFlagRVTs(xsltTransformContextPtr ctxt, xmlXPathObjectPtr obj, int val) { + * @ctxt: an XSLT transformation context + * @RVT: a result value tree (Result Tree Fragment) + * +- * Either frees the RVT (which is an xmlDoc) or stores +- * it in the context's cache for later reuse. ++ * Either frees the RVT (which is an xmlDoc) or stores it in the context's ++ * cache for later reuse. Preserved for ABI/API compatibility; internal use ++ * has all migrated to xsltReleaseRVTList(). + */ + void + xsltReleaseRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) +@@ -353,36 +375,64 @@ xsltReleaseRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) + if (RVT == NULL) + return; + ++ xsltRVTListPtr list = xsltRVTListCreate(); ++ if (list == NULL) { ++ if (RVT->_private != NULL) { ++ xsltFreeDocumentKeys((xsltDocumentPtr) RVT->_private); ++ xmlFree(RVT->_private); ++ } ++ xmlFreeDoc(RVT); ++ return; ++ } ++ ++ xsltReleaseRVTList(ctxt, list); ++} ++ ++/** ++ * xsltReleaseRVTList: ++ * @ctxt: an XSLT transformation context ++ * @list: a list node containing a result value tree (Result Tree Fragment) ++ * ++ * Either frees the list node or stores it in the context's cache for later ++ * reuse. Optimization to avoid adding a fallible allocation path when the ++ * caller already has a RVT list node. ++ */ ++void ++xsltReleaseRVTList(xsltTransformContextPtr ctxt, xsltRVTListPtr list) ++{ ++ if (list == NULL) ++ return; ++ + if (ctxt && (ctxt->cache->nbRVT < 40)) { + /* + * Store the Result Tree Fragment. + * Free the document info. + */ +- if (RVT->_private != NULL) { +- xsltFreeDocumentKeys((xsltDocumentPtr) RVT->_private); +- xmlFree(RVT->_private); +- RVT->_private = NULL; ++ if (list->RVT->_private != NULL) { ++ xsltFreeDocumentKeys((xsltDocumentPtr) list->RVT->_private); ++ xmlFree(list->RVT->_private); ++ list->RVT->_private = NULL; + } + /* + * Clear the document tree. + */ +- if (RVT->children != NULL) { +- xmlFreeNodeList(RVT->children); +- RVT->children = NULL; +- RVT->last = NULL; ++ if (list->RVT->children != NULL) { ++ xmlFreeNodeList(list->RVT->children); ++ list->RVT->children = NULL; ++ list->RVT->last = NULL; + } +- if (RVT->ids != NULL) { +- xmlFreeIDTable((xmlIDTablePtr) RVT->ids); +- RVT->ids = NULL; ++ if (list->RVT->ids != NULL) { ++ xmlFreeIDTable((xmlIDTablePtr) list->RVT->ids); ++ list->RVT->ids = NULL; + } + + /* + * Reset the ownership information. + */ +- RVT->compression = 0; ++ list->RVT->compression = 0; + +- RVT->next = (xmlNodePtr) ctxt->cache->RVT; +- ctxt->cache->RVT = RVT; ++ list->next = ctxt->cache->rvtList; ++ ctxt->cache->rvtList = list; + + ctxt->cache->nbRVT++; + +@@ -394,11 +444,12 @@ xsltReleaseRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) + /* + * Free it. + */ +- if (RVT->_private != NULL) { +- xsltFreeDocumentKeys((xsltDocumentPtr) RVT->_private); +- xmlFree(RVT->_private); ++ if (list->RVT->_private != NULL) { ++ xsltFreeDocumentKeys((xsltDocumentPtr) list->RVT->_private); ++ xmlFree(list->RVT->_private); + } +- xmlFreeDoc(RVT); ++ xmlFreeDoc(list->RVT); ++ xmlFree(list); + } + + /** +@@ -416,14 +467,17 @@ xsltReleaseRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) + int + xsltRegisterPersistRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) + { ++ xsltRVTListPtr list; ++ + if ((ctxt == NULL) || (RVT == NULL)) return(-1); + ++ list = xsltRVTListCreate(); ++ if (list == NULL) return(-1); ++ + RVT->compression = XSLT_RVT_GLOBAL; +- RVT->prev = NULL; +- RVT->next = (xmlNodePtr) ctxt->persistRVT; +- if (ctxt->persistRVT != NULL) +- ctxt->persistRVT->prev = (xmlNodePtr) RVT; +- ctxt->persistRVT = RVT; ++ list->RVT = RVT; ++ list->next = ctxt->persistRVTList; ++ ctxt->persistRVTList = list; + return(0); + } + +@@ -438,52 +492,55 @@ xsltRegisterPersistRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) + void + xsltFreeRVTs(xsltTransformContextPtr ctxt) + { +- xmlDocPtr cur, next; ++ xsltRVTListPtr cur, next; + + if (ctxt == NULL) + return; + /* + * Local fragments. + */ +- cur = ctxt->localRVT; ++ cur = ctxt->localRVTList; + while (cur != NULL) { +- next = (xmlDocPtr) cur->next; +- if (cur->_private != NULL) { +- xsltFreeDocumentKeys(cur->_private); +- xmlFree(cur->_private); ++ next = cur->next; ++ if (cur->RVT->_private != NULL) { ++ xsltFreeDocumentKeys(cur->RVT->_private); ++ xmlFree(cur->RVT->_private); + } +- xmlFreeDoc(cur); ++ xmlFreeDoc(cur->RVT); ++ xmlFree(cur); + cur = next; + } +- ctxt->localRVT = NULL; ++ ctxt->localRVTList = NULL; + /* + * User-created per-template fragments. + */ +- cur = ctxt->tmpRVT; ++ cur = ctxt->tmpRVTList; + while (cur != NULL) { +- next = (xmlDocPtr) cur->next; +- if (cur->_private != NULL) { +- xsltFreeDocumentKeys(cur->_private); +- xmlFree(cur->_private); ++ next = cur->next; ++ if (cur->RVT->_private != NULL) { ++ xsltFreeDocumentKeys(cur->RVT->_private); ++ xmlFree(cur->RVT->_private); + } +- xmlFreeDoc(cur); ++ xmlFreeDoc(cur->RVT); ++ xmlFree(cur); + cur = next; + } +- ctxt->tmpRVT = NULL; ++ ctxt->tmpRVTList = NULL; + /* + * Global fragments. + */ +- cur = ctxt->persistRVT; ++ cur = ctxt->persistRVTList; + while (cur != NULL) { +- next = (xmlDocPtr) cur->next; +- if (cur->_private != NULL) { +- xsltFreeDocumentKeys(cur->_private); +- xmlFree(cur->_private); ++ next = cur->next; ++ if (cur->RVT->_private != NULL) { ++ xsltFreeDocumentKeys(cur->RVT->_private); ++ xmlFree(cur->RVT->_private); + } +- xmlFreeDoc(cur); ++ xmlFreeDoc(cur->RVT); ++ xmlFree(cur); + cur = next; + } +- ctxt->persistRVT = NULL; ++ ctxt->persistRVTList = NULL; + } + + /************************************************************************ +@@ -571,21 +628,22 @@ xsltFreeStackElem(xsltStackElemPtr elem) { + * Release the list of temporary Result Tree Fragments. + */ + if (elem->context) { +- xmlDocPtr cur; ++ xsltRVTListPtr cur; + + while (elem->fragment != NULL) { + cur = elem->fragment; +- elem->fragment = (xmlDocPtr) cur->next; +- +- if (cur->compression == XSLT_RVT_LOCAL) { +- xsltReleaseRVT(elem->context, cur); +- } else if (cur->compression == XSLT_RVT_FUNC_RESULT) { +- xsltRegisterLocalRVT(elem->context, cur); +- cur->compression = XSLT_RVT_FUNC_RESULT; ++ elem->fragment = cur->next; ++ ++ if (cur->RVT->compression == XSLT_RVT_LOCAL) { ++ xsltReleaseRVTList(elem->context, cur); ++ } else if (cur->RVT->compression == XSLT_RVT_FUNC_RESULT) { ++ xsltRegisterLocalRVT(elem->context, cur->RVT); ++ cur->RVT->compression = XSLT_RVT_FUNC_RESULT; ++ xmlFree(cur); + } else { + xmlGenericError(xmlGenericErrorContext, + "xsltFreeStackElem: Unexpected RVT flag %d\n", +- cur->compression); ++ cur->RVT->compression); + } + } + } +@@ -944,6 +1002,7 @@ xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr variable, + } else { + if (variable->tree) { + xmlDocPtr container; ++ xsltRVTListPtr rvtList; + xmlNodePtr oldInsert; + xmlDocPtr oldOutput; + const xmlChar *oldLastText; +@@ -968,7 +1027,11 @@ xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr variable, + * when the variable is freed, it will also free + * the Result Tree Fragment. + */ +- variable->fragment = container; ++ rvtList = xsltRVTListCreate(); ++ if (rvtList == NULL) ++ goto error; ++ rvtList->RVT = container; ++ variable->fragment = rvtList; + container->compression = XSLT_RVT_LOCAL; + + oldOutput = ctxt->output; +@@ -2361,5 +2424,3 @@ local_variable_found: + + return(valueObj); + } +- +- +diff --git a/libxslt/xsltInternals.h b/libxslt/xsltInternals.h +index 6faa07db52995..ec84e1dfff4f5 100644 +--- a/libxslt/xsltInternals.h ++++ b/libxslt/xsltInternals.h +@@ -1410,6 +1410,8 @@ struct _xsltStylePreComp { + + #endif /* XSLT_REFACTORED */ + ++typedef struct _xsltRVTList xsltRVTList; ++typedef xsltRVTList *xsltRVTListPtr; + + /* + * The in-memory structure corresponding to an XSLT Variable +@@ -1427,7 +1429,7 @@ struct _xsltStackElem { + xmlNodePtr tree; /* the sequence constructor if no eval + string or the location */ + xmlXPathObjectPtr value; /* The value if computed */ +- xmlDocPtr fragment; /* The Result Tree Fragments (needed for XSLT 1.0) ++ xsltRVTListPtr fragment; /* The Result Tree Fragments (needed for XSLT 1.0) + which are bound to the variable's lifetime. */ + int level; /* the depth in the tree; + -1 if persistent (e.g. a given xsl:with-param) */ +@@ -1639,10 +1641,15 @@ struct _xsltStylesheet { + unsigned long opCount; + }; + ++struct _xsltRVTList { ++ xmlDocPtr RVT; ++ xsltRVTListPtr next; ++}; ++ + typedef struct _xsltTransformCache xsltTransformCache; + typedef xsltTransformCache *xsltTransformCachePtr; + struct _xsltTransformCache { +- xmlDocPtr RVT; ++ xsltRVTListPtr rvtList; + int nbRVT; + xsltStackElemPtr stackItems; + int nbStackItems; +@@ -1749,8 +1756,8 @@ struct _xsltTransformContext { + * handling of temporary Result Value Tree + * (XSLT 1.0 term: "Result Tree Fragment") + */ +- xmlDocPtr tmpRVT; /* list of RVT without persistance */ +- xmlDocPtr persistRVT; /* list of persistant RVTs */ ++ xsltRVTListPtr tmpRVTList; /* list of RVT without persistance */ ++ xsltRVTListPtr persistRVTList; /* list of persistant RVTs */ + int ctxtflags; /* context processing flags */ + + /* +@@ -1783,7 +1790,7 @@ struct _xsltTransformContext { + xmlDocPtr initialContextDoc; + xsltTransformCachePtr cache; + void *contextVariable; /* the current variable item */ +- xmlDocPtr localRVT; /* list of local tree fragments; will be freed when ++ xsltRVTListPtr localRVTList; /* list of local tree fragments; will be freed when + the instruction which created the fragment + exits */ + xmlDocPtr localRVTBase; /* Obsolete */ +@@ -1932,8 +1939,11 @@ XSLTPUBFUN int XSLTCALL + XSLTPUBFUN void XSLTCALL + xsltFreeRVTs (xsltTransformContextPtr ctxt); + XSLTPUBFUN void XSLTCALL +- xsltReleaseRVT (xsltTransformContextPtr ctxt, ++ xsltReleaseRVT (xsltTransformContextPtr ctxt, + xmlDocPtr RVT); ++XSLTPUBFUN void XSLTCALL ++ xsltReleaseRVTList (xsltTransformContextPtr ctxt, ++ xsltRVTListPtr list); + /* + * Extra functions for Attribute Value Templates + */ +@@ -1992,4 +2002,3 @@ XSLTPUBFUN int XSLTCALL + #endif + + #endif /* __XML_XSLT_H__ */ +- +-- +2.50.0.rc0.642.g800a2b2222-goog + diff -Nru chromium-145.0.7632.116/third_party/libxslt/chromium/roll.py chromium-145.0.7632.159/third_party/libxslt/chromium/roll.py --- chromium-145.0.7632.116/third_party/libxslt/chromium/roll.py 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/chromium/roll.py 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,440 @@ +#!/usr/bin/env python3 + +# Copyright 2017 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import argparse +import os +import shutil +import stat +import subprocess +import sys +import tempfile + +# How to patch libxslt in Chromium: +# +# 1. Write a .patch file and add it to third_party/libxslt/chromium. +# 2. Apply the patch in src: patch -p1 <../chromium/foo.patch +# 3. Add the patch to the list of patches in this file. +# 4. Update README.chromium with the provenance of the patch. +# 5. Upload a change with the modified documentation, roll script, +# patch, applied patch and any other relevant changes like +# regression tests. Go through the usual review and commit process. +# +# How to roll libxslt in Chromium: +# +# Prerequisites: +# +# 1. Check out Chromium somewhere on Linux, Mac and Windows. +# 2. On Linux: +# a. sudo apt-get install libicu-dev +# b. git clone https://gitlab.gnome.org/GNOME/libxslt.git somewhere +# 3. On Mac, install these packages with brew: +# autoconf automake libtool pkgconfig icu4c +# +# Procedure: +# +# Warning: This process is destructive. Run it on a clean branch. +# +# 1. On Linux, in the libxslt repo directory: +# a. git remote update origin +# b. git checkout origin/master +# +# This will be the upstream version of libxslt you are rolling to. +# +# 2. On Linux, in the Chromium src director: +# a. third_party/libxslt/chromium/roll.py --linux /path/to/libxslt +# +# If this fails, it may be a patch no longer applies. Reset to +# head; modify the patch files, this script, and +# README.chromium; then commit the result and run it again. +# +# b. Upload a Cl but do not start review +# +# 2. On Windows, in the Chromium src directory: +# a. git cl patch +# b. third_party\libxslt\chromium\roll.py --win32 +# c. git cl upload +# +# 3. On Mac, in the Chromium src directory: +# a. git cl patch +# b. third_party/libxslt/chromium/roll.py --mac +# c. Make and commit any final changes to README.chromium, BUILD.gn, etc. +# d. Complete the code review process as usual: git cl upload -d; +# git cl try-results; etc. +# +# The --linuxfast argument is an alternative to --linux which also deletes +# files which are not intended to be checked in. This would normally happen at +# the end of the --mac run, but if you want to run the roll script and get to +# the final state without running the configure scripts on all three platforms, +# this is helpful. + +PATCHES = [ + 'xslt-locale.patch', + '0004-Use-a-dedicated-node-type-to-maintain-the-list-of-ca.patch', +] + + +# See libxslt configure.ac and win32/configure.js to learn what +# options are available. + +# These two sets of options should be in sync. You can check the +# generated #defines in (win32|mac|linux)/config.h to confirm +# this. +SHARED_XSLT_CONFIGURE_OPTIONS = [ + # These options are turned OFF + ('--without-debug', 'xslt_debug=no'), + ('--without-debugger', 'debugger=no'), + ('--without-mem-debug', 'mem_debug=no'), + ('--without-plugins', 'modules=no'), + ('--without-crypto', 'crypto=no'), + ('--without-python', 'python=no'), +] + +# These options are only available in configure.ac for Linux and Mac. +EXTRA_NIX_XSLT_CONFIGURE_OPTIONS = [ +] + + +# These options are only available in win32/configure.js for Windows. +EXTRA_WIN32_XSLT_CONFIGURE_OPTIONS = [ + 'compiler=msvc', + 'iconv=no', +] + + +XSLT_CONFIGURE_OPTIONS = ( + [option[0] for option in SHARED_XSLT_CONFIGURE_OPTIONS] + + EXTRA_NIX_XSLT_CONFIGURE_OPTIONS) + + +XSLT_WIN32_CONFIGURE_OPTIONS = ( + [option[1] for option in SHARED_XSLT_CONFIGURE_OPTIONS] + + EXTRA_WIN32_XSLT_CONFIGURE_OPTIONS) + + +FILES_TO_REMOVE = [ + # TODO: Excluding ChangeLog and NEWS because encoding problems mean + # bots can't patch these. Reinclude them when there is a consistent + # encoding. + 'src/NEWS', + 'src/ChangeLog', + # These are auto-generated by autoconf/automake and should not be included + # with the source code + 'src/Makefile.in', + 'src/aclocal.m4', + 'src/CMakeLists.txt', + 'src/compile', + 'src/config.guess', + 'src/config.sub', + 'src/configure', + 'src/configure.ac', + 'src/depcomp', + 'src/install-sh', + 'src/libexslt/Makefile.in', + 'src/libxslt.spec.in', + 'src/libxslt/Makefile.in', + 'src/libxslt/libxslt.syms', + 'src/ltmain.sh', + 'src/m4/ax_append_flag.m4', + 'src/missing', + 'src/win32/Makefile.msvc', + 'src/xslt-config.in', + # These are not needed. + 'src/doc', + 'src/python', + 'src/tests', + 'src/xsltproc', + 'src/examples', + 'src/vms', +] + + +THIRD_PARTY_LIBXML_LINUX = 'third_party/libxml/linux' +THIRD_PARTY_LIBXSLT = 'third_party/libxslt' +THIRD_PARTY_LIBXSLT_SRC = os.path.join(THIRD_PARTY_LIBXSLT, 'src') + + +def libxml_path_option(src_path): + """Gets the path to libxml/linux in Chromium. + + libxslt needs to be configured with libxml source. + + Args: + src_path: The Chromium src path. + + Returns: + The path to the libxml2 third_party/libxml/linux configure + output. + """ + libxml_linux_path = os.path.join(src_path, THIRD_PARTY_LIBXML_LINUX) + return ['--with-libxml-src=%s' % libxml_linux_path] + + +class WorkingDir(object): + """Changes the working directory and resets it on exit.""" + def __init__(self, path): + self.prev_path = os.getcwd() + self.path = path + + def __enter__(self): + os.chdir(self.path) + + def __exit__(self, exc_type, exc_value, traceback): + if exc_value: + print('was in %s; %s before that' % (self.path, self.prev_path)) + os.chdir(self.prev_path) + + +def git(*args): + """Runs a git subcommand. + + On Windows this uses the shell because there's a git wrapper + batch file in depot_tools. + + Arguments: + args: The arguments to pass to git. + """ + command = ['git'] + list(args) + subprocess.check_call(command, shell=(os.name == 'nt')) + + +def remove_tracked_and_local_dir(path): + """Removes the contents of a directory from git, and the filesystem. + + Arguments: + path: The path to remove. + """ + remove_tracked_files([path]) + shutil.rmtree(path, ignore_errors=True) + os.mkdir(path) + + +def remove_tracked_files(files_to_remove): + """Removes tracked files from git. + + Arguments: + files_to_remove: The files to remove. + """ + files_to_remove = [f for f in files_to_remove if os.path.exists(f)] + git('rm', '-rf', '--ignore-unmatch', *files_to_remove) + + +def sed_in_place(input_filename, program): + """Replaces text in a file. + + Arguments: + input_filename: The file to edit. + program: The sed program to perform edits on the file. + """ + # OS X's sed requires -e + subprocess.check_call(['sed', '-i', '-e', program, input_filename]) + + +def check_copying(path='.'): + path = os.path.join(path, 'COPYING') + if not os.path.exists(path): + return + with open(path) as f: + s = f.read() + if 'GNU' in s: + raise Exception('check COPYING') + + +def patch_config(): + """Changes autoconf results which can not be changed with options.""" + sed_in_place('config.h', 's/#define HAVE_CLOCK_GETTIME 1//') + + # https://crbug.com/670720 + sed_in_place('config.h', 's/#define HAVE_ASCTIME 1//') + sed_in_place('config.h', 's/#define HAVE_LOCALTIME 1//') + sed_in_place('config.h', 's/#define HAVE_MKTIME 1//') + + sed_in_place('config.log', + r's/[a-z.0-9]\+\.corp\.google\.com/REDACTED/') + + +def prepare_libxslt_distribution(src_path, libxslt_repo_path, temp_dir): + """Makes a libxslt distribution. + + Args: + src_path: The Chromium repository src path, for finding libxslt. + libxslt_repo_path: The path to the local clone of the libxslt repo. + temp_dir: A temporary directory to stage the distribution to. + + Returns: A tuple of commit hash and full path to the archive. + """ + # If it was necessary to push from a distribution prepared upstream, + # this is the point to inject it: Return the version string and the + # distribution tar file. + + # The libxslt repo we're pulling changes from should not have + # local changes. This *should* be a commit that's publicly visible + # in the upstream repo; reviewers should check this. + check_clean(libxslt_repo_path) + + temp_config_path = os.path.join(temp_dir, 'config') + os.mkdir(temp_config_path) + temp_src_path = os.path.join(temp_dir, 'src') + os.mkdir(temp_src_path) + + with WorkingDir(libxslt_repo_path): + commit = subprocess.check_output( + ['git', 'log', '-n', '1', '--pretty=format:%H', 'HEAD']).decode('ascii') + subprocess.check_call( + 'git archive HEAD | tar -x -C "%s"' % temp_src_path, + shell=True) + with WorkingDir(temp_src_path): + os.remove('.gitignore') + for patch in PATCHES: + print('applying %s' % patch) + subprocess.check_call( + 'patch -p1 --fuzz=0 < %s' % os.path.join( + src_path, THIRD_PARTY_LIBXSLT_SRC, '..', 'chromium', patch), + shell=True) + with WorkingDir(temp_config_path): + subprocess.check_call(['../src/autogen.sh'] + XSLT_CONFIGURE_OPTIONS + + libxml_path_option(src_path)) + subprocess.check_call(['make', 'dist-all']) + + # Work out what it is called + tar_file = subprocess.check_output( + '''awk '/PACKAGE =/ {p=$3} /VERSION =/ {v=$3} ''' + '''END {printf("%s-%s.tar.xz", p, v)}' Makefile''', + shell=True).decode('ascii') + return commit, os.path.abspath(tar_file) + + +def roll_libxslt_linux(src_path, repo_path, fast): + check_clean(src_path) + with WorkingDir(src_path): + try: + temp_dir = tempfile.mkdtemp() + print('temporary directory is: %s' % temp_dir) + commit, tar_file = prepare_libxslt_distribution( + src_path, repo_path, temp_dir) + + # Remove all of the old libxslt to ensure only desired + # cruft accumulates + remove_tracked_and_local_dir(THIRD_PARTY_LIBXSLT_SRC) + + # Export the libxslt distribution to the Chromium tree + with WorkingDir(THIRD_PARTY_LIBXSLT_SRC): + subprocess.check_call( + 'tar xJf %s --strip-components=1' % tar_file, + shell=True) + finally: + shutil.rmtree(temp_dir) + + with WorkingDir(THIRD_PARTY_LIBXSLT_SRC): + # Write the commit ID into the README.chromium file + sed_in_place('../README.chromium', + 's/Revision: .*$/Revision: %s/' % commit) + # TODO(crbug.com/349529871): Use the version number instead of + # commit hash once it has been added upstream: + # https://gitlab.gnome.org/GNOME/libxslt/-/issues/117 + sed_in_place('../README.chromium', + 's/Version: .*$/Version: %s/' % commit) + check_copying() + + with WorkingDir('../linux'): + subprocess.check_call(['../src/configure'] + + XSLT_CONFIGURE_OPTIONS + + libxml_path_option(src_path)) + check_copying() + patch_config() + # Other platforms share this, even though it is + # generated on Linux. Android and Windows do not have + # xlocale. + sed_in_place('libxslt/xsltconfig.h', + '/Locale support/,/#if 1/s/#if 1/#if 0/') + shutil.move('libxslt/xsltconfig.h', '../src/libxslt') + + git('add', '*') + if fast: + with WorkingDir('..'): + remove_tracked_files(FILES_TO_REMOVE) + git('commit', '-am', '%s libxslt, linux' % commit) + + if fast: + print('Now upload for review, etc.') + else: + print('Now push to Windows and runs steps there.') + + +def roll_libxslt_win32(src_path): + full_path_to_libxslt = os.path.join(src_path, THIRD_PARTY_LIBXSLT) + with WorkingDir(full_path_to_libxslt): + with WorkingDir('src/win32'): + # Run the configure script. + subprocess.check_call(['cscript', '//E:jscript', 'configure.js'] + + XSLT_WIN32_CONFIGURE_OPTIONS) + shutil.copy('src/config.h', 'win32/config.h') + git('add', 'win32/config.h') + git('commit', '--allow-empty', '-m', 'Windows') + print('Now push to Mac and run steps there.') + + +def roll_libxslt_mac(src_path): + full_path_to_libxslt = os.path.join(src_path, THIRD_PARTY_LIBXSLT) + with WorkingDir(full_path_to_libxslt): + with WorkingDir('mac'): + subprocess.check_call(['autoreconf', '-i', '../src']) + os.chmod('../src/configure', + os.stat('../src/configure').st_mode | stat.S_IXUSR) + # /linux in the configure options is not a typo; configure + # looks here to find xml2-config + subprocess.check_call(['../src/configure'] + + XSLT_CONFIGURE_OPTIONS) + check_copying() + patch_config() + # Commit and upload the result + git('add', 'config.h') + remove_tracked_files(FILES_TO_REMOVE) + git('commit', '-m', 'Mac') + print('Now upload for review, etc.') + + +def check_clean(path): + with WorkingDir(path): + status = subprocess.check_output(['git', 'status', '-s', '-uno']).decode('ascii') + if len(status) > 0: + raise Exception('repository at %s is not clean' % path) + + +def main(): + src_dir = os.getcwd() + if not os.path.exists(os.path.join(src_dir, 'third_party')): + print('error: run this script from the Chromium src directory') + sys.exit(1) + + parser = argparse.ArgumentParser( + description='Roll the libxslt dependency in Chromium') + platform = parser.add_mutually_exclusive_group(required=True) + platform.add_argument('--linux', action='store_true') + platform.add_argument('--win32', action='store_true') + platform.add_argument('--mac', action='store_true') + platform.add_argument('--linuxfast', action='store_true') + parser.add_argument( + 'libxslt_repo_path', + type=str, + nargs='?', + help='The path to the local clone of the libxslt git repo.') + args = parser.parse_args() + + if args.linux or args.linuxfast: + libxslt_repo_path = args.libxslt_repo_path + if not libxslt_repo_path: + print('Specify the path to the local libxslt repo clone.') + sys.exit(1) + libxslt_repo_path = os.path.abspath(libxslt_repo_path) + roll_libxslt_linux(src_dir, libxslt_repo_path, args.linuxfast) + elif args.win32: + roll_libxslt_win32(src_dir) + elif args.mac: + roll_libxslt_mac(src_dir) + + +if __name__ == '__main__': + main() diff -Nru chromium-145.0.7632.116/third_party/libxslt/chromium/xslt-locale.patch chromium-145.0.7632.159/third_party/libxslt/chromium/xslt-locale.patch --- chromium-145.0.7632.116/third_party/libxslt/chromium/xslt-locale.patch 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/chromium/xslt-locale.patch 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,45 @@ +WebKit sets a custom xslt sort function with the expectation that libxslt passes +strings directly from the input. If locale support is enabled, libxslt will +transform the string using into something WebKit does not expect. This will +break third_party/WebKit/LayoutTests/fast/xsl/sort-locale.xml. By disabling +POSIX and Windows locale support, we preserve the behavior WebKit expects in +XsltUnicodeSortFunction. + +In addition, it would seem that strxfrm_l is not supported on Fuchsia as using +it without this patch causes a compile error. + +diff --git a/libxslt/xsltlocale.c b/libxslt/xsltlocale.c +index 5a929188..9324f284 100644 +--- a/libxslt/xsltlocale.c ++++ b/libxslt/xsltlocale.c +@@ -19,29 +19,7 @@ + #include "xsltlocale.h" + #include "xsltutils.h" + +-#ifdef HAVE_STRXFRM_L +- +- #define XSLT_LOCALE_POSIX +- +- #ifdef HAVE_LOCALE_H +- #include +- #endif +- #ifdef HAVE_XLOCALE_H +- #include +- #endif +- +-#elif defined(_WIN32) +- +- #define XSLT_LOCALE_WINAPI +- +- #include +- #include +- +-#else +- +- #define XSLT_LOCALE_NONE +- +-#endif ++#define XSLT_LOCALE_NONE + + #define TOUPPER(c) (c & ~0x20) + #define TOLOWER(c) (c | 0x20) diff -Nru chromium-145.0.7632.116/third_party/libxslt/linux/COPYING chromium-145.0.7632.159/third_party/libxslt/linux/COPYING --- chromium-145.0.7632.116/third_party/libxslt/linux/COPYING 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/linux/COPYING 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,53 @@ +Licence for libxslt except libexslt +---------------------------------------------------------------------- + Copyright (C) 2001-2002 Daniel Veillard. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is fur- +nished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- +NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +DANIEL VEILLARD BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON- +NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Daniel Veillard shall not +be used in advertising or otherwise to promote the sale, use or other deal- +ings in this Software without prior written authorization from him. + +---------------------------------------------------------------------- + +Licence for libexslt +---------------------------------------------------------------------- + Copyright (C) 2001-2002 Thomas Broyer, Charlie Bozeman and Daniel Veillard. + All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is fur- +nished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- +NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON- +NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the authors shall not +be used in advertising or otherwise to promote the sale, use or other deal- +ings in this Software without prior written authorization from him. +---------------------------------------------------------------------- diff -Nru chromium-145.0.7632.116/third_party/libxslt/linux/config.h chromium-145.0.7632.159/third_party/libxslt/linux/config.h --- chromium-145.0.7632.116/third_party/libxslt/linux/config.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/linux/config.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,225 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the 'clock_gettime' function. */ + + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the 'ftime' function. */ +#define HAVE_FTIME 1 + +/* Define if gcrypt library is available. */ +/* #undef HAVE_GCRYPT */ + +/* Define to 1 if you have the 'gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the 'gmtime_r' function. */ +#define HAVE_GMTIME_R 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define if pthread library is there (-lpthread) */ +#define HAVE_LIBPTHREAD /**/ + +/* Define to 1 if you have the header file. */ +#define HAVE_LOCALE_H 1 + +/* Define to 1 if you have the 'localtime_r' function. */ +#define HAVE_LOCALTIME_R 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MINIX_CONFIG_H */ + +/* Define if is there */ +#define HAVE_PTHREAD_H /**/ + +/* Define to 1 if you have the 'snprintf' function. */ +#define HAVE_SNPRINTF 1 + +/* Define to 1 if you have the 'stat' function. */ +#define HAVE_STAT 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the 'strxfrm_l' function. */ +#define HAVE_STRXFRM_L 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIMEB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the 'vsnprintf' function. */ +#define HAVE_VSNPRINTF 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_WCHAR_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_XLOCALE_H */ + +/* Define to 1 if you have the '_stat' function. */ +/* #undef HAVE__STAT */ + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#define LT_OBJDIR ".libs/" + +/* plugin file extension */ +/* #undef MODULE_EXTENSION */ + +/* Name of package */ +#define PACKAGE "libxslt" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "libxslt" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "libxslt 1.1.45" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "libxslt" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.1.45" + +/* Define to 1 if all of the C89 standard headers exist (not just the ones + required in a freestanding environment). This macro is provided for + backward compatibility; new code need not use it. */ +#define STDC_HEADERS 1 + +/* Enable extensions on AIX, Interix, z/OS. */ +#ifndef _ALL_SOURCE +# define _ALL_SOURCE 1 +#endif +/* Enable general extensions on macOS. */ +#ifndef _DARWIN_C_SOURCE +# define _DARWIN_C_SOURCE 1 +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# define __EXTENSIONS__ 1 +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif +/* Enable X/Open compliant socket functions that do not require linking + with -lxnet on HP-UX 11.11. */ +#ifndef _HPUX_ALT_XOPEN_SOCKET_API +# define _HPUX_ALT_XOPEN_SOCKET_API 1 +#endif +/* Identify the host operating system as Minix. + This macro does not affect the system headers' behavior. + A future release of Autoconf may stop defining this macro. */ +#ifndef _MINIX +/* # undef _MINIX */ +#endif +/* Enable general extensions on NetBSD. + Enable NetBSD compatibility extensions on Minix. */ +#ifndef _NETBSD_SOURCE +# define _NETBSD_SOURCE 1 +#endif +/* Enable OpenBSD compatibility extensions on NetBSD. + Oddly enough, this does nothing on OpenBSD. */ +#ifndef _OPENBSD_SOURCE +# define _OPENBSD_SOURCE 1 +#endif +/* Define to 1 if needed for POSIX-compatible behavior. */ +#ifndef _POSIX_SOURCE +/* # undef _POSIX_SOURCE */ +#endif +/* Define to 2 if needed for POSIX-compatible behavior. */ +#ifndef _POSIX_1_SOURCE +/* # undef _POSIX_1_SOURCE */ +#endif +/* Enable POSIX-compatible threading on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# define _POSIX_PTHREAD_SEMANTICS 1 +#endif +/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */ +#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ +# define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1 +#endif +/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */ +#ifndef __STDC_WANT_IEC_60559_BFP_EXT__ +# define __STDC_WANT_IEC_60559_BFP_EXT__ 1 +#endif +/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */ +#ifndef __STDC_WANT_IEC_60559_DFP_EXT__ +# define __STDC_WANT_IEC_60559_DFP_EXT__ 1 +#endif +/* Enable extensions specified by C23 Annex F. */ +#ifndef __STDC_WANT_IEC_60559_EXT__ +# define __STDC_WANT_IEC_60559_EXT__ 1 +#endif +/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ +#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ +# define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1 +#endif +/* Enable extensions specified by C23 Annex H and ISO/IEC TS 18661-3:2015. */ +#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ +# define __STDC_WANT_IEC_60559_TYPES_EXT__ 1 +#endif +/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */ +#ifndef __STDC_WANT_LIB_EXT2__ +# define __STDC_WANT_LIB_EXT2__ 1 +#endif +/* Enable extensions specified by ISO/IEC 24747:2009. */ +#ifndef __STDC_WANT_MATH_SPEC_FUNCS__ +# define __STDC_WANT_MATH_SPEC_FUNCS__ 1 +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# define _TANDEM_SOURCE 1 +#endif +/* Enable X/Open extensions. Define to 500 only if necessary + to make mbstate_t available. */ +#ifndef _XOPEN_SOURCE +/* # undef _XOPEN_SOURCE */ +#endif + + +/* Version number of package */ +#define VERSION "1.1.45" + +/* Define if debugging support is enabled */ +/* #undef WITH_DEBUGGER */ + +/* Define if profiling support is enabled */ +#define WITH_PROFILER /**/ diff -Nru chromium-145.0.7632.116/third_party/libxslt/linux/libexslt/exsltconfig.h chromium-145.0.7632.159/third_party/libxslt/linux/libexslt/exsltconfig.h --- chromium-145.0.7632.116/third_party/libxslt/linux/libexslt/exsltconfig.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/linux/libexslt/exsltconfig.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,70 @@ +/* + * exsltconfig.h: compile-time version information for the EXSLT library + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#ifndef __XML_EXSLTCONFIG_H__ +#define __XML_EXSLTCONFIG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * LIBEXSLT_DOTTED_VERSION: + * + * the version string like "1.2.3" + */ +#define LIBEXSLT_DOTTED_VERSION "0.8.25" + +/** + * LIBEXSLT_VERSION: + * + * the version number: 1.2.3 value is 10203 + */ +#define LIBEXSLT_VERSION 825 + +/** + * LIBEXSLT_VERSION_STRING: + * + * the version number string, 1.2.3 value is "10203" + */ +#define LIBEXSLT_VERSION_STRING "825" + +/** + * LIBEXSLT_VERSION_EXTRA: + * + * extra version information, used to show a Git commit description + */ +#define LIBEXSLT_VERSION_EXTRA "" + +/** + * WITH_CRYPTO: + * + * Whether crypto support is configured into exslt + */ +#if 0 +#define EXSLT_CRYPTO_ENABLED +#endif + +/** + * ATTRIBUTE_UNUSED: + * + * This macro is used to flag unused function parameters to GCC + */ +#ifdef __GNUC__ +#ifndef ATTRIBUTE_UNUSED +#define ATTRIBUTE_UNUSED __attribute__((unused)) +#endif +#else +#define ATTRIBUTE_UNUSED +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_EXSLTCONFIG_H__ */ diff -Nru chromium-145.0.7632.116/third_party/libxslt/linux/libxslt/xsltwin32config.h chromium-145.0.7632.159/third_party/libxslt/linux/libxslt/xsltwin32config.h --- chromium-145.0.7632.116/third_party/libxslt/linux/libxslt/xsltwin32config.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/linux/libxslt/xsltwin32config.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,105 @@ +/* + * Summary: compile-time version information for the XSLT engine + * when compiled on windows + * Description: compile-time version information for the XSLT engine + * when compiled on windows. This file is generated. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLTWIN32CONFIG_H__ +#define __XML_XSLTWIN32CONFIG_H__ + +#include "win32config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * LIBXSLT_DOTTED_VERSION: + * + * the version string like "1.2.3" + */ +#define LIBXSLT_DOTTED_VERSION "1.1.34" + +/** + * LIBXSLT_VERSION: + * + * the version number: 1.2.3 value is 1002003 + */ +#define LIBXSLT_VERSION 10134 + +/** + * LIBXSLT_VERSION_STRING: + * + * the version number string, 1.2.3 value is "1002003" + */ +#define LIBXSLT_VERSION_STRING "10134" + +/** + * LIBXSLT_VERSION_EXTRA: + * + * extra version information, used to show a CVS compilation + */ +#define LIBXSLT_VERSION_EXTRA "-win32" + +/** + * WITH_XSLT_DEBUG: + * + * Activate the compilation of the debug reporting. Speed penalty + * is insignifiant and being able to run xsltpoc -v is useful. On + * by default + */ +#if 1 +#define WITH_XSLT_DEBUG +#endif + +/** + * WITH_MODULES: + * + * Whether module support is configured into libxslt + */ +#if 0 +#ifndef WITH_MODULES +#define WITH_MODULES +#endif +#define LIBXSLT_PLUGINS_PATH() getenv("LIBXSLT_PLUGINS_PATH") +#endif + +#if 0 +/** + * DEBUG_MEMORY: + * + * should be activated only when debugging libxslt. It replaces the + * allocator with a collect and debug shell to the libc allocator. + * Use configure --with-mem-debug to activate it on both library + */ +#define DEBUG_MEMORY + +/** + * DEBUG_MEMORY_LOCATION: + * + * should be activated only when debugging libxslt. + * DEBUG_MEMORY_LOCATION should be activated only when libxml has + * been configured with --with-debug-mem too + */ +#define DEBUG_MEMORY_LOCATION +#endif + +/** + * ATTRIBUTE_UNUSED: + * + * This macro is used to flag unused function parameters to GCC, useless here + */ +#ifndef ATTRIBUTE_UNUSED +#define ATTRIBUTE_UNUSED +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLTWIN32CONFIG_H__ */ diff -Nru chromium-145.0.7632.116/third_party/libxslt/mac/config.h chromium-145.0.7632.159/third_party/libxslt/mac/config.h --- chromium-145.0.7632.116/third_party/libxslt/mac/config.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/mac/config.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,225 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the 'clock_gettime' function. */ + + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the 'ftime' function. */ +#define HAVE_FTIME 1 + +/* Define if gcrypt library is available. */ +/* #undef HAVE_GCRYPT */ + +/* Define to 1 if you have the 'gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the 'gmtime_r' function. */ +#define HAVE_GMTIME_R 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define if pthread library is there (-lpthread) */ +#define HAVE_LIBPTHREAD /**/ + +/* Define to 1 if you have the header file. */ +#define HAVE_LOCALE_H 1 + +/* Define to 1 if you have the 'localtime_r' function. */ +#define HAVE_LOCALTIME_R 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MINIX_CONFIG_H */ + +/* Define if is there */ +#define HAVE_PTHREAD_H /**/ + +/* Define to 1 if you have the 'snprintf' function. */ +#define HAVE_SNPRINTF 1 + +/* Define to 1 if you have the 'stat' function. */ +#define HAVE_STAT 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the 'strxfrm_l' function. */ +#define HAVE_STRXFRM_L 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIMEB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the 'vsnprintf' function. */ +#define HAVE_VSNPRINTF 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_WCHAR_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_XLOCALE_H 1 + +/* Define to 1 if you have the '_stat' function. */ +/* #undef HAVE__STAT */ + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#define LT_OBJDIR ".libs/" + +/* plugin file extension */ +/* #undef MODULE_EXTENSION */ + +/* Name of package */ +#define PACKAGE "libxslt" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "libxslt" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "libxslt 1.1.44" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "libxslt" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.1.44" + +/* Define to 1 if all of the C89 standard headers exist (not just the ones + required in a freestanding environment). This macro is provided for + backward compatibility; new code need not use it. */ +#define STDC_HEADERS 1 + +/* Enable extensions on AIX, Interix, z/OS. */ +#ifndef _ALL_SOURCE +# define _ALL_SOURCE 1 +#endif +/* Enable general extensions on macOS. */ +#ifndef _DARWIN_C_SOURCE +# define _DARWIN_C_SOURCE 1 +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# define __EXTENSIONS__ 1 +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif +/* Enable X/Open compliant socket functions that do not require linking + with -lxnet on HP-UX 11.11. */ +#ifndef _HPUX_ALT_XOPEN_SOCKET_API +# define _HPUX_ALT_XOPEN_SOCKET_API 1 +#endif +/* Identify the host operating system as Minix. + This macro does not affect the system headers' behavior. + A future release of Autoconf may stop defining this macro. */ +#ifndef _MINIX +/* # undef _MINIX */ +#endif +/* Enable general extensions on NetBSD. + Enable NetBSD compatibility extensions on Minix. */ +#ifndef _NETBSD_SOURCE +# define _NETBSD_SOURCE 1 +#endif +/* Enable OpenBSD compatibility extensions on NetBSD. + Oddly enough, this does nothing on OpenBSD. */ +#ifndef _OPENBSD_SOURCE +# define _OPENBSD_SOURCE 1 +#endif +/* Define to 1 if needed for POSIX-compatible behavior. */ +#ifndef _POSIX_SOURCE +/* # undef _POSIX_SOURCE */ +#endif +/* Define to 2 if needed for POSIX-compatible behavior. */ +#ifndef _POSIX_1_SOURCE +/* # undef _POSIX_1_SOURCE */ +#endif +/* Enable POSIX-compatible threading on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# define _POSIX_PTHREAD_SEMANTICS 1 +#endif +/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */ +#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ +# define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1 +#endif +/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */ +#ifndef __STDC_WANT_IEC_60559_BFP_EXT__ +# define __STDC_WANT_IEC_60559_BFP_EXT__ 1 +#endif +/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */ +#ifndef __STDC_WANT_IEC_60559_DFP_EXT__ +# define __STDC_WANT_IEC_60559_DFP_EXT__ 1 +#endif +/* Enable extensions specified by C23 Annex F. */ +#ifndef __STDC_WANT_IEC_60559_EXT__ +# define __STDC_WANT_IEC_60559_EXT__ 1 +#endif +/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ +#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ +# define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1 +#endif +/* Enable extensions specified by C23 Annex H and ISO/IEC TS 18661-3:2015. */ +#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ +# define __STDC_WANT_IEC_60559_TYPES_EXT__ 1 +#endif +/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */ +#ifndef __STDC_WANT_LIB_EXT2__ +# define __STDC_WANT_LIB_EXT2__ 1 +#endif +/* Enable extensions specified by ISO/IEC 24747:2009. */ +#ifndef __STDC_WANT_MATH_SPEC_FUNCS__ +# define __STDC_WANT_MATH_SPEC_FUNCS__ 1 +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# define _TANDEM_SOURCE 1 +#endif +/* Enable X/Open extensions. Define to 500 only if necessary + to make mbstate_t available. */ +#ifndef _XOPEN_SOURCE +/* # undef _XOPEN_SOURCE */ +#endif + + +/* Version number of package */ +#define VERSION "1.1.44" + +/* Define if debugging support is enabled */ +/* #undef WITH_DEBUGGER */ + +/* Define if profiling support is enabled */ +#define WITH_PROFILER /**/ diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/AUTHORS chromium-145.0.7632.159/third_party/libxslt/src/AUTHORS --- chromium-145.0.7632.116/third_party/libxslt/src/AUTHORS 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/AUTHORS 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,64 @@ +Daniel Veillard: + daniel@veillard.com + DV on #gnome IRC channel + http://veillard.com/ + Used to work at W3C, now Red Hat + co-chair of W3C XML Linking WG + invited expert on the W3C XML Core WG + Author of libxml2 upon which this library is based. + +Bjorn Reese: + breese@users.sourceforge.net + http://home1.stofanet.dk/breese/ + Software developer at http://www.systematic.dk/ + Member of the XML-MTF Mapping WG. + +William Brack + +Thomas Broyer + +Igor Zlatkovic for the Windows port + +Patches gently provided by a multitude of people : + +Abhishek Arya +Ben Walton +Bjorn Reese +C. M. Sperberg-McQueen +Colin Walters +Daniel Mustieles +Daniel Richard G +Darin Adler +ÉRDI Gergo +Fatih Demir +Federico Mena Quintero +Frederic Crozat +Hao Hu +Havoc Pennington +IlyaS +jacob berkman +Jason Viers +Jérôme Carretero +Joachim Breitner +Johan Dahlin +John Fleck +Jose Maria Celorio +Julio M. Merino Vidal +Kasimier T. Buchcik +Kjartan Maraas +Laurence Rowe +Malcolm Purvis +Martin +Michael Bonfils +Mike Hommey +money_seshu Dronamraju +Nick Wellnhofer +Nix +Pedro F. Giffuni +Peter Williams +Rob Richards +Roumen Petrov +Stefan Kost +Tomasz Kłoczko +Chris Evans +Iván Chavero diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/Copyright chromium-145.0.7632.159/third_party/libxslt/src/Copyright --- chromium-145.0.7632.116/third_party/libxslt/src/Copyright 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/Copyright 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,53 @@ +Licence for libxslt except libexslt +---------------------------------------------------------------------- + Copyright (C) 2001-2002 Daniel Veillard. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is fur- +nished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- +NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +DANIEL VEILLARD BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON- +NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Daniel Veillard shall not +be used in advertising or otherwise to promote the sale, use or other deal- +ings in this Software without prior written authorization from him. + +---------------------------------------------------------------------- + +Licence for libexslt +---------------------------------------------------------------------- + Copyright (C) 2001-2002 Thomas Broyer, Charlie Bozeman and Daniel Veillard. + All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is fur- +nished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- +NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON- +NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the authors shall not +be used in advertising or otherwise to promote the sale, use or other deal- +ings in this Software without prior written authorization from him. +---------------------------------------------------------------------- diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/FEATURES chromium-145.0.7632.159/third_party/libxslt/src/FEATURES --- chromium-145.0.7632.116/third_party/libxslt/src/FEATURES 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/FEATURES 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,242 @@ + Status of implementation of the XSLT 1.0 Features: + ================================================== + +Stylesheet Constructs: +====================== + +YES xsl:stylesheet +? id = id +YES extension-element-prefixes = tokens +YES exclude-result-prefixes = tokens +YES version = number + +YES xsl:transform +? id = id +YES extension-element-prefixes = tokens +YES exclude-result-prefixes = tokens +YES version = number + + +YES Literal Result Element as Stylesheet + +YES Embedding Stylesheets + +NO mediaType + +Top Level Elements: +=================== + +YES xsl:include +YES href = uri-reference + +YES xsl:import +YES href = uri-reference + +YES xsl:strip-space +YES elements = tokens + +YES xsl:preserve-space +YES elements = tokens + +YES xsl:template +YES match = pattern +YES name = qname +YES priority = number +YES mode = qname + +YES xsl:namespace-alias +YES stylesheet-prefix = prefix | "#default" +YES result-prefix = prefix | "#default" + +YES xsl:attribute-set +YES name = qname +YES use-attribute-sets = qnames + +YES xsl:variable +YES name = qname +YES select = expression +YES Content: template + +YES xsl:param +YES name = qname +YES select = expression +YES Content: template + +YES xsl:key +YES name = qname +YES match = pattern +YES use = expression + +YES xsl:output +YES method = "xml" | "html" | "text" | qname-but-not-ncname +YES version = nmtoken +YES encoding = string +YES omit-xml-declaration = "yes" | "no" +YES standalone = "yes" | "no" +YES doctype-public = string +YES doctype-system = string +YES cdata-section-elements = qnames +YES indent = "yes" | "no" +YES media-type = string + +Instructions: +============= + +YES xsl:apply-templates +YES select = node-set-expression +YES mode = qname + +YES xsl:apply-imports + +YES xsl:call-template +YES name = qname + +YES xsl:element +YES name = { qname } +YES namespace = { uri-reference } +YES use-attribute-sets = qnames + +YES xsl:attribute +YES name = { qname } +YES namespace = { uri-reference } + +YES xsl:text +YES disable-output-escaping = "yes" | "no" + +YES xsl:processing-instruction +YES name = { ncname } + +YES xsl:comment + +YES xsl:copy +YES use-attribute-sets = qnames + +YES xsl:value-of +YES select = string-expression +YES disable-output-escaping = "yes" | "no" + +YES xsl:number +YES level = "single" | "multiple" | "any" +YES count = pattern +YES from = pattern +YES value = number-expression +YES format = { string } +NO lang = { nmtoken } +NO letter-value = { "alphabetic" | "traditional" } +YES grouping-separator = { char } +YES grouping-size = { number } + +YES xsl:for-each +YES select = node-set-expression + +YES xsl:if +YES test = boolean-expression + +YES xsl:choose + +YES xsl:when +YES test = boolean-expression + +YES xsl:otherwise + +YES xsl:sort +YES select = string-expression +NO lang = { nmtoken } +YES data-type = { "text" | "number" | qname-but-not-ncname } +YES order = { "ascending" | "descending" } +NO case-order = { "upper-first" | "lower-first" } + +YES xsl:variable +YES name = qname +YES select = expression +YES Content: template + +YES xsl:param +YES name = qname +YES select = expression +YES Content: template + +YES xsl:copy-of +YES select = expression + +YES xsl:with-param +YES name = qname +YES select = expression + +YES xsl:decimal-format +YES name = qname +YES decimal-separator = char +YES grouping-separator = char +YES infinity = string +YES minus-sign = char +YES NaN = string +YES percent = char +YES per-mille = char +YES zero-digit = char +YES digit = char +YES pattern-separator = char + +YES xsl:message +YES terminate = "yes" | "no" + +YES xsl:fallback + +General: +======== + +YES Conflict Resolution for Template Rules + +YES Whitespace Stripping + +YES Built-in Template Rules +YES match="*|/" +YES match="text()|@*" +YES match="processing-instruction()|comment()" +YES Namespace +YES Mode + +YES Extension Elements + +YES Extension Functions + +YES Attribute Value Templates + +YES Result Tree Fragments + +Functions: +========== + +YES node-set document(object, node-set?) +YES node-set key(string, object) +YES string format-number(number, string, string?) +YES node-set current() +YES string unparsed-entity-uri(string) +YES string generate-id(node-set?) +YES object system-property(string) +YES boolean element-available(string) +YES boolean function-available(string) + +Patterns: +========= + +YES para +YES * +YES chapter|appendix +YES olist/item +YES appendix//para +YES / +YES text() +YES processing-instruction() +YES node() +YES id("W11") +YES para[1] +YES *[position()=1 and self::para] +YES para[last()=1] +YES items/item[position()>1] +YES item[position() mod 2 = 1] +YES div[@class="appendix"]//p +YES @class +YES @* +YES except ns for key key('a','b') + +daniel@veillard.com diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/FindGcrypt.cmake chromium-145.0.7632.159/third_party/libxslt/src/FindGcrypt.cmake --- chromium-145.0.7632.116/third_party/libxslt/src/FindGcrypt.cmake 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/FindGcrypt.cmake 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,40 @@ +include(FindPackageHandleStandardArgs) +include(SelectLibraryConfigurations) + +find_path(GCRYPT_INCLUDE_DIRS NAMES gcrypt.h) + +mark_as_advanced(GCRYPT_INCLUDE_DIRS) + +find_library(GCRYPT_LIBRARY_DEBUG NAMES gcryptd) +find_library(GCRYPT_LIBRARY_RELEASE NAMES gcrypt) + +select_library_configurations(GCRYPT) + +if(GCRYPT_INCLUDE_DIRS AND EXISTS "${GCRYPT_INCLUDE_DIRS}/gcrypt.h") + file(STRINGS "${GCRYPT_INCLUDE_DIRS}/gcrypt.h" _GCRYPT_VERSION_DEFINE REGEX "#define[\t ]+GCRYPT_VERSION[\t ]+\"[^\"]*\".*") + string(REGEX REPLACE "#define[\t ]+GCRYPT_VERSION[\t ]+\"([^\"]*)\".*" "\\1" GCRYPT_VERSION "${_GCRYPT_VERSION_DEFINE}") + unset(_GCRYPT_VERSION_DEFINE) +endif() + +find_package_handle_standard_args( + Gcrypt + FOUND_VAR GCRYPT_FOUND + REQUIRED_VARS GCRYPT_INCLUDE_DIRS GCRYPT_LIBRARIES + VERSION_VAR GCRYPT_VERSION +) + +if(GCRYPT_FOUND AND NOT TARGET Gcrypt::Gcrypt) + add_library(Gcrypt::Gcrypt UNKNOWN IMPORTED) + if(GCRYPT_LIBRARY_RELEASE) + set_property(TARGET Gcrypt::Gcrypt APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) + set_target_properties(Gcrypt::Gcrypt PROPERTIES IMPORTED_LOCATION_RELEASE "${GCRYPT_LIBRARY_RELEASE}") + endif() + if(GCRYPT_LIBRARY_DEBUG) + set_property(TARGET Gcrypt::Gcrypt APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) + set_target_properties(Gcrypt::Gcrypt PROPERTIES IMPORTED_LOCATION_DEBUG "${GCRYPT_LIBRARY_DEBUG}") + endif() + set_target_properties( + Gcrypt::Gcrypt PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${GCRYPT_INCLUDE_DIRS}" + ) +endif() diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/INSTALL chromium-145.0.7632.159/third_party/libxslt/src/INSTALL --- chromium-145.0.7632.116/third_party/libxslt/src/INSTALL 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/INSTALL 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,50 @@ + How to install the XSLT library: + +Requirements: +============= + +this library requires a recent version of libxml2 which you can grab from +either the GNOME download server or the GitLab release page: + + https://gitlab.gnome.org/GNOME/libxml2/-/releases + https://download.gnome.org/sources/libxml2/ + +When installing from a distribution package like a tar.gz: +========================================================== + +expand the package + +run ./configure possibly indicating the desired installation prefix: + + ./configure --prefix=/usr + +then run + + make + +to build the project and + + make install + +(possibly after having gained root access) to install the library +and associated include and scripts. + +When installing from a Git clone: +================================= + + +run ./autogen.sh possibly indicating the desired installation prefix: + + ./autogen.sh --prefix=/usr + +then run + + make + +to build the project and + + make install + +(possibly after having gained root access) to instal the library +and associated include and scripts. + diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/Makefile.am chromium-145.0.7632.159/third_party/libxslt/src/Makefile.am --- chromium-145.0.7632.116/third_party/libxslt/src/Makefile.am 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/Makefile.am 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,51 @@ +ACLOCAL_AMFLAGS = -I m4 + +SUBDIRS = libxslt libexslt xsltproc doc tests +if WITH_PYTHON +SUBDIRS += python +endif + +DIST_SUBDIRS = libxslt libexslt xsltproc python doc tests + +confexecdir=$(libdir) +confexec_DATA = xsltConf.sh + +bin_SCRIPTS = xslt-config + +dist-hook: cleanup + touch $(distdir)/doc/*.xml + touch $(distdir)/doc/EXSLT/*.xml + touch $(distdir)/libxslt/*.syms + (cd $(srcdir) ; tar -cf - win32 vms examples) | (cd $(distdir); tar xf -) + +EXTRA_DIST = xsltConf.sh.in \ + FEATURES TODO Copyright \ + CMakeLists.txt config.h.cmake.in libxslt-config.cmake.in libxslt-config.cmake.cmake.in + +## We create xsltConf.sh here and not from configure because we want +## to get the paths expanded correctly. Macros like srcdir are given +## the value NONE in configure if the user doesn't specify them (this +## is an autoconf feature, not a bug). + +xsltConf.sh: xsltConf.sh.in Makefile +## Use sed and then mv to avoid problems if the user interrupts. + sed -e 's?\@XSLT_LIBDIR\@?$(XSLT_LIBDIR)?g' \ + -e 's?\@XSLT_INCLUDEDIR\@?$(XSLT_INCLUDEDIR)?g' \ + -e 's?\@VERSION\@?$(VERSION)?g' \ + -e 's?\@XSLT_LIBS\@?$(XSLT_LIBS) $(EXTRA_LIBS)?g' \ + -e 's?\@XSLT_PRIVATE_LIBS\@?$(XSLT_PRIVATE_LIBS)?g' \ + < $(srcdir)/xsltConf.sh.in > xsltConf.tmp \ + && mv xsltConf.tmp xsltConf.sh + +CLEANFILES = xsltConf.sh + +cleanup: + -@(find . -name .\#\* -exec rm {} \;) + +pkgconfigdir=$(libdir)/pkgconfig +pkgconfig_DATA = libxslt.pc libexslt.pc + +cmakedir = $(libdir)/cmake/libxslt +dist_cmake_DATA = FindGcrypt.cmake +cmake_DATA = libxslt-config.cmake + diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/README.md chromium-145.0.7632.159/third_party/libxslt/src/README.md --- chromium-145.0.7632.116/third_party/libxslt/src/README.md 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/README.md 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,19 @@ +# libxslt + +libxslt is an XSLT processor based on libxml2. + +Official releases can be downloaded from + + +The git repository is hosted on GNOME's GitLab server: + + +Bugs should be reported at + + +Documentation is available at + + +The build system is similar to libxml2. Refer to libxml2's README for +build instructions. + diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/TODO chromium-145.0.7632.159/third_party/libxslt/src/TODO --- chromium-145.0.7632.116/third_party/libxslt/src/TODO 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/TODO 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,124 @@ + ******** + * * + * TODO * + * * + ******** + +Lifetime of result Value Tree, make sure we keep pointers. Exslt +handling of node set values is especially nasty in this respect, +lots of potential mem leaks... + +Pattern tester: + -> try to optimize for ID scan and tests. + +Pattern scanner: + -> add error checks on all returns + +Sorting: + -> add lang and case-order + -> add foreign sorting functions (interfaces ?). + + ******** + * * + * DONE * + * * + ******** + +Design: + - should transforms for a given stylesheet be thread clean, + -> the precompilation now occur only at stylesheet processing + time (except the binding for named templates and extension + functions which need to be computed once at run-time). + Multiple threads should be able to reuse the same stylesheet + now. + +Embedding Stylesheets: + - example in 2.7 would force to validate, we do it by default now + +ID and Key support: + -> Done + +Extra functions: + -> document() should not be a problem since Result Tree Fragments are + implemented + => Done + +Templates: + -> check the built-in template rule for attributes + -> make sure @xxx matches are applied + +Contextual error reporting: + -> provide a couple of functions providing context analysis, not urgent + +Validity: + -> should we add validation by default ? Make this an option + -> redirrect validity errors + => done added a special parsing mode + +Import: + -> parse them + -> provide functions to circulate in the import tree of stylesheets + -> make sure we use the cascade wherever it's needed + +Extra functions: + -> make a separate module. + => done functions.[ch] + +Support Attribute value templates: + -> starts to be urgent. Design it in flexible ways but try to optimize + to handle most of it at the stylesheet parse time ... + => Done for the most part need to check all attributes in XSLT constructs + using them and use the dedicated readin function. + -> optimization by checking their existence at stylesheet parse time. + => done when building the preproc function + +Sorting: + -> add support for imbricated sorts + => done but not well tested. + +Separate util module: + -> macros, config, verbosity ? + => xsltutils.[ch] + +Support for disable-output-escaping="yes": + -> looks problematic, libxml has no support for anything like this, + and unless adding a new node type :-( or tweaking text node and + output routines this is gonna be messy ... must be handled at libxml + level. + => Done with a trick, text node name is different, requires > 2.2.11 + +Pattern scanner: + -> compute priority + -> handle unions + -> support for mode + => done + +Pattern tester: + -> also put fast lookup for "text()", "comment()", "node()" + based patterns lists. + => done + +Support Attribute value templates: + -> namespace support for attribute value templates is not done, need + a small API redesign + +Doc: + - put a page at http://xmlsoft.org/XSLT/ + - generate/transform the DocBook to HTML + - add HTML to package + - manpage and doc for xsltproc + + +Error handling: + -> check the version stuff, design a separate module for error interfacing + and default handling, parsing vs. runtime, fatal / compat / warning, + and lack of optionnal features. + -> reports context + +ID and Key support: + -> done but namespace support in keys is not defined + -> make sure keys are recomputed on new document input + +Profiler: + -> added looks good enough + -> autocorrection of initial calibration loop diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/config.h.cmake.in chromium-145.0.7632.159/third_party/libxslt/src/config.h.cmake.in --- chromium-145.0.7632.116/third_party/libxslt/src/config.h.cmake.in 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/config.h.cmake.in 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,136 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the `clock_gettime' function. */ +#cmakedefine HAVE_CLOCK_GETTIME 1 + +/* Define to 1 if you have the `ftime' function. */ +#cmakedefine HAVE_FTIME 1 + +/* Define if gcrypt library is available. */ +#cmakedefine HAVE_GCRYPT 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +#cmakedefine HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the `gmtime_r' function. */ +#cmakedefine HAVE_GMTIME_R 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_INTTYPES_H 1 + +/* Define if pthread library is there (-lpthread) */ +#cmakedefine HAVE_LIBPTHREAD + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LOCALE_H 1 + +/* Define to 1 if you have the `localtime_r' function. */ +#cmakedefine HAVE_LOCALTIME_R 1 + +/* Define if is there */ +#cmakedefine HAVE_PTHREAD_H + +/* Define to 1 if you have the `snprintf' function. */ +#cmakedefine HAVE_SNPRINTF 1 + +/* Define to 1 if you have the `stat' function. */ +#cmakedefine HAVE_STAT 1 + +/* Define to 1 if you have the `strxfrm_l' function. */ +#cmakedefine HAVE_STRXFRM_L 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_TIMEB_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_UNISTD_H 1 + +/* Define to 1 if you have the `vsnprintf' function. */ +#cmakedefine HAVE_VSNPRINTF 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_XLOCALE_H 1 + +/* Define to 1 if you have the `_stat' function. */ +#cmakedefine HAVE__STAT 1 + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#cmakedefine LT_OBJDIR "@LT_OBJDIR@" + +/* plugin file extension */ +#define MODULE_EXTENSION "@MODULE_EXTENSION@" + +/* Name of package */ +#cmakedefine PACKAGE "@PACKAGE@" + +/* Define to the address where bug reports for this package should be sent. */ +#cmakedefine PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@" + +/* Define to the full name of this package. */ +#cmakedefine PACKAGE_NAME "@PACKAGE_NAME@" + +/* Define to the full name and version of this package. */ +#cmakedefine PACKAGE_STRING "@PACKAGE_STRING@" + +/* Define to the one symbol short name of this package. */ +#cmakedefine PACKAGE_TARNAME "@PACKAGE_TARNAME@" + +/* Define to the home page for this package. */ +#cmakedefine PACKAGE_URL "@PACKAGE_URL@" + +/* Define to the version of this package. */ +#cmakedefine PACKAGE_VERSION "@PACKAGE_VERSION@" + +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +#cmakedefine _ALL_SOURCE 1 +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +#cmakedefine _GNU_SOURCE 1 +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +#cmakedefine _POSIX_PTHREAD_SEMANTICS 1 +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +#cmakedefine _TANDEM_SOURCE 1 +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +#cmakedefine __EXTENSIONS__ 1 +#endif + + +/* Version number of package */ +#cmakedefine VERSION "@VERSION@" + +/* Define if debugging support is enabled */ +#cmakedefine WITH_DEBUGGER 1 + +/* Define if profiling support is enabled */ +#cmakedefine WITH_PROFILER 1 + +/* Define to 1 if on MINIX. */ +#cmakedefine _MINIX 1 + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +#cmakedefine _POSIX_1_SOURCE 2 + +/* Define to 1 if you need to in order for `stat' and other things to work. */ +#cmakedefine _POSIX_SOURCE 1 diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/config.h.in chromium-145.0.7632.159/third_party/libxslt/src/config.h.in --- chromium-145.0.7632.116/third_party/libxslt/src/config.h.in 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/config.h.in 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,224 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the 'clock_gettime' function. */ +#undef HAVE_CLOCK_GETTIME + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the 'ftime' function. */ +#undef HAVE_FTIME + +/* Define if gcrypt library is available. */ +#undef HAVE_GCRYPT + +/* Define to 1 if you have the 'gettimeofday' function. */ +#undef HAVE_GETTIMEOFDAY + +/* Define to 1 if you have the 'gmtime_r' function. */ +#undef HAVE_GMTIME_R + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define if pthread library is there (-lpthread) */ +#undef HAVE_LIBPTHREAD + +/* Define to 1 if you have the header file. */ +#undef HAVE_LOCALE_H + +/* Define to 1 if you have the 'localtime_r' function. */ +#undef HAVE_LOCALTIME_R + +/* Define to 1 if you have the header file. */ +#undef HAVE_MINIX_CONFIG_H + +/* Define if is there */ +#undef HAVE_PTHREAD_H + +/* Define to 1 if you have the 'snprintf' function. */ +#undef HAVE_SNPRINTF + +/* Define to 1 if you have the 'stat' function. */ +#undef HAVE_STAT + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDIO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the 'strxfrm_l' function. */ +#undef HAVE_STRXFRM_L + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIMEB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the 'vsnprintf' function. */ +#undef HAVE_VSNPRINTF + +/* Define to 1 if you have the header file. */ +#undef HAVE_WCHAR_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_XLOCALE_H + +/* Define to 1 if you have the '_stat' function. */ +#undef HAVE__STAT + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#undef LT_OBJDIR + +/* plugin file extension */ +#undef MODULE_EXTENSION + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if all of the C89 standard headers exist (not just the ones + required in a freestanding environment). This macro is provided for + backward compatibility; new code need not use it. */ +#undef STDC_HEADERS + +/* Enable extensions on AIX, Interix, z/OS. */ +#ifndef _ALL_SOURCE +# undef _ALL_SOURCE +#endif +/* Enable general extensions on macOS. */ +#ifndef _DARWIN_C_SOURCE +# undef _DARWIN_C_SOURCE +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# undef __EXTENSIONS__ +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# undef _GNU_SOURCE +#endif +/* Enable X/Open compliant socket functions that do not require linking + with -lxnet on HP-UX 11.11. */ +#ifndef _HPUX_ALT_XOPEN_SOCKET_API +# undef _HPUX_ALT_XOPEN_SOCKET_API +#endif +/* Identify the host operating system as Minix. + This macro does not affect the system headers' behavior. + A future release of Autoconf may stop defining this macro. */ +#ifndef _MINIX +# undef _MINIX +#endif +/* Enable general extensions on NetBSD. + Enable NetBSD compatibility extensions on Minix. */ +#ifndef _NETBSD_SOURCE +# undef _NETBSD_SOURCE +#endif +/* Enable OpenBSD compatibility extensions on NetBSD. + Oddly enough, this does nothing on OpenBSD. */ +#ifndef _OPENBSD_SOURCE +# undef _OPENBSD_SOURCE +#endif +/* Define to 1 if needed for POSIX-compatible behavior. */ +#ifndef _POSIX_SOURCE +# undef _POSIX_SOURCE +#endif +/* Define to 2 if needed for POSIX-compatible behavior. */ +#ifndef _POSIX_1_SOURCE +# undef _POSIX_1_SOURCE +#endif +/* Enable POSIX-compatible threading on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# undef _POSIX_PTHREAD_SEMANTICS +#endif +/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */ +#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ +# undef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ +#endif +/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */ +#ifndef __STDC_WANT_IEC_60559_BFP_EXT__ +# undef __STDC_WANT_IEC_60559_BFP_EXT__ +#endif +/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */ +#ifndef __STDC_WANT_IEC_60559_DFP_EXT__ +# undef __STDC_WANT_IEC_60559_DFP_EXT__ +#endif +/* Enable extensions specified by C23 Annex F. */ +#ifndef __STDC_WANT_IEC_60559_EXT__ +# undef __STDC_WANT_IEC_60559_EXT__ +#endif +/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ +#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ +# undef __STDC_WANT_IEC_60559_FUNCS_EXT__ +#endif +/* Enable extensions specified by C23 Annex H and ISO/IEC TS 18661-3:2015. */ +#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ +# undef __STDC_WANT_IEC_60559_TYPES_EXT__ +#endif +/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */ +#ifndef __STDC_WANT_LIB_EXT2__ +# undef __STDC_WANT_LIB_EXT2__ +#endif +/* Enable extensions specified by ISO/IEC 24747:2009. */ +#ifndef __STDC_WANT_MATH_SPEC_FUNCS__ +# undef __STDC_WANT_MATH_SPEC_FUNCS__ +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# undef _TANDEM_SOURCE +#endif +/* Enable X/Open extensions. Define to 500 only if necessary + to make mbstate_t available. */ +#ifndef _XOPEN_SOURCE +# undef _XOPEN_SOURCE +#endif + + +/* Version number of package */ +#undef VERSION + +/* Define if debugging support is enabled */ +#undef WITH_DEBUGGER + +/* Define if profiling support is enabled */ +#undef WITH_PROFILER diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libexslt/Makefile.am chromium-145.0.7632.159/third_party/libxslt/src/libexslt/Makefile.am --- chromium-145.0.7632.116/third_party/libxslt/src/libexslt/Makefile.am 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libexslt/Makefile.am 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,35 @@ +AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/libxslt -I$(top_srcdir)/libexslt \ + -I$(top_builddir) -I$(top_builddir)/libxslt \ + -I$(top_builddir)/libexslt + +lib_LTLIBRARIES = libexslt.la + +exsltincdir = $(includedir)/libexslt + +exsltinc_HEADERS = \ + exslt.h \ + exsltexports.h +nodist_exsltinc_HEADERS = \ + exsltconfig.h + +libexslt_la_SOURCES = \ + exslt.c \ + common.c \ + crypto.c \ + math.c \ + sets.c \ + functions.c \ + strings.c \ + date.c \ + saxon.c \ + libexslt.h \ + dynamic.c + +libexslt_la_CFLAGS = $(AM_CFLAGS) $(LIBGCRYPT_CFLAGS) +libexslt_la_LIBADD = $(top_builddir)/libxslt/libxslt.la $(LIBXML_LIBS) $(EXTRA_LIBS) $(LIBGCRYPT_LIBS) $(LIBM) +libexslt_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined \ + -version-info $(LIBEXSLT_VERSION_INFO) + +man_MANS = libexslt.3 + +EXTRA_DIST = $(man_MANS) diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libexslt/common.c chromium-145.0.7632.159/third_party/libxslt/src/libexslt/common.c --- chromium-145.0.7632.116/third_party/libxslt/src/libexslt/common.c 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libexslt/common.c 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,124 @@ +#define IN_LIBEXSLT +#include "libexslt/libexslt.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "exslt.h" + +static void +exsltNodeSetFunction (xmlXPathParserContextPtr ctxt, int nargs) { + if (nargs != 1) { + xmlXPathSetArityError(ctxt); + return; + } + if (xmlXPathStackIsNodeSet (ctxt)) { + xsltFunctionNodeSet (ctxt, nargs); + return; + } else { + xmlDocPtr fragment; + xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt); + xmlNodePtr txt; + xmlChar *strval; + xmlXPathObjectPtr obj; + /* + * SPEC EXSLT: + * "You can also use this function to turn a string into a text + * node, which is helpful if you want to pass a string to a + * function that only accepts a node-set." + */ + fragment = xsltCreateRVT(tctxt); + if (fragment == NULL) { + xsltTransformError(tctxt, NULL, tctxt->inst, + "exsltNodeSetFunction: Failed to create a tree fragment.\n"); + tctxt->state = XSLT_STATE_STOPPED; + return; + } + xsltRegisterLocalRVT(tctxt, fragment); + + strval = xmlXPathPopString (ctxt); + + txt = xmlNewDocText (fragment, strval); + xmlAddChild((xmlNodePtr) fragment, txt); + obj = xmlXPathNewNodeSet(txt); + if (obj == NULL) { + xsltTransformError(tctxt, NULL, tctxt->inst, + "exsltNodeSetFunction: Failed to create a node set object.\n"); + tctxt->state = XSLT_STATE_STOPPED; + } + if (strval != NULL) + xmlFree (strval); + + valuePush (ctxt, obj); + } +} + +static void +exsltObjectTypeFunction (xmlXPathParserContextPtr ctxt, int nargs) { + xmlXPathObjectPtr obj, ret; + + if (nargs != 1) { + xmlXPathSetArityError(ctxt); + return; + } + + obj = valuePop(ctxt); + + switch (obj->type) { + case XPATH_STRING: + ret = xmlXPathNewCString("string"); + break; + case XPATH_NUMBER: + ret = xmlXPathNewCString("number"); + break; + case XPATH_BOOLEAN: + ret = xmlXPathNewCString("boolean"); + break; + case XPATH_NODESET: + ret = xmlXPathNewCString("node-set"); + break; + case XPATH_XSLT_TREE: + ret = xmlXPathNewCString("RTF"); + break; + case XPATH_USERS: + ret = xmlXPathNewCString("external"); + break; + default: + xsltGenericError(xsltGenericErrorContext, + "object-type() invalid arg\n"); + ctxt->error = XPATH_INVALID_TYPE; + xmlXPathFreeObject(obj); + return; + } + xmlXPathFreeObject(obj); + valuePush(ctxt, ret); +} + + +/** + * exsltCommonRegister: + * + * Registers the EXSLT - Common module + */ + +void +exsltCommonRegister (void) { + xsltRegisterExtModuleFunction((const xmlChar *) "node-set", + EXSLT_COMMON_NAMESPACE, + exsltNodeSetFunction); + xsltRegisterExtModuleFunction((const xmlChar *) "object-type", + EXSLT_COMMON_NAMESPACE, + exsltObjectTypeFunction); + xsltRegisterExtModuleElement((const xmlChar *) "document", + EXSLT_COMMON_NAMESPACE, + xsltDocumentComp, + xsltDocumentElem); +} diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libexslt/crypto.c chromium-145.0.7632.159/third_party/libxslt/src/libexslt/crypto.c --- chromium-145.0.7632.116/third_party/libxslt/src/libexslt/crypto.c 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libexslt/crypto.c 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,806 @@ +#define IN_LIBEXSLT +#include "libexslt/libexslt.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "exslt.h" + +#ifdef EXSLT_CRYPTO_ENABLED + +#define HASH_DIGEST_LENGTH 32 +#define MD5_DIGEST_LENGTH 16 +#define SHA1_DIGEST_LENGTH 20 + +/* gcrypt rc4 can do 256 bit keys, but cryptoapi limit + seems to be 128 for the default provider */ +#define RC4_KEY_LENGTH 128 + +/* The following routines have been declared static - this should be + reviewed to consider whether we want to expose them to the API + exsltCryptoBin2Hex + exsltCryptoHex2Bin + exsltCryptoGcryptInit + exsltCryptoGcryptHash + exsltCryptoGcryptRc4Encrypt + exsltCryptoGcryptRC4Decrypt +*/ + +/** + * exsltCryptoBin2Hex: + * @bin: binary blob to convert + * @binlen: length of binary blob + * @hex: buffer to store hex version of blob + * @hexlen: length of buffer to store hex version of blob + * + * Helper function which encodes a binary blob as hex. + */ +static void +exsltCryptoBin2Hex (const unsigned char *bin, int binlen, + unsigned char *hex, int hexlen) { + static const char bin2hex[] = { '0', '1', '2', '3', + '4', '5', '6', '7', + '8', '9', 'a', 'b', + 'c', 'd', 'e', 'f' + }; + + unsigned char lo, hi; + int i, pos; + for (i = 0, pos = 0; (i < binlen && pos < hexlen); i++) { + lo = bin[i] & 0xf; + hi = bin[i] >> 4; + hex[pos++] = bin2hex[hi]; + hex[pos++] = bin2hex[lo]; + } + + hex[pos] = '\0'; +} + +/** + * exsltCryptoHex2Bin: + * @hex: hex version of blob to convert + * @hexlen: length of hex buffer + * @bin: destination binary buffer + * @binlen: length of binary buffer + * + * Helper function which decodes a hex blob to binary + */ +static int +exsltCryptoHex2Bin (const unsigned char *hex, int hexlen, + unsigned char *bin, int binlen) { + int i = 0, j = 0; + unsigned char lo, hi, result, tmp; + + while (i < hexlen && j < binlen) { + hi = lo = 0; + + tmp = hex[i++]; + if (tmp >= '0' && tmp <= '9') + hi = tmp - '0'; + else if (tmp >= 'a' && tmp <= 'f') + hi = 10 + (tmp - 'a'); + + tmp = hex[i++]; + if (tmp >= '0' && tmp <= '9') + lo = tmp - '0'; + else if (tmp >= 'a' && tmp <= 'f') + lo = 10 + (tmp - 'a'); + + result = hi << 4; + result += lo; + bin[j++] = result; + } + + return j; +} + +#if defined(_WIN32) + +#define HAVE_CRYPTO +#define PLATFORM_HASH exsltCryptoCryptoApiHash +#define PLATFORM_RC4_ENCRYPT exsltCryptoCryptoApiRc4Encrypt +#define PLATFORM_RC4_DECRYPT exsltCryptoCryptoApiRc4Decrypt +#define PLATFORM_MD4 CALG_MD4 +#define PLATFORM_MD5 CALG_MD5 +#define PLATFORM_SHA1 CALG_SHA1 + +#include +#include +#ifdef _MSC_VER +#pragma comment(lib, "advapi32.lib") +#endif + +static void +exsltCryptoCryptoApiReportError (xmlXPathParserContextPtr ctxt, + int line) { + char *lpMsgBuf; + DWORD dw = GetLastError (); + + FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, NULL, dw, + MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)&lpMsgBuf, 0, NULL); + + xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, NULL, + "exslt:crypto error (line %d). %s", line, + lpMsgBuf); + LocalFree (lpMsgBuf); +} + +static HCRYPTHASH +exsltCryptoCryptoApiCreateHash (xmlXPathParserContextPtr ctxt, + HCRYPTPROV hCryptProv, ALG_ID algorithm, + const unsigned char *msg, unsigned int msglen, + char *dest, unsigned int destlen) +{ + HCRYPTHASH hHash = 0; + DWORD dwHashLen = destlen; + + if (!CryptCreateHash (hCryptProv, algorithm, 0, 0, &hHash)) { + exsltCryptoCryptoApiReportError (ctxt, __LINE__); + return 0; + } + + if (!CryptHashData (hHash, msg, msglen, 0)) { + exsltCryptoCryptoApiReportError (ctxt, __LINE__); + goto fail; + } + + if (!CryptGetHashParam (hHash, HP_HASHVAL, (BYTE *) dest, &dwHashLen, 0)) { + exsltCryptoCryptoApiReportError (ctxt, __LINE__); + goto fail; + } + + fail: + return hHash; +} + +/** + * exsltCryptoCryptoApiHash: + * @ctxt: an XPath parser context + * @algorithm: hashing algorithm to use + * @msg: text to be hashed + * @msglen: length of text to be hashed + * @dest: buffer to place hash result + * + * Helper function which hashes a message using MD4, MD5, or SHA1. + * Uses Win32 CryptoAPI. + */ +static void +exsltCryptoCryptoApiHash (xmlXPathParserContextPtr ctxt, + ALG_ID algorithm, const char *msg, + unsigned long msglen, + char dest[HASH_DIGEST_LENGTH]) { + HCRYPTPROV hCryptProv; + HCRYPTHASH hHash; + + if (!CryptAcquireContext (&hCryptProv, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { + exsltCryptoCryptoApiReportError (ctxt, __LINE__); + return; + } + + hHash = exsltCryptoCryptoApiCreateHash (ctxt, hCryptProv, + algorithm, (unsigned char *) msg, + msglen, dest, HASH_DIGEST_LENGTH); + if (0 != hHash) { + CryptDestroyHash (hHash); + } + + CryptReleaseContext (hCryptProv, 0); +} + +static void +exsltCryptoCryptoApiRc4Encrypt (xmlXPathParserContextPtr ctxt, + const unsigned char *key, + const unsigned char *msg, int msglen, + unsigned char *dest, int destlen) { + HCRYPTPROV hCryptProv; + HCRYPTKEY hKey; + HCRYPTHASH hHash; + DWORD dwDataLen; + char hash[HASH_DIGEST_LENGTH]; + + if (msglen > destlen) { + xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, + NULL, + "exslt:crypto : internal error exsltCryptoCryptoApiRc4Encrypt dest buffer too small.\n"); + return; + } + + if (!CryptAcquireContext (&hCryptProv, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { + exsltCryptoCryptoApiReportError (ctxt, __LINE__); + return; + } + + hHash = exsltCryptoCryptoApiCreateHash (ctxt, hCryptProv, + CALG_SHA1, key, + RC4_KEY_LENGTH, hash, + HASH_DIGEST_LENGTH); + + if (!CryptDeriveKey + (hCryptProv, CALG_RC4, hHash, 0x00800000, &hKey)) { + exsltCryptoCryptoApiReportError (ctxt, __LINE__); + goto fail; + } +/* Now encrypt data. */ + dwDataLen = msglen; + memcpy (dest, msg, msglen); + if (!CryptEncrypt (hKey, 0, TRUE, 0, dest, &dwDataLen, msglen)) { + exsltCryptoCryptoApiReportError (ctxt, __LINE__); + goto fail; + } + + fail: + if (0 != hHash) { + CryptDestroyHash (hHash); + } + + CryptDestroyKey (hKey); + CryptReleaseContext (hCryptProv, 0); +} + +static void +exsltCryptoCryptoApiRc4Decrypt (xmlXPathParserContextPtr ctxt, + const unsigned char *key, + const unsigned char *msg, int msglen, + unsigned char *dest, int destlen) { + HCRYPTPROV hCryptProv; + HCRYPTKEY hKey; + HCRYPTHASH hHash; + DWORD dwDataLen; + char hash[HASH_DIGEST_LENGTH]; + + if (msglen > destlen) { + xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, + NULL, + "exslt:crypto : internal error exsltCryptoCryptoApiRc4Encrypt dest buffer too small.\n"); + return; + } + + if (!CryptAcquireContext (&hCryptProv, NULL, NULL, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { + exsltCryptoCryptoApiReportError (ctxt, __LINE__); + return; + } + + hHash = exsltCryptoCryptoApiCreateHash (ctxt, hCryptProv, + CALG_SHA1, key, + RC4_KEY_LENGTH, hash, + HASH_DIGEST_LENGTH); + + if (!CryptDeriveKey + (hCryptProv, CALG_RC4, hHash, 0x00800000, &hKey)) { + exsltCryptoCryptoApiReportError (ctxt, __LINE__); + goto fail; + } +/* Now encrypt data. */ + dwDataLen = msglen; + memcpy (dest, msg, msglen); + if (!CryptDecrypt (hKey, 0, TRUE, 0, dest, &dwDataLen)) { + exsltCryptoCryptoApiReportError (ctxt, __LINE__); + goto fail; + } + + fail: + if (0 != hHash) { + CryptDestroyHash (hHash); + } + + CryptDestroyKey (hKey); + CryptReleaseContext (hCryptProv, 0); +} + +#endif /* defined(_WIN32) */ + +#if defined(HAVE_GCRYPT) + +#define HAVE_CRYPTO +#define PLATFORM_HASH exsltCryptoGcryptHash +#define PLATFORM_RC4_ENCRYPT exsltCryptoGcryptRc4Encrypt +#define PLATFORM_RC4_DECRYPT exsltCryptoGcryptRc4Decrypt +#define PLATFORM_MD4 GCRY_MD_MD4 +#define PLATFORM_MD5 GCRY_MD_MD5 +#define PLATFORM_SHA1 GCRY_MD_SHA1 + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#ifdef HAVE_SYS_SELECT_H +#include /* needed by gcrypt.h 4 Jul 04 */ +#endif +#include + +static void +exsltCryptoGcryptInit (void) { + static int gcrypt_init; + xmlLockLibrary (); + + if (!gcrypt_init) { +/* The function `gcry_check_version' must be called before any other + function in the library, because it initializes the thread support + subsystem in Libgcrypt. To achieve this in all generality, it is + necessary to synchronize the call to this function with all other calls + to functions in the library, using the synchronization mechanisms + available in your thread library. (from gcrypt.info) +*/ + gcry_check_version (GCRYPT_VERSION); + gcrypt_init = 1; + } + + xmlUnlockLibrary (); +} + +/** + * exsltCryptoGcryptHash: + * @ctxt: an XPath parser context + * @algorithm: hashing algorithm to use + * @msg: text to be hashed + * @msglen: length of text to be hashed + * @dest: buffer to place hash result + * + * Helper function which hashes a message using MD4, MD5, or SHA1. + * using gcrypt + */ +static void +exsltCryptoGcryptHash (xmlXPathParserContextPtr ctxt ATTRIBUTE_UNUSED, +/* changed the enum to int */ + int algorithm, const char *msg, + unsigned long msglen, + char dest[HASH_DIGEST_LENGTH]) { + exsltCryptoGcryptInit (); + gcry_md_hash_buffer (algorithm, dest, msg, msglen); +} + +static void +exsltCryptoGcryptRc4Encrypt (xmlXPathParserContextPtr ctxt, + const unsigned char *key, + const unsigned char *msg, int msglen, + unsigned char *dest, int destlen) { + gcry_cipher_hd_t cipher; + gcry_error_t rc = 0; + + exsltCryptoGcryptInit (); + + rc = gcry_cipher_open (&cipher, GCRY_CIPHER_ARCFOUR, + GCRY_CIPHER_MODE_STREAM, 0); + if (rc) { + xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, + NULL, + "exslt:crypto internal error %s (gcry_cipher_open)\n", + gcry_strerror (rc)); + } + + rc = gcry_cipher_setkey (cipher, key, RC4_KEY_LENGTH); + if (rc) { + xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, + NULL, + "exslt:crypto internal error %s (gcry_cipher_setkey)\n", + gcry_strerror (rc)); + } + + rc = gcry_cipher_encrypt (cipher, (unsigned char *) dest, destlen, + (const unsigned char *) msg, msglen); + if (rc) { + xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, + NULL, + "exslt:crypto internal error %s (gcry_cipher_encrypt)\n", + gcry_strerror (rc)); + } + + gcry_cipher_close (cipher); +} + +static void +exsltCryptoGcryptRc4Decrypt (xmlXPathParserContextPtr ctxt, + const unsigned char *key, + const unsigned char *msg, int msglen, + unsigned char *dest, int destlen) { + gcry_cipher_hd_t cipher; + gcry_error_t rc = 0; + + exsltCryptoGcryptInit (); + + rc = gcry_cipher_open (&cipher, GCRY_CIPHER_ARCFOUR, + GCRY_CIPHER_MODE_STREAM, 0); + if (rc) { + xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, + NULL, + "exslt:crypto internal error %s (gcry_cipher_open)\n", + gcry_strerror (rc)); + } + + rc = gcry_cipher_setkey (cipher, key, RC4_KEY_LENGTH); + if (rc) { + xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, + NULL, + "exslt:crypto internal error %s (gcry_cipher_setkey)\n", + gcry_strerror (rc)); + } + + rc = gcry_cipher_decrypt (cipher, (unsigned char *) dest, destlen, + (const unsigned char *) msg, msglen); + if (rc) { + xsltTransformError (xsltXPathGetTransformContext (ctxt), NULL, + NULL, + "exslt:crypto internal error %s (gcry_cipher_decrypt)\n", + gcry_strerror (rc)); + } + + gcry_cipher_close (cipher); +} + +#endif /* defined(HAVE_GCRYPT) */ + +#if defined(HAVE_CRYPTO) + +/** + * exsltCryptoPopString: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Helper function which checks for and returns first string argument and its + * length in bytes. + */ +static int +exsltCryptoPopString (xmlXPathParserContextPtr ctxt, int nargs, + xmlChar ** str) { + + int str_len = 0; + + if ((nargs < 1) || (nargs > 2)) { + xmlXPathSetArityError (ctxt); + return 0; + } + + *str = xmlXPathPopString (ctxt); + str_len = xmlStrlen (*str); + + if (str_len == 0) { + xmlXPathReturnEmptyString (ctxt); + xmlFree (*str); + return 0; + } + + return str_len; +} + +/** + * exsltCryptoMd4Function: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * computes the md4 hash of a string and returns as hex + */ +static void +exsltCryptoMd4Function (xmlXPathParserContextPtr ctxt, int nargs) { + + int str_len = 0; + xmlChar *str = NULL, *ret = NULL; + unsigned char hash[HASH_DIGEST_LENGTH]; + unsigned char hex[MD5_DIGEST_LENGTH * 2 + 1]; + + str_len = exsltCryptoPopString (ctxt, nargs, &str); + if (str_len == 0) + return; + + PLATFORM_HASH (ctxt, PLATFORM_MD4, (const char *) str, str_len, + (char *) hash); + exsltCryptoBin2Hex (hash, sizeof (hash) - 1, hex, sizeof (hex) - 1); + + ret = xmlStrdup ((xmlChar *) hex); + xmlXPathReturnString (ctxt, ret); + + if (str != NULL) + xmlFree (str); +} + +/** + * exsltCryptoMd5Function: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * computes the md5 hash of a string and returns as hex + */ +static void +exsltCryptoMd5Function (xmlXPathParserContextPtr ctxt, int nargs) { + + int str_len = 0; + xmlChar *str = NULL, *ret = NULL; + unsigned char hash[HASH_DIGEST_LENGTH]; + unsigned char hex[MD5_DIGEST_LENGTH * 2 + 1]; + + str_len = exsltCryptoPopString (ctxt, nargs, &str); + if (str_len == 0) + return; + + PLATFORM_HASH (ctxt, PLATFORM_MD5, (const char *) str, str_len, + (char *) hash); + exsltCryptoBin2Hex (hash, sizeof (hash) - 1, hex, sizeof (hex) - 1); + + ret = xmlStrdup ((xmlChar *) hex); + xmlXPathReturnString (ctxt, ret); + + if (str != NULL) + xmlFree (str); +} + +/** + * exsltCryptoSha1Function: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * computes the sha1 hash of a string and returns as hex + */ +static void +exsltCryptoSha1Function (xmlXPathParserContextPtr ctxt, int nargs) { + + int str_len = 0; + xmlChar *str = NULL, *ret = NULL; + unsigned char hash[HASH_DIGEST_LENGTH]; + unsigned char hex[SHA1_DIGEST_LENGTH * 2 + 1]; + + str_len = exsltCryptoPopString (ctxt, nargs, &str); + if (str_len == 0) + return; + + PLATFORM_HASH (ctxt, PLATFORM_SHA1, (const char *) str, str_len, + (char *) hash); + exsltCryptoBin2Hex (hash, sizeof (hash) - 1, hex, sizeof (hex) - 1); + + ret = xmlStrdup ((xmlChar *) hex); + xmlXPathReturnString (ctxt, ret); + + if (str != NULL) + xmlFree (str); +} + +/** + * exsltCryptoRc4EncryptFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * computes the sha1 hash of a string and returns as hex + */ +static void +exsltCryptoRc4EncryptFunction (xmlXPathParserContextPtr ctxt, int nargs) { + + int key_len = 0; + int str_len = 0, bin_len = 0, hex_len = 0; + xmlChar *key = NULL, *str = NULL, *padkey = NULL; + xmlChar *bin = NULL, *hex = NULL; + xsltTransformContextPtr tctxt = NULL; + + if (nargs != 2) { + xmlXPathSetArityError (ctxt); + return; + } + tctxt = xsltXPathGetTransformContext(ctxt); + + str = xmlXPathPopString (ctxt); + str_len = xmlStrlen (str); + + if (str_len == 0) { + xmlXPathReturnEmptyString (ctxt); + xmlFree (str); + return; + } + + key = xmlXPathPopString (ctxt); + key_len = xmlStrlen (key); + + if (key_len == 0) { + xmlXPathReturnEmptyString (ctxt); + xmlFree (key); + xmlFree (str); + return; + } + + padkey = xmlMallocAtomic (RC4_KEY_LENGTH + 1); + if (padkey == NULL) { + xsltTransformError(tctxt, NULL, tctxt->inst, + "exsltCryptoRc4EncryptFunction: Failed to allocate padkey\n"); + tctxt->state = XSLT_STATE_STOPPED; + xmlXPathReturnEmptyString (ctxt); + goto done; + } + memset(padkey, 0, RC4_KEY_LENGTH + 1); + + if ((key_len > RC4_KEY_LENGTH) || (key_len < 0)) { + xsltTransformError(tctxt, NULL, tctxt->inst, + "exsltCryptoRc4EncryptFunction: key size too long or key broken\n"); + tctxt->state = XSLT_STATE_STOPPED; + xmlXPathReturnEmptyString (ctxt); + goto done; + } + memcpy (padkey, key, key_len); + +/* encrypt it */ + bin_len = str_len; + bin = xmlStrdup (str); + if (bin == NULL) { + xsltTransformError(tctxt, NULL, tctxt->inst, + "exsltCryptoRc4EncryptFunction: Failed to allocate string\n"); + tctxt->state = XSLT_STATE_STOPPED; + xmlXPathReturnEmptyString (ctxt); + goto done; + } + PLATFORM_RC4_ENCRYPT (ctxt, padkey, str, str_len, bin, bin_len); + +/* encode it */ + hex_len = str_len * 2 + 1; + hex = xmlMallocAtomic (hex_len); + if (hex == NULL) { + xsltTransformError(tctxt, NULL, tctxt->inst, + "exsltCryptoRc4EncryptFunction: Failed to allocate result\n"); + tctxt->state = XSLT_STATE_STOPPED; + xmlXPathReturnEmptyString (ctxt); + goto done; + } + + exsltCryptoBin2Hex (bin, str_len, hex, hex_len); + xmlXPathReturnString (ctxt, hex); + +done: + if (key != NULL) + xmlFree (key); + if (str != NULL) + xmlFree (str); + if (padkey != NULL) + xmlFree (padkey); + if (bin != NULL) + xmlFree (bin); +} + +/** + * exsltCryptoRc4DecryptFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * computes the sha1 hash of a string and returns as hex + */ +static void +exsltCryptoRc4DecryptFunction (xmlXPathParserContextPtr ctxt, int nargs) { + + int key_len = 0; + int str_len = 0, bin_len = 0, ret_len = 0; + xmlChar *key = NULL, *str = NULL, *padkey = NULL, *bin = + NULL, *ret = NULL; + xsltTransformContextPtr tctxt = NULL; + + if (nargs != 2) { + xmlXPathSetArityError (ctxt); + return; + } + tctxt = xsltXPathGetTransformContext(ctxt); + + str = xmlXPathPopString (ctxt); + str_len = xmlStrlen (str); + + if (str_len == 0) { + xmlXPathReturnEmptyString (ctxt); + xmlFree (str); + return; + } + + key = xmlXPathPopString (ctxt); + key_len = xmlStrlen (key); + + if (key_len == 0) { + xmlXPathReturnEmptyString (ctxt); + xmlFree (key); + xmlFree (str); + return; + } + + padkey = xmlMallocAtomic (RC4_KEY_LENGTH + 1); + if (padkey == NULL) { + xsltTransformError(tctxt, NULL, tctxt->inst, + "exsltCryptoRc4EncryptFunction: Failed to allocate padkey\n"); + tctxt->state = XSLT_STATE_STOPPED; + xmlXPathReturnEmptyString (ctxt); + goto done; + } + memset(padkey, 0, RC4_KEY_LENGTH + 1); + if ((key_len > RC4_KEY_LENGTH) || (key_len < 0)) { + xsltTransformError(tctxt, NULL, tctxt->inst, + "exsltCryptoRc4EncryptFunction: key size too long or key broken\n"); + tctxt->state = XSLT_STATE_STOPPED; + xmlXPathReturnEmptyString (ctxt); + goto done; + } + memcpy (padkey, key, key_len); + +/* decode hex to binary */ + bin_len = str_len; + bin = xmlMallocAtomic (bin_len); + if (bin == NULL) { + xsltTransformError(tctxt, NULL, tctxt->inst, + "exsltCryptoRc4EncryptFunction: Failed to allocate string\n"); + tctxt->state = XSLT_STATE_STOPPED; + xmlXPathReturnEmptyString (ctxt); + goto done; + } + ret_len = exsltCryptoHex2Bin (str, str_len, bin, bin_len); + +/* decrypt the binary blob */ + ret = xmlMallocAtomic (ret_len + 1); + if (ret == NULL) { + xsltTransformError(tctxt, NULL, tctxt->inst, + "exsltCryptoRc4EncryptFunction: Failed to allocate result\n"); + tctxt->state = XSLT_STATE_STOPPED; + xmlXPathReturnEmptyString (ctxt); + goto done; + } + PLATFORM_RC4_DECRYPT (ctxt, padkey, bin, ret_len, ret, ret_len); + ret[ret_len] = 0; + + if (xmlCheckUTF8(ret) == 0) { + xsltTransformError(tctxt, NULL, tctxt->inst, + "exsltCryptoRc4DecryptFunction: Invalid UTF-8\n"); + xmlFree(ret); + xmlXPathReturnEmptyString(ctxt); + } else { + xmlXPathReturnString(ctxt, ret); + } + +done: + if (key != NULL) + xmlFree (key); + if (str != NULL) + xmlFree (str); + if (padkey != NULL) + xmlFree (padkey); + if (bin != NULL) + xmlFree (bin); +} + +/** + * exsltCryptoRegister: + * + * Registers the EXSLT - Crypto module + */ + +void +exsltCryptoRegister (void) { + xsltRegisterExtModuleFunction ((const xmlChar *) "md4", + EXSLT_CRYPTO_NAMESPACE, + exsltCryptoMd4Function); + xsltRegisterExtModuleFunction ((const xmlChar *) "md5", + EXSLT_CRYPTO_NAMESPACE, + exsltCryptoMd5Function); + xsltRegisterExtModuleFunction ((const xmlChar *) "sha1", + EXSLT_CRYPTO_NAMESPACE, + exsltCryptoSha1Function); + xsltRegisterExtModuleFunction ((const xmlChar *) "rc4_encrypt", + EXSLT_CRYPTO_NAMESPACE, + exsltCryptoRc4EncryptFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "rc4_decrypt", + EXSLT_CRYPTO_NAMESPACE, + exsltCryptoRc4DecryptFunction); +} + +#else +/** + * exsltCryptoRegister: + * + * Registers the EXSLT - Crypto module + */ +void +exsltCryptoRegister (void) { +} + +#endif /* defined(HAVE_CRYPTO) */ + +#endif /* EXSLT_CRYPTO_ENABLED */ diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libexslt/date.c chromium-145.0.7632.159/third_party/libxslt/src/libexslt/date.c --- chromium-145.0.7632.116/third_party/libxslt/src/libexslt/date.c 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libexslt/date.c 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,3956 @@ +/* + * date.c: Implementation of the EXSLT -- Dates and Times module + * + * References: + * http://www.exslt.org/date/date.html + * + * See Copyright for the status of this software. + * + * Authors: + * Charlie Bozeman + * Thomas Broyer + * + * TODO: + * elements: + * date-format + * functions: + * format-date + * parse-date + * sum + */ + +#define IN_LIBEXSLT +#include "libexslt/libexslt.h" + +#if defined(HAVE_LOCALTIME_R) && defined(__GLIBC__) /* _POSIX_SOURCE required by gnu libc */ +#ifndef _AIX51 /* but on AIX we're not using gnu libc */ +#define _POSIX_SOURCE +#endif +#endif + +#include +#include +#include + +#include +#include +#include + +#include "exslt.h" + +#include +#include +#include +#include +#include + +/* needed to get localtime_r on Solaris */ +#ifdef __sun +#ifndef __EXTENSIONS__ +#define __EXTENSIONS__ +#endif +#endif + +#include + +#if defined(_MSC_VER) && _MSC_VER >= 1400 || \ + defined(_WIN32) && \ + defined(__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR >= 4 + #define HAVE_MSVCRT +#endif + +/* + * types of date and/or time (from schema datatypes) + * somewhat ordered from least specific to most specific (i.e. + * most truncated to least truncated). + */ +typedef enum { + EXSLT_UNKNOWN = 0, + XS_TIME = 1, /* time is left-truncated */ + XS_GDAY = (XS_TIME << 1), + XS_GMONTH = (XS_GDAY << 1), + XS_GMONTHDAY = (XS_GMONTH | XS_GDAY), + XS_GYEAR = (XS_GMONTH << 1), + XS_GYEARMONTH = (XS_GYEAR | XS_GMONTH), + XS_DATE = (XS_GYEAR | XS_GMONTH | XS_GDAY), + XS_DATETIME = (XS_DATE | XS_TIME) +} exsltDateType; + +/* Date value */ +typedef struct _exsltDateVal exsltDateVal; +typedef exsltDateVal *exsltDateValPtr; +struct _exsltDateVal { + exsltDateType type; + long year; + unsigned int mon :4; /* 1 <= mon <= 12 */ + unsigned int day :5; /* 1 <= day <= 31 */ + unsigned int hour :5; /* 0 <= hour <= 23 */ + unsigned int min :6; /* 0 <= min <= 59 */ + double sec; + unsigned int tz_flag :1; /* is tzo explicitely set? */ + signed int tzo :12; /* -1440 <= tzo <= 1440 currently only -840 to +840 are needed */ +}; + +/* Duration value */ +typedef struct _exsltDateDurVal exsltDateDurVal; +typedef exsltDateDurVal *exsltDateDurValPtr; +struct _exsltDateDurVal { + long mon; /* mon stores years also */ + long day; + double sec; /* sec stores min and hour also + 0 <= sec < SECS_PER_DAY */ +}; + +/**************************************************************** + * * + * Convenience macros and functions * + * * + ****************************************************************/ + +#define IS_TZO_CHAR(c) \ + ((c == 0) || (c == 'Z') || (c == '+') || (c == '-')) + +#define VALID_ALWAYS(num) (num >= 0) +#define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12)) +/* VALID_DAY should only be used when month is unknown */ +#define VALID_DAY(day) ((day >= 1) && (day <= 31)) +#define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23)) +#define VALID_MIN(min) ((min >= 0) && (min <= 59)) +#define VALID_SEC(sec) ((sec >= 0) && (sec < 60)) +#define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440)) +#define IS_LEAP(y) \ + (((y & 3) == 0) && ((y % 25 != 0) || ((y & 15) == 0))) + +static const long daysInMonth[12] = + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; +static const long daysInMonthLeap[12] = + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + +#define MAX_DAYINMONTH(yr,mon) \ + (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1]) + +#define VALID_MDAY(dt) \ + (IS_LEAP(dt->year) ? \ + (dt->day <= daysInMonthLeap[dt->mon - 1]) : \ + (dt->day <= daysInMonth[dt->mon - 1])) + +#define VALID_DATE(dt) \ + (VALID_MONTH(dt->mon) && VALID_MDAY(dt)) + +/* + hour and min structure vals are unsigned, so normal macros give + warnings on some compilers. +*/ +#define VALID_TIME(dt) \ + ((dt->hour <=23 ) && (dt->min <= 59) && \ + VALID_SEC(dt->sec) && VALID_TZO(dt->tzo)) + +#define VALID_DATETIME(dt) \ + (VALID_DATE(dt) && VALID_TIME(dt)) + +#define SECS_PER_MIN 60 +#define MINS_PER_HOUR 60 +#define HOURS_PER_DAY 24 +#define SECS_PER_HOUR (MINS_PER_HOUR * SECS_PER_MIN) +#define SECS_PER_DAY (HOURS_PER_DAY * SECS_PER_HOUR) +#define MINS_PER_DAY (HOURS_PER_DAY * MINS_PER_HOUR) +#define DAYS_PER_EPOCH (400 * 365 + 100 - 4 + 1) +#define YEARS_PER_EPOCH 400 + +static const long dayInYearByMonth[12] = + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; +static const long dayInLeapYearByMonth[12] = + { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }; + +#define DAY_IN_YEAR(day, month, year) \ + ((IS_LEAP(year) ? \ + dayInLeapYearByMonth[month - 1] : \ + dayInYearByMonth[month - 1]) + day) + +#define YEAR_MAX LONG_MAX +#define YEAR_MIN (-LONG_MAX + 1) + +/** + * _exsltDateParseGYear: + * @dt: pointer to a date structure + * @str: pointer to the string to analyze + * + * Parses a xs:gYear without time zone and fills in the appropriate + * field of the @dt structure. @str is updated to point just after the + * xs:gYear. It is supposed that @dt->year is big enough to contain + * the year. + * + * According to XML Schema Part 2, the year "0000" is an illegal year value + * which probably means that the year preceding AD 1 is BC 1. Internally, + * we allow a year 0 and adjust the value when parsing and formatting. + * + * Returns 0 or the error code + */ +static int +_exsltDateParseGYear (exsltDateValPtr dt, const xmlChar **str) +{ + const xmlChar *cur = *str, *firstChar; + int isneg = 0, digcnt = 0; + + if (((*cur < '0') || (*cur > '9')) && + (*cur != '-') && (*cur != '+')) + return -1; + + if (*cur == '-') { + isneg = 1; + cur++; + } + + firstChar = cur; + + while ((*cur >= '0') && (*cur <= '9')) { + if (dt->year >= YEAR_MAX / 10) /* Not really exact */ + return -1; + dt->year = dt->year * 10 + (*cur - '0'); + cur++; + digcnt++; + } + + /* year must be at least 4 digits (CCYY); over 4 + * digits cannot have a leading zero. */ + if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0'))) + return 1; + + if (dt->year == 0) + return 2; + + /* The internal representation of negative years is continuous. */ + if (isneg) + dt->year = -dt->year + 1; + + *str = cur; + +#ifdef DEBUG_EXSLT_DATE + xsltGenericDebug(xsltGenericDebugContext, + "Parsed year %04ld\n", dt->year); +#endif + + return 0; +} + +/** + * exsltFormatGYear: + * @cur: a pointer to a pointer to an allocated buffer + * @end: a pointer to the end of @cur buffer + * @yr: the year to format + * + * Formats @yr in xsl:gYear format. Result is appended to @cur and + * @cur is updated to point after the xsl:gYear. + */ +static void +exsltFormatGYear(xmlChar **cur, xmlChar *end, long yr) +{ + long year; + xmlChar tmp_buf[100], *tmp = tmp_buf, *tmp_end = tmp_buf + 99; + + if (yr <= 0 && *cur < end) { + *(*cur)++ = '-'; + } + + year = (yr <= 0) ? -yr + 1 : yr; + /* result is in reverse-order */ + while (year > 0 && tmp < tmp_end) { + *tmp++ = '0' + (xmlChar)(year % 10); + year /= 10; + } + + /* virtually adds leading zeros */ + while ((tmp - tmp_buf) < 4) + *tmp++ = '0'; + + /* restore the correct order */ + while (tmp > tmp_buf && *cur < end) { + tmp--; + *(*cur)++ = *tmp; + } +} + +/** + * PARSE_2_DIGITS: + * @num: the integer to fill in + * @cur: an #xmlChar * + * @func: validation function for the number + * @invalid: an integer + * + * Parses a 2-digits integer and updates @num with the value. @cur is + * updated to point just after the integer. + * In case of error, @invalid is set to %TRUE, values of @num and + * @cur are undefined. + */ +#define PARSE_2_DIGITS(num, cur, func, invalid) \ + if ((cur[0] < '0') || (cur[0] > '9') || \ + (cur[1] < '0') || (cur[1] > '9')) \ + invalid = 1; \ + else { \ + int val; \ + val = (cur[0] - '0') * 10 + (cur[1] - '0'); \ + if (!func(val)) \ + invalid = 2; \ + else \ + num = val; \ + } \ + cur += 2; + +/** + * exsltFormat2Digits: + * @cur: a pointer to a pointer to an allocated buffer + * @end: a pointer to the end of @cur buffer + * @num: the integer to format + * + * Formats a 2-digits integer. Result is appended to @cur and + * @cur is updated to point after the integer. + */ +static void +exsltFormat2Digits(xmlChar **cur, xmlChar *end, unsigned int num) +{ + if (*cur < end) + *(*cur)++ = '0' + ((num / 10) % 10); + if (*cur < end) + *(*cur)++ = '0' + (num % 10); +} + +/** + * PARSE_FLOAT: + * @num: the double to fill in + * @cur: an #xmlChar * + * @invalid: an integer + * + * Parses a float and updates @num with the value. @cur is + * updated to point just after the float. The float must have a + * 2-digits integer part and may or may not have a decimal part. + * In case of error, @invalid is set to %TRUE, values of @num and + * @cur are undefined. + */ +#define PARSE_FLOAT(num, cur, invalid) \ + PARSE_2_DIGITS(num, cur, VALID_ALWAYS, invalid); \ + if (!invalid && (*cur == '.')) { \ + double mult = 1; \ + cur++; \ + if ((*cur < '0') || (*cur > '9')) \ + invalid = 1; \ + while ((*cur >= '0') && (*cur <= '9')) { \ + mult /= 10; \ + num += (*cur - '0') * mult; \ + cur++; \ + } \ + } + +/** + * _exsltDateParseGMonth: + * @dt: pointer to a date structure + * @str: pointer to the string to analyze + * + * Parses a xs:gMonth without time zone and fills in the appropriate + * field of the @dt structure. @str is updated to point just after the + * xs:gMonth. + * + * Returns 0 or the error code + */ +static int +_exsltDateParseGMonth (exsltDateValPtr dt, const xmlChar **str) +{ + const xmlChar *cur = *str; + int ret = 0; + + PARSE_2_DIGITS(dt->mon, cur, VALID_MONTH, ret); + if (ret != 0) + return ret; + + *str = cur; + +#ifdef DEBUG_EXSLT_DATE + xsltGenericDebug(xsltGenericDebugContext, + "Parsed month %02i\n", dt->mon); +#endif + + return 0; +} + +/** + * _exsltDateParseGDay: + * @dt: pointer to a date structure + * @str: pointer to the string to analyze + * + * Parses a xs:gDay without time zone and fills in the appropriate + * field of the @dt structure. @str is updated to point just after the + * xs:gDay. + * + * Returns 0 or the error code + */ +static int +_exsltDateParseGDay (exsltDateValPtr dt, const xmlChar **str) +{ + const xmlChar *cur = *str; + int ret = 0; + + PARSE_2_DIGITS(dt->day, cur, VALID_DAY, ret); + if (ret != 0) + return ret; + + *str = cur; + +#ifdef DEBUG_EXSLT_DATE + xsltGenericDebug(xsltGenericDebugContext, + "Parsed day %02i\n", dt->day); +#endif + + return 0; +} + +/** + * exsltFormatYearMonthDay: + * @cur: a pointer to a pointer to an allocated buffer + * @end: a pointer to the end of @cur buffer + * @dt: the #exsltDateVal to format + * + * Formats @dt in xsl:date format. Result is appended to @cur and + * @cur is updated to point after the xsl:date. + */ +static void +exsltFormatYearMonthDay(xmlChar **cur, xmlChar *end, const exsltDateValPtr dt) +{ + exsltFormatGYear(cur, end, dt->year); + if (*cur < end) + *(*cur)++ = '-'; + exsltFormat2Digits(cur, end, dt->mon); + if (*cur < end) + *(*cur)++ = '-'; + exsltFormat2Digits(cur, end, dt->day); +} + +/** + * _exsltDateParseTime: + * @dt: pointer to a date structure + * @str: pointer to the string to analyze + * + * Parses a xs:time without time zone and fills in the appropriate + * fields of the @dt structure. @str is updated to point just after the + * xs:time. + * In case of error, values of @dt fields are undefined. + * + * Returns 0 or the error code + */ +static int +_exsltDateParseTime (exsltDateValPtr dt, const xmlChar **str) +{ + const xmlChar *cur = *str; + unsigned int hour = 0; /* use temp var in case str is not xs:time */ + int ret = 0; + + PARSE_2_DIGITS(hour, cur, VALID_HOUR, ret); + if (ret != 0) + return ret; + + if (*cur != ':') + return 1; + cur++; + + /* the ':' insures this string is xs:time */ + dt->hour = hour; + + PARSE_2_DIGITS(dt->min, cur, VALID_MIN, ret); + if (ret != 0) + return ret; + + if (*cur != ':') + return 1; + cur++; + + PARSE_FLOAT(dt->sec, cur, ret); + if (ret != 0) + return ret; + + if (!VALID_TIME(dt)) + return 2; + + *str = cur; + +#ifdef DEBUG_EXSLT_DATE + xsltGenericDebug(xsltGenericDebugContext, + "Parsed time %02i:%02i:%02.f\n", + dt->hour, dt->min, dt->sec); +#endif + + return 0; +} + +/** + * _exsltDateParseTimeZone: + * @dt: pointer to a date structure + * @str: pointer to the string to analyze + * + * Parses a time zone without time zone and fills in the appropriate + * field of the @dt structure. @str is updated to point just after the + * time zone. + * + * Returns 0 or the error code + */ +static int +_exsltDateParseTimeZone (exsltDateValPtr dt, const xmlChar **str) +{ + const xmlChar *cur; + int ret = 0; + + if (str == NULL) + return -1; + cur = *str; + switch (*cur) { + case 0: + dt->tz_flag = 0; + dt->tzo = 0; + break; + + case 'Z': + dt->tz_flag = 1; + dt->tzo = 0; + cur++; + break; + + case '+': + case '-': { + int isneg = 0, tmp = 0; + isneg = (*cur == '-'); + + cur++; + + PARSE_2_DIGITS(tmp, cur, VALID_HOUR, ret); + if (ret != 0) + return ret; + + if (*cur != ':') + return 1; + cur++; + + dt->tzo = tmp * 60; + + PARSE_2_DIGITS(tmp, cur, VALID_MIN, ret); + if (ret != 0) + return ret; + + dt->tzo += tmp; + if (isneg) + dt->tzo = - dt->tzo; + + if (!VALID_TZO(dt->tzo)) + return 2; + + break; + } + default: + return 1; + } + + *str = cur; + +#ifdef DEBUG_EXSLT_DATE + xsltGenericDebug(xsltGenericDebugContext, + "Parsed time zone offset (%s) %i\n", + dt->tz_flag ? "explicit" : "implicit", dt->tzo); +#endif + + return 0; +} + +/** + * exsltFormatTimeZone: + * @cur: a pointer to a pointer to an allocated buffer + * @end: a pointer to the end of @cur buffer + * @tzo: the timezone offset to format + * + * Formats @tzo timezone. Result is appended to @cur and + * @cur is updated to point after the timezone. + */ +static void +exsltFormatTimeZone(xmlChar **cur, xmlChar *end, int tzo) +{ + if (tzo == 0) { + if (*cur < end) + *(*cur)++ = 'Z'; + } else { + unsigned int aTzo = (tzo < 0) ? -tzo : tzo; + unsigned int tzHh = aTzo / 60, tzMm = aTzo % 60; + if (*cur < end) + *(*cur)++ = (tzo < 0) ? '-' : '+'; + exsltFormat2Digits(cur, end, tzHh); + if (*cur < end) + *(*cur)++ = ':'; + exsltFormat2Digits(cur, end, tzMm); + } +} + +/**************************************************************** + * * + * XML Schema Dates/Times Datatypes Handling * + * * + ****************************************************************/ + +/** + * exsltDateCreateDate: + * @type: type to create + * + * Creates a new #exsltDateVal, uninitialized. + * + * Returns the #exsltDateValPtr + */ +static exsltDateValPtr +exsltDateCreateDate (exsltDateType type) +{ + exsltDateValPtr ret; + + ret = (exsltDateValPtr) xmlMalloc(sizeof(exsltDateVal)); + if (ret == NULL) { + xsltGenericError(xsltGenericErrorContext, + "exsltDateCreateDate: out of memory\n"); + return (NULL); + } + memset (ret, 0, sizeof(exsltDateVal)); + + ret->mon = 1; + ret->day = 1; + + if (type != EXSLT_UNKNOWN) + ret->type = type; + + return ret; +} + +/** + * exsltDateFreeDate: + * @date: an #exsltDateValPtr + * + * Frees up the @date + */ +static void +exsltDateFreeDate (exsltDateValPtr date) { + if (date == NULL) + return; + + xmlFree(date); +} + +/** + * exsltDateCreateDuration: + * + * Creates a new #exsltDateDurVal, uninitialized. + * + * Returns the #exsltDateDurValPtr + */ +static exsltDateDurValPtr +exsltDateCreateDuration (void) +{ + exsltDateDurValPtr ret; + + ret = (exsltDateDurValPtr) xmlMalloc(sizeof(exsltDateDurVal)); + if (ret == NULL) { + xsltGenericError(xsltGenericErrorContext, + "exsltDateCreateDuration: out of memory\n"); + return (NULL); + } + memset (ret, 0, sizeof(exsltDateDurVal)); + + return ret; +} + +/** + * exsltDateFreeDuration: + * @date: an #exsltDateDurValPtr + * + * Frees up the @duration + */ +static void +exsltDateFreeDuration (exsltDateDurValPtr duration) { + if (duration == NULL) + return; + + xmlFree(duration); +} + +/** + * exsltDateCurrent: + * + * Returns the current date and time. + */ +static exsltDateValPtr +exsltDateCurrent (void) +{ + struct tm localTm, gmTm; +#if !defined(HAVE_GMTIME_R) && !defined(HAVE_MSVCRT) + struct tm *tb = NULL; +#endif + time_t secs; + int local_s, gm_s; + exsltDateValPtr ret; + char *source_date_epoch; + int override = 0; + + ret = exsltDateCreateDate(XS_DATETIME); + if (ret == NULL) + return NULL; + + /* + * Allow the date and time to be set externally by an exported + * environment variable to enable reproducible builds. + */ + source_date_epoch = getenv("SOURCE_DATE_EPOCH"); + if (source_date_epoch) { + errno = 0; + secs = (time_t) strtol (source_date_epoch, NULL, 10); + if (errno == 0) { +#ifdef HAVE_MSVCRT + struct tm *gm = gmtime_s(&localTm, &secs) ? NULL : &localTm; + if (gm != NULL) + override = 1; +#elif HAVE_GMTIME_R + if (gmtime_r(&secs, &localTm) != NULL) + override = 1; +#else + tb = gmtime(&secs); + if (tb != NULL) { + localTm = *tb; + override = 1; + } +#endif + } + } + + if (override == 0) { + /* get current time */ + secs = time(NULL); + +#ifdef HAVE_MSVCRT + localtime_s(&localTm, &secs); +#elif HAVE_LOCALTIME_R + localtime_r(&secs, &localTm); +#else + localTm = *localtime(&secs); +#endif + } + + /* get real year, not years since 1900 */ + ret->year = localTm.tm_year + 1900; + + ret->mon = localTm.tm_mon + 1; + ret->day = localTm.tm_mday; + ret->hour = localTm.tm_hour; + ret->min = localTm.tm_min; + + /* floating point seconds */ + ret->sec = (double) localTm.tm_sec; + + /* determine the time zone offset from local to gm time */ +#ifdef HAVE_MSVCRT + gmtime_s(&gmTm, &secs); +#elif HAVE_GMTIME_R + gmtime_r(&secs, &gmTm); +#else + tb = gmtime(&secs); + if (tb == NULL) + return NULL; + gmTm = *tb; +#endif + ret->tz_flag = 0; +#if 0 + ret->tzo = (((ret->day * 1440) + + (ret->hour * 60) + + ret->min) - + ((gmTm.tm_mday * 1440) + (gmTm.tm_hour * 60) + + gmTm.tm_min)); +#endif + local_s = localTm.tm_hour * SECS_PER_HOUR + + localTm.tm_min * SECS_PER_MIN + + localTm.tm_sec; + + gm_s = gmTm.tm_hour * SECS_PER_HOUR + + gmTm.tm_min * SECS_PER_MIN + + gmTm.tm_sec; + + if (localTm.tm_year < gmTm.tm_year) { + ret->tzo = -((SECS_PER_DAY - local_s) + gm_s)/60; + } else if (localTm.tm_year > gmTm.tm_year) { + ret->tzo = ((SECS_PER_DAY - gm_s) + local_s)/60; + } else if (localTm.tm_mon < gmTm.tm_mon) { + ret->tzo = -((SECS_PER_DAY - local_s) + gm_s)/60; + } else if (localTm.tm_mon > gmTm.tm_mon) { + ret->tzo = ((SECS_PER_DAY - gm_s) + local_s)/60; + } else if (localTm.tm_mday < gmTm.tm_mday) { + ret->tzo = -((SECS_PER_DAY - local_s) + gm_s)/60; + } else if (localTm.tm_mday > gmTm.tm_mday) { + ret->tzo = ((SECS_PER_DAY - gm_s) + local_s)/60; + } else { + ret->tzo = (local_s - gm_s)/60; + } + + return ret; +} + +/** + * exsltDateParse: + * @dateTime: string to analyze + * + * Parses a date/time string + * + * Returns a newly built #exsltDateValPtr of NULL in case of error + */ +static exsltDateValPtr +exsltDateParse (const xmlChar *dateTime) +{ + exsltDateValPtr dt; + int ret; + const xmlChar *cur = dateTime; + +#define RETURN_TYPE_IF_VALID(t) \ + if (IS_TZO_CHAR(*cur)) { \ + ret = _exsltDateParseTimeZone(dt, &cur); \ + if (ret == 0) { \ + if (*cur != 0) \ + goto error; \ + dt->type = t; \ + return dt; \ + } \ + } + + if (dateTime == NULL) + return NULL; + + if ((*cur != '-') && (*cur < '0') && (*cur > '9')) + return NULL; + + dt = exsltDateCreateDate(EXSLT_UNKNOWN); + if (dt == NULL) + return NULL; + + if ((cur[0] == '-') && (cur[1] == '-')) { + /* + * It's an incomplete date (xs:gMonthDay, xs:gMonth or + * xs:gDay) + */ + cur += 2; + + /* is it an xs:gDay? */ + if (*cur == '-') { + ++cur; + ret = _exsltDateParseGDay(dt, &cur); + if (ret != 0) + goto error; + + RETURN_TYPE_IF_VALID(XS_GDAY); + + goto error; + } + + /* + * it should be an xs:gMonthDay or xs:gMonth + */ + ret = _exsltDateParseGMonth(dt, &cur); + if (ret != 0) + goto error; + + if (*cur != '-') + goto error; + cur++; + + /* is it an xs:gMonth? */ + if (*cur == '-') { + cur++; + RETURN_TYPE_IF_VALID(XS_GMONTH); + goto error; + } + + /* it should be an xs:gMonthDay */ + ret = _exsltDateParseGDay(dt, &cur); + if (ret != 0) + goto error; + + RETURN_TYPE_IF_VALID(XS_GMONTHDAY); + + goto error; + } + + /* + * It's a right-truncated date or an xs:time. + * Try to parse an xs:time then fallback on right-truncated dates. + */ + if ((*cur >= '0') && (*cur <= '9')) { + ret = _exsltDateParseTime(dt, &cur); + if (ret == 0) { + /* it's an xs:time */ + RETURN_TYPE_IF_VALID(XS_TIME); + } + } + + /* fallback on date parsing */ + cur = dateTime; + + ret = _exsltDateParseGYear(dt, &cur); + if (ret != 0) + goto error; + + /* is it an xs:gYear? */ + RETURN_TYPE_IF_VALID(XS_GYEAR); + + if (*cur != '-') + goto error; + cur++; + + ret = _exsltDateParseGMonth(dt, &cur); + if (ret != 0) + goto error; + + /* is it an xs:gYearMonth? */ + RETURN_TYPE_IF_VALID(XS_GYEARMONTH); + + if (*cur != '-') + goto error; + cur++; + + ret = _exsltDateParseGDay(dt, &cur); + if ((ret != 0) || !VALID_DATE(dt)) + goto error; + + /* is it an xs:date? */ + RETURN_TYPE_IF_VALID(XS_DATE); + + if (*cur != 'T') + goto error; + cur++; + + /* it should be an xs:dateTime */ + ret = _exsltDateParseTime(dt, &cur); + if (ret != 0) + goto error; + + ret = _exsltDateParseTimeZone(dt, &cur); + if ((ret != 0) || (*cur != 0) || !VALID_DATETIME(dt)) + goto error; + + dt->type = XS_DATETIME; + + return dt; + +error: + if (dt != NULL) + exsltDateFreeDate(dt); + return NULL; +} + +/** + * exsltDateParseDuration: + * @duration: string to analyze + * + * Parses a duration string + * + * Returns a newly built #exsltDateDurValPtr of NULL in case of error + */ +static exsltDateDurValPtr +exsltDateParseDuration (const xmlChar *duration) +{ + const xmlChar *cur = duration; + exsltDateDurValPtr dur; + int isneg = 0; + unsigned int seq = 0; + long days, secs = 0; + double sec_frac = 0.0; + + if (duration == NULL) + return NULL; + + if (*cur == '-') { + isneg = 1; + cur++; + } + + /* duration must start with 'P' (after sign) */ + if (*cur++ != 'P') + return NULL; + + if (*cur == 0) + return NULL; + + dur = exsltDateCreateDuration(); + if (dur == NULL) + return NULL; + + while (*cur != 0) { + long num = 0; + size_t has_digits = 0; + int has_frac = 0; + const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'}; + + /* input string should be empty or invalid date/time item */ + if (seq >= sizeof(desig)) + goto error; + + /* T designator must be present for time items */ + if (*cur == 'T') { + if (seq > 3) + goto error; + cur++; + seq = 3; + } else if (seq == 3) + goto error; + + /* Parse integral part. */ + while (*cur >= '0' && *cur <= '9') { + long digit = *cur - '0'; + + if (num > LONG_MAX / 10) + goto error; + num *= 10; + if (num > LONG_MAX - digit) + goto error; + num += digit; + + has_digits = 1; + cur++; + } + + if (*cur == '.') { + /* Parse fractional part. */ + double mult = 1.0; + cur++; + has_frac = 1; + while (*cur >= '0' && *cur <= '9') { + mult /= 10.0; + sec_frac += (*cur - '0') * mult; + has_digits = 1; + cur++; + } + } + + while (*cur != desig[seq]) { + seq++; + /* No T designator or invalid char. */ + if (seq == 3 || seq == sizeof(desig)) + goto error; + } + cur++; + + if (!has_digits || (has_frac && (seq != 5))) + goto error; + + switch (seq) { + case 0: + /* Year */ + if (num > LONG_MAX / 12) + goto error; + dur->mon = num * 12; + break; + case 1: + /* Month */ + if (dur->mon > LONG_MAX - num) + goto error; + dur->mon += num; + break; + case 2: + /* Day */ + dur->day = num; + break; + case 3: + /* Hour */ + days = num / HOURS_PER_DAY; + if (dur->day > LONG_MAX - days) + goto error; + dur->day += days; + secs = (num % HOURS_PER_DAY) * SECS_PER_HOUR; + break; + case 4: + /* Minute */ + days = num / MINS_PER_DAY; + if (dur->day > LONG_MAX - days) + goto error; + dur->day += days; + secs += (num % MINS_PER_DAY) * SECS_PER_MIN; + break; + case 5: + /* Second */ + days = num / SECS_PER_DAY; + if (dur->day > LONG_MAX - days) + goto error; + dur->day += days; + secs += num % SECS_PER_DAY; + break; + } + + seq++; + } + + days = secs / SECS_PER_DAY; + if (dur->day > LONG_MAX - days) + goto error; + dur->day += days; + dur->sec = (secs % SECS_PER_DAY) + sec_frac; + + if (isneg) { + dur->mon = -dur->mon; + dur->day = -dur->day; + if (dur->sec != 0.0) { + dur->sec = SECS_PER_DAY - dur->sec; + dur->day -= 1; + } + } + +#ifdef DEBUG_EXSLT_DATE + xsltGenericDebug(xsltGenericDebugContext, + "Parsed duration %f\n", dur->sec); +#endif + + return dur; + +error: + if (dur != NULL) + exsltDateFreeDuration(dur); + return NULL; +} + +static void +exsltFormatLong(xmlChar **cur, xmlChar *end, long num) { + xmlChar buf[20]; + int i = 0; + + while (i < 20) { + buf[i++] = '0' + num % 10; + num /= 10; + if (num == 0) + break; + } + + while (i > 0) { + if (*cur < end) + *(*cur)++ = buf[--i]; + } +} + +static void +exsltFormatNanoseconds(xmlChar **cur, xmlChar *end, long nsecs) { + long p10, digit; + + if (nsecs > 0) { + if (*cur < end) + *(*cur)++ = '.'; + p10 = 100000000; + while (nsecs > 0) { + digit = nsecs / p10; + if (*cur < end) + *(*cur)++ = '0' + digit; + nsecs -= digit * p10; + p10 /= 10; + } + } +} + +/** + * exsltDateFormatDuration: + * @dur: an #exsltDateDurValPtr + * + * Formats the duration. + * + * Returns a newly allocated string, or NULL in case of error + */ +static xmlChar * +exsltDateFormatDuration (const exsltDateDurValPtr dur) +{ + xmlChar buf[100], *cur = buf, *end = buf + 99; + double secs, tmp; + long days, months, intSecs, nsecs; + + if (dur == NULL) + return NULL; + + /* quick and dirty check */ + if ((dur->sec == 0.0) && (dur->day == 0) && (dur->mon == 0)) + return xmlStrdup((xmlChar*)"P0D"); + + secs = dur->sec; + days = dur->day; + months = dur->mon; + + *cur = '\0'; + if (days < 0) { + if (secs != 0.0) { + secs = SECS_PER_DAY - secs; + days += 1; + } + days = -days; + *cur = '-'; + } + if (months < 0) { + months = -months; + *cur = '-'; + } + if (*cur == '-') + cur++; + + *cur++ = 'P'; + + if (months >= 12) { + long years = months / 12; + + months -= years * 12; + exsltFormatLong(&cur, end, years); + if (cur < end) + *cur++ = 'Y'; + } + + if (months != 0) { + exsltFormatLong(&cur, end, months); + if (cur < end) + *cur++ = 'M'; + } + + if (days != 0) { + exsltFormatLong(&cur, end, days); + if (cur < end) + *cur++ = 'D'; + } + + tmp = floor(secs); + intSecs = (long) tmp; + /* Round to nearest to avoid issues with floating point precision */ + nsecs = (long) floor((secs - tmp) * 1000000000 + 0.5); + if (nsecs >= 1000000000) { + nsecs -= 1000000000; + intSecs += 1; + } + + if ((intSecs > 0) || (nsecs > 0)) { + if (cur < end) + *cur++ = 'T'; + + if (intSecs >= SECS_PER_HOUR) { + long hours = intSecs / SECS_PER_HOUR; + + intSecs -= hours * SECS_PER_HOUR; + exsltFormatLong(&cur, end, hours); + if (cur < end) + *cur++ = 'H'; + } + + if (intSecs >= SECS_PER_MIN) { + long mins = intSecs / SECS_PER_MIN; + + intSecs -= mins * SECS_PER_MIN; + exsltFormatLong(&cur, end, mins); + if (cur < end) + *cur++ = 'M'; + } + + if ((intSecs > 0) || (nsecs > 0)) { + exsltFormatLong(&cur, end, intSecs); + exsltFormatNanoseconds(&cur, end, nsecs); + if (cur < end) + *cur++ = 'S'; + } + } + + *cur = 0; + + return xmlStrdup(buf); +} + +static void +exsltFormatTwoDigits(xmlChar **cur, xmlChar *end, int num) { + if (num < 0 || num >= 100) + return; + if (*cur < end) + *(*cur)++ = '0' + num / 10; + if (*cur < end) + *(*cur)++ = '0' + num % 10; +} + +static void +exsltFormatTime(xmlChar **cur, xmlChar *end, exsltDateValPtr dt) { + double tmp; + long intSecs, nsecs; + + exsltFormatTwoDigits(cur, end, dt->hour); + if (*cur < end) + *(*cur)++ = ':'; + + exsltFormatTwoDigits(cur, end, dt->min); + if (*cur < end) + *(*cur)++ = ':'; + + tmp = floor(dt->sec); + intSecs = (long) tmp; + /* + * Round to nearest to avoid issues with floating point precision, + * but don't carry over so seconds stay below 60. + */ + nsecs = (long) floor((dt->sec - tmp) * 1000000000 + 0.5); + if (nsecs > 999999999) + nsecs = 999999999; + exsltFormatTwoDigits(cur, end, intSecs); + exsltFormatNanoseconds(cur, end, nsecs); +} + +/** + * exsltDateFormatDateTime: + * @dt: an #exsltDateValPtr + * + * Formats @dt in xs:dateTime format. + * + * Returns a newly allocated string, or NULL in case of error + */ +static xmlChar * +exsltDateFormatDateTime (const exsltDateValPtr dt) +{ + xmlChar buf[100], *cur = buf, *end = buf + 99; + + if ((dt == NULL) || !VALID_DATETIME(dt)) + return NULL; + + exsltFormatYearMonthDay(&cur, end, dt); + if (cur < end) + *cur++ = 'T'; + exsltFormatTime(&cur, end, dt); + exsltFormatTimeZone(&cur, end, dt->tzo); + *cur = 0; + + return xmlStrdup(buf); +} + +/** + * exsltDateFormatDate: + * @dt: an #exsltDateValPtr + * + * Formats @dt in xs:date format. + * + * Returns a newly allocated string, or NULL in case of error + */ +static xmlChar * +exsltDateFormatDate (const exsltDateValPtr dt) +{ + xmlChar buf[100], *cur = buf, *end = buf + 99; + + if ((dt == NULL) || !VALID_DATETIME(dt)) + return NULL; + + exsltFormatYearMonthDay(&cur, end, dt); + if (dt->tz_flag || (dt->tzo != 0)) { + exsltFormatTimeZone(&cur, end, dt->tzo); + } + *cur = 0; + + return xmlStrdup(buf); +} + +/** + * exsltDateFormatTime: + * @dt: an #exsltDateValPtr + * + * Formats @dt in xs:time format. + * + * Returns a newly allocated string, or NULL in case of error + */ +static xmlChar * +exsltDateFormatTime (const exsltDateValPtr dt) +{ + xmlChar buf[100], *cur = buf, *end = buf + 99; + + if ((dt == NULL) || !VALID_TIME(dt)) + return NULL; + + exsltFormatTime(&cur, end, dt); + if (dt->tz_flag || (dt->tzo != 0)) { + exsltFormatTimeZone(&cur, end, dt->tzo); + } + *cur = 0; + + return xmlStrdup(buf); +} + +/** + * exsltDateFormat: + * @dt: an #exsltDateValPtr + * + * Formats @dt in the proper format. + * Note: xs:gmonth and xs:gday are not formatted as there are no + * routines that output them. + * + * Returns a newly allocated string, or NULL in case of error + */ +static xmlChar * +exsltDateFormat (const exsltDateValPtr dt) +{ + if (dt == NULL) + return NULL; + + switch (dt->type) { + case XS_DATETIME: + return exsltDateFormatDateTime(dt); + case XS_DATE: + return exsltDateFormatDate(dt); + case XS_TIME: + return exsltDateFormatTime(dt); + default: + break; + } + + if (dt->type & XS_GYEAR) { + xmlChar buf[100], *cur = buf, *end = buf + 99; + + exsltFormatGYear(&cur, end, dt->year); + if (dt->type == XS_GYEARMONTH) { + if (cur < end) + *cur++ = '-'; + exsltFormat2Digits(&cur, end, dt->mon); + } + + if (dt->tz_flag || (dt->tzo != 0)) { + exsltFormatTimeZone(&cur, end, dt->tzo); + } + *cur = 0; + return xmlStrdup(buf); + } + + return NULL; +} + +/** + * _exsltDateCastYMToDays: + * @dt: an #exsltDateValPtr + * + * Convert mon and year of @dt to total number of days. Take the + * number of years since (or before) 1 AD and add the number of leap + * years. This is a function because negative + * years must be handled a little differently. + * + * Returns number of days. + */ +static long +_exsltDateCastYMToDays (const exsltDateValPtr dt) +{ + long ret; + + if (dt->year <= 0) + ret = ((dt->year-1) * 365) + + (((dt->year)/4)-((dt->year)/100)+ + ((dt->year)/400)) + + DAY_IN_YEAR(0, dt->mon, dt->year) - 1; + else + ret = ((dt->year-1) * 365) + + (((dt->year-1)/4)-((dt->year-1)/100)+ + ((dt->year-1)/400)) + + DAY_IN_YEAR(0, dt->mon, dt->year); + + return ret; +} + +/** + * TIME_TO_NUMBER: + * @dt: an #exsltDateValPtr + * + * Calculates the number of seconds in the time portion of @dt. + * + * Returns seconds. + */ +#define TIME_TO_NUMBER(dt) \ + ((double)((dt->hour * SECS_PER_HOUR) + \ + (dt->min * SECS_PER_MIN)) + dt->sec) + +/** + * _exsltDateTruncateDate: + * @dt: an #exsltDateValPtr + * @type: dateTime type to set to + * + * Set @dt to truncated @type. + * + * Returns 0 success, non-zero otherwise. + */ +static int +_exsltDateTruncateDate (exsltDateValPtr dt, exsltDateType type) +{ + if (dt == NULL) + return 1; + + if ((type & XS_TIME) != XS_TIME) { + dt->hour = 0; + dt->min = 0; + dt->sec = 0.0; + } + + if ((type & XS_GDAY) != XS_GDAY) + dt->day = 1; + + if ((type & XS_GMONTH) != XS_GMONTH) + dt->mon = 1; + + if ((type & XS_GYEAR) != XS_GYEAR) + dt->year = 0; + + dt->type = type; + + return 0; +} + +/** + * _exsltDayInWeek: + * @yday: year day (1-366) + * @yr: year + * + * Determine the day-in-week from @yday and @yr. 0001-01-01 was + * a Monday so all other days are calculated from there. Take the + * number of years since (or before) add the number of leap years and + * the day-in-year and mod by 7. This is a function because negative + * years must be handled a little differently. + * + * Returns day in week (Sunday = 0). + */ +static long +_exsltDateDayInWeek(long yday, long yr) +{ + long ret; + + if (yr <= 0) { + /* Compute modulus twice to avoid integer overflow */ + ret = ((yr%7-2 + ((yr/4)-(yr/100)+(yr/400)) + yday) % 7); + if (ret < 0) + ret += 7; + } else + ret = (((yr%7-1) + (((yr-1)/4)-((yr-1)/100)+((yr-1)/400)) + yday) % 7); + + return ret; +} + +/** + * _exsltDateAdd: + * @dt: an #exsltDateValPtr + * @dur: an #exsltDateDurValPtr + * + * Compute a new date/time from @dt and @dur. This function assumes @dt + * is either #XS_DATETIME, #XS_DATE, #XS_GYEARMONTH, or #XS_GYEAR. + * + * Returns date/time pointer or NULL. + */ +static exsltDateValPtr +_exsltDateAdd (exsltDateValPtr dt, exsltDateDurValPtr dur) +{ + exsltDateValPtr ret; + long carry, temp; + double sum; + + if ((dt == NULL) || (dur == NULL)) + return NULL; + + ret = exsltDateCreateDate(dt->type); + if (ret == NULL) + return NULL; + + /* + * Note that temporary values may need more bits than the values in + * bit field. + */ + + /* month */ + temp = dt->mon + dur->mon % 12; + carry = dur->mon / 12; + if (temp < 1) { + temp += 12; + carry -= 1; + } + else if (temp > 12) { + temp -= 12; + carry += 1; + } + ret->mon = temp; + + /* + * year (may be modified later) + * + * Add epochs from dur->day now to avoid overflow later and to speed up + * pathological cases. + */ + carry += (dur->day / DAYS_PER_EPOCH) * YEARS_PER_EPOCH; + if ((carry > 0 && dt->year > YEAR_MAX - carry) || + (carry < 0 && dt->year < YEAR_MIN - carry)) { + /* Overflow */ + exsltDateFreeDate(ret); + return NULL; + } + ret->year = dt->year + carry; + + /* time zone */ + ret->tzo = dt->tzo; + ret->tz_flag = dt->tz_flag; + + /* seconds */ + sum = dt->sec + dur->sec; + ret->sec = fmod(sum, 60.0); + carry = (long)(sum / 60.0); + + /* minute */ + temp = dt->min + carry % 60; + carry = carry / 60; + if (temp >= 60) { + temp -= 60; + carry += 1; + } + ret->min = temp; + + /* hours */ + temp = dt->hour + carry % 24; + carry = carry / 24; + if (temp >= 24) { + temp -= 24; + carry += 1; + } + ret->hour = temp; + + /* days */ + if (dt->day > MAX_DAYINMONTH(ret->year, ret->mon)) + temp = MAX_DAYINMONTH(ret->year, ret->mon); + else if (dt->day < 1) + temp = 1; + else + temp = dt->day; + + temp += dur->day % DAYS_PER_EPOCH + carry; + + while (1) { + if (temp < 1) { + if (ret->mon > 1) { + ret->mon -= 1; + } + else { + if (ret->year == YEAR_MIN) { + exsltDateFreeDate(ret); + return NULL; + } + ret->mon = 12; + ret->year -= 1; + } + temp += MAX_DAYINMONTH(ret->year, ret->mon); + } else if (temp > (long)MAX_DAYINMONTH(ret->year, ret->mon)) { + temp -= MAX_DAYINMONTH(ret->year, ret->mon); + if (ret->mon < 12) { + ret->mon += 1; + } + else { + if (ret->year == YEAR_MAX) { + exsltDateFreeDate(ret); + return NULL; + } + ret->mon = 1; + ret->year += 1; + } + } else + break; + } + + ret->day = temp; + + /* + * adjust the date/time type to the date values + */ + if (ret->type != XS_DATETIME) { + if ((ret->hour) || (ret->min) || (ret->sec)) + ret->type = XS_DATETIME; + else if (ret->type != XS_DATE) { + if (ret->day != 1) + ret->type = XS_DATE; + else if ((ret->type != XS_GYEARMONTH) && (ret->mon != 1)) + ret->type = XS_GYEARMONTH; + } + } + + return ret; +} + +/** + * _exsltDateDifference: + * @x: an #exsltDateValPtr + * @y: an #exsltDateValPtr + * @flag: force difference in days + * + * Calculate the difference between @x and @y as a duration + * (i.e. y - x). If the @flag is set then even if the least specific + * format of @x or @y is xs:gYear or xs:gYearMonth. + * + * Returns a duration pointer or NULL. + */ +static exsltDateDurValPtr +_exsltDateDifference (exsltDateValPtr x, exsltDateValPtr y, int flag) +{ + exsltDateDurValPtr ret; + + if ((x == NULL) || (y == NULL)) + return NULL; + + if (((x->type < XS_GYEAR) || (x->type > XS_DATETIME)) || + ((y->type < XS_GYEAR) || (y->type > XS_DATETIME))) + return NULL; + + /* + * the operand with the most specific format must be converted to + * the same type as the operand with the least specific format. + */ + if (x->type != y->type) { + if (x->type < y->type) { + _exsltDateTruncateDate(y, x->type); + } else { + _exsltDateTruncateDate(x, y->type); + } + } + + ret = exsltDateCreateDuration(); + if (ret == NULL) + return NULL; + + if (((x->type == XS_GYEAR) || (x->type == XS_GYEARMONTH)) && (!flag)) { + /* compute the difference in months */ + if ((x->year >= LONG_MAX / 24) || (x->year <= LONG_MIN / 24) || + (y->year >= LONG_MAX / 24) || (y->year <= LONG_MIN / 24)) { + /* Possible overflow. */ + exsltDateFreeDuration(ret); + return NULL; + } + ret->mon = (y->year - x->year) * 12 + (y->mon - x->mon); + } else { + long carry; + + if ((x->year > LONG_MAX / 731) || (x->year < LONG_MIN / 731) || + (y->year > LONG_MAX / 731) || (y->year < LONG_MIN / 731)) { + /* Possible overflow. */ + exsltDateFreeDuration(ret); + return NULL; + } + + ret->sec = TIME_TO_NUMBER(y) - TIME_TO_NUMBER(x); + ret->sec += (x->tzo - y->tzo) * SECS_PER_MIN; + carry = (long)floor(ret->sec / SECS_PER_DAY); + ret->sec = ret->sec - carry * SECS_PER_DAY; + + ret->day = _exsltDateCastYMToDays(y) - _exsltDateCastYMToDays(x); + ret->day += y->day - x->day; + ret->day += carry; + } + + return ret; +} + +/** + * _exsltDateAddDurCalc + * @ret: an exsltDateDurValPtr for the return value: + * @x: an exsltDateDurValPtr for the first operand + * @y: an exsltDateDurValPtr for the second operand + * + * Add two durations, catering for possible negative values. + * The sum is placed in @ret. + * + * Returns 1 for success, 0 if error detected. + */ +static int +_exsltDateAddDurCalc (exsltDateDurValPtr ret, exsltDateDurValPtr x, + exsltDateDurValPtr y) +{ + /* months */ + if ((x->mon > 0 && y->mon > LONG_MAX - x->mon) || + (x->mon < 0 && y->mon <= LONG_MIN - x->mon)) { + /* Overflow */ + return 0; + } + ret->mon = x->mon + y->mon; + + /* days */ + if ((x->day > 0 && y->day > LONG_MAX - x->day) || + (x->day < 0 && y->day <= LONG_MIN - x->day)) { + /* Overflow */ + return 0; + } + ret->day = x->day + y->day; + + /* seconds */ + ret->sec = x->sec + y->sec; + if (ret->sec >= SECS_PER_DAY) { + if (ret->day == LONG_MAX) { + /* Overflow */ + return 0; + } + ret->sec -= SECS_PER_DAY; + ret->day += 1; + } + + /* + * are the results indeterminate? i.e. how do you subtract days from + * months or years? + */ + if (ret->day >= 0) { + if (((ret->day > 0) || (ret->sec > 0)) && (ret->mon < 0)) + return 0; + } + else { + if (ret->mon > 0) + return 0; + } + return 1; +} + +/** + * _exsltDateAddDuration: + * @x: an #exsltDateDurValPtr + * @y: an #exsltDateDurValPtr + * + * Compute a new duration from @x and @y. + * + * Returns a duration pointer or NULL. + */ +static exsltDateDurValPtr +_exsltDateAddDuration (exsltDateDurValPtr x, exsltDateDurValPtr y) +{ + exsltDateDurValPtr ret; + + if ((x == NULL) || (y == NULL)) + return NULL; + + ret = exsltDateCreateDuration(); + if (ret == NULL) + return NULL; + + if (_exsltDateAddDurCalc(ret, x, y)) + return ret; + + exsltDateFreeDuration(ret); + return NULL; +} + +/**************************************************************** + * * + * EXSLT - Dates and Times functions * + * * + ****************************************************************/ + +/** + * exsltDateDateTime: + * + * Implements the EXSLT - Dates and Times date-time() function: + * string date:date-time() + * + * Returns the current date and time as a date/time string. + */ +static xmlChar * +exsltDateDateTime (void) +{ + xmlChar *ret = NULL; + exsltDateValPtr cur; + + cur = exsltDateCurrent(); + if (cur != NULL) { + ret = exsltDateFormatDateTime(cur); + exsltDateFreeDate(cur); + } + + return ret; +} + +/** + * exsltDateDate: + * @dateTime: a date/time string + * + * Implements the EXSLT - Dates and Times date() function: + * string date:date (string?) + * + * Returns the date specified in the date/time string given as the + * argument. If no argument is given, then the current local + * date/time, as returned by date:date-time is used as a default + * argument. + * The date/time string specified as an argument must be a string in + * the format defined as the lexical representation of either + * xs:dateTime or xs:date. If the argument is not in either of these + * formats, returns NULL. + */ +static xmlChar * +exsltDateDate (const xmlChar *dateTime) +{ + exsltDateValPtr dt = NULL; + xmlChar *ret = NULL; + + if (dateTime == NULL) { + dt = exsltDateCurrent(); + if (dt == NULL) + return NULL; + } else { + dt = exsltDateParse(dateTime); + if (dt == NULL) + return NULL; + if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE)) { + exsltDateFreeDate(dt); + return NULL; + } + } + + ret = exsltDateFormatDate(dt); + exsltDateFreeDate(dt); + + return ret; +} + +/** + * exsltDateTime: + * @dateTime: a date/time string + * + * Implements the EXSLT - Dates and Times time() function: + * string date:time (string?) + * + * Returns the time specified in the date/time string given as the + * argument. If no argument is given, then the current local + * date/time, as returned by date:date-time is used as a default + * argument. + * The date/time string specified as an argument must be a string in + * the format defined as the lexical representation of either + * xs:dateTime or xs:time. If the argument is not in either of these + * formats, returns NULL. + */ +static xmlChar * +exsltDateTime (const xmlChar *dateTime) +{ + exsltDateValPtr dt = NULL; + xmlChar *ret = NULL; + + if (dateTime == NULL) { + dt = exsltDateCurrent(); + if (dt == NULL) + return NULL; + } else { + dt = exsltDateParse(dateTime); + if (dt == NULL) + return NULL; + if ((dt->type != XS_DATETIME) && (dt->type != XS_TIME)) { + exsltDateFreeDate(dt); + return NULL; + } + } + + ret = exsltDateFormatTime(dt); + exsltDateFreeDate(dt); + + return ret; +} + +/** + * exsltDateYear: + * @dateTime: a date/time string + * + * Implements the EXSLT - Dates and Times year() function + * number date:year (string?) + * Returns the year of a date as a number. If no argument is given, + * then the current local date/time, as returned by date:date-time is + * used as a default argument. + * The date/time string specified as the first argument must be a + * right-truncated string in the format defined as the lexical + * representation of xs:dateTime in one of the formats defined in [XML + * Schema Part 2: Datatypes]. The permitted formats are as follows: + * - xs:dateTime (CCYY-MM-DDThh:mm:ss) + * - xs:date (CCYY-MM-DD) + * - xs:gYearMonth (CCYY-MM) + * - xs:gYear (CCYY) + * If the date/time string is not in one of these formats, then NaN is + * returned. + */ +static double +exsltDateYear (const xmlChar *dateTime) +{ + exsltDateValPtr dt; + long year; + double ret; + + if (dateTime == NULL) { + dt = exsltDateCurrent(); + if (dt == NULL) + return NAN; + } else { + dt = exsltDateParse(dateTime); + if (dt == NULL) + return NAN; + if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE) && + (dt->type != XS_GYEARMONTH) && (dt->type != XS_GYEAR)) { + exsltDateFreeDate(dt); + return NAN; + } + } + + year = dt->year; + if (year <= 0) year -= 1; /* Adjust for missing year 0. */ + ret = (double) year; + exsltDateFreeDate(dt); + + return ret; +} + +/** + * exsltDateLeapYear: + * @dateTime: a date/time string + * + * Implements the EXSLT - Dates and Times leap-year() function: + * boolean date:leap-yea (string?) + * Returns true if the year given in a date is a leap year. If no + * argument is given, then the current local date/time, as returned by + * date:date-time is used as a default argument. + * The date/time string specified as the first argument must be a + * right-truncated string in the format defined as the lexical + * representation of xs:dateTime in one of the formats defined in [XML + * Schema Part 2: Datatypes]. The permitted formats are as follows: + * - xs:dateTime (CCYY-MM-DDThh:mm:ss) + * - xs:date (CCYY-MM-DD) + * - xs:gYearMonth (CCYY-MM) + * - xs:gYear (CCYY) + * If the date/time string is not in one of these formats, then NaN is + * returned. + */ +static xmlXPathObjectPtr +exsltDateLeapYear (const xmlChar *dateTime) +{ + exsltDateValPtr dt = NULL; + xmlXPathObjectPtr ret; + + if (dateTime == NULL) { + dt = exsltDateCurrent(); + } else { + dt = exsltDateParse(dateTime); + if ((dt != NULL) && + (dt->type != XS_DATETIME) && (dt->type != XS_DATE) && + (dt->type != XS_GYEARMONTH) && (dt->type != XS_GYEAR)) { + exsltDateFreeDate(dt); + dt = NULL; + } + } + + if (dt == NULL) { + ret = xmlXPathNewFloat(NAN); + } + else { + ret = xmlXPathNewBoolean(IS_LEAP(dt->year)); + exsltDateFreeDate(dt); + } + + return ret; +} + +/** + * exsltDateMonthInYear: + * @dateTime: a date/time string + * + * Implements the EXSLT - Dates and Times month-in-year() function: + * number date:month-in-year (string?) + * Returns the month of a date as a number. If no argument is given, + * then the current local date/time, as returned by date:date-time is + * used the default argument. + * The date/time string specified as the argument is a left or + * right-truncated string in the format defined as the lexical + * representation of xs:dateTime in one of the formats defined in [XML + * Schema Part 2: Datatypes]. The permitted formats are as follows: + * - xs:dateTime (CCYY-MM-DDThh:mm:ss) + * - xs:date (CCYY-MM-DD) + * - xs:gYearMonth (CCYY-MM) + * - xs:gMonth (--MM--) + * - xs:gMonthDay (--MM-DD) + * If the date/time string is not in one of these formats, then NaN is + * returned. + */ +static double +exsltDateMonthInYear (const xmlChar *dateTime) +{ + exsltDateValPtr dt; + double ret; + + if (dateTime == NULL) { + dt = exsltDateCurrent(); + if (dt == NULL) + return NAN; + } else { + dt = exsltDateParse(dateTime); + if (dt == NULL) + return NAN; + if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE) && + (dt->type != XS_GYEARMONTH) && (dt->type != XS_GMONTH) && + (dt->type != XS_GMONTHDAY)) { + exsltDateFreeDate(dt); + return NAN; + } + } + + ret = (double) dt->mon; + exsltDateFreeDate(dt); + + return ret; +} + +/** + * exsltDateMonthName: + * @dateTime: a date/time string + * + * Implements the EXSLT - Dates and Time month-name() function + * string date:month-name (string?) + * Returns the full name of the month of a date. If no argument is + * given, then the current local date/time, as returned by + * date:date-time is used the default argument. + * The date/time string specified as the argument is a left or + * right-truncated string in the format defined as the lexical + * representation of xs:dateTime in one of the formats defined in [XML + * Schema Part 2: Datatypes]. The permitted formats are as follows: + * - xs:dateTime (CCYY-MM-DDThh:mm:ss) + * - xs:date (CCYY-MM-DD) + * - xs:gYearMonth (CCYY-MM) + * - xs:gMonth (--MM--) + * If the date/time string is not in one of these formats, then an + * empty string ('') is returned. + * The result is an English month name: one of 'January', 'February', + * 'March', 'April', 'May', 'June', 'July', 'August', 'September', + * 'October', 'November' or 'December'. + */ +static const xmlChar * +exsltDateMonthName (const xmlChar *dateTime) +{ + static const xmlChar monthNames[13][10] = { + { 0 }, + { 'J', 'a', 'n', 'u', 'a', 'r', 'y', 0 }, + { 'F', 'e', 'b', 'r', 'u', 'a', 'r', 'y', 0 }, + { 'M', 'a', 'r', 'c', 'h', 0 }, + { 'A', 'p', 'r', 'i', 'l', 0 }, + { 'M', 'a', 'y', 0 }, + { 'J', 'u', 'n', 'e', 0 }, + { 'J', 'u', 'l', 'y', 0 }, + { 'A', 'u', 'g', 'u', 's', 't', 0 }, + { 'S', 'e', 'p', 't', 'e', 'm', 'b', 'e', 'r', 0 }, + { 'O', 'c', 't', 'o', 'b', 'e', 'r', 0 }, + { 'N', 'o', 'v', 'e', 'm', 'b', 'e', 'r', 0 }, + { 'D', 'e', 'c', 'e', 'm', 'b', 'e', 'r', 0 } + }; + double month; + int index = 0; + month = exsltDateMonthInYear(dateTime); + if (!xmlXPathIsNaN(month) && (month >= 1.0) && (month <= 12.0)) + index = (int) month; + return monthNames[index]; +} + +/** + * exsltDateMonthAbbreviation: + * @dateTime: a date/time string + * + * Implements the EXSLT - Dates and Time month-abbreviation() function + * string date:month-abbreviation (string?) + * Returns the abbreviation of the month of a date. If no argument is + * given, then the current local date/time, as returned by + * date:date-time is used the default argument. + * The date/time string specified as the argument is a left or + * right-truncated string in the format defined as the lexical + * representation of xs:dateTime in one of the formats defined in [XML + * Schema Part 2: Datatypes]. The permitted formats are as follows: + * - xs:dateTime (CCYY-MM-DDThh:mm:ss) + * - xs:date (CCYY-MM-DD) + * - xs:gYearMonth (CCYY-MM) + * - xs:gMonth (--MM--) + * If the date/time string is not in one of these formats, then an + * empty string ('') is returned. + * The result is an English month abbreviation: one of 'Jan', 'Feb', + * 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov' or + * 'Dec'. + */ +static const xmlChar * +exsltDateMonthAbbreviation (const xmlChar *dateTime) +{ + static const xmlChar monthAbbreviations[13][4] = { + { 0 }, + { 'J', 'a', 'n', 0 }, + { 'F', 'e', 'b', 0 }, + { 'M', 'a', 'r', 0 }, + { 'A', 'p', 'r', 0 }, + { 'M', 'a', 'y', 0 }, + { 'J', 'u', 'n', 0 }, + { 'J', 'u', 'l', 0 }, + { 'A', 'u', 'g', 0 }, + { 'S', 'e', 'p', 0 }, + { 'O', 'c', 't', 0 }, + { 'N', 'o', 'v', 0 }, + { 'D', 'e', 'c', 0 } + }; + double month; + int index = 0; + month = exsltDateMonthInYear(dateTime); + if (!xmlXPathIsNaN(month) && (month >= 1.0) && (month <= 12.0)) + index = (int) month; + return monthAbbreviations[index]; +} + +/** + * exsltDateWeekInYear: + * @dateTime: a date/time string + * + * Implements the EXSLT - Dates and Times week-in-year() function + * number date:week-in-year (string?) + * Returns the week of the year as a number. If no argument is given, + * then the current local date/time, as returned by date:date-time is + * used as the default argument. For the purposes of numbering, + * counting follows ISO 8601: week 1 in a year is the week containing + * the first Thursday of the year, with new weeks beginning on a + * Monday. + * The date/time string specified as the argument is a right-truncated + * string in the format defined as the lexical representation of + * xs:dateTime in one of the formats defined in [XML Schema Part 2: + * Datatypes]. The permitted formats are as follows: + * - xs:dateTime (CCYY-MM-DDThh:mm:ss) + * - xs:date (CCYY-MM-DD) + * If the date/time string is not in one of these formats, then NaN is + * returned. + */ +static double +exsltDateWeekInYear (const xmlChar *dateTime) +{ + exsltDateValPtr dt; + long diy, diw, year, ret; + + if (dateTime == NULL) { + dt = exsltDateCurrent(); + if (dt == NULL) + return NAN; + } else { + dt = exsltDateParse(dateTime); + if (dt == NULL) + return NAN; + if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE)) { + exsltDateFreeDate(dt); + return NAN; + } + } + + diy = DAY_IN_YEAR(dt->day, dt->mon, dt->year); + + /* + * Determine day-in-week (0=Sun, 1=Mon, etc.) then adjust so Monday + * is the first day-in-week + */ + diw = (_exsltDateDayInWeek(diy, dt->year) + 6) % 7; + + /* ISO 8601 adjustment, 3 is Thu */ + diy += (3 - diw); + if(diy < 1) { + year = dt->year - 1; + if(year == 0) year--; + diy = DAY_IN_YEAR(31, 12, year) + diy; + } else if (diy > (long)DAY_IN_YEAR(31, 12, dt->year)) { + diy -= DAY_IN_YEAR(31, 12, dt->year); + } + + ret = ((diy - 1) / 7) + 1; + + exsltDateFreeDate(dt); + + return (double) ret; +} + +/** + * exsltDateWeekInMonth: + * @dateTime: a date/time string + * + * Implements the EXSLT - Dates and Times week-in-month() function + * number date:week-in-month (string?) + * The date:week-in-month function returns the week in a month of a + * date as a number. If no argument is given, then the current local + * date/time, as returned by date:date-time is used the default + * argument. For the purposes of numbering, the first day of the month + * is in week 1 and new weeks begin on a Monday (so the first and last + * weeks in a month will often have less than 7 days in them). + * The date/time string specified as the argument is a right-truncated + * string in the format defined as the lexical representation of + * xs:dateTime in one of the formats defined in [XML Schema Part 2: + * Datatypes]. The permitted formats are as follows: + * - xs:dateTime (CCYY-MM-DDThh:mm:ss) + * - xs:date (CCYY-MM-DD) + * If the date/time string is not in one of these formats, then NaN is + * returned. + */ +static double +exsltDateWeekInMonth (const xmlChar *dateTime) +{ + exsltDateValPtr dt; + long fdiy, fdiw, ret; + + if (dateTime == NULL) { + dt = exsltDateCurrent(); + if (dt == NULL) + return NAN; + } else { + dt = exsltDateParse(dateTime); + if (dt == NULL) + return NAN; + if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE)) { + exsltDateFreeDate(dt); + return NAN; + } + } + + fdiy = DAY_IN_YEAR(1, dt->mon, dt->year); + /* + * Determine day-in-week (0=Sun, 1=Mon, etc.) then adjust so Monday + * is the first day-in-week + */ + fdiw = (_exsltDateDayInWeek(fdiy, dt->year) + 6) % 7; + + ret = ((dt->day + fdiw - 1) / 7) + 1; + + exsltDateFreeDate(dt); + + return (double) ret; +} + +/** + * exsltDateDayInYear: + * @dateTime: a date/time string + * + * Implements the EXSLT - Dates and Times day-in-year() function + * number date:day-in-year (string?) + * Returns the day of a date in a year as a number. If no argument is + * given, then the current local date/time, as returned by + * date:date-time is used the default argument. + * The date/time string specified as the argument is a right-truncated + * string in the format defined as the lexical representation of + * xs:dateTime in one of the formats defined in [XML Schema Part 2: + * Datatypes]. The permitted formats are as follows: + * - xs:dateTime (CCYY-MM-DDThh:mm:ss) + * - xs:date (CCYY-MM-DD) + * If the date/time string is not in one of these formats, then NaN is + * returned. + */ +static double +exsltDateDayInYear (const xmlChar *dateTime) +{ + exsltDateValPtr dt; + long ret; + + if (dateTime == NULL) { + dt = exsltDateCurrent(); + if (dt == NULL) + return NAN; + } else { + dt = exsltDateParse(dateTime); + if (dt == NULL) + return NAN; + if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE)) { + exsltDateFreeDate(dt); + return NAN; + } + } + + ret = DAY_IN_YEAR(dt->day, dt->mon, dt->year); + + exsltDateFreeDate(dt); + + return (double) ret; +} + +/** + * exsltDateDayInMonth: + * @dateTime: a date/time string + * + * Implements the EXSLT - Dates and Times day-in-month() function: + * number date:day-in-month (string?) + * Returns the day of a date as a number. If no argument is given, + * then the current local date/time, as returned by date:date-time is + * used the default argument. + * The date/time string specified as the argument is a left or + * right-truncated string in the format defined as the lexical + * representation of xs:dateTime in one of the formats defined in [XML + * Schema Part 2: Datatypes]. The permitted formats are as follows: + * - xs:dateTime (CCYY-MM-DDThh:mm:ss) + * - xs:date (CCYY-MM-DD) + * - xs:gMonthDay (--MM-DD) + * - xs:gDay (---DD) + * If the date/time string is not in one of these formats, then NaN is + * returned. + */ +static double +exsltDateDayInMonth (const xmlChar *dateTime) +{ + exsltDateValPtr dt; + double ret; + + if (dateTime == NULL) { + dt = exsltDateCurrent(); + if (dt == NULL) + return NAN; + } else { + dt = exsltDateParse(dateTime); + if (dt == NULL) + return NAN; + if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE) && + (dt->type != XS_GMONTHDAY) && (dt->type != XS_GDAY)) { + exsltDateFreeDate(dt); + return NAN; + } + } + + ret = (double) dt->day; + exsltDateFreeDate(dt); + + return ret; +} + +/** + * exsltDateDayOfWeekInMonth: + * @dateTime: a date/time string + * + * Implements the EXSLT - Dates and Times day-of-week-in-month() function: + * number date:day-of-week-in-month (string?) + * Returns the day-of-the-week in a month of a date as a number + * (e.g. 3 for the 3rd Tuesday in May). If no argument is + * given, then the current local date/time, as returned by + * date:date-time is used the default argument. + * The date/time string specified as the argument is a right-truncated + * string in the format defined as the lexical representation of + * xs:dateTime in one of the formats defined in [XML Schema Part 2: + * Datatypes]. The permitted formats are as follows: + * - xs:dateTime (CCYY-MM-DDThh:mm:ss) + * - xs:date (CCYY-MM-DD) + * If the date/time string is not in one of these formats, then NaN is + * returned. + */ +static double +exsltDateDayOfWeekInMonth (const xmlChar *dateTime) +{ + exsltDateValPtr dt; + long ret; + + if (dateTime == NULL) { + dt = exsltDateCurrent(); + if (dt == NULL) + return NAN; + } else { + dt = exsltDateParse(dateTime); + if (dt == NULL) + return NAN; + if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE)) { + exsltDateFreeDate(dt); + return NAN; + } + } + + ret = ((dt->day -1) / 7) + 1; + + exsltDateFreeDate(dt); + + return (double) ret; +} + +/** + * exsltDateDayInWeek: + * @dateTime: a date/time string + * + * Implements the EXSLT - Dates and Times day-in-week() function: + * number date:day-in-week (string?) + * Returns the day of the week given in a date as a number. If no + * argument is given, then the current local date/time, as returned by + * date:date-time is used the default argument. + * The date/time string specified as the argument is a left or + * right-truncated string in the format defined as the lexical + * representation of xs:dateTime in one of the formats defined in [XML + * Schema Part 2: Datatypes]. The permitted formats are as follows: + * - xs:dateTime (CCYY-MM-DDThh:mm:ss) + * - xs:date (CCYY-MM-DD) + * If the date/time string is not in one of these formats, then NaN is + * returned. + * The numbering of days of the week starts at 1 for Sunday, 2 for + * Monday and so on up to 7 for Saturday. + */ +static double +exsltDateDayInWeek (const xmlChar *dateTime) +{ + exsltDateValPtr dt; + long diy, ret; + + if (dateTime == NULL) { + dt = exsltDateCurrent(); + if (dt == NULL) + return NAN; + } else { + dt = exsltDateParse(dateTime); + if (dt == NULL) + return NAN; + if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE)) { + exsltDateFreeDate(dt); + return NAN; + } + } + + diy = DAY_IN_YEAR(dt->day, dt->mon, dt->year); + + ret = _exsltDateDayInWeek(diy, dt->year) + 1; + + exsltDateFreeDate(dt); + + return (double) ret; +} + +/** + * exsltDateDayName: + * @dateTime: a date/time string + * + * Implements the EXSLT - Dates and Time day-name() function + * string date:day-name (string?) + * Returns the full name of the day of the week of a date. If no + * argument is given, then the current local date/time, as returned by + * date:date-time is used the default argument. + * The date/time string specified as the argument is a left or + * right-truncated string in the format defined as the lexical + * representation of xs:dateTime in one of the formats defined in [XML + * Schema Part 2: Datatypes]. The permitted formats are as follows: + * - xs:dateTime (CCYY-MM-DDThh:mm:ss) + * - xs:date (CCYY-MM-DD) + * If the date/time string is not in one of these formats, then an + * empty string ('') is returned. + * The result is an English day name: one of 'Sunday', 'Monday', + * 'Tuesday', 'Wednesday', 'Thursday' or 'Friday'. + */ +static const xmlChar * +exsltDateDayName (const xmlChar *dateTime) +{ + static const xmlChar dayNames[8][10] = { + { 0 }, + { 'S', 'u', 'n', 'd', 'a', 'y', 0 }, + { 'M', 'o', 'n', 'd', 'a', 'y', 0 }, + { 'T', 'u', 'e', 's', 'd', 'a', 'y', 0 }, + { 'W', 'e', 'd', 'n', 'e', 's', 'd', 'a', 'y', 0 }, + { 'T', 'h', 'u', 'r', 's', 'd', 'a', 'y', 0 }, + { 'F', 'r', 'i', 'd', 'a', 'y', 0 }, + { 'S', 'a', 't', 'u', 'r', 'd', 'a', 'y', 0 } + }; + double day; + int index = 0; + day = exsltDateDayInWeek(dateTime); + if(!xmlXPathIsNaN(day) && (day >= 1.0) && (day <= 7.0)) + index = (int) day; + return dayNames[index]; +} + +/** + * exsltDateDayAbbreviation: + * @dateTime: a date/time string + * + * Implements the EXSLT - Dates and Time day-abbreviation() function + * string date:day-abbreviation (string?) + * Returns the abbreviation of the day of the week of a date. If no + * argument is given, then the current local date/time, as returned by + * date:date-time is used the default argument. + * The date/time string specified as the argument is a left or + * right-truncated string in the format defined as the lexical + * representation of xs:dateTime in one of the formats defined in [XML + * Schema Part 2: Datatypes]. The permitted formats are as follows: + * - xs:dateTime (CCYY-MM-DDThh:mm:ss) + * - xs:date (CCYY-MM-DD) + * If the date/time string is not in one of these formats, then an + * empty string ('') is returned. + * The result is a three-letter English day abbreviation: one of + * 'Sun', 'Mon', 'Tue', 'Wed', 'Thu' or 'Fri'. + */ +static const xmlChar * +exsltDateDayAbbreviation (const xmlChar *dateTime) +{ + static const xmlChar dayAbbreviations[8][4] = { + { 0 }, + { 'S', 'u', 'n', 0 }, + { 'M', 'o', 'n', 0 }, + { 'T', 'u', 'e', 0 }, + { 'W', 'e', 'd', 0 }, + { 'T', 'h', 'u', 0 }, + { 'F', 'r', 'i', 0 }, + { 'S', 'a', 't', 0 } + }; + double day; + int index = 0; + day = exsltDateDayInWeek(dateTime); + if(!xmlXPathIsNaN(day) && (day >= 1.0) && (day <= 7.0)) + index = (int) day; + return dayAbbreviations[index]; +} + +/** + * exsltDateHourInDay: + * @dateTime: a date/time string + * + * Implements the EXSLT - Dates and Times day-in-month() function: + * number date:day-in-month (string?) + * Returns the hour of the day as a number. If no argument is given, + * then the current local date/time, as returned by date:date-time is + * used the default argument. + * The date/time string specified as the argument is a left or + * right-truncated string in the format defined as the lexical + * representation of xs:dateTime in one of the formats defined in [XML + * Schema Part 2: Datatypes]. The permitted formats are as follows: + * - xs:dateTime (CCYY-MM-DDThh:mm:ss) + * - xs:time (hh:mm:ss) + * If the date/time string is not in one of these formats, then NaN is + * returned. + */ +static double +exsltDateHourInDay (const xmlChar *dateTime) +{ + exsltDateValPtr dt; + double ret; + + if (dateTime == NULL) { + dt = exsltDateCurrent(); + if (dt == NULL) + return NAN; + } else { + dt = exsltDateParse(dateTime); + if (dt == NULL) + return NAN; + if ((dt->type != XS_DATETIME) && (dt->type != XS_TIME)) { + exsltDateFreeDate(dt); + return NAN; + } + } + + ret = (double) dt->hour; + exsltDateFreeDate(dt); + + return ret; +} + +/** + * exsltDateMinuteInHour: + * @dateTime: a date/time string + * + * Implements the EXSLT - Dates and Times day-in-month() function: + * number date:day-in-month (string?) + * Returns the minute of the hour as a number. If no argument is + * given, then the current local date/time, as returned by + * date:date-time is used the default argument. + * The date/time string specified as the argument is a left or + * right-truncated string in the format defined as the lexical + * representation of xs:dateTime in one of the formats defined in [XML + * Schema Part 2: Datatypes]. The permitted formats are as follows: + * - xs:dateTime (CCYY-MM-DDThh:mm:ss) + * - xs:time (hh:mm:ss) + * If the date/time string is not in one of these formats, then NaN is + * returned. + */ +static double +exsltDateMinuteInHour (const xmlChar *dateTime) +{ + exsltDateValPtr dt; + double ret; + + if (dateTime == NULL) { + dt = exsltDateCurrent(); + if (dt == NULL) + return NAN; + } else { + dt = exsltDateParse(dateTime); + if (dt == NULL) + return NAN; + if ((dt->type != XS_DATETIME) && (dt->type != XS_TIME)) { + exsltDateFreeDate(dt); + return NAN; + } + } + + ret = (double) dt->min; + exsltDateFreeDate(dt); + + return ret; +} + +/** + * exsltDateSecondInMinute: + * @dateTime: a date/time string + * + * Implements the EXSLT - Dates and Times second-in-minute() function: + * number date:day-in-month (string?) + * Returns the second of the minute as a number. If no argument is + * given, then the current local date/time, as returned by + * date:date-time is used the default argument. + * The date/time string specified as the argument is a left or + * right-truncated string in the format defined as the lexical + * representation of xs:dateTime in one of the formats defined in [XML + * Schema Part 2: Datatypes]. The permitted formats are as follows: + * - xs:dateTime (CCYY-MM-DDThh:mm:ss) + * - xs:time (hh:mm:ss) + * If the date/time string is not in one of these formats, then NaN is + * returned. + * + * Returns the second or NaN. + */ +static double +exsltDateSecondInMinute (const xmlChar *dateTime) +{ + exsltDateValPtr dt; + double ret; + + if (dateTime == NULL) { + dt = exsltDateCurrent(); + if (dt == NULL) + return NAN; + } else { + dt = exsltDateParse(dateTime); + if (dt == NULL) + return NAN; + if ((dt->type != XS_DATETIME) && (dt->type != XS_TIME)) { + exsltDateFreeDate(dt); + return NAN; + } + } + + ret = dt->sec; + exsltDateFreeDate(dt); + + return ret; +} + +/** + * exsltDateAdd: + * @xstr: date/time string + * @ystr: date/time string + * + * Implements the date:add (string,string) function which returns the + * date/time * resulting from adding a duration to a date/time. + * The first argument (@xstr) must be right-truncated date/time + * strings in one of the formats defined in [XML Schema Part 2: + * Datatypes]. The permitted formats are as follows: + * - xs:dateTime (CCYY-MM-DDThh:mm:ss) + * - xs:date (CCYY-MM-DD) + * - xs:gYearMonth (CCYY-MM) + * - xs:gYear (CCYY) + * The second argument (@ystr) is a string in the format defined for + * xs:duration in [3.2.6 duration] of [XML Schema Part 2: Datatypes]. + * The return value is a right-truncated date/time strings in one of + * the formats defined in [XML Schema Part 2: Datatypes] and listed + * above. This value is calculated using the algorithm described in + * [Appendix E Adding durations to dateTimes] of [XML Schema Part 2: + * Datatypes]. + + * Returns date/time string or NULL. + */ +static xmlChar * +exsltDateAdd (const xmlChar *xstr, const xmlChar *ystr) +{ + exsltDateValPtr dt, res; + exsltDateDurValPtr dur; + xmlChar *ret; + + if ((xstr == NULL) || (ystr == NULL)) + return NULL; + + dt = exsltDateParse(xstr); + if (dt == NULL) + return NULL; + else if ((dt->type < XS_GYEAR) || (dt->type > XS_DATETIME)) { + exsltDateFreeDate(dt); + return NULL; + } + + dur = exsltDateParseDuration(ystr); + if (dur == NULL) { + exsltDateFreeDate(dt); + return NULL; + } + + res = _exsltDateAdd(dt, dur); + + exsltDateFreeDate(dt); + exsltDateFreeDuration(dur); + + if (res == NULL) + return NULL; + + ret = exsltDateFormat(res); + exsltDateFreeDate(res); + + return ret; +} + +/** + * exsltDateAddDuration: + * @xstr: first duration string + * @ystr: second duration string + * + * Implements the date:add-duration (string,string) function which returns + * the duration resulting from adding two durations together. + * Both arguments are strings in the format defined for xs:duration + * in [3.2.6 duration] of [XML Schema Part 2: Datatypes]. If either + * argument is not in this format, the function returns an empty string + * (''). + * The return value is a string in the format defined for xs:duration + * in [3.2.6 duration] of [XML Schema Part 2: Datatypes]. + * The durations can usually be added by summing the numbers given for + * each of the components in the durations. However, if the durations + * are differently signed, then this sometimes results in durations + * that are impossible to express in this syntax (e.g. 'P1M' + '-P1D'). + * In these cases, the function returns an empty string (''). + * + * Returns duration string or NULL. + */ +static xmlChar * +exsltDateAddDuration (const xmlChar *xstr, const xmlChar *ystr) +{ + exsltDateDurValPtr x, y, res; + xmlChar *ret; + + if ((xstr == NULL) || (ystr == NULL)) + return NULL; + + x = exsltDateParseDuration(xstr); + if (x == NULL) + return NULL; + + y = exsltDateParseDuration(ystr); + if (y == NULL) { + exsltDateFreeDuration(x); + return NULL; + } + + res = _exsltDateAddDuration(x, y); + + exsltDateFreeDuration(x); + exsltDateFreeDuration(y); + + if (res == NULL) + return NULL; + + ret = exsltDateFormatDuration(res); + exsltDateFreeDuration(res); + + return ret; +} + +/** + * exsltDateSumFunction: + * @ns: a node set of duration strings + * + * The date:sum function adds a set of durations together. + * The string values of the nodes in the node set passed as an argument + * are interpreted as durations and added together as if using the + * date:add-duration function. (from exslt.org) + * + * The return value is a string in the format defined for xs:duration + * in [3.2.6 duration] of [XML Schema Part 2: Datatypes]. + * The durations can usually be added by summing the numbers given for + * each of the components in the durations. However, if the durations + * are differently signed, then this sometimes results in durations + * that are impossible to express in this syntax (e.g. 'P1M' + '-P1D'). + * In these cases, the function returns an empty string (''). + * + * Returns duration string or NULL. + */ +static void +exsltDateSumFunction (xmlXPathParserContextPtr ctxt, int nargs) +{ + xmlNodeSetPtr ns; + void *user = NULL; + xmlChar *tmp; + exsltDateDurValPtr x, total; + xmlChar *ret; + int i; + + if (nargs != 1) { + xmlXPathSetArityError (ctxt); + return; + } + + /* We need to delay the freeing of value->user */ + if ((ctxt->value != NULL) && ctxt->value->boolval != 0) { + user = ctxt->value->user; + ctxt->value->boolval = 0; + ctxt->value->user = NULL; + } + + ns = xmlXPathPopNodeSet (ctxt); + if (xmlXPathCheckError (ctxt)) + return; + + if ((ns == NULL) || (ns->nodeNr == 0)) { + xmlXPathReturnEmptyString (ctxt); + if (ns != NULL) + xmlXPathFreeNodeSet (ns); + return; + } + + total = exsltDateCreateDuration (); + if (total == NULL) { + xmlXPathFreeNodeSet (ns); + return; + } + + for (i = 0; i < ns->nodeNr; i++) { + int result; + tmp = xmlXPathCastNodeToString (ns->nodeTab[i]); + if (tmp == NULL) { + xmlXPathFreeNodeSet (ns); + exsltDateFreeDuration (total); + return; + } + + x = exsltDateParseDuration (tmp); + if (x == NULL) { + xmlFree (tmp); + exsltDateFreeDuration (total); + xmlXPathFreeNodeSet (ns); + xmlXPathReturnEmptyString (ctxt); + return; + } + + result = _exsltDateAddDurCalc(total, total, x); + + exsltDateFreeDuration (x); + xmlFree (tmp); + if (!result) { + exsltDateFreeDuration (total); + xmlXPathFreeNodeSet (ns); + xmlXPathReturnEmptyString (ctxt); + return; + } + } + + ret = exsltDateFormatDuration (total); + exsltDateFreeDuration (total); + + xmlXPathFreeNodeSet (ns); + if (user != NULL) + xmlFreeNodeList ((xmlNodePtr) user); + + if (ret == NULL) + xmlXPathReturnEmptyString (ctxt); + else + xmlXPathReturnString (ctxt, ret); +} + +/** + * exsltDateSeconds: + * @dateTime: a date/time string + * + * Implements the EXSLT - Dates and Times seconds() function: + * number date:seconds(string?) + * The date:seconds function returns the number of seconds specified + * by the argument string. If no argument is given, then the current + * local date/time, as returned by exsltDateCurrent() is used as the + * default argument. If the date/time string is a xs:duration, then the + * years and months must be zero (or not present). Parsing a duration + * converts the fields to seconds. If the date/time string is not a + * duration (and not null), then the legal formats are: + * - xs:dateTime (CCYY-MM-DDThh:mm:ss) + * - xs:date (CCYY-MM-DD) + * - xs:gYearMonth (CCYY-MM) + * - xs:gYear (CCYY) + * In these cases the difference between the @dateTime and + * 1970-01-01T00:00:00Z is calculated and converted to seconds. + * + * Note that there was some confusion over whether "difference" meant + * that a dateTime of 1970-01-01T00:00:01Z should be a positive one or + * a negative one. After correspondence with exslt.org, it was determined + * that the intent of the specification was to have it positive. The + * coding was modified in July 2003 to reflect this. + * + * Returns seconds or Nan. + */ +static double +exsltDateSeconds (const xmlChar *dateTime) +{ + exsltDateValPtr dt; + exsltDateDurValPtr dur = NULL; + double ret = NAN; + + if (dateTime == NULL) { + dt = exsltDateCurrent(); + if (dt == NULL) + return NAN; + } else { + dt = exsltDateParse(dateTime); + if (dt == NULL) + dur = exsltDateParseDuration(dateTime); + } + + if ((dt != NULL) && (dt->type >= XS_GYEAR)) { + exsltDateValPtr y; + exsltDateDurValPtr diff; + + /* + * compute the difference between the given (or current) date + * and epoch date + */ + y = exsltDateCreateDate(XS_DATETIME); + if (y != NULL) { + y->year = 1970; + y->mon = 1; + y->day = 1; + y->tz_flag = 1; + + diff = _exsltDateDifference(y, dt, 1); + if (diff != NULL) { + ret = (double)diff->day * SECS_PER_DAY + diff->sec; + exsltDateFreeDuration(diff); + } + exsltDateFreeDate(y); + } + + } else if ((dur != NULL) && (dur->mon == 0)) { + ret = (double)dur->day * SECS_PER_DAY + dur->sec; + } + + if (dt != NULL) + exsltDateFreeDate(dt); + if (dur != NULL) + exsltDateFreeDuration(dur); + + return ret; +} + +/** + * exsltDateDifference: + * @xstr: date/time string + * @ystr: date/time string + * + * Implements the date:difference (string,string) function which returns + * the duration between the first date and the second date. If the first + * date occurs before the second date, then the result is a positive + * duration; if it occurs after the second date, the result is a + * negative duration. The two dates must both be right-truncated + * date/time strings in one of the formats defined in [XML Schema Part + * 2: Datatypes]. The date/time with the most specific format (i.e. the + * least truncation) is converted into the same format as the date with + * the least specific format (i.e. the most truncation). The permitted + * formats are as follows, from most specific to least specific: + * - xs:dateTime (CCYY-MM-DDThh:mm:ss) + * - xs:date (CCYY-MM-DD) + * - xs:gYearMonth (CCYY-MM) + * - xs:gYear (CCYY) + * If either of the arguments is not in one of these formats, + * date:difference returns the empty string (''). + * The difference between the date/times is returned as a string in the + * format defined for xs:duration in [3.2.6 duration] of [XML Schema + * Part 2: Datatypes]. + * If the date/time string with the least specific format is in either + * xs:gYearMonth or xs:gYear format, then the number of days, hours, + * minutes and seconds in the duration string must be equal to zero. + * (The format of the string will be PnYnM.) The number of months + * specified in the duration must be less than 12. + * Otherwise, the number of years and months in the duration string + * must be equal to zero. (The format of the string will be + * PnDTnHnMnS.) The number of seconds specified in the duration string + * must be less than 60; the number of minutes must be less than 60; + * the number of hours must be less than 24. + * + * Returns duration string or NULL. + */ +static xmlChar * +exsltDateDifference (const xmlChar *xstr, const xmlChar *ystr) +{ + exsltDateValPtr x, y; + exsltDateDurValPtr dur; + xmlChar *ret = NULL; + + if ((xstr == NULL) || (ystr == NULL)) + return NULL; + + x = exsltDateParse(xstr); + if (x == NULL) + return NULL; + + y = exsltDateParse(ystr); + if (y == NULL) { + exsltDateFreeDate(x); + return NULL; + } + + if (((x->type < XS_GYEAR) || (x->type > XS_DATETIME)) || + ((y->type < XS_GYEAR) || (y->type > XS_DATETIME))) { + exsltDateFreeDate(x); + exsltDateFreeDate(y); + return NULL; + } + + dur = _exsltDateDifference(x, y, 0); + + exsltDateFreeDate(x); + exsltDateFreeDate(y); + + if (dur == NULL) + return NULL; + + ret = exsltDateFormatDuration(dur); + exsltDateFreeDuration(dur); + + return ret; +} + +/** + * exsltDateDuration: + * @number: a xmlChar string + * + * Implements the The date:duration function returns a duration string + * representing the number of seconds specified by the argument string. + * If no argument is given, then the result of calling date:seconds + * without any arguments is used as a default argument. + * The duration is returned as a string in the format defined for + * xs:duration in [3.2.6 duration] of [XML Schema Part 2: Datatypes]. + * The number of years and months in the duration string must be equal + * to zero. (The format of the string will be PnDTnHnMnS.) The number + * of seconds specified in the duration string must be less than 60; + * the number of minutes must be less than 60; the number of hours must + * be less than 24. + * If the argument is Infinity, -Infinity or NaN, then date:duration + * returns an empty string (''). + * + * Returns duration string or NULL. + */ +static xmlChar * +exsltDateDuration (const xmlChar *number) +{ + exsltDateDurValPtr dur; + double secs, days; + xmlChar *ret; + + if (number == NULL) + secs = exsltDateSeconds(number); + else + secs = xmlXPathCastStringToNumber(number); + + if (xmlXPathIsNaN(secs)) + return NULL; + + days = floor(secs / SECS_PER_DAY); + if ((days <= (double)LONG_MIN) || (days >= (double)LONG_MAX)) + return NULL; + + dur = exsltDateCreateDuration(); + if (dur == NULL) + return NULL; + + dur->day = (long)days; + dur->sec = secs - days * SECS_PER_DAY; + + ret = exsltDateFormatDuration(dur); + exsltDateFreeDuration(dur); + + return ret; +} + +/**************************************************************** + * * + * Wrappers for use by the XPath engine * + * * + ****************************************************************/ + +/** + * exsltDateDateTimeFunction: + * @ctxt: an XPath parser context + * @nargs : the number of arguments + * + * Wraps exsltDateDateTime() for use by the XPath engine. + */ +static void +exsltDateDateTimeFunction (xmlXPathParserContextPtr ctxt, int nargs) +{ + xmlChar *ret; + + if (nargs != 0) { + xmlXPathSetArityError(ctxt); + return; + } + + ret = exsltDateDateTime(); + if (ret == NULL) + xmlXPathReturnEmptyString(ctxt); + else + xmlXPathReturnString(ctxt, ret); +} + +/** + * exsltDateDateFunction: + * @ctxt: an XPath parser context + * @nargs : the number of arguments + * + * Wraps exsltDateDate() for use by the XPath engine. + */ +static void +exsltDateDateFunction (xmlXPathParserContextPtr ctxt, int nargs) +{ + xmlChar *ret, *dt = NULL; + + if ((nargs < 0) || (nargs > 1)) { + xmlXPathSetArityError(ctxt); + return; + } + if (nargs == 1) { + dt = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt)) { + xmlXPathSetTypeError(ctxt); + return; + } + } + + ret = exsltDateDate(dt); + + if (ret == NULL) { + xsltGenericDebug(xsltGenericDebugContext, + "{http://exslt.org/dates-and-times}date: " + "invalid date or format %s\n", dt); + xmlXPathReturnEmptyString(ctxt); + } else { + xmlXPathReturnString(ctxt, ret); + } + + if (dt != NULL) + xmlFree(dt); +} + +/** + * exsltDateTimeFunction: + * @ctxt: an XPath parser context + * @nargs : the number of arguments + * + * Wraps exsltDateTime() for use by the XPath engine. + */ +static void +exsltDateTimeFunction (xmlXPathParserContextPtr ctxt, int nargs) +{ + xmlChar *ret, *dt = NULL; + + if ((nargs < 0) || (nargs > 1)) { + xmlXPathSetArityError(ctxt); + return; + } + if (nargs == 1) { + dt = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt)) { + xmlXPathSetTypeError(ctxt); + return; + } + } + + ret = exsltDateTime(dt); + + if (ret == NULL) { + xsltGenericDebug(xsltGenericDebugContext, + "{http://exslt.org/dates-and-times}time: " + "invalid date or format %s\n", dt); + xmlXPathReturnEmptyString(ctxt); + } else { + xmlXPathReturnString(ctxt, ret); + } + + if (dt != NULL) + xmlFree(dt); +} + +/** + * exsltDateYearFunction: + * @ctxt: an XPath parser context + * @nargs : the number of arguments + * + * Wraps exsltDateYear() for use by the XPath engine. + */ +static void +exsltDateYearFunction (xmlXPathParserContextPtr ctxt, int nargs) +{ + xmlChar *dt = NULL; + double ret; + + if ((nargs < 0) || (nargs > 1)) { + xmlXPathSetArityError(ctxt); + return; + } + + if (nargs == 1) { + dt = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt)) { + xmlXPathSetTypeError(ctxt); + return; + } + } + + ret = exsltDateYear(dt); + + if (dt != NULL) + xmlFree(dt); + + xmlXPathReturnNumber(ctxt, ret); +} + +/** + * exsltDateLeapYearFunction: + * @ctxt: an XPath parser context + * @nargs : the number of arguments + * + * Wraps exsltDateLeapYear() for use by the XPath engine. + */ +static void +exsltDateLeapYearFunction (xmlXPathParserContextPtr ctxt, int nargs) +{ + xmlChar *dt = NULL; + xmlXPathObjectPtr ret; + + if ((nargs < 0) || (nargs > 1)) { + xmlXPathSetArityError(ctxt); + return; + } + + if (nargs == 1) { + dt = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt)) { + xmlXPathSetTypeError(ctxt); + return; + } + } + + ret = exsltDateLeapYear(dt); + + if (dt != NULL) + xmlFree(dt); + + valuePush(ctxt, ret); +} + +#define X_IN_Y(x, y) \ +static void \ +exsltDate##x##In##y##Function (xmlXPathParserContextPtr ctxt, \ + int nargs) { \ + xmlChar *dt = NULL; \ + double ret; \ + \ + if ((nargs < 0) || (nargs > 1)) { \ + xmlXPathSetArityError(ctxt); \ + return; \ + } \ + \ + if (nargs == 1) { \ + dt = xmlXPathPopString(ctxt); \ + if (xmlXPathCheckError(ctxt)) { \ + xmlXPathSetTypeError(ctxt); \ + return; \ + } \ + } \ + \ + ret = exsltDate##x##In##y(dt); \ + \ + if (dt != NULL) \ + xmlFree(dt); \ + \ + xmlXPathReturnNumber(ctxt, ret); \ +} + +/** + * exsltDateMonthInYearFunction: + * @ctxt: an XPath parser context + * @nargs : the number of arguments + * + * Wraps exsltDateMonthInYear() for use by the XPath engine. + */ +X_IN_Y(Month,Year) + +/** + * exsltDateMonthNameFunction: + * @ctxt: an XPath parser context + * @nargs : the number of arguments + * + * Wraps exsltDateMonthName() for use by the XPath engine. + */ +static void +exsltDateMonthNameFunction (xmlXPathParserContextPtr ctxt, int nargs) +{ + xmlChar *dt = NULL; + const xmlChar *ret; + + if ((nargs < 0) || (nargs > 1)) { + xmlXPathSetArityError(ctxt); + return; + } + + if (nargs == 1) { + dt = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt)) { + xmlXPathSetTypeError(ctxt); + return; + } + } + + ret = exsltDateMonthName(dt); + + if (dt != NULL) + xmlFree(dt); + + if (ret == NULL) + xmlXPathReturnEmptyString(ctxt); + else + xmlXPathReturnString(ctxt, xmlStrdup(ret)); +} + +/** + * exsltDateMonthAbbreviationFunction: + * @ctxt: an XPath parser context + * @nargs : the number of arguments + * + * Wraps exsltDateMonthAbbreviation() for use by the XPath engine. + */ +static void +exsltDateMonthAbbreviationFunction (xmlXPathParserContextPtr ctxt, int nargs) +{ + xmlChar *dt = NULL; + const xmlChar *ret; + + if ((nargs < 0) || (nargs > 1)) { + xmlXPathSetArityError(ctxt); + return; + } + + if (nargs == 1) { + dt = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt)) { + xmlXPathSetTypeError(ctxt); + return; + } + } + + ret = exsltDateMonthAbbreviation(dt); + + if (dt != NULL) + xmlFree(dt); + + if (ret == NULL) + xmlXPathReturnEmptyString(ctxt); + else + xmlXPathReturnString(ctxt, xmlStrdup(ret)); +} + +/** + * exsltDateWeekInYearFunction: + * @ctxt: an XPath parser context + * @nargs : the number of arguments + * + * Wraps exsltDateWeekInYear() for use by the XPath engine. + */ +X_IN_Y(Week,Year) + +/** + * exsltDateWeekInMonthFunction: + * @ctxt: an XPath parser context + * @nargs : the number of arguments + * + * Wraps exsltDateWeekInMonthYear() for use by the XPath engine. + */ +X_IN_Y(Week,Month) + +/** + * exsltDateDayInYearFunction: + * @ctxt: an XPath parser context + * @nargs : the number of arguments + * + * Wraps exsltDateDayInYear() for use by the XPath engine. + */ +X_IN_Y(Day,Year) + +/** + * exsltDateDayInMonthFunction: + * @ctxt: an XPath parser context + * @nargs : the number of arguments + * + * Wraps exsltDateDayInMonth() for use by the XPath engine. + */ +X_IN_Y(Day,Month) + +/** + * exsltDateDayOfWeekInMonthFunction: + * @ctxt: an XPath parser context + * @nargs : the number of arguments + * + * Wraps exsltDayOfWeekInMonth() for use by the XPath engine. + */ +X_IN_Y(DayOfWeek,Month) + +/** + * exsltDateDayInWeekFunction: + * @ctxt: an XPath parser context + * @nargs : the number of arguments + * + * Wraps exsltDateDayInWeek() for use by the XPath engine. + */ +X_IN_Y(Day,Week) + +/** + * exsltDateDayNameFunction: + * @ctxt: an XPath parser context + * @nargs : the number of arguments + * + * Wraps exsltDateDayName() for use by the XPath engine. + */ +static void +exsltDateDayNameFunction (xmlXPathParserContextPtr ctxt, int nargs) +{ + xmlChar *dt = NULL; + const xmlChar *ret; + + if ((nargs < 0) || (nargs > 1)) { + xmlXPathSetArityError(ctxt); + return; + } + + if (nargs == 1) { + dt = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt)) { + xmlXPathSetTypeError(ctxt); + return; + } + } + + ret = exsltDateDayName(dt); + + if (dt != NULL) + xmlFree(dt); + + if (ret == NULL) + xmlXPathReturnEmptyString(ctxt); + else + xmlXPathReturnString(ctxt, xmlStrdup(ret)); +} + +/** + * exsltDateMonthDayFunction: + * @ctxt: an XPath parser context + * @nargs : the number of arguments + * + * Wraps exsltDateDayAbbreviation() for use by the XPath engine. + */ +static void +exsltDateDayAbbreviationFunction (xmlXPathParserContextPtr ctxt, int nargs) +{ + xmlChar *dt = NULL; + const xmlChar *ret; + + if ((nargs < 0) || (nargs > 1)) { + xmlXPathSetArityError(ctxt); + return; + } + + if (nargs == 1) { + dt = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt)) { + xmlXPathSetTypeError(ctxt); + return; + } + } + + ret = exsltDateDayAbbreviation(dt); + + if (dt != NULL) + xmlFree(dt); + + if (ret == NULL) + xmlXPathReturnEmptyString(ctxt); + else + xmlXPathReturnString(ctxt, xmlStrdup(ret)); +} + + +/** + * exsltDateHourInDayFunction: + * @ctxt: an XPath parser context + * @nargs : the number of arguments + * + * Wraps exsltDateHourInDay() for use by the XPath engine. + */ +X_IN_Y(Hour,Day) + +/** + * exsltDateMinuteInHourFunction: + * @ctxt: an XPath parser context + * @nargs : the number of arguments + * + * Wraps exsltDateMinuteInHour() for use by the XPath engine. + */ +X_IN_Y(Minute,Hour) + +/** + * exsltDateSecondInMinuteFunction: + * @ctxt: an XPath parser context + * @nargs : the number of arguments + * + * Wraps exsltDateSecondInMinute() for use by the XPath engine. + */ +X_IN_Y(Second,Minute) + +/** + * exsltDateSecondsFunction: + * @ctxt: an XPath parser context + * @nargs : the number of arguments + * + * Wraps exsltDateSeconds() for use by the XPath engine. + */ +static void +exsltDateSecondsFunction (xmlXPathParserContextPtr ctxt, int nargs) +{ + xmlChar *str = NULL; + double ret; + + if (nargs > 1) { + xmlXPathSetArityError(ctxt); + return; + } + + if (nargs == 1) { + str = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt)) { + xmlXPathSetTypeError(ctxt); + return; + } + } + + ret = exsltDateSeconds(str); + if (str != NULL) + xmlFree(str); + + xmlXPathReturnNumber(ctxt, ret); +} + +/** + * exsltDateAddFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Wraps exsltDateAdd() for use by the XPath processor. + */ +static void +exsltDateAddFunction (xmlXPathParserContextPtr ctxt, int nargs) +{ + xmlChar *ret, *xstr, *ystr; + + if (nargs != 2) { + xmlXPathSetArityError(ctxt); + return; + } + ystr = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + + xstr = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt)) { + xmlFree(ystr); + return; + } + + ret = exsltDateAdd(xstr, ystr); + + xmlFree(ystr); + xmlFree(xstr); + + if (ret == NULL) + xmlXPathReturnEmptyString(ctxt); + else + xmlXPathReturnString(ctxt, ret); +} + +/** + * exsltDateAddDurationFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Wraps exsltDateAddDuration() for use by the XPath processor. + */ +static void +exsltDateAddDurationFunction (xmlXPathParserContextPtr ctxt, int nargs) +{ + xmlChar *ret, *xstr, *ystr; + + if (nargs != 2) { + xmlXPathSetArityError(ctxt); + return; + } + ystr = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + + xstr = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt)) { + xmlFree(ystr); + return; + } + + ret = exsltDateAddDuration(xstr, ystr); + + xmlFree(ystr); + xmlFree(xstr); + + if (ret == NULL) + xmlXPathReturnEmptyString(ctxt); + else + xmlXPathReturnString(ctxt, ret); +} + +/** + * exsltDateDifferenceFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Wraps exsltDateDifference() for use by the XPath processor. + */ +static void +exsltDateDifferenceFunction (xmlXPathParserContextPtr ctxt, int nargs) +{ + xmlChar *ret, *xstr, *ystr; + + if (nargs != 2) { + xmlXPathSetArityError(ctxt); + return; + } + ystr = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + + xstr = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt)) { + xmlFree(ystr); + return; + } + + ret = exsltDateDifference(xstr, ystr); + + xmlFree(ystr); + xmlFree(xstr); + + if (ret == NULL) + xmlXPathReturnEmptyString(ctxt); + else + xmlXPathReturnString(ctxt, ret); +} + +/** + * exsltDateDurationFunction: + * @ctxt: an XPath parser context + * @nargs : the number of arguments + * + * Wraps exsltDateDuration() for use by the XPath engine + */ +static void +exsltDateDurationFunction (xmlXPathParserContextPtr ctxt, int nargs) +{ + xmlChar *ret; + xmlChar *number = NULL; + + if ((nargs < 0) || (nargs > 1)) { + xmlXPathSetArityError(ctxt); + return; + } + + if (nargs == 1) { + number = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt)) { + xmlXPathSetTypeError(ctxt); + return; + } + } + + ret = exsltDateDuration(number); + + if (number != NULL) + xmlFree(number); + + if (ret == NULL) + xmlXPathReturnEmptyString(ctxt); + else + xmlXPathReturnString(ctxt, ret); +} + +/** + * exsltDateRegister: + * + * Registers the EXSLT - Dates and Times module + */ +void +exsltDateRegister (void) +{ + xsltRegisterExtModuleFunction ((const xmlChar *) "add", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateAddFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "add-duration", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateAddDurationFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "date", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateDateFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "date-time", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateDateTimeFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "day-abbreviation", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateDayAbbreviationFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "day-in-month", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateDayInMonthFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "day-in-week", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateDayInWeekFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "day-in-year", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateDayInYearFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "day-name", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateDayNameFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "day-of-week-in-month", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateDayOfWeekInMonthFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "difference", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateDifferenceFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "duration", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateDurationFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "hour-in-day", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateHourInDayFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "leap-year", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateLeapYearFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "minute-in-hour", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateMinuteInHourFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "month-abbreviation", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateMonthAbbreviationFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "month-in-year", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateMonthInYearFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "month-name", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateMonthNameFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "second-in-minute", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateSecondInMinuteFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "seconds", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateSecondsFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "sum", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateSumFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "time", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateTimeFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "week-in-month", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateWeekInMonthFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "week-in-year", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateWeekInYearFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "year", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateYearFunction); +} + +/** + * exsltDateXpathCtxtRegister: + * + * Registers the EXSLT - Dates and Times module for use outside XSLT + */ +int +exsltDateXpathCtxtRegister (xmlXPathContextPtr ctxt, const xmlChar *prefix) +{ + if (ctxt + && prefix + && !xmlXPathRegisterNs(ctxt, + prefix, + (const xmlChar *) EXSLT_DATE_NAMESPACE) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "add", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateAddFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "add-duration", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateAddDurationFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "date", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateDateFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "date-time", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateDateTimeFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "day-abbreviation", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateDayAbbreviationFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "day-in-month", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateDayInMonthFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "day-in-week", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateDayInWeekFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "day-in-year", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateDayInYearFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "day-name", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateDayNameFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "day-of-week-in-month", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateDayOfWeekInMonthFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "difference", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateDifferenceFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "duration", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateDurationFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "hour-in-day", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateHourInDayFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "leap-year", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateLeapYearFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "minute-in-hour", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateMinuteInHourFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "month-abbreviation", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateMonthAbbreviationFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "month-in-year", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateMonthInYearFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "month-name", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateMonthNameFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "second-in-minute", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateSecondInMinuteFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "seconds", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateSecondsFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "sum", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateSumFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "time", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateTimeFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "week-in-month", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateWeekInMonthFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "week-in-year", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateWeekInYearFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "year", + (const xmlChar *) EXSLT_DATE_NAMESPACE, + exsltDateYearFunction)) { + return 0; + } + return -1; +} diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libexslt/dynamic.c chromium-145.0.7632.159/third_party/libxslt/src/libexslt/dynamic.c --- chromium-145.0.7632.116/third_party/libxslt/src/libexslt/dynamic.c 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libexslt/dynamic.c 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,296 @@ +/* + * dynamic.c: Implementation of the EXSLT -- Dynamic module + * + * References: + * http://www.exslt.org/dyn/dyn.html + * + * See Copyright for the status of this software. + * + * Authors: + * Mark Vakoc + * Thomas Broyer + * + * TODO: + * elements: + * functions: + * min + * max + * sum + * map + * closure + */ + +#define IN_LIBEXSLT +#include "libexslt/libexslt.h" + +#include +#include +#include + +#include +#include +#include + +#include "exslt.h" + +/** + * exsltDynEvaluateFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Evaluates the string as an XPath expression and returns the result + * value, which may be a boolean, number, string, node set, result tree + * fragment or external object. + */ + +static void +exsltDynEvaluateFunction(xmlXPathParserContextPtr ctxt, int nargs) { + xmlChar *str = NULL; + xmlXPathObjectPtr ret = NULL; + + if (ctxt == NULL) + return; + if (nargs != 1) { + xsltPrintErrorContext(xsltXPathGetTransformContext(ctxt), NULL, NULL); + xsltGenericError(xsltGenericErrorContext, + "dyn:evalute() : invalid number of args %d\n", nargs); + ctxt->error = XPATH_INVALID_ARITY; + return; + } + str = xmlXPathPopString(ctxt); + /* return an empty node-set if an empty string is passed in */ + if (!str||!xmlStrlen(str)) { + if (str) xmlFree(str); + valuePush(ctxt,xmlXPathNewNodeSet(NULL)); + return; + } +#if LIBXML_VERSION >= 20911 + /* + * Recursive evaluation can grow the call stack quickly. + */ + ctxt->context->depth += 5; +#endif + ret = xmlXPathEval(str,ctxt->context); +#if LIBXML_VERSION >= 20911 + ctxt->context->depth -= 5; +#endif + if (ret) + valuePush(ctxt,ret); + else { + xsltGenericError(xsltGenericErrorContext, + "dyn:evaluate() : unable to evaluate expression '%s'\n",str); + valuePush(ctxt,xmlXPathNewNodeSet(NULL)); + } + xmlFree(str); + return; +} + +/** + * exsltDynMapFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Evaluates the string as an XPath expression and returns the result + * value, which may be a boolean, number, string, node set, result tree + * fragment or external object. + */ + +static void +exsltDynMapFunction(xmlXPathParserContextPtr ctxt, int nargs) +{ + xmlChar *str = NULL; + xmlNodeSetPtr nodeset = NULL; + xsltTransformContextPtr tctxt; + xmlXPathCompExprPtr comp = NULL; + xmlXPathObjectPtr ret = NULL; + xmlDocPtr oldDoc, container = NULL; + xmlNodePtr oldNode; + int oldContextSize; + int oldProximityPosition; + int i, j; + + + if (nargs != 2) { + xmlXPathSetArityError(ctxt); + return; + } + str = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt)) + goto cleanup; + + nodeset = xmlXPathPopNodeSet(ctxt); + if (xmlXPathCheckError(ctxt)) + goto cleanup; + + ret = xmlXPathNewNodeSet(NULL); + if (ret == NULL) { + xsltGenericError(xsltGenericErrorContext, + "exsltDynMapFunction: ret == NULL\n"); + goto cleanup; + } + + tctxt = xsltXPathGetTransformContext(ctxt); + if (tctxt == NULL) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "dyn:map : internal error tctxt == NULL\n"); + goto cleanup; + } + + if (str == NULL || !xmlStrlen(str) || + !(comp = xmlXPathCtxtCompile(tctxt->xpathCtxt, str))) + goto cleanup; + + oldDoc = ctxt->context->doc; + oldNode = ctxt->context->node; + oldContextSize = ctxt->context->contextSize; + oldProximityPosition = ctxt->context->proximityPosition; + + /** + * since we really don't know we're going to be adding node(s) + * down the road we create the RVT regardless + */ + container = xsltCreateRVT(tctxt); + if (container == NULL) { + xsltTransformError(tctxt, NULL, NULL, + "dyn:map : internal error container == NULL\n"); + goto cleanup; + } + xsltRegisterLocalRVT(tctxt, container); + if (nodeset && nodeset->nodeNr > 0) { + xmlXPathNodeSetSort(nodeset); + ctxt->context->contextSize = nodeset->nodeNr; + ctxt->context->proximityPosition = 0; + for (i = 0; i < nodeset->nodeNr; i++) { + xmlXPathObjectPtr subResult = NULL; + xmlNodePtr cur = nodeset->nodeTab[i]; + + ctxt->context->proximityPosition++; + ctxt->context->node = cur; + + if (cur->type == XML_NAMESPACE_DECL) { + /* + * The XPath module sets the owner element of a ns-node on + * the ns->next field. + */ + cur = (xmlNodePtr) ((xmlNsPtr) cur)->next; + if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE)) { + xsltGenericError(xsltGenericErrorContext, + "Internal error in exsltDynMapFunction: " + "Cannot retrieve the doc of a namespace node.\n"); + continue; + } + ctxt->context->doc = cur->doc; + } else { + ctxt->context->doc = cur->doc; + } + + subResult = xmlXPathCompiledEval(comp, ctxt->context); + if (subResult != NULL) { + switch (subResult->type) { + case XPATH_NODESET: + if (subResult->nodesetval != NULL) + for (j = 0; j < subResult->nodesetval->nodeNr; + j++) + xmlXPathNodeSetAdd(ret->nodesetval, + subResult->nodesetval-> + nodeTab[j]); + break; + case XPATH_BOOLEAN: + if (container != NULL) { + xmlNodePtr newChildNode = + xmlNewTextChild((xmlNodePtr) container, NULL, + BAD_CAST "boolean", + BAD_CAST (subResult-> + boolval ? "true" : "")); + if (newChildNode != NULL) { + newChildNode->ns = + xmlNewNs(newChildNode, + BAD_CAST + "http://exslt.org/common", + BAD_CAST "exsl"); + xmlXPathNodeSetAddUnique(ret->nodesetval, + newChildNode); + } + } + break; + case XPATH_NUMBER: + if (container != NULL) { + xmlChar *val = + xmlXPathCastNumberToString(subResult-> + floatval); + xmlNodePtr newChildNode = + xmlNewTextChild((xmlNodePtr) container, NULL, + BAD_CAST "number", val); + if (val != NULL) + xmlFree(val); + + if (newChildNode != NULL) { + newChildNode->ns = + xmlNewNs(newChildNode, + BAD_CAST + "http://exslt.org/common", + BAD_CAST "exsl"); + xmlXPathNodeSetAddUnique(ret->nodesetval, + newChildNode); + } + } + break; + case XPATH_STRING: + if (container != NULL) { + xmlNodePtr newChildNode = + xmlNewTextChild((xmlNodePtr) container, NULL, + BAD_CAST "string", + subResult->stringval); + if (newChildNode != NULL) { + newChildNode->ns = + xmlNewNs(newChildNode, + BAD_CAST + "http://exslt.org/common", + BAD_CAST "exsl"); + xmlXPathNodeSetAddUnique(ret->nodesetval, + newChildNode); + } + } + break; + default: + break; + } + xmlXPathFreeObject(subResult); + } + } + } + ctxt->context->doc = oldDoc; + ctxt->context->node = oldNode; + ctxt->context->contextSize = oldContextSize; + ctxt->context->proximityPosition = oldProximityPosition; + + + cleanup: + /* restore the xpath context */ + if (comp != NULL) + xmlXPathFreeCompExpr(comp); + if (nodeset != NULL) + xmlXPathFreeNodeSet(nodeset); + if (str != NULL) + xmlFree(str); + valuePush(ctxt, ret); + return; +} + + +/** + * exsltDynRegister: + * + * Registers the EXSLT - Dynamic module + */ + +void +exsltDynRegister (void) { + xsltRegisterExtModuleFunction ((const xmlChar *) "evaluate", + EXSLT_DYNAMIC_NAMESPACE, + exsltDynEvaluateFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "map", + EXSLT_DYNAMIC_NAMESPACE, + exsltDynMapFunction); + +} diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libexslt/exslt.c chromium-145.0.7632.159/third_party/libxslt/src/libexslt/exslt.c --- chromium-145.0.7632.116/third_party/libxslt/src/libexslt/exslt.c 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libexslt/exslt.c 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,35 @@ +#define IN_LIBEXSLT +#include "libexslt/libexslt.h" + +#include + +#include +#include "exslt.h" + +const char *exsltLibraryVersion = LIBEXSLT_VERSION_STRING + LIBEXSLT_VERSION_EXTRA; +const int exsltLibexsltVersion = LIBEXSLT_VERSION; +const int exsltLibxsltVersion = LIBXSLT_VERSION; +const int exsltLibxmlVersion = LIBXML_VERSION; + +/** + * exsltRegisterAll: + * + * Registers all available EXSLT extensions + */ +void +exsltRegisterAll (void) { + xsltInitGlobals(); + exsltCommonRegister(); +#ifdef EXSLT_CRYPTO_ENABLED + exsltCryptoRegister(); +#endif + exsltMathRegister(); + exsltSetsRegister(); + exsltFuncRegister(); + exsltStrRegister(); + exsltDateRegister(); + exsltSaxonRegister(); + exsltDynRegister(); +} + diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libexslt/exslt.h chromium-145.0.7632.159/third_party/libxslt/src/libexslt/exslt.h --- chromium-145.0.7632.116/third_party/libxslt/src/libexslt/exslt.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libexslt/exslt.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,108 @@ +/* + * Summary: main header file + * + * Copy: See Copyright for the status of this software. + */ + + +#ifndef __EXSLT_H__ +#define __EXSLT_H__ + +#include +#include +#include "exsltexports.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +EXSLTPUBVAR const char *exsltLibraryVersion; +EXSLTPUBVAR const int exsltLibexsltVersion; +EXSLTPUBVAR const int exsltLibxsltVersion; +EXSLTPUBVAR const int exsltLibxmlVersion; + +/** + * EXSLT_COMMON_NAMESPACE: + * + * Namespace for EXSLT common functions + */ +#define EXSLT_COMMON_NAMESPACE ((const xmlChar *) "http://exslt.org/common") +/** + * EXSLT_CRYPTO_NAMESPACE: + * + * Namespace for EXSLT crypto functions + */ +#define EXSLT_CRYPTO_NAMESPACE ((const xmlChar *) "http://exslt.org/crypto") +/** + * EXSLT_MATH_NAMESPACE: + * + * Namespace for EXSLT math functions + */ +#define EXSLT_MATH_NAMESPACE ((const xmlChar *) "http://exslt.org/math") +/** + * EXSLT_SETS_NAMESPACE: + * + * Namespace for EXSLT set functions + */ +#define EXSLT_SETS_NAMESPACE ((const xmlChar *) "http://exslt.org/sets") +/** + * EXSLT_FUNCTIONS_NAMESPACE: + * + * Namespace for EXSLT functions extension functions + */ +#define EXSLT_FUNCTIONS_NAMESPACE ((const xmlChar *) "http://exslt.org/functions") +/** + * EXSLT_STRINGS_NAMESPACE: + * + * Namespace for EXSLT strings functions + */ +#define EXSLT_STRINGS_NAMESPACE ((const xmlChar *) "http://exslt.org/strings") +/** + * EXSLT_DATE_NAMESPACE: + * + * Namespace for EXSLT date functions + */ +#define EXSLT_DATE_NAMESPACE ((const xmlChar *) "http://exslt.org/dates-and-times") +/** + * EXSLT_DYNAMIC_NAMESPACE: + * + * Namespace for EXSLT dynamic functions + */ +#define EXSLT_DYNAMIC_NAMESPACE ((const xmlChar *) "http://exslt.org/dynamic") + +/** + * SAXON_NAMESPACE: + * + * Namespace for SAXON extensions functions + */ +#define SAXON_NAMESPACE ((const xmlChar *) "http://icl.com/saxon") + +EXSLTPUBFUN void EXSLTCALL exsltCommonRegister (void); +#ifdef EXSLT_CRYPTO_ENABLED +EXSLTPUBFUN void EXSLTCALL exsltCryptoRegister (void); +#endif +EXSLTPUBFUN void EXSLTCALL exsltMathRegister (void); +EXSLTPUBFUN void EXSLTCALL exsltSetsRegister (void); +EXSLTPUBFUN void EXSLTCALL exsltFuncRegister (void); +EXSLTPUBFUN void EXSLTCALL exsltStrRegister (void); +EXSLTPUBFUN void EXSLTCALL exsltDateRegister (void); +EXSLTPUBFUN void EXSLTCALL exsltSaxonRegister (void); +EXSLTPUBFUN void EXSLTCALL exsltDynRegister(void); + +EXSLTPUBFUN void EXSLTCALL exsltRegisterAll (void); + +EXSLTPUBFUN int EXSLTCALL exsltDateXpathCtxtRegister (xmlXPathContextPtr ctxt, + const xmlChar *prefix); +EXSLTPUBFUN int EXSLTCALL exsltMathXpathCtxtRegister (xmlXPathContextPtr ctxt, + const xmlChar *prefix); +EXSLTPUBFUN int EXSLTCALL exsltSetsXpathCtxtRegister (xmlXPathContextPtr ctxt, + const xmlChar *prefix); +EXSLTPUBFUN int EXSLTCALL exsltStrXpathCtxtRegister (xmlXPathContextPtr ctxt, + const xmlChar *prefix); + +#ifdef __cplusplus +} +#endif +#endif /* __EXSLT_H__ */ + diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libexslt/exsltconfig.h.in chromium-145.0.7632.159/third_party/libxslt/src/libexslt/exsltconfig.h.in --- chromium-145.0.7632.116/third_party/libxslt/src/libexslt/exsltconfig.h.in 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libexslt/exsltconfig.h.in 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,70 @@ +/* + * exsltconfig.h: compile-time version information for the EXSLT library + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#ifndef __XML_EXSLTCONFIG_H__ +#define __XML_EXSLTCONFIG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * LIBEXSLT_DOTTED_VERSION: + * + * the version string like "1.2.3" + */ +#define LIBEXSLT_DOTTED_VERSION "@LIBEXSLT_VERSION@" + +/** + * LIBEXSLT_VERSION: + * + * the version number: 1.2.3 value is 10203 + */ +#define LIBEXSLT_VERSION @LIBEXSLT_VERSION_NUMBER@ + +/** + * LIBEXSLT_VERSION_STRING: + * + * the version number string, 1.2.3 value is "10203" + */ +#define LIBEXSLT_VERSION_STRING "@LIBEXSLT_VERSION_NUMBER@" + +/** + * LIBEXSLT_VERSION_EXTRA: + * + * extra version information, used to show a Git commit description + */ +#define LIBEXSLT_VERSION_EXTRA "@LIBEXSLT_VERSION_EXTRA@" + +/** + * WITH_CRYPTO: + * + * Whether crypto support is configured into exslt + */ +#if @WITH_CRYPTO@ +#define EXSLT_CRYPTO_ENABLED +#endif + +/** + * ATTRIBUTE_UNUSED: + * + * This macro is used to flag unused function parameters to GCC + */ +#ifdef __GNUC__ +#ifndef ATTRIBUTE_UNUSED +#define ATTRIBUTE_UNUSED __attribute__((unused)) +#endif +#else +#define ATTRIBUTE_UNUSED +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_EXSLTCONFIG_H__ */ diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libexslt/exsltexports.h chromium-145.0.7632.159/third_party/libxslt/src/libexslt/exsltexports.h --- chromium-145.0.7632.116/third_party/libxslt/src/libexslt/exsltexports.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libexslt/exsltexports.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,63 @@ +/* + * Summary: macros for marking symbols as exportable/importable. + * + * Copy: See Copyright for the status of this software. + */ + +#ifndef __EXSLT_EXPORTS_H__ +#define __EXSLT_EXPORTS_H__ + +#if defined(_WIN32) || defined(__CYGWIN__) +/** DOC_DISABLE */ + +#ifdef LIBEXSLT_STATIC + #define EXSLTPUBLIC +#elif defined(IN_LIBEXSLT) + #define EXSLTPUBLIC __declspec(dllexport) +#else + #define EXSLTPUBLIC __declspec(dllimport) +#endif + +#define EXSLTCALL __cdecl + +/** DOC_ENABLE */ +#else /* not Windows */ + +/** + * EXSLTPUBLIC: + * + * Macro which declares a public symbol + */ +#define EXSLTPUBLIC + +/** + * EXSLTCALL: + * + * Macro which declares the calling convention for exported functions + */ +#define EXSLTCALL + +#endif /* platform switch */ + +/* + * EXSLTPUBFUN: + * + * Macro which declares an exportable function + */ +#define EXSLTPUBFUN EXSLTPUBLIC + +/** + * EXSLTPUBVAR: + * + * Macro which declares an exportable variable + */ +#define EXSLTPUBVAR EXSLTPUBLIC extern + +/* Compatibility */ +#if !defined(LIBEXSLT_PUBLIC) +#define LIBEXSLT_PUBLIC EXSLTPUBVAR +#endif + +#endif /* __EXSLT_EXPORTS_H__ */ + + diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libexslt/functions.c chromium-145.0.7632.159/third_party/libxslt/src/libexslt/functions.c --- chromium-145.0.7632.116/third_party/libxslt/src/libexslt/functions.c 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libexslt/functions.c 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,837 @@ +#define IN_LIBEXSLT +#include "libexslt/libexslt.h" + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "exslt.h" + +typedef struct _exsltFuncFunctionData exsltFuncFunctionData; +struct _exsltFuncFunctionData { + int nargs; /* number of arguments to the function */ + xmlNodePtr content; /* the func:fuction template content */ +}; + +typedef struct _exsltFuncData exsltFuncData; +struct _exsltFuncData { + xmlHashTablePtr funcs; /* pointer to the stylesheet module data */ + xmlXPathObjectPtr result; /* returned by func:result */ + xsltStackElemPtr ctxtVar; /* context variable */ + int error; /* did an error occur? */ +}; + +typedef struct _exsltFuncResultPreComp exsltFuncResultPreComp; +struct _exsltFuncResultPreComp { + xsltElemPreComp comp; + xmlXPathCompExprPtr select; + xmlNsPtr *nsList; + int nsNr; +}; + +/* Used for callback function in exsltInitFunc */ +typedef struct _exsltFuncImportRegData exsltFuncImportRegData; +struct _exsltFuncImportRegData { + xsltTransformContextPtr ctxt; + xmlHashTablePtr hash; +}; + +static void exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, + int nargs); +static exsltFuncFunctionData *exsltFuncNewFunctionData(void); + +/*static const xmlChar *exsltResultDataID = (const xmlChar *) "EXSLT Result";*/ + +/** + * exsltFuncRegisterFunc: + * @func: the #exsltFuncFunctionData for the function + * @ctxt: an XSLT transformation context + * @URI: the function namespace URI + * @name: the function name + * + * Registers a function declared by a func:function element + */ +static void +exsltFuncRegisterFunc (void *payload, void *vctxt, + const xmlChar *URI, const xmlChar *name, + ATTRIBUTE_UNUSED const xmlChar *ignored) { + exsltFuncFunctionData *data = (exsltFuncFunctionData *) payload; + xsltTransformContextPtr ctxt = (xsltTransformContextPtr) vctxt; + + if ((data == NULL) || (ctxt == NULL) || (URI == NULL) || (name == NULL)) + return; + + xsltGenericDebug(xsltGenericDebugContext, + "exsltFuncRegisterFunc: register {%s}%s\n", + URI, name); + xsltRegisterExtFunction(ctxt, name, URI, + exsltFuncFunctionFunction); +} + +/* + * exsltFuncRegisterImportFunc + * @data: the exsltFuncFunctionData for the function + * @ch: structure containing context and hash table + * @URI: the function namespace URI + * @name: the function name + * + * Checks if imported function is already registered in top-level + * stylesheet. If not, copies function data and registers function + */ +static void +exsltFuncRegisterImportFunc (void *payload, void *vctxt, + const xmlChar *URI, const xmlChar *name, + ATTRIBUTE_UNUSED const xmlChar *ignored) { + exsltFuncFunctionData *data = (exsltFuncFunctionData *) payload; + exsltFuncImportRegData *ch = (exsltFuncImportRegData *) vctxt; + exsltFuncFunctionData *func=NULL; + + if ((data == NULL) || (ch == NULL) || (URI == NULL) || (name == NULL)) + return; + + if (ch->ctxt == NULL || ch->hash == NULL) + return; + + /* Check if already present */ + func = (exsltFuncFunctionData*)xmlHashLookup2(ch->hash, URI, name); + if (func == NULL) { /* Not yet present - copy it in */ + func = exsltFuncNewFunctionData(); + if (func == NULL) + return; + memcpy(func, data, sizeof(exsltFuncFunctionData)); + if (xmlHashAddEntry2(ch->hash, URI, name, func) < 0) { + xsltGenericError(xsltGenericErrorContext, + "Failed to register function {%s}%s\n", + URI, name); + xmlFree(func); + } else { /* Do the registration */ + xsltGenericDebug(xsltGenericDebugContext, + "exsltFuncRegisterImportFunc: register {%s}%s\n", + URI, name); + xsltRegisterExtFunction(ch->ctxt, name, URI, + exsltFuncFunctionFunction); + } + } +} + +/** + * exsltFuncInit: + * @ctxt: an XSLT transformation context + * @URI: the namespace URI for the extension + * + * Initializes the EXSLT - Functions module. + * Called at transformation-time; merges all + * functions declared in the import tree taking + * import precedence into account, i.e. overriding + * functions with lower import precedence. + * + * Returns the data for this transformation + */ +static void * +exsltFuncInit (xsltTransformContextPtr ctxt, const xmlChar *URI) { + exsltFuncData *ret; + xsltStylesheetPtr tmp; + exsltFuncImportRegData ch; + xmlHashTablePtr hash; + + ret = (exsltFuncData *) xmlMalloc (sizeof(exsltFuncData)); + if (ret == NULL) { + xsltGenericError(xsltGenericErrorContext, + "exsltFuncInit: not enough memory\n"); + return(NULL); + } + memset(ret, 0, sizeof(exsltFuncData)); + + ret->result = NULL; + ret->error = 0; + + ch.hash = (xmlHashTablePtr) xsltStyleGetExtData(ctxt->style, URI); + ret->funcs = ch.hash; + xmlHashScanFull(ch.hash, exsltFuncRegisterFunc, ctxt); + tmp = ctxt->style; + ch.ctxt = ctxt; + while ((tmp=xsltNextImport(tmp))!=NULL) { + hash = xsltGetExtInfo(tmp, URI); + if (hash != NULL) { + xmlHashScanFull(hash, exsltFuncRegisterImportFunc, &ch); + } + } + + return(ret); +} + +/** + * exsltFuncShutdown: + * @ctxt: an XSLT transformation context + * @URI: the namespace URI for the extension + * @data: the module data to free up + * + * Shutdown the EXSLT - Functions module + * Called at transformation-time. + */ +static void +exsltFuncShutdown (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, + const xmlChar *URI ATTRIBUTE_UNUSED, + void *vdata) { + exsltFuncData *data = (exsltFuncData *) vdata; + + if (data != NULL) { + if (data->result != NULL) + xmlXPathFreeObject(data->result); + xmlFree(data); + } +} + +/** + * exsltFuncStyleInit: + * @style: an XSLT stylesheet + * @URI: the namespace URI for the extension + * + * Allocates the stylesheet data for EXSLT - Function + * Called at compile-time. + * + * Returns the allocated data + */ +static void * +exsltFuncStyleInit (xsltStylesheetPtr style ATTRIBUTE_UNUSED, + const xmlChar *URI ATTRIBUTE_UNUSED) { + return xmlHashCreate(1); +} + +static void +exsltFuncFreeDataEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { + xmlFree(payload); +} + +/** + * exsltFuncStyleShutdown: + * @style: an XSLT stylesheet + * @URI: the namespace URI for the extension + * @data: the stylesheet data to free up + * + * Shutdown the EXSLT - Function module + * Called at compile-time. + */ +static void +exsltFuncStyleShutdown (xsltStylesheetPtr style ATTRIBUTE_UNUSED, + const xmlChar *URI ATTRIBUTE_UNUSED, + void *vdata) { + xmlHashTablePtr data = (xmlHashTablePtr) vdata; + xmlHashFree(data, exsltFuncFreeDataEntry); +} + +/** + * exsltFuncNewFunctionData: + * + * Allocates an #exslFuncFunctionData object + * + * Returns the new structure + */ +static exsltFuncFunctionData * +exsltFuncNewFunctionData (void) { + exsltFuncFunctionData *ret; + + ret = (exsltFuncFunctionData *) xmlMalloc (sizeof(exsltFuncFunctionData)); + if (ret == NULL) { + xsltGenericError(xsltGenericErrorContext, + "exsltFuncNewFunctionData: not enough memory\n"); + return (NULL); + } + memset(ret, 0, sizeof(exsltFuncFunctionData)); + + ret->nargs = 0; + ret->content = NULL; + + return(ret); +} + +/** + * exsltFreeFuncResultPreComp: + * @comp: the #exsltFuncResultPreComp to free up + * + * Deallocates an #exsltFuncResultPreComp + */ +static void +exsltFreeFuncResultPreComp (xsltElemPreCompPtr ecomp) { + exsltFuncResultPreComp *comp = (exsltFuncResultPreComp *) ecomp; + + if (comp == NULL) + return; + + if (comp->select != NULL) + xmlXPathFreeCompExpr (comp->select); + if (comp->nsList != NULL) + xmlFree(comp->nsList); + xmlFree(comp); +} + +/** + * exsltFuncFunctionFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Evaluates the func:function element that defines the called function. + */ +static void +exsltFuncFunctionFunction (xmlXPathParserContextPtr ctxt, int nargs) { + xmlXPathObjectPtr oldResult, ret; + exsltFuncData *data; + exsltFuncFunctionData *func; + xmlNodePtr paramNode, oldInsert, oldXPNode, fake; + int oldBase, newBase; + void *oldCtxtVar; + xsltStackElemPtr params = NULL, param; + xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt); + int i; + xmlXPathObjectPtr *args = NULL; + + /* + * retrieve func:function template + */ + data = (exsltFuncData *) xsltGetExtData (tctxt, + EXSLT_FUNCTIONS_NAMESPACE); + oldResult = data->result; + data->result = NULL; + + func = (exsltFuncFunctionData*) xmlHashLookup2 (data->funcs, + ctxt->context->functionURI, + ctxt->context->function); + if (func == NULL) { + /* Should never happen */ + xsltGenericError(xsltGenericErrorContext, + "{%s}%s: not found\n", + ctxt->context->functionURI, ctxt->context->function); + ctxt->error = XPATH_UNKNOWN_FUNC_ERROR; + return; + } + + /* + * params handling + */ + if (nargs > func->nargs) { + xsltGenericError(xsltGenericErrorContext, + "{%s}%s: called with too many arguments\n", + ctxt->context->functionURI, ctxt->context->function); + ctxt->error = XPATH_INVALID_ARITY; + return; + } + if (func->content != NULL) { + paramNode = func->content->prev; + } + else + paramNode = NULL; + if ((paramNode == NULL) && (func->nargs != 0)) { + xsltGenericError(xsltGenericErrorContext, + "exsltFuncFunctionFunction: nargs != 0 and " + "param == NULL\n"); + return; + } + + /* + * When a function is called recursively during evaluation of its + * arguments, the recursion check in xsltApplySequenceConstructor + * isn't reached. + */ + if (tctxt->depth >= tctxt->maxTemplateDepth) { + xsltTransformError(tctxt, NULL, NULL, + "exsltFuncFunctionFunction: Potentially infinite recursion " + "detected in function {%s}%s.\n", + ctxt->context->functionURI, ctxt->context->function); + tctxt->state = XSLT_STATE_STOPPED; + return; + } + tctxt->depth++; + + /* Evaluating templates can change the XPath context node. */ + oldXPNode = tctxt->xpathCtxt->node; + + fake = xmlNewDocNode(tctxt->output, NULL, + (const xmlChar *)"fake", NULL); + if (fake == NULL) + goto error; + /* + * We have a problem with the evaluation of function parameters. + * The original library code did not evaluate XPath expressions until + * the last moment. After version 1.1.17 of the libxslt, the logic + * of other parts of the library was changed, and the evaluation of + * XPath expressions within parameters now takes place as soon as the + * parameter is parsed/evaluated (xsltParseStylesheetCallerParam). + * This means that the parameters need to be evaluated in lexical + * order (since a variable is "in scope" as soon as it is declared). + * However, on entry to this routine, the values (from the caller) are + * in reverse order (held on the XPath context variable stack). To + * accomplish what is required, I have added code to pop the XPath + * objects off of the stack at the beginning and save them, then use + * them (in the reverse order) as the params are evaluated. This + * requires an xmlMalloc/xmlFree for each param set by the caller, + * which is not very nice. There is probably a much better solution + * (like change other code to delay the evaluation). + */ + /* + * In order to give the function params and variables a new 'scope' + * we change varsBase in the context. + */ + newBase = tctxt->varsNr; + /* If there are any parameters */ + if (paramNode != NULL) { + if (nargs > 0) { + args = (xmlXPathObjectPtr *) xmlMalloc(sizeof(*args) * nargs); + if (args == NULL) + goto error; + /* Fetch the stored argument values from the caller */ + for (i = nargs - 1; i >= 0; i--) { + args[i] = valuePop(ctxt); + } + } + + /* + * Prepare to process params in reverse order. First, go to + * the beginning of the param chain. + */ + for (i = 1; i <= func->nargs; i++) { + if (paramNode->prev == NULL) + break; + paramNode = paramNode->prev; + } + /* + * i has total # params found, nargs is number which are present + * as arguments from the caller + * Calculate the number of un-set parameters + */ + for (i = 0; i < func->nargs; i++) { + param = xsltParseStylesheetCallerParam (tctxt, paramNode); + if (param == NULL) { + xsltLocalVariablePop(tctxt, newBase, -2); + xsltFreeStackElemList(params); + for (; i < nargs; i++) + xmlXPathFreeObject(args[i]); + goto error; + } + if (i < nargs) { /* if parameter value set */ + param->computed = 1; + if (param->value != NULL) + xmlXPathFreeObject(param->value); + param->value = args[i]; + } + xsltLocalVariablePush(tctxt, param, -1); + param->next = params; + params = param; + paramNode = paramNode->next; + } + } + /* + * Actual processing. The context variable is cleared and restored + * when func:result is evaluated. + */ + oldBase = tctxt->varsBase; + oldInsert = tctxt->insert; + oldCtxtVar = data->ctxtVar; + data->ctxtVar = tctxt->contextVariable; + tctxt->varsBase = newBase; + tctxt->insert = fake; + tctxt->contextVariable = NULL; + xsltApplyOneTemplate (tctxt, tctxt->node, + func->content, NULL, NULL); + xsltLocalVariablePop(tctxt, tctxt->varsBase, -2); + tctxt->insert = oldInsert; + tctxt->contextVariable = data->ctxtVar; + tctxt->varsBase = oldBase; /* restore original scope */ + data->ctxtVar = oldCtxtVar; + if (params != NULL) + xsltFreeStackElemList(params); + tctxt->xpathCtxt->node = oldXPNode; + + if (data->error != 0) + goto error; + + if (data->result != NULL) { + ret = data->result; + /* + * IMPORTANT: This enables previously tree fragments marked as + * being results of a function, to be garbage-collected after + * the calling process exits. + */ + xsltFlagRVTs(tctxt, ret, XSLT_RVT_LOCAL); + } else + ret = xmlXPathNewCString(""); + + data->result = oldResult; + + /* + * It is an error if the instantiation of the template results in + * the generation of result nodes. + */ + if (fake->children != NULL) { + xsltGenericError(xsltGenericErrorContext, + "{%s}%s: cannot write to result tree while " + "executing a function\n", + ctxt->context->functionURI, ctxt->context->function); + xmlXPathFreeObject(ret); + goto error; + } + valuePush(ctxt, ret); + +error: + xmlFree(args); + xmlFreeNode(fake); + tctxt->depth--; +} + + +static void +exsltFuncFunctionComp (xsltStylesheetPtr style, xmlNodePtr inst) { + xmlChar *name, *prefix; + xmlNsPtr ns; + xmlHashTablePtr data; + exsltFuncFunctionData *func; + + if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) + return; + + { + xmlChar *qname; + + qname = xmlGetProp(inst, (const xmlChar *) "name"); + name = xmlSplitQName2 (qname, &prefix); + xmlFree(qname); + } + if ((name == NULL) || (prefix == NULL)) { + xsltGenericError(xsltGenericErrorContext, + "func:function: not a QName\n"); + if (name != NULL) + xmlFree(name); + return; + } + /* namespace lookup */ + ns = xmlSearchNs (inst->doc, inst, prefix); + if (ns == NULL) { + xsltGenericError(xsltGenericErrorContext, + "func:function: undeclared prefix %s\n", + prefix); + xmlFree(name); + xmlFree(prefix); + return; + } + xmlFree(prefix); + + xsltParseTemplateContent(style, inst); + + /* + * Create function data + */ + func = exsltFuncNewFunctionData(); + if (func == NULL) { + xmlFree(name); + return; + } + func->content = inst->children; + while (IS_XSLT_ELEM(func->content) && + IS_XSLT_NAME(func->content, "param")) { + func->content = func->content->next; + func->nargs++; + } + + /* + * Register the function data such that it can be retrieved + * by exslFuncFunctionFunction + */ +#ifdef XSLT_REFACTORED + /* + * Ensure that the hash table will be stored in the *current* + * stylesheet level in order to correctly evaluate the + * import precedence. + */ + data = (xmlHashTablePtr) + xsltStyleStylesheetLevelGetExtData(style, + EXSLT_FUNCTIONS_NAMESPACE); +#else + data = (xmlHashTablePtr) + xsltStyleGetExtData (style, EXSLT_FUNCTIONS_NAMESPACE); +#endif + if (data == NULL) { + xsltGenericError(xsltGenericErrorContext, + "exsltFuncFunctionComp: no stylesheet data\n"); + xmlFree(name); + xmlFree(func); + return; + } + + if (xmlHashAddEntry2 (data, ns->href, name, func) < 0) { + xsltTransformError(NULL, style, inst, + "Failed to register function {%s}%s\n", + ns->href, name); + style->errors++; + xmlFree(func); + } else { + xsltGenericDebug(xsltGenericDebugContext, + "exsltFuncFunctionComp: register {%s}%s\n", + ns->href, name); + } + xmlFree(name); +} + +static xsltElemPreCompPtr +exsltFuncResultComp (xsltStylesheetPtr style, xmlNodePtr inst, + xsltTransformFunction function) { + xmlNodePtr test; + xmlChar *sel; + exsltFuncResultPreComp *ret; + + if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) + return (NULL); + + /* + * "Validity" checking + */ + /* it is an error to have any following sibling elements aside + * from the xsl:fallback element. + */ + for (test = inst->next; test != NULL; test = test->next) { + if (test->type != XML_ELEMENT_NODE) + continue; + if (IS_XSLT_ELEM(test) && IS_XSLT_NAME(test, "fallback")) + continue; + xsltGenericError(xsltGenericErrorContext, + "exsltFuncResultElem: only xsl:fallback is " + "allowed to follow func:result\n"); + style->errors++; + return (NULL); + } + /* it is an error for a func:result element to not be a descendant + * of func:function. + * it is an error if a func:result occurs within a func:result + * element. + * it is an error if instanciating the content of a variable + * binding element (i.e. xsl:variable, xsl:param) results in the + * instanciation of a func:result element. + */ + for (test = inst->parent; test != NULL; test = test->parent) { + if (/* Traversal has reached the top-level document without + * finding a func:function ancestor. */ + (test != NULL && test->type == XML_DOCUMENT_NODE) || + /* Traversal reached a stylesheet-namespace node, + * and has left the function namespace. */ + (IS_XSLT_ELEM(test) && + IS_XSLT_NAME(test, "stylesheet"))) { + xsltGenericError(xsltGenericErrorContext, + "func:result element not a descendant " + "of a func:function\n"); + style->errors++; + return (NULL); + } + if ((test->ns != NULL) && + (xmlStrEqual(test->ns->href, EXSLT_FUNCTIONS_NAMESPACE))) { + if (xmlStrEqual(test->name, (const xmlChar *) "function")) { + break; + } + if (xmlStrEqual(test->name, (const xmlChar *) "result")) { + xsltGenericError(xsltGenericErrorContext, + "func:result element not allowed within" + " another func:result element\n"); + style->errors++; + return (NULL); + } + } + if (IS_XSLT_ELEM(test) && + (IS_XSLT_NAME(test, "variable") || + IS_XSLT_NAME(test, "param"))) { + xsltGenericError(xsltGenericErrorContext, + "func:result element not allowed within" + " a variable binding element\n"); + style->errors++; + return (NULL); + } + } + + /* + * Precomputation + */ + ret = (exsltFuncResultPreComp *) + xmlMalloc (sizeof(exsltFuncResultPreComp)); + if (ret == NULL) { + xsltPrintErrorContext(NULL, NULL, NULL); + xsltGenericError(xsltGenericErrorContext, + "exsltFuncResultComp : malloc failed\n"); + style->errors++; + return (NULL); + } + memset(ret, 0, sizeof(exsltFuncResultPreComp)); + + xsltInitElemPreComp ((xsltElemPreCompPtr) ret, style, inst, function, + exsltFreeFuncResultPreComp); + ret->select = NULL; + + /* + * Precompute the select attribute + */ + sel = xmlGetNsProp(inst, (const xmlChar *) "select", NULL); + if (sel != NULL) { + ret->select = xsltXPathCompileFlags(style, sel, 0); + xmlFree(sel); + } + /* + * Precompute the namespace list + */ + ret->nsList = xmlGetNsList(inst->doc, inst); + if (ret->nsList != NULL) { + int i = 0; + while (ret->nsList[i] != NULL) + i++; + ret->nsNr = i; + } + return ((xsltElemPreCompPtr) ret); +} + +static void +exsltFuncResultElem (xsltTransformContextPtr ctxt, + xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst, + xsltElemPreCompPtr ecomp) { + exsltFuncResultPreComp *comp = (exsltFuncResultPreComp *) ecomp; + exsltFuncData *data; + xmlXPathObjectPtr ret; + + + /* It is an error if instantiating the content of the + * func:function element results in the instantiation of more than + * one func:result elements. + */ + data = (exsltFuncData *) xsltGetExtData (ctxt, EXSLT_FUNCTIONS_NAMESPACE); + if (data == NULL) { + xsltGenericError(xsltGenericErrorContext, + "exsltFuncReturnElem: data == NULL\n"); + return; + } + if (data->result != NULL) { + xsltGenericError(xsltGenericErrorContext, + "func:result already instanciated\n"); + data->error = 1; + return; + } + /* + * Restore context variable, so that it will receive the function + * result RVTs. + */ + ctxt->contextVariable = data->ctxtVar; + /* + * Processing + */ + if (comp->select != NULL) { + xmlNsPtr *oldXPNsList; + int oldXPNsNr; + xmlNodePtr oldXPContextNode; + /* If the func:result element has a select attribute, then the + * value of the attribute must be an expression and the + * returned value is the object that results from evaluating + * the expression. In this case, the content must be empty. + */ + if (inst->children != NULL) { + xsltGenericError(xsltGenericErrorContext, + "func:result content must be empty if" + " the function has a select attribute\n"); + data->error = 1; + return; + } + oldXPNsList = ctxt->xpathCtxt->namespaces; + oldXPNsNr = ctxt->xpathCtxt->nsNr; + oldXPContextNode = ctxt->xpathCtxt->node; + + ctxt->xpathCtxt->namespaces = comp->nsList; + ctxt->xpathCtxt->nsNr = comp->nsNr; + ctxt->xpathCtxt->node = ctxt->node; + + ret = xmlXPathCompiledEval(comp->select, ctxt->xpathCtxt); + + ctxt->xpathCtxt->node = oldXPContextNode; + ctxt->xpathCtxt->nsNr = oldXPNsNr; + ctxt->xpathCtxt->namespaces = oldXPNsList; + + if (ret == NULL) { + xsltGenericError(xsltGenericErrorContext, + "exsltFuncResultElem: ret == NULL\n"); + return; + } + /* + * Mark it as a function result in order to avoid garbage + * collecting of tree fragments before the function exits. + */ + xsltFlagRVTs(ctxt, ret, XSLT_RVT_FUNC_RESULT); + } else if (inst->children != NULL) { + /* If the func:result element does not have a select attribute + * and has non-empty content (i.e. the func:result element has + * one or more child nodes), then the content of the + * func:result element specifies the value. + */ + xmlNodePtr oldInsert; + xmlDocPtr container; + + container = xsltCreateRVT(ctxt); + if (container == NULL) { + xsltGenericError(xsltGenericErrorContext, + "exsltFuncResultElem: out of memory\n"); + data->error = 1; + return; + } + /* Mark as function result. */ + xsltRegisterLocalRVT(ctxt, container); + container->compression = XSLT_RVT_FUNC_RESULT; + + oldInsert = ctxt->insert; + ctxt->insert = (xmlNodePtr) container; + xsltApplyOneTemplate (ctxt, ctxt->node, + inst->children, NULL, NULL); + ctxt->insert = oldInsert; + + ret = xmlXPathNewValueTree((xmlNodePtr) container); + if (ret == NULL) { + xsltGenericError(xsltGenericErrorContext, + "exsltFuncResultElem: ret == NULL\n"); + data->error = 1; + } else { + /* + * This stops older libxml2 versions from freeing the nodes + * in the tree. + */ + ret->boolval = 0; + } + } else { + /* If the func:result element has empty content and does not + * have a select attribute, then the returned value is an + * empty string. + */ + ret = xmlXPathNewCString(""); + } + data->result = ret; +} + +/** + * exsltFuncRegister: + * + * Registers the EXSLT - Functions module + */ +void +exsltFuncRegister (void) { + xsltRegisterExtModuleFull (EXSLT_FUNCTIONS_NAMESPACE, + exsltFuncInit, + exsltFuncShutdown, + exsltFuncStyleInit, + exsltFuncStyleShutdown); + + xsltRegisterExtModuleTopLevel ((const xmlChar *) "function", + EXSLT_FUNCTIONS_NAMESPACE, + exsltFuncFunctionComp); + xsltRegisterExtModuleElement ((const xmlChar *) "result", + EXSLT_FUNCTIONS_NAMESPACE, + exsltFuncResultComp, + exsltFuncResultElem); +} diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libexslt/libexslt.3 chromium-145.0.7632.159/third_party/libxslt/src/libexslt/libexslt.3 --- chromium-145.0.7632.116/third_party/libxslt/src/libexslt/libexslt.3 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libexslt/libexslt.3 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,270 @@ +.TH LIBEXSLT 3 "04 November 2003" libxslt +.SH NAME +libexslt \- extension library for XSLT +.SH SYNOPSIS +.B #include +.sp +.B void exsltCommonRegister(void); +.br +.B void exsltDateRegister(void); +.br +.B void exsltDynRegister(void); +.br +.B void exsltFuncRegister(void); +.br +.B void exsltMathRegister(void); +.br +.B void exsltSetsRegister(void); +.br +.B void exsltStrRegister(void); +.br +.B void exsltRegisterAll(void); +.br +.B void exsltSaxonRegister(void); +.SH DESCRIPTION +The +.B libexslt +library is used to provide extensions to +.SM XSLT +functions. These extensions come from the +.SM EXSLT +project +.LP +.SH USAGE +To make use of these functions in +.SM XSLT +the appropriate namespace must be defined on the +.B xsl:stylesheet +element. To enable support for them in +.BR libxslt (3) +you must call the appropriate functions (listed in the +.B SYNOPSIS +section) to register the extensions. The +.I xslt-config +shell script can be used to obtain the necessary flags for +the pre-processor and linker. +The supported extensions are: +.SS COMMON +.TP 2.2i +Namespace: http://exslt.org/common +.TP 2.2i +See http://www.exslt.org/exsl/index.html for a description. +.TP 2.2i +.B node-set() +convert the given RTF into a node-set. +.TP +.B object-type() +returns the type of the given argument. +.TP +.B document +Create multiple output documents. See http://www.exslt.org/exsl/elements/document/index.html + +.SS MATH +.TP 2.2i +Namespace: http://exslt.org/math +.TP 2.2i +See http://www.exslt.org/math/index.html for a description. +.TP 2.2i +.B min() +returns the minimum value of the given node-set +.TP +.B max() +returns the maximum value of the given node-set +.TP +.B highest() +returns the nodes in the node-set whose value is the maximum value for the node-set. +.TP +.B lowest() +returns the nodes in the node-set whose value is the minimum value for the node-set. +.TP +.B constant() +returns a number value of the given constant with the given precision. The constants are PI, E, SQRRT2, LN2, LN10, LOG2E, and SQRT1_2. +.TP +.B random() +returns a random number between 0 and 1 inclusive. +.TP +.B abs() +returns the absolute value of the argument. +.TP +.B sqrt() +returns the square root of the argument. +.TP +.B power() +returns the power base and power arguments. +.TP +.B log() +returns the natural log of the argument. +.TP +.B sin() +returns the sine of the argument. +.TP +.B cos() +returns the cosine of the argument. +.TP +.B tan() +returns the tangent of the argument. +.TP +.B asin() +returns the arc sine of the argument. +.TP +.B acos() +returns the arc cosine of the argument. +.TP +.B atan() +returns the arc tangent of the argument. +.TP +.B atan2() +returns the arc tangent function of the y/x arguments. +.TP +.B exp() +returns the exponential function of the argument. + +.SS SETS +.TP 2.2i +Namespace: http://exslt.org/sets +.TP 2.2i +See http://www.exslt.org/set/index.html for a description. +.TP 2.2i +.B difference() +returns the difference between the two given node-sets. +.TP +.B intersection() +returns a node-set of the nodes within both given node-sets. +.TP +.B distinct() +returns a node-set of all nodes in the first argument that are not in the seconds argument. +.TP +.B has-same-node() +returns TRUE if there is an intersection between the two given node-sets. +.TP +.B leading() +returns a node-set of all nodes in the first argument that precede the first node in the second argument. +.TP +.B trailing() +returns a node-set of all nodes in the first argument that follow the first node in the second argument. + +.SS "DATES and TIMES" +.TP 2.2i +Namespace: http://exslt.org/dates-and-times +.TP 2.2i +See http://www.exslt.org/date/date.html for a description. +.TP 2.2i +.B date-time() +returns the current date and time as a date/time string. +.TP +.B date() +returns the date specified in the given date/time string. +.TP +.B time() +returns the time specified in the date/time string given as the argument. +.TP +.B year() +returns the year of a date as a number. +.TP +.B leap-year() +returns true if the year given in a date is a leap year. +.TP +.B month-in-year() +returns the month of a date as a number. +.TP +.B month-name() +returns the full name of the month of a date. +.TP +.B month-abbreviation() +returns the abbreviation of the month of a date. +.TP +.B week-in-year() +returns the week of the year as a number. +.TP +.B week-in-month() +returns the week in a month of a date as a number. +.TP +.B day-in-year() +returns the month of a date as a number. +.TP +.B day-in-month() +returns the day of a date as a number. +.TP +.B day-of-week-in-month() +returns the day-of-the-week in a month of a date as a number. +.TP +.B day-in-week() +returns the day of the week given in a date as a number. +.TP +.B day-name() +returns the full name of the day of the week of a date. +.TP +.B day-abbreviation() +returns the abbreviation of the day of the week of a date. +.TP +.B hour-in-day() +returns the hour of the day as a number. +.TP +.B minute-in-hour() +returns the minute of the hour as a number. +.TP +.B second-in-minute() +returns the second of the minute as a number. +.TP +.B seconds() +returns the number of seconds specified by the argument string. +.TP +.B add() +returns the date/time resulting from adding a duration to a date/time. +.TP +.B add-duration() +returns the duration resulting from adding two given durations together. +.TP +.B difference() +returns the duration between the first date and the second date. +.TP +.B duration() +returns a duration string that represents the given number of seconds since 1970-01-01T00:00:00. + +.SS STRINGS +.TP 2.2i +Namespace: http://exslt.org/strings +.TP 2.2i +See http://www.exslt.org/str/index.html for a description. +.TP 2.2i +.B tokenize() +returns a node set of token elements, each containing one token from the string. +.TP +.B padding() +returns a string padded to a certain length. +.TP +.B align() +returns a string aligned within another string. +.TP +.B concat() +returns the concatenation of the string values of the nodes in that node set. + +.SS FUNCTIONS +.TP 2.2i +Namespace: http://exslt.org/functions +.TP 2.2i +See http://www.exslt.org/func/index.html for a description. +.TP 2.2i +.B function +declares an extension function. +.TP +.B result +returns the result of an extension function declared in function(). +.SH FILES +.TP +.I /usr/bin/xslt-config +shell script giving pre-processor and linker flags. +.TP +.I /usr/lib/libexslt.a +static library +.TP +.I /usr/lib/libexslt.so +sharable library +.SH AUTHORS +Manual page by Heiko W. Rupp (hwr@pilhuhn.de) +.SH "SEE ALSO" +.BR libxml (3), +.BR libxslt (3), +.BR xmllint (1) +.BR xsltproc (1), +.\" end of manual page diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libexslt/libexslt.h chromium-145.0.7632.159/third_party/libxslt/src/libexslt/libexslt.h --- chromium-145.0.7632.116/third_party/libxslt/src/libexslt/libexslt.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libexslt/libexslt.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,35 @@ +/* + * libexslt.h: internal header only used during the compilation of libexslt + * + * See COPYRIGHT for the status of this software + * + * Author: daniel@veillard.com + */ + +#ifndef __XSLT_LIBEXSLT_H__ +#define __XSLT_LIBEXSLT_H__ + +#if defined(_WIN32) && !defined (__MINGW32__) +#include +#else +#include "config.h" +#endif + +#include +#include + +#if !defined LIBEXSLT_PUBLIC +#if (defined (__CYGWIN__) || defined _MSC_VER) && !defined IN_LIBEXSLT && !defined LIBEXSLT_STATIC +#define LIBEXSLT_PUBLIC __declspec(dllimport) +#else +#define LIBEXSLT_PUBLIC +#endif +#endif + +#ifdef __GNUC__ +#define ATTRIBUTE_UNUSED __attribute__((unused)) +#else +#define ATTRIBUTE_UNUSED +#endif + +#endif /* ! __XSLT_LIBEXSLT_H__ */ diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libexslt/math.c chromium-145.0.7632.159/third_party/libxslt/src/libexslt/math.c --- chromium-145.0.7632.116/third_party/libxslt/src/libexslt/math.c 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libexslt/math.c 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,1173 @@ +#define IN_LIBEXSLT +#include "libexslt/libexslt.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "exslt.h" + +/** + * exsltMathMin: + * @ns: a node-set + * + * Implements the EXSLT - Math min() function: + * number math:min (node-set) + * + * Returns the minimum value of the nodes passed as the argument, or + * NAN if @ns is NULL or empty or if one of the nodes + * turns into NaN. + */ +static double +exsltMathMin (xmlNodeSetPtr ns) { + double ret, cur; + int i; + + if ((ns == NULL) || (ns->nodeNr == 0)) + return(NAN); + ret = xmlXPathCastNodeToNumber(ns->nodeTab[0]); + if (xmlXPathIsNaN(ret)) + return(NAN); + for (i = 1; i < ns->nodeNr; i++) { + cur = xmlXPathCastNodeToNumber(ns->nodeTab[i]); + if (xmlXPathIsNaN(cur)) + return(NAN); + if (cur < ret) + ret = cur; + } + return(ret); +} + +/** + * exsltMathMinFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Wraps #exsltMathMin for use by the XPath processor. + */ +static void +exsltMathMinFunction (xmlXPathParserContextPtr ctxt, int nargs) { + xmlNodeSetPtr ns; + double ret; + void *user = NULL; + + if (nargs != 1) { + xsltGenericError(xsltGenericErrorContext, + "math:min: invalid number of arguments\n"); + ctxt->error = XPATH_INVALID_ARITY; + return; + } + /* We need to delay the freeing of value->user */ + if ((ctxt->value != NULL) && (ctxt->value->boolval != 0)) { + user = ctxt->value->user; + ctxt->value->boolval = 0; + ctxt->value->user = NULL; + } + ns = xmlXPathPopNodeSet(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + + ret = exsltMathMin(ns); + + xmlXPathFreeNodeSet(ns); + if (user != NULL) + xmlFreeNodeList((xmlNodePtr)user); + + xmlXPathReturnNumber(ctxt, ret); +} + +/** + * exsltMathMax: + * @ns: a node-set + * + * Implements the EXSLT - Math max() function: + * number math:max (node-set) + * + * Returns the maximum value of the nodes passed as arguments, or + * NAN if @ns is NULL or empty or if one of the nodes + * turns into NaN. + */ +static double +exsltMathMax (xmlNodeSetPtr ns) { + double ret, cur; + int i; + + if ((ns == NULL) || (ns->nodeNr == 0)) + return(NAN); + ret = xmlXPathCastNodeToNumber(ns->nodeTab[0]); + if (xmlXPathIsNaN(ret)) + return(NAN); + for (i = 1; i < ns->nodeNr; i++) { + cur = xmlXPathCastNodeToNumber(ns->nodeTab[i]); + if (xmlXPathIsNaN(cur)) + return(NAN); + if (cur > ret) + ret = cur; + } + return(ret); +} + +/** + * exsltMathMaxFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Wraps #exsltMathMax for use by the XPath processor. + */ +static void +exsltMathMaxFunction (xmlXPathParserContextPtr ctxt, int nargs) { + xmlNodeSetPtr ns; + double ret; + void *user = NULL; + + if (nargs != 1) { + xmlXPathSetArityError(ctxt); + return; + } + + /* We need to delay the freeing of value->user */ + if ((ctxt->value != NULL) && (ctxt->value->boolval != 0)) { + user = ctxt->value->user; + ctxt->value->boolval = 0; + ctxt->value->user = 0; + } + ns = xmlXPathPopNodeSet(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + + ret = exsltMathMax(ns); + + xmlXPathFreeNodeSet(ns); + + if (user != NULL) + xmlFreeNodeList((xmlNodePtr)user); + xmlXPathReturnNumber(ctxt, ret); +} + +/** + * exsltMathHighest: + * @ns: a node-set + * + * Implements the EXSLT - Math highest() function: + * node-set math:highest (node-set) + * + * Returns the nodes in the node-set whose value is the maximum value + * for the node-set. + */ +static xmlNodeSetPtr +exsltMathHighest (xmlNodeSetPtr ns) { + xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL); + double max, cur; + int i; + + if ((ns == NULL) || (ns->nodeNr == 0)) + return(ret); + + max = xmlXPathCastNodeToNumber(ns->nodeTab[0]); + if (xmlXPathIsNaN(max)) + return(ret); + else + xmlXPathNodeSetAddUnique(ret, ns->nodeTab[0]); + + for (i = 1; i < ns->nodeNr; i++) { + cur = xmlXPathCastNodeToNumber(ns->nodeTab[i]); + if (xmlXPathIsNaN(cur)) { + xmlXPathEmptyNodeSet(ret); + return(ret); + } + if (cur < max) + continue; + if (cur > max) { + max = cur; + xmlXPathEmptyNodeSet(ret); + xmlXPathNodeSetAddUnique(ret, ns->nodeTab[i]); + continue; + } + xmlXPathNodeSetAddUnique(ret, ns->nodeTab[i]); + } + return(ret); +} + +/** + * exsltMathHighestFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Wraps #exsltMathHighest for use by the XPath processor + */ +static void +exsltMathHighestFunction (xmlXPathParserContextPtr ctxt, int nargs) { + xmlNodeSetPtr ns, ret; + void *user = NULL; + + if (nargs != 1) { + xmlXPathSetArityError(ctxt); + return; + } + + /* We need to delay the freeing of value->user */ + if ((ctxt->value != NULL) && ctxt->value->boolval != 0) { + user = ctxt->value->user; + ctxt->value->boolval = 0; + ctxt->value->user = NULL; + } + ns = xmlXPathPopNodeSet(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + + ret = exsltMathHighest(ns); + + xmlXPathFreeNodeSet(ns); + if (user != NULL) + xmlFreeNodeList((xmlNodePtr)user); + + xmlXPathReturnNodeSet(ctxt, ret); +} + +/** + * exsltMathLowest: + * @ns: a node-set + * + * Implements the EXSLT - Math lowest() function + * node-set math:lowest (node-set) + * + * Returns the nodes in the node-set whose value is the minimum value + * for the node-set. + */ +static xmlNodeSetPtr +exsltMathLowest (xmlNodeSetPtr ns) { + xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL); + double min, cur; + int i; + + if ((ns == NULL) || (ns->nodeNr == 0)) + return(ret); + + min = xmlXPathCastNodeToNumber(ns->nodeTab[0]); + if (xmlXPathIsNaN(min)) + return(ret); + else + xmlXPathNodeSetAddUnique(ret, ns->nodeTab[0]); + + for (i = 1; i < ns->nodeNr; i++) { + cur = xmlXPathCastNodeToNumber(ns->nodeTab[i]); + if (xmlXPathIsNaN(cur)) { + xmlXPathEmptyNodeSet(ret); + return(ret); + } + if (cur > min) + continue; + if (cur < min) { + min = cur; + xmlXPathEmptyNodeSet(ret); + xmlXPathNodeSetAddUnique(ret, ns->nodeTab[i]); + continue; + } + xmlXPathNodeSetAddUnique(ret, ns->nodeTab[i]); + } + return(ret); +} + +/** + * exsltMathLowestFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Wraps #exsltMathLowest for use by the XPath processor + */ +static void +exsltMathLowestFunction (xmlXPathParserContextPtr ctxt, int nargs) { + xmlNodeSetPtr ns, ret; + void *user = NULL; + + + if (nargs != 1) { + xmlXPathSetArityError(ctxt); + return; + } + + /* We need to delay the freeing of value->user */ + if ((ctxt->value != NULL) && (ctxt->value->boolval != 0)) { + user = ctxt->value->user; + ctxt->value->boolval = 0; + ctxt->value->user = NULL; + } + ns = xmlXPathPopNodeSet(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + + ret = exsltMathLowest(ns); + + xmlXPathFreeNodeSet(ns); + if (user != NULL) + xmlFreeNodeList((xmlNodePtr)user); + + xmlXPathReturnNodeSet(ctxt, ret); +} + +/* math other functions */ + +/* constant values */ +#define EXSLT_PI (const xmlChar *) \ + "3.1415926535897932384626433832795028841971693993751" +#define EXSLT_E (const xmlChar *) \ + "2.71828182845904523536028747135266249775724709369996" +#define EXSLT_SQRRT2 (const xmlChar *) \ + "1.41421356237309504880168872420969807856967187537694" +#define EXSLT_LN2 (const xmlChar *) \ + "0.69314718055994530941723212145817656807550013436025" +#define EXSLT_LN10 (const xmlChar *) \ + "2.30258509299404568402" +#define EXSLT_LOG2E (const xmlChar *) \ + "1.4426950408889634074" +#define EXSLT_SQRT1_2 (const xmlChar *) \ + "0.70710678118654752440" + +/** + * exsltMathConstant + * @name: string + * @precision: number + * + * Implements the EXSLT - Math constant function: + * number math:constant(string, number) + * + * Returns a number value of the given constant with the given precision or + * NAN if name is unknown. + * The constants are PI, E, SQRRT2, LN2, LN10, LOG2E, and SQRT1_2 + */ +static double +exsltMathConstant (xmlChar *name, double precision) { + xmlChar *str; + double ret; + + if ((name == NULL) || (xmlXPathIsNaN(precision)) || (precision < 1.0)) { + return NAN; + } + + if (xmlStrEqual(name, BAD_CAST "PI")) { + int len = xmlStrlen(EXSLT_PI); + + if (precision <= len) + len = (int)precision; + + str = xmlStrsub(EXSLT_PI, 0, len); + + } else if (xmlStrEqual(name, BAD_CAST "E")) { + int len = xmlStrlen(EXSLT_E); + + if (precision <= len) + len = (int)precision; + + str = xmlStrsub(EXSLT_E, 0, len); + + } else if (xmlStrEqual(name, BAD_CAST "SQRRT2")) { + int len = xmlStrlen(EXSLT_SQRRT2); + + if (precision <= len) + len = (int)precision; + + str = xmlStrsub(EXSLT_SQRRT2, 0, len); + + } else if (xmlStrEqual(name, BAD_CAST "LN2")) { + int len = xmlStrlen(EXSLT_LN2); + + if (precision <= len) + len = (int)precision; + + str = xmlStrsub(EXSLT_LN2, 0, len); + + } else if (xmlStrEqual(name, BAD_CAST "LN10")) { + int len = xmlStrlen(EXSLT_LN10); + + if (precision <= len) + len = (int)precision; + + str = xmlStrsub(EXSLT_LN10, 0, len); + + } else if (xmlStrEqual(name, BAD_CAST "LOG2E")) { + int len = xmlStrlen(EXSLT_LOG2E); + + if (precision <= len) + len = (int)precision; + + str = xmlStrsub(EXSLT_LOG2E, 0, len); + + } else if (xmlStrEqual(name, BAD_CAST "SQRT1_2")) { + int len = xmlStrlen(EXSLT_SQRT1_2); + + if (precision <= len) + len = (int)precision; + + str = xmlStrsub(EXSLT_SQRT1_2, 0, len); + + } else { + str = NULL; + } + if (str == NULL) + return NAN; + ret = xmlXPathCastStringToNumber(str); + xmlFree(str); + return ret; +} + +/** + * exsltMathConstantFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Wraps #exsltMathConstant for use by the XPath processor. + */ +static void +exsltMathConstantFunction (xmlXPathParserContextPtr ctxt, int nargs) { + double ret; + xmlChar *name; + + if (nargs != 2) { + xmlXPathSetArityError(ctxt); + return; + } + ret = xmlXPathPopNumber(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + + name = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + + ret = exsltMathConstant(name, ret); + if (name != NULL) + xmlFree(name); + + xmlXPathReturnNumber(ctxt, ret); +} + +/** + * exsltMathRandom: + * + * Implements the EXSLT - Math random() function: + * number math:random () + * + * Returns a random number between 0 and 1 inclusive. + */ +static double +exsltMathRandom (void) { + double ret; + int num; + + num = rand(); + ret = (double)num / (double)RAND_MAX; + return(ret); +} + +/** + * exsltMathRandomFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Wraps #exsltMathRandom for use by the XPath processor. + */ +static void +exsltMathRandomFunction (xmlXPathParserContextPtr ctxt, int nargs) { + double ret; + + if (nargs != 0) { + xmlXPathSetArityError(ctxt); + return; + } + + ret = exsltMathRandom(); + + xmlXPathReturnNumber(ctxt, ret); +} + +/** + * exsltMathAbs: + * @num: a double + * + * Implements the EXSLT - Math abs() function: + * number math:abs (number) + * + * Returns the absolute value of the argument, or NAN if @num is Nan. + */ +static double +exsltMathAbs (double num) { + double ret; + + if (xmlXPathIsNaN(num)) + return(NAN); + ret = fabs(num); + return(ret); +} + +/** + * exsltMathAbsFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Wraps #exsltMathAbs for use by the XPath processor. + */ +static void +exsltMathAbsFunction (xmlXPathParserContextPtr ctxt, int nargs) { + double ret; + + if (nargs != 1) { + xmlXPathSetArityError(ctxt); + return; + } + ret = xmlXPathPopNumber(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + + ret = exsltMathAbs(ret); + + xmlXPathReturnNumber(ctxt, ret); +} + +/** + * exsltMathSqrt: + * @num: a double + * + * Implements the EXSLT - Math sqrt() function: + * number math:sqrt (number) + * + * Returns the square root of the argument, or NAN if @num is Nan. + */ +static double +exsltMathSqrt (double num) { + double ret; + + if (xmlXPathIsNaN(num)) + return(NAN); + ret = sqrt(num); + return(ret); +} + +/** + * exsltMathSqrtFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Wraps #exsltMathSqrt for use by the XPath processor. + */ +static void +exsltMathSqrtFunction (xmlXPathParserContextPtr ctxt, int nargs) { + double ret; + + if (nargs != 1) { + xmlXPathSetArityError(ctxt); + return; + } + ret = xmlXPathPopNumber(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + + ret = exsltMathSqrt(ret); + + xmlXPathReturnNumber(ctxt, ret); +} + +/** + * exsltMathPower: + * @base: a double + * @power: a double + * + * Implements the EXSLT - Math power() function: + * number math:power (number, number) + * + * Returns the power base and power arguments, or NAN + * if either @base or @power is Nan. + */ +static double +exsltMathPower (double base, double power) { + double ret; + + if ((xmlXPathIsNaN(base) || xmlXPathIsNaN(power))) + return(NAN); + ret = pow(base, power); + return(ret); +} + +/** + * exsltMathPower: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Wraps #exsltMathPower for use by the XPath processor. + */ +static void +exsltMathPowerFunction (xmlXPathParserContextPtr ctxt, int nargs) { + double ret, base; + + if (nargs != 2) { + xmlXPathSetArityError(ctxt); + return; + } + ret = xmlXPathPopNumber(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + + /* power */ + base = xmlXPathPopNumber(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + + ret = exsltMathPower(base, ret); + + xmlXPathReturnNumber(ctxt, ret); +} + +/** + * exsltMathLog: + * @num: a double + * + * Implements the EXSLT - Math log() function: + * number math:log (number) + * + * Returns the natural log of the argument, or NAN if @num is Nan. + */ +static double +exsltMathLog (double num) { + double ret; + + if (xmlXPathIsNaN(num)) + return(NAN); + ret = log(num); + return(ret); +} + +/** + * exsltMathLogFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Wraps #exsltMathLog for use by the XPath processor. + */ +static void +exsltMathLogFunction (xmlXPathParserContextPtr ctxt, int nargs) { + double ret; + + if (nargs != 1) { + xmlXPathSetArityError(ctxt); + return; + } + ret = xmlXPathPopNumber(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + + ret = exsltMathLog(ret); + + xmlXPathReturnNumber(ctxt, ret); +} + +/** + * exsltMathSin: + * @num: a double + * + * Implements the EXSLT - Math sin() function: + * number math:sin (number) + * + * Returns the sine of the argument, or NAN if @num is Nan. + */ +static double +exsltMathSin (double num) { + double ret; + + if (xmlXPathIsNaN(num)) + return(NAN); + ret = sin(num); + return(ret); +} + +/** + * exsltMathSinFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Wraps #exsltMathSin for use by the XPath processor. + */ +static void +exsltMathSinFunction (xmlXPathParserContextPtr ctxt, int nargs) { + double ret; + + if (nargs != 1) { + xmlXPathSetArityError(ctxt); + return; + } + ret = xmlXPathPopNumber(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + + ret = exsltMathSin(ret); + + xmlXPathReturnNumber(ctxt, ret); +} + +/** + * exsltMathCos: + * @num: a double + * + * Implements the EXSLT - Math cos() function: + * number math:cos (number) + * + * Returns the cosine of the argument, or NAN if @num is Nan. + */ +static double +exsltMathCos (double num) { + double ret; + + if (xmlXPathIsNaN(num)) + return(NAN); + ret = cos(num); + return(ret); +} + +/** + * exsltMathCosFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Wraps #exsltMathCos for use by the XPath processor. + */ +static void +exsltMathCosFunction (xmlXPathParserContextPtr ctxt, int nargs) { + double ret; + + if (nargs != 1) { + xmlXPathSetArityError(ctxt); + return; + } + ret = xmlXPathPopNumber(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + + ret = exsltMathCos(ret); + + xmlXPathReturnNumber(ctxt, ret); +} + +/** + * exsltMathTan: + * @num: a double + * + * Implements the EXSLT - Math tan() function: + * number math:tan (number) + * + * Returns the tangent of the argument, or NAN if @num is Nan. + */ +static double +exsltMathTan (double num) { + double ret; + + if (xmlXPathIsNaN(num)) + return(NAN); + ret = tan(num); + return(ret); +} + +/** + * exsltMathTanFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Wraps #exsltMathTan for use by the XPath processor. + */ +static void +exsltMathTanFunction (xmlXPathParserContextPtr ctxt, int nargs) { + double ret; + + if (nargs != 1) { + xmlXPathSetArityError(ctxt); + return; + } + ret = xmlXPathPopNumber(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + + ret = exsltMathTan(ret); + + xmlXPathReturnNumber(ctxt, ret); +} + +/** + * exsltMathAsin: + * @num: a double + * + * Implements the EXSLT - Math asin() function: + * number math:asin (number) + * + * Returns the arc sine of the argument, or NAN if @num is Nan. + */ +static double +exsltMathAsin (double num) { + double ret; + + if (xmlXPathIsNaN(num)) + return(NAN); + ret = asin(num); + return(ret); +} + +/** + * exsltMathAsinFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Wraps #exsltMathAsin for use by the XPath processor. + */ +static void +exsltMathAsinFunction (xmlXPathParserContextPtr ctxt, int nargs) { + double ret; + + if (nargs != 1) { + xmlXPathSetArityError(ctxt); + return; + } + ret = xmlXPathPopNumber(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + + ret = exsltMathAsin(ret); + + xmlXPathReturnNumber(ctxt, ret); +} + +/** + * exsltMathAcos: + * @num: a double + * + * Implements the EXSLT - Math acos() function: + * number math:acos (number) + * + * Returns the arc cosine of the argument, or NAN if @num is Nan. + */ +static double +exsltMathAcos (double num) { + double ret; + + if (xmlXPathIsNaN(num)) + return(NAN); + ret = acos(num); + return(ret); +} + +/** + * exsltMathAcosFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Wraps #exsltMathAcos for use by the XPath processor. + */ +static void +exsltMathAcosFunction (xmlXPathParserContextPtr ctxt, int nargs) { + double ret; + + if (nargs != 1) { + xmlXPathSetArityError(ctxt); + return; + } + ret = xmlXPathPopNumber(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + + ret = exsltMathAcos(ret); + + xmlXPathReturnNumber(ctxt, ret); +} + +/** + * exsltMathAtan: + * @num: a double + * + * Implements the EXSLT - Math atan() function: + * number math:atan (number) + * + * Returns the arc tangent of the argument, or NAN if @num is Nan. + */ +static double +exsltMathAtan (double num) { + double ret; + + if (xmlXPathIsNaN(num)) + return(NAN); + ret = atan(num); + return(ret); +} + +/** + * exsltMathAtanFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Wraps #exsltMathAtan for use by the XPath processor. + */ +static void +exsltMathAtanFunction (xmlXPathParserContextPtr ctxt, int nargs) { + double ret; + + if (nargs != 1) { + xmlXPathSetArityError(ctxt); + return; + } + ret = xmlXPathPopNumber(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + + ret = exsltMathAtan(ret); + + xmlXPathReturnNumber(ctxt, ret); +} + +/** + * exsltMathAtan2: + * @y: a double + * @x: a double + * + * Implements the EXSLT - Math atan2() function: + * number math:atan2 (number, number) + * + * Returns the arc tangent function of the y/x arguments, or NAN + * if either @y or @x is Nan. + */ +static double +exsltMathAtan2 (double y, double x) { + double ret; + + if ((xmlXPathIsNaN(y) || xmlXPathIsNaN(x))) + return(NAN); + ret = atan2(y, x); + return(ret); +} + +/** + * exsltMathAtan2Function: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Wraps #exsltMathAtan2 for use by the XPath processor. + */ +static void +exsltMathAtan2Function (xmlXPathParserContextPtr ctxt, int nargs) { + double ret, x; + + if (nargs != 2) { + xmlXPathSetArityError(ctxt); + return; + } + x = xmlXPathPopNumber(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + + /* y */ + ret = xmlXPathPopNumber(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + + ret = exsltMathAtan2(ret, x); + + xmlXPathReturnNumber(ctxt, ret); +} + +/** + * exsltMathExp: + * @num: a double + * + * Implements the EXSLT - Math exp() function: + * number math:exp (number) + * + * Returns the exponential function of the argument, or NAN if + * @num is Nan. + */ +static double +exsltMathExp (double num) { + double ret; + + if (xmlXPathIsNaN(num)) + return(NAN); + ret = exp(num); + return(ret); +} + +/** + * exsltMathExpFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Wraps #exsltMathExp for use by the XPath processor. + */ +static void +exsltMathExpFunction (xmlXPathParserContextPtr ctxt, int nargs) { + double ret; + + if (nargs != 1) { + xmlXPathSetArityError(ctxt); + return; + } + ret = xmlXPathPopNumber(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + + ret = exsltMathExp(ret); + + xmlXPathReturnNumber(ctxt, ret); +} + +/** + * exsltMathRegister: + * + * Registers the EXSLT - Math module + */ + +void +exsltMathRegister (void) { + xsltRegisterExtModuleFunction ((const xmlChar *) "min", + EXSLT_MATH_NAMESPACE, + exsltMathMinFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "max", + EXSLT_MATH_NAMESPACE, + exsltMathMaxFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "highest", + EXSLT_MATH_NAMESPACE, + exsltMathHighestFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "lowest", + EXSLT_MATH_NAMESPACE, + exsltMathLowestFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "constant", + EXSLT_MATH_NAMESPACE, + exsltMathConstantFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "random", + EXSLT_MATH_NAMESPACE, + exsltMathRandomFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "abs", + EXSLT_MATH_NAMESPACE, + exsltMathAbsFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "sqrt", + EXSLT_MATH_NAMESPACE, + exsltMathSqrtFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "power", + EXSLT_MATH_NAMESPACE, + exsltMathPowerFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "log", + EXSLT_MATH_NAMESPACE, + exsltMathLogFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "sin", + EXSLT_MATH_NAMESPACE, + exsltMathSinFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "cos", + EXSLT_MATH_NAMESPACE, + exsltMathCosFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "tan", + EXSLT_MATH_NAMESPACE, + exsltMathTanFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "asin", + EXSLT_MATH_NAMESPACE, + exsltMathAsinFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "acos", + EXSLT_MATH_NAMESPACE, + exsltMathAcosFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "atan", + EXSLT_MATH_NAMESPACE, + exsltMathAtanFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "atan2", + EXSLT_MATH_NAMESPACE, + exsltMathAtan2Function); + xsltRegisterExtModuleFunction ((const xmlChar *) "exp", + EXSLT_MATH_NAMESPACE, + exsltMathExpFunction); +} + +/** + * exsltMathXpathCtxtRegister: + * + * Registers the EXSLT - Math module for use outside XSLT + */ +int +exsltMathXpathCtxtRegister (xmlXPathContextPtr ctxt, const xmlChar *prefix) +{ + if (ctxt + && prefix + && !xmlXPathRegisterNs(ctxt, + prefix, + (const xmlChar *) EXSLT_MATH_NAMESPACE) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "min", + (const xmlChar *) EXSLT_MATH_NAMESPACE, + exsltMathMinFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "max", + (const xmlChar *) EXSLT_MATH_NAMESPACE, + exsltMathMaxFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "highest", + (const xmlChar *) EXSLT_MATH_NAMESPACE, + exsltMathHighestFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "lowest", + (const xmlChar *) EXSLT_MATH_NAMESPACE, + exsltMathLowestFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "random", + (const xmlChar *) EXSLT_MATH_NAMESPACE, + exsltMathRandomFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "abs", + (const xmlChar *) EXSLT_MATH_NAMESPACE, + exsltMathAbsFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "sqrt", + (const xmlChar *) EXSLT_MATH_NAMESPACE, + exsltMathSqrtFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "power", + (const xmlChar *) EXSLT_MATH_NAMESPACE, + exsltMathPowerFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "log", + (const xmlChar *) EXSLT_MATH_NAMESPACE, + exsltMathLogFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "sin", + (const xmlChar *) EXSLT_MATH_NAMESPACE, + exsltMathSinFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "cos", + (const xmlChar *) EXSLT_MATH_NAMESPACE, + exsltMathCosFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "tan", + (const xmlChar *) EXSLT_MATH_NAMESPACE, + exsltMathTanFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "asin", + (const xmlChar *) EXSLT_MATH_NAMESPACE, + exsltMathAsinFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "acos", + (const xmlChar *) EXSLT_MATH_NAMESPACE, + exsltMathAcosFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "atan", + (const xmlChar *) EXSLT_MATH_NAMESPACE, + exsltMathAtanFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "atan2", + (const xmlChar *) EXSLT_MATH_NAMESPACE, + exsltMathAtan2Function) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "exp", + (const xmlChar *) EXSLT_MATH_NAMESPACE, + exsltMathExpFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "constant", + (const xmlChar *) EXSLT_MATH_NAMESPACE, + exsltMathConstantFunction)) { + return 0; + } + return -1; +} diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libexslt/saxon.c chromium-145.0.7632.159/third_party/libxslt/src/libexslt/saxon.c --- chromium-145.0.7632.116/third_party/libxslt/src/libexslt/saxon.c 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libexslt/saxon.c 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,318 @@ +#define IN_LIBEXSLT +#include "libexslt/libexslt.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "exslt.h" + +/** + * exsltSaxonInit: + * @ctxt: an XSLT transformation context + * @URI: the namespace URI for the extension + * + * Initializes the SAXON module. + * + * Returns the data for this transformation + */ +static void * +exsltSaxonInit (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, + const xmlChar *URI ATTRIBUTE_UNUSED) { + return xmlHashCreate(1); +} + +static void +exsltSaxonFreeCompExprEntry(void *payload, + const xmlChar *name ATTRIBUTE_UNUSED) { + xmlXPathFreeCompExpr((xmlXPathCompExprPtr) payload); +} + +/** + * exsltSaxonShutdown: + * @ctxt: an XSLT transformation context + * @URI: the namespace URI for the extension + * @data: the module data to free up + * + * Shutdown the SAXON extension module + */ +static void +exsltSaxonShutdown (xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, + const xmlChar *URI ATTRIBUTE_UNUSED, + void *vdata) { + xmlHashTablePtr data = (xmlHashTablePtr) vdata; + xmlHashFree(data, exsltSaxonFreeCompExprEntry); +} + + +/** + * exsltSaxonExpressionFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * The supplied string must contain an XPath expression. The result of + * the function is a stored expression, which may be supplied as an + * argument to other extension functions such as saxon:eval(), + * saxon:sum() and saxon:distinct(). The result of the expression will + * usually depend on the current node. The expression may contain + * references to variables that are in scope at the point where + * saxon:expression() is called: these variables will be replaced in + * the stored expression with the values they take at the time + * saxon:expression() is called, not the values of the variables at + * the time the stored expression is evaluated. Similarly, if the + * expression contains namespace prefixes, these are interpreted in + * terms of the namespace declarations in scope at the point where the + * saxon:expression() function is called, not those in scope where the + * stored expression is evaluated. + * + * TODO: current implementation doesn't conform to SAXON behaviour + * regarding context and namespaces. + */ +static void +exsltSaxonExpressionFunction (xmlXPathParserContextPtr ctxt, int nargs) { + xmlChar *arg; + xmlXPathCompExprPtr ret; + xmlHashTablePtr hash; + xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt); + + if (nargs != 1) { + xmlXPathSetArityError(ctxt); + return; + } + + arg = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt) || (arg == NULL)) { + xmlXPathSetTypeError(ctxt); + return; + } + + hash = (xmlHashTablePtr) xsltGetExtData(tctxt, + ctxt->context->functionURI); + + ret = xmlHashLookup(hash, arg); + + if (ret == NULL) { + ret = xmlXPathCtxtCompile(tctxt->xpathCtxt, arg); + if (ret == NULL) { + xmlFree(arg); + xmlXPathSetError(ctxt, XPATH_EXPR_ERROR); + return; + } + if (xmlHashAddEntry(hash, arg, (void *) ret) < 0) { + xmlXPathFreeCompExpr(ret); + xmlFree(arg); + xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); + return; + } + } + + xmlFree(arg); + + xmlXPathReturnExternal(ctxt, ret); +} + +/** + * exsltSaxonEvalFunction: + * @ctxt: an XPath parser context + * @nargs: number of arguments + * + * Implements de SAXON eval() function: + * object saxon:eval (saxon:stored-expression) + * Returns the result of evaluating the supplied stored expression. + * A stored expression may be obtained as the result of calling + * the saxon:expression() function. + * The stored expression is evaluated in the current context, that + * is, the context node is the current node, and the context position + * and context size are the same as the result of calling position() + * or last() respectively. + */ +static void +exsltSaxonEvalFunction (xmlXPathParserContextPtr ctxt, int nargs) { + xmlXPathCompExprPtr expr; + xmlXPathObjectPtr ret; + + if (nargs != 1) { + xmlXPathSetArityError(ctxt); + return; + } + + if (!xmlXPathStackIsExternal(ctxt)) { + xmlXPathSetTypeError(ctxt); + return; + } + + expr = (xmlXPathCompExprPtr) xmlXPathPopExternal(ctxt); + + ret = xmlXPathCompiledEval(expr, ctxt->context); + if (ret == NULL) { + xmlXPathSetError(ctxt, XPATH_EXPR_ERROR); + return; + } + + valuePush(ctxt, ret); +} + +/** + * exsltSaxonEvaluateFunction: + * @ctxt: an XPath parser context + * @nargs: number of arguments + * + * Implements the SAXON evaluate() function + * object saxon:evaluate (string) + * The supplied string must contain an XPath expression. The result of + * the function is the result of evaluating the XPath expression. This + * is useful where an expression needs to be constructed at run-time or + * passed to the stylesheet as a parameter, for example where the sort + * key is determined dynamically. The context for the expression (e.g. + * which variables and namespaces are available) is exactly the same as + * if the expression were written explicitly at this point in the + * stylesheet. The function saxon:evaluate(string) is shorthand for + * saxon:eval(saxon:expression(string)). + */ +static void +exsltSaxonEvaluateFunction (xmlXPathParserContextPtr ctxt, int nargs) { + if (nargs != 1) { + xmlXPathSetArityError(ctxt); + return; + } + + exsltSaxonExpressionFunction(ctxt, 1); + exsltSaxonEvalFunction(ctxt, 1); +} + +/** + * exsltSaxonSystemIdFunction: + * @ctxt: an XPath parser context + * @nargs: number of arguments + * + * Implements the SAXON systemId() function + * string saxon:systemId () + * This function returns the system ID of the document being styled. + */ +static void +exsltSaxonSystemIdFunction(xmlXPathParserContextPtr ctxt, int nargs) +{ + if (ctxt == NULL) + return; + if (nargs != 0) { + xmlXPathSetArityError(ctxt); + return; + } + + if ((ctxt->context) && (ctxt->context->doc) && + (ctxt->context->doc->URL)) + valuePush(ctxt, xmlXPathNewString(ctxt->context->doc->URL)); + else + valuePush(ctxt, xmlXPathNewString(BAD_CAST "")); +} + +/** + * exsltSaxonLineNumberFunction: + * @ctxt: an XPath parser context + * @nargs: number of arguments + * + * Implements the SAXON line-number() function + * integer saxon:line-number() + * + * This returns the line number of the context node in the source document + * within the entity that contains it. There are no arguments. If line numbers + * are not maintained for the current document, the function returns -1. (To + * ensure that line numbers are maintained, use the -l option on the command + * line) + * + * The extension has been extended to have the following form: + * integer saxon:line-number([node-set-1]) + * If a node-set is given, this extension will return the line number of the + * node in the argument node-set that is first in document order. + */ +static void +exsltSaxonLineNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { + xmlNodePtr cur = NULL; + xmlXPathObjectPtr obj = NULL; + long lineNo = -1; + + if (nargs == 0) { + cur = ctxt->context->node; + } else if (nargs == 1) { + xmlNodeSetPtr nodelist; + int i; + + if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "saxon:line-number() : invalid arg expecting a node-set\n"); + ctxt->error = XPATH_INVALID_TYPE; + return; + } + + obj = valuePop(ctxt); + nodelist = obj->nodesetval; + if ((nodelist != NULL) && (nodelist->nodeNr > 0)) { + cur = nodelist->nodeTab[0]; + for (i = 1;i < nodelist->nodeNr;i++) { + int ret = xmlXPathCmpNodes(cur, nodelist->nodeTab[i]); + if (ret == -1) + cur = nodelist->nodeTab[i]; + } + } + } else { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "saxon:line-number() : invalid number of args %d\n", + nargs); + ctxt->error = XPATH_INVALID_ARITY; + return; + } + + if ((cur != NULL) && (cur->type == XML_NAMESPACE_DECL)) { + /* + * The XPath module sets the owner element of a ns-node on + * the ns->next field. + */ + cur = (xmlNodePtr) ((xmlNsPtr) cur)->next; + if (cur == NULL || cur->type != XML_ELEMENT_NODE) { + xsltGenericError(xsltGenericErrorContext, + "Internal error in exsltSaxonLineNumberFunction: " + "Cannot retrieve the doc of a namespace node.\n"); + cur = NULL; + } + } + + if (cur != NULL) + lineNo = xmlGetLineNo(cur); + + valuePush(ctxt, xmlXPathNewFloat(lineNo)); + + xmlXPathFreeObject(obj); +} + +/** + * exsltSaxonRegister: + * + * Registers the SAXON extension module + */ +void +exsltSaxonRegister (void) { + xsltRegisterExtModule (SAXON_NAMESPACE, + exsltSaxonInit, + exsltSaxonShutdown); + xsltRegisterExtModuleFunction((const xmlChar *) "expression", + SAXON_NAMESPACE, + exsltSaxonExpressionFunction); + xsltRegisterExtModuleFunction((const xmlChar *) "eval", + SAXON_NAMESPACE, + exsltSaxonEvalFunction); + xsltRegisterExtModuleFunction((const xmlChar *) "evaluate", + SAXON_NAMESPACE, + exsltSaxonEvaluateFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "line-number", + SAXON_NAMESPACE, + exsltSaxonLineNumberFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "systemId", + SAXON_NAMESPACE, + exsltSaxonSystemIdFunction); +} diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libexslt/sets.c chromium-145.0.7632.159/third_party/libxslt/src/libexslt/sets.c --- chromium-145.0.7632.116/third_party/libxslt/src/libexslt/sets.c 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libexslt/sets.c 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,320 @@ +#define IN_LIBEXSLT +#include "libexslt/libexslt.h" + +#include +#include +#include + +#include +#include +#include + +#include "exslt.h" + +/** + * exsltSetsDifferenceFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Wraps #xmlXPathDifference for use by the XPath processor + */ +static void +exsltSetsDifferenceFunction (xmlXPathParserContextPtr ctxt, int nargs) { + xmlNodeSetPtr arg1, arg2, ret; + + if (nargs != 2) { + xmlXPathSetArityError(ctxt); + return; + } + + arg2 = xmlXPathPopNodeSet(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + + arg1 = xmlXPathPopNodeSet(ctxt); + if (xmlXPathCheckError(ctxt)) { + xmlXPathFreeNodeSet(arg2); + return; + } + + ret = xmlXPathDifference(arg1, arg2); + + if (ret != arg1) + xmlXPathFreeNodeSet(arg1); + xmlXPathFreeNodeSet(arg2); + + xmlXPathReturnNodeSet(ctxt, ret); +} + +/** + * exsltSetsIntersectionFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Wraps #xmlXPathIntersection for use by the XPath processor + */ +static void +exsltSetsIntersectionFunction (xmlXPathParserContextPtr ctxt, int nargs) { + xmlNodeSetPtr arg1, arg2, ret; + + if (nargs != 2) { + xmlXPathSetArityError(ctxt); + return; + } + + arg2 = xmlXPathPopNodeSet(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + + arg1 = xmlXPathPopNodeSet(ctxt); + if (xmlXPathCheckError(ctxt)) { + xmlXPathFreeNodeSet(arg2); + return; + } + + ret = xmlXPathIntersection(arg1, arg2); + + xmlXPathFreeNodeSet(arg1); + xmlXPathFreeNodeSet(arg2); + + xmlXPathReturnNodeSet(ctxt, ret); +} + +/** + * exsltSetsDistinctFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Wraps #xmlXPathDistinct for use by the XPath processor + */ +static void +exsltSetsDistinctFunction (xmlXPathParserContextPtr ctxt, int nargs) { + xmlXPathObjectPtr obj; + xmlNodeSetPtr ns, ret; + int boolval = 0; + void *user = NULL; + + if (nargs != 1) { + xmlXPathSetArityError(ctxt); + return; + } + + if (ctxt->value != NULL) { + boolval = ctxt->value->boolval; + user = ctxt->value->user; + ctxt->value->boolval = 0; + ctxt->value->user = NULL; + } + ns = xmlXPathPopNodeSet(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + + /* !!! must be sorted !!! */ + ret = xmlXPathDistinctSorted(ns); + + if (ret != ns) + xmlXPathFreeNodeSet(ns); + + obj = xmlXPathWrapNodeSet(ret); + if (obj != NULL) { + obj->user = user; + obj->boolval = boolval; + } + valuePush(ctxt, obj); +} + +/** + * exsltSetsHasSameNodesFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Wraps #xmlXPathHasSameNodes for use by the XPath processor + */ +static void +exsltSetsHasSameNodesFunction (xmlXPathParserContextPtr ctxt, + int nargs) { + xmlNodeSetPtr arg1, arg2; + int ret; + + if (nargs != 2) { + xmlXPathSetArityError(ctxt); + return; + } + + arg2 = xmlXPathPopNodeSet(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + + arg1 = xmlXPathPopNodeSet(ctxt); + if (xmlXPathCheckError(ctxt)) { + xmlXPathFreeNodeSet(arg2); + return; + } + + ret = xmlXPathHasSameNodes(arg1, arg2); + + xmlXPathFreeNodeSet(arg1); + xmlXPathFreeNodeSet(arg2); + + xmlXPathReturnBoolean(ctxt, ret); +} + +/** + * exsltSetsLeadingFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Wraps #xmlXPathLeading for use by the XPath processor + */ +static void +exsltSetsLeadingFunction (xmlXPathParserContextPtr ctxt, int nargs) { + xmlNodeSetPtr arg1, arg2, ret; + + if (nargs != 2) { + xmlXPathSetArityError(ctxt); + return; + } + + arg2 = xmlXPathPopNodeSet(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + + arg1 = xmlXPathPopNodeSet(ctxt); + if (xmlXPathCheckError(ctxt)) { + xmlXPathFreeNodeSet(arg2); + return; + } + + /* If the second node set is empty, then the first node set is + * returned. + */ + if (xmlXPathNodeSetIsEmpty(arg2)) { + xmlXPathReturnNodeSet(ctxt, arg1); + + xmlXPathFreeNodeSet(arg2); + + return; + } + /* !!! must be sorted */ + ret = xmlXPathNodeLeadingSorted(arg1, xmlXPathNodeSetItem(arg2, 0)); + + xmlXPathFreeNodeSet(arg1); + xmlXPathFreeNodeSet(arg2); + + xmlXPathReturnNodeSet(ctxt, ret); +} + +/** + * exsltSetsTrailingFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Wraps #xmlXPathTrailing for use by the XPath processor + */ +static void +exsltSetsTrailingFunction (xmlXPathParserContextPtr ctxt, int nargs) { + xmlNodeSetPtr arg1, arg2, ret; + + if (nargs != 2) { + xmlXPathSetArityError(ctxt); + return; + } + + arg2 = xmlXPathPopNodeSet(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + + arg1 = xmlXPathPopNodeSet(ctxt); + if (xmlXPathCheckError(ctxt)) { + xmlXPathFreeNodeSet(arg2); + return; + } + + /* If the second node set is empty, then the first node set is + * returned. + */ + if (xmlXPathNodeSetIsEmpty(arg2)) { + xmlXPathReturnNodeSet(ctxt, arg1); + + xmlXPathFreeNodeSet(arg2); + + return; + } + /* !!! mist be sorted */ + ret = xmlXPathNodeTrailingSorted(arg1, xmlXPathNodeSetItem(arg2, 0)); + + xmlXPathFreeNodeSet(arg1); + xmlXPathFreeNodeSet(arg2); + + xmlXPathReturnNodeSet(ctxt, ret); +} + +/** + * exsltSetsRegister: + * + * Registers the EXSLT - Sets module + */ + +void +exsltSetsRegister (void) { + xsltRegisterExtModuleFunction ((const xmlChar *) "difference", + EXSLT_SETS_NAMESPACE, + exsltSetsDifferenceFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "intersection", + EXSLT_SETS_NAMESPACE, + exsltSetsIntersectionFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "distinct", + EXSLT_SETS_NAMESPACE, + exsltSetsDistinctFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "has-same-node", + EXSLT_SETS_NAMESPACE, + exsltSetsHasSameNodesFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "leading", + EXSLT_SETS_NAMESPACE, + exsltSetsLeadingFunction); + xsltRegisterExtModuleFunction ((const xmlChar *) "trailing", + EXSLT_SETS_NAMESPACE, + exsltSetsTrailingFunction); +} + +/** + * exsltSetsXpathCtxtRegister: + * + * Registers the EXSLT - Sets module for use outside XSLT + */ +int +exsltSetsXpathCtxtRegister (xmlXPathContextPtr ctxt, const xmlChar *prefix) +{ + if (ctxt + && prefix + && !xmlXPathRegisterNs(ctxt, + prefix, + (const xmlChar *) EXSLT_SETS_NAMESPACE) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "difference", + (const xmlChar *) EXSLT_SETS_NAMESPACE, + exsltSetsDifferenceFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "intersection", + (const xmlChar *) EXSLT_SETS_NAMESPACE, + exsltSetsIntersectionFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "distinct", + (const xmlChar *) EXSLT_SETS_NAMESPACE, + exsltSetsDistinctFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "has-same-node", + (const xmlChar *) EXSLT_SETS_NAMESPACE, + exsltSetsHasSameNodesFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "leading", + (const xmlChar *) EXSLT_SETS_NAMESPACE, + exsltSetsLeadingFunction) + && !xmlXPathRegisterFuncNS(ctxt, + (const xmlChar *) "trailing", + (const xmlChar *) EXSLT_SETS_NAMESPACE, + exsltSetsTrailingFunction)) { + return 0; + } + return -1; +} diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libexslt/strings.c chromium-145.0.7632.159/third_party/libxslt/src/libexslt/strings.c --- chromium-145.0.7632.116/third_party/libxslt/src/libexslt/strings.c 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libexslt/strings.c 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,884 @@ +#define IN_LIBEXSLT +#include "libexslt/libexslt.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "exslt.h" + +/** + * exsltStrTokenizeFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Splits up a string on the characters of the delimiter string and returns a + * node set of token elements, each containing one token from the string. + */ +static void +exsltStrTokenizeFunction(xmlXPathParserContextPtr ctxt, int nargs) +{ + xsltTransformContextPtr tctxt; + xmlChar *str, *delimiters, *cur; + const xmlChar *token, *delimiter; + xmlNodePtr node; + xmlDocPtr container; + xmlXPathObjectPtr ret = NULL; + int clen; + + if ((nargs < 1) || (nargs > 2)) { + xmlXPathSetArityError(ctxt); + return; + } + + if (nargs == 2) { + delimiters = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + } else { + delimiters = xmlStrdup((const xmlChar *) "\t\r\n "); + } + if (delimiters == NULL) + return; + + str = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt) || (str == NULL)) { + xmlFree(delimiters); + return; + } + + /* Return a result tree fragment */ + tctxt = xsltXPathGetTransformContext(ctxt); + if (tctxt == NULL) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "exslt:tokenize : internal error tctxt == NULL\n"); + goto fail; + } + + container = xsltCreateRVT(tctxt); + if (container != NULL) { + xsltRegisterLocalRVT(tctxt, container); + ret = xmlXPathNewNodeSet(NULL); + if (ret != NULL) { + for (cur = str, token = str; *cur != 0; cur += clen) { + clen = xmlUTF8Strsize(cur, 1); + if (*delimiters == 0) { /* empty string case */ + xmlChar ctmp; + ctmp = *(cur+clen); + *(cur+clen) = 0; + node = xmlNewDocRawNode(container, NULL, + (const xmlChar *) "token", cur); + xmlAddChild((xmlNodePtr) container, node); + xmlXPathNodeSetAddUnique(ret->nodesetval, node); + *(cur+clen) = ctmp; /* restore the changed byte */ + token = cur + clen; + } else for (delimiter = delimiters; *delimiter != 0; + delimiter += xmlUTF8Strsize(delimiter, 1)) { + if (!xmlUTF8Charcmp(cur, delimiter)) { + if (cur == token) { + /* discard empty tokens */ + token = cur + clen; + break; + } + *cur = 0; /* terminate the token */ + node = xmlNewDocRawNode(container, NULL, + (const xmlChar *) "token", token); + xmlAddChild((xmlNodePtr) container, node); + xmlXPathNodeSetAddUnique(ret->nodesetval, node); + *cur = *delimiter; /* restore the changed byte */ + token = cur + clen; + break; + } + } + } + if (token != cur) { + node = xmlNewDocRawNode(container, NULL, + (const xmlChar *) "token", token); + xmlAddChild((xmlNodePtr) container, node); + xmlXPathNodeSetAddUnique(ret->nodesetval, node); + } + } + } + +fail: + if (str != NULL) + xmlFree(str); + if (delimiters != NULL) + xmlFree(delimiters); + if (ret != NULL) + valuePush(ctxt, ret); + else + valuePush(ctxt, xmlXPathNewNodeSet(NULL)); +} + +/** + * exsltStrSplitFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Splits up a string on a delimiting string and returns a node set of token + * elements, each containing one token from the string. + */ +static void +exsltStrSplitFunction(xmlXPathParserContextPtr ctxt, int nargs) { + xsltTransformContextPtr tctxt; + xmlChar *str, *delimiter, *cur; + const xmlChar *token; + xmlNodePtr node; + xmlDocPtr container; + xmlXPathObjectPtr ret = NULL; + int delimiterLength; + + if ((nargs < 1) || (nargs > 2)) { + xmlXPathSetArityError(ctxt); + return; + } + + if (nargs == 2) { + delimiter = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt)) + return; + } else { + delimiter = xmlStrdup((const xmlChar *) " "); + } + if (delimiter == NULL) + return; + delimiterLength = xmlStrlen (delimiter); + + str = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt) || (str == NULL)) { + xmlFree(delimiter); + return; + } + + /* Return a result tree fragment */ + tctxt = xsltXPathGetTransformContext(ctxt); + if (tctxt == NULL) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "exslt:tokenize : internal error tctxt == NULL\n"); + goto fail; + } + + /* + * OPTIMIZE TODO: We are creating an xmlDoc for every split! + */ + container = xsltCreateRVT(tctxt); + if (container != NULL) { + xsltRegisterLocalRVT(tctxt, container); + ret = xmlXPathNewNodeSet(NULL); + if (ret != NULL) { + for (cur = str, token = str; *cur != 0; cur++) { + if (delimiterLength == 0) { + if (cur != token) { + xmlChar tmp = *cur; + *cur = 0; + node = xmlNewDocRawNode(container, NULL, + (const xmlChar *) "token", token); + xmlAddChild((xmlNodePtr) container, node); + xmlXPathNodeSetAddUnique(ret->nodesetval, node); + *cur = tmp; + token++; + } + } + else if (!xmlStrncasecmp(cur, delimiter, delimiterLength)) { + if (cur == token) { + /* discard empty tokens */ + cur = cur + delimiterLength - 1; + token = cur + 1; + continue; + } + *cur = 0; + node = xmlNewDocRawNode(container, NULL, + (const xmlChar *) "token", token); + xmlAddChild((xmlNodePtr) container, node); + xmlXPathNodeSetAddUnique(ret->nodesetval, node); + *cur = *delimiter; + cur = cur + delimiterLength - 1; + token = cur + 1; + } + } + if (token != cur) { + node = xmlNewDocRawNode(container, NULL, + (const xmlChar *) "token", token); + xmlAddChild((xmlNodePtr) container, node); + xmlXPathNodeSetAddUnique(ret->nodesetval, node); + } + } + } + +fail: + if (str != NULL) + xmlFree(str); + if (delimiter != NULL) + xmlFree(delimiter); + if (ret != NULL) + valuePush(ctxt, ret); + else + valuePush(ctxt, xmlXPathNewNodeSet(NULL)); +} + +/** + * exsltStrEncodeUriFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * URI-Escapes a string + */ +static void +exsltStrEncodeUriFunction (xmlXPathParserContextPtr ctxt, int nargs) { + int escape_all = 1, str_len = 0; + xmlChar *str = NULL, *ret = NULL, *tmp; + + if ((nargs < 2) || (nargs > 3)) { + xmlXPathSetArityError(ctxt); + return; + } + + if (nargs >= 3) { + /* check for UTF-8 if encoding was explicitly given; + we don't support anything else yet */ + tmp = xmlXPathPopString(ctxt); + if (xmlUTF8Strlen(tmp) != 5 || xmlStrcmp((const xmlChar *)"UTF-8",tmp)) { + xmlXPathReturnEmptyString(ctxt); + xmlFree(tmp); + return; + } + xmlFree(tmp); + } + + escape_all = xmlXPathPopBoolean(ctxt); + + str = xmlXPathPopString(ctxt); + str_len = xmlUTF8Strlen(str); + + if (str_len <= 0) { + if (str_len < 0) + xsltGenericError(xsltGenericErrorContext, + "exsltStrEncodeUriFunction: invalid UTF-8\n"); + xmlXPathReturnEmptyString(ctxt); + xmlFree(str); + return; + } + + ret = xmlURIEscapeStr(str,(const xmlChar *)(escape_all?"-_.!~*'()":"-_.!~*'();/?:@&=+$,[]")); + xmlXPathReturnString(ctxt, ret); + + if (str != NULL) + xmlFree(str); +} + +/** + * exsltStrDecodeUriFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * reverses URI-Escaping of a string + */ +static void +exsltStrDecodeUriFunction (xmlXPathParserContextPtr ctxt, int nargs) { + int str_len = 0; + xmlChar *str = NULL, *ret = NULL, *tmp; + + if ((nargs < 1) || (nargs > 2)) { + xmlXPathSetArityError(ctxt); + return; + } + + if (nargs >= 2) { + /* check for UTF-8 if encoding was explicitly given; + we don't support anything else yet */ + tmp = xmlXPathPopString(ctxt); + if (xmlUTF8Strlen(tmp) != 5 || xmlStrcmp((const xmlChar *)"UTF-8",tmp)) { + xmlXPathReturnEmptyString(ctxt); + xmlFree(tmp); + return; + } + xmlFree(tmp); + } + + str = xmlXPathPopString(ctxt); + str_len = xmlUTF8Strlen(str); + + if (str_len <= 0) { + if (str_len < 0) + xsltGenericError(xsltGenericErrorContext, + "exsltStrDecodeUriFunction: invalid UTF-8\n"); + xmlXPathReturnEmptyString(ctxt); + xmlFree(str); + return; + } + + ret = (xmlChar *) xmlURIUnescapeString((const char *)str,0,NULL); + if (!xmlCheckUTF8(ret)) { + /* FIXME: instead of throwing away the whole URI, we should + only discard the invalid sequence(s). How to do that? */ + xmlXPathReturnEmptyString(ctxt); + xmlFree(str); + xmlFree(ret); + return; + } + + xmlXPathReturnString(ctxt, ret); + + if (str != NULL) + xmlFree(str); +} + +/** + * exsltStrPaddingFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Creates a padding string of a certain length. + */ +static void +exsltStrPaddingFunction (xmlXPathParserContextPtr ctxt, int nargs) { + int number, str_len = 0, str_size = 0; + double floatval; + xmlChar *str = NULL; + xmlBufferPtr buf; + + if ((nargs < 1) || (nargs > 2)) { + xmlXPathSetArityError(ctxt); + return; + } + + if (nargs == 2) { + str = xmlXPathPopString(ctxt); + str_len = xmlUTF8Strlen(str); + str_size = xmlStrlen(str); + } + + floatval = xmlXPathPopNumber(ctxt); + + if (str_len <= 0) { + if (str_len < 0) { + xsltGenericError(xsltGenericErrorContext, + "exsltStrPaddingFunction: invalid UTF-8\n"); + xmlXPathReturnEmptyString(ctxt); + xmlFree(str); + return; + } + if (str != NULL) xmlFree(str); + str = xmlStrdup((const xmlChar *) " "); + str_len = 1; + str_size = 1; + } + + if (xmlXPathIsNaN(floatval) || floatval < 0.0) { + number = 0; + } else if (floatval >= 100000.0) { + number = 100000; + } + else { + number = (int) floatval; + } + + if (number <= 0) { + xmlXPathReturnEmptyString(ctxt); + xmlFree(str); + return; + } + + buf = xmlBufferCreateSize(number); + if (buf == NULL) { + xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); + xmlFree(str); + return; + } + xmlBufferSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT); + + while (number >= str_len) { + xmlBufferAdd(buf, str, str_size); + number -= str_len; + } + if (number > 0) { + str_size = xmlUTF8Strsize(str, number); + xmlBufferAdd(buf, str, str_size); + } + + xmlXPathReturnString(ctxt, xmlBufferDetach(buf)); + + xmlBufferFree(buf); + if (str != NULL) + xmlFree(str); +} + +/** + * exsltStrAlignFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Aligns a string within another string. + */ +static void +exsltStrAlignFunction (xmlXPathParserContextPtr ctxt, int nargs) { + xmlChar *str, *padding, *alignment, *ret; + int str_l, padding_l; + + if ((nargs < 2) || (nargs > 3)) { + xmlXPathSetArityError(ctxt); + return; + } + + if (nargs == 3) + alignment = xmlXPathPopString(ctxt); + else + alignment = NULL; + + padding = xmlXPathPopString(ctxt); + str = xmlXPathPopString(ctxt); + + str_l = xmlUTF8Strlen (str); + padding_l = xmlUTF8Strlen (padding); + + if (str_l < 0 || padding_l < 0) { + xsltGenericError(xsltGenericErrorContext, + "exsltStrAlignFunction: invalid UTF-8\n"); + xmlXPathReturnEmptyString(ctxt); + xmlFree(str); + xmlFree(padding); + xmlFree(alignment); + return; + } + + if (str_l == padding_l) { + xmlXPathReturnString (ctxt, str); + xmlFree(padding); + xmlFree(alignment); + return; + } + + if (str_l > padding_l) { + ret = xmlUTF8Strndup (str, padding_l); + } else { + if (xmlStrEqual(alignment, (const xmlChar *) "right")) { + ret = xmlUTF8Strndup (padding, padding_l - str_l); + ret = xmlStrcat (ret, str); + } else if (xmlStrEqual(alignment, (const xmlChar *) "center")) { + int left = (padding_l - str_l) / 2; + int right_start; + + ret = xmlUTF8Strndup (padding, left); + ret = xmlStrcat (ret, str); + + right_start = xmlUTF8Strsize (padding, left + str_l); + ret = xmlStrcat (ret, padding + right_start); + } else { + int str_s; + + str_s = xmlUTF8Strsize(padding, str_l); + ret = xmlStrdup (str); + ret = xmlStrcat (ret, padding + str_s); + } + } + + xmlXPathReturnString (ctxt, ret); + + xmlFree(str); + xmlFree(padding); + xmlFree(alignment); +} + +/** + * exsltStrConcatFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Takes a node set and returns the concatenation of the string values + * of the nodes in that node set. If the node set is empty, it + * returns an empty string. + */ +static void +exsltStrConcatFunction (xmlXPathParserContextPtr ctxt, int nargs) { + xmlXPathObjectPtr obj; + xmlBufferPtr buf; + int i; + + if (nargs != 1) { + xmlXPathSetArityError(ctxt); + return; + } + + if (!xmlXPathStackIsNodeSet(ctxt)) { + xmlXPathSetTypeError(ctxt); + return; + } + + obj = valuePop (ctxt); + + if (xmlXPathNodeSetIsEmpty(obj->nodesetval)) { + xmlXPathFreeObject(obj); + xmlXPathReturnEmptyString(ctxt); + return; + } + + buf = xmlBufferCreate(); + if (buf == NULL) { + xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); + xmlXPathFreeObject(obj); + return; + } + xmlBufferSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT); + + for (i = 0; i < obj->nodesetval->nodeNr; i++) { + xmlChar *tmp; + tmp = xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]); + + xmlBufferCat(buf, tmp); + + xmlFree(tmp); + } + + xmlXPathFreeObject (obj); + + xmlXPathReturnString(ctxt, xmlBufferDetach(buf)); + xmlBufferFree(buf); +} + +/** + * exsltStrReturnString: + * @ctxt: an XPath parser context + * @str: a string + * @len: length of string + * + * Returns a string as a node set. + */ +static int +exsltStrReturnString(xmlXPathParserContextPtr ctxt, const xmlChar *str, + int len) +{ + xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt); + xmlDocPtr container; + xmlNodePtr text_node; + xmlXPathObjectPtr ret; + + container = xsltCreateRVT(tctxt); + if (container == NULL) { + xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); + return(-1); + } + xsltRegisterLocalRVT(tctxt, container); + + text_node = xmlNewTextLen(str, len); + if (text_node == NULL) { + xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); + return(-1); + } + xmlAddChild((xmlNodePtr) container, text_node); + + ret = xmlXPathNewNodeSet(text_node); + if (ret == NULL) { + xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); + return(-1); + } + + valuePush(ctxt, ret); + + return(0); +} + +/** + * exsltStrReplaceFunction: + * @ctxt: an XPath parser context + * @nargs: the number of arguments + * + * Takes a string, and two node sets and returns the string with all strings in + * the first node set replaced by all strings in the second node set. + */ +static void +exsltStrReplaceFunction (xmlXPathParserContextPtr ctxt, int nargs) { + int i, i_empty, n, slen0, rlen0, *slen, *rlen; + void *mem = NULL; + const xmlChar *src, *start; + xmlChar *string, *search_str = NULL, *replace_str = NULL; + xmlChar **search, **replace; + xmlNodeSetPtr search_set = NULL, replace_set = NULL; + xmlBufferPtr buf; + + if (nargs != 3) { + xmlXPathSetArityError(ctxt); + return; + } + + /* get replace argument */ + + if (!xmlXPathStackIsNodeSet(ctxt)) + replace_str = xmlXPathPopString(ctxt); + else + replace_set = xmlXPathPopNodeSet(ctxt); + + if (xmlXPathCheckError(ctxt)) + goto fail_replace; + + /* get search argument */ + + if (!xmlXPathStackIsNodeSet(ctxt)) { + search_str = xmlXPathPopString(ctxt); + n = 1; + } + else { + search_set = xmlXPathPopNodeSet(ctxt); + n = search_set != NULL ? search_set->nodeNr : 0; + } + + if (xmlXPathCheckError(ctxt)) + goto fail_search; + + /* get string argument */ + + string = xmlXPathPopString(ctxt); + if (xmlXPathCheckError(ctxt)) + goto fail_string; + + /* check for empty search node list */ + + if (n <= 0) { + exsltStrReturnString(ctxt, string, xmlStrlen(string)); + goto done_empty_search; + } + + /* allocate memory for string pointer and length arrays */ + + if (n == 1) { + search = &search_str; + replace = &replace_str; + slen = &slen0; + rlen = &rlen0; + } + else { + mem = xmlMalloc(2 * n * (sizeof(const xmlChar *) + sizeof(int))); + if (mem == NULL) { + xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); + goto fail_malloc; + } + search = (xmlChar **) mem; + replace = search + n; + slen = (int *) (replace + n); + rlen = slen + n; + } + + /* process arguments */ + + i_empty = -1; + + for (i=0; inodeTab[i]); + if (search[i] == NULL) { + n = i; + goto fail_process_args; + } + } + + slen[i] = xmlStrlen(search[i]); + if (i_empty < 0 && slen[i] == 0) + i_empty = i; + + if (replace_set != NULL) { + if (i < replace_set->nodeNr) { + replace[i] = xmlXPathCastNodeToString(replace_set->nodeTab[i]); + if (replace[i] == NULL) { + n = i + 1; + goto fail_process_args; + } + } + else + replace[i] = NULL; + } + else { + if (i == 0) + replace[i] = replace_str; + else + replace[i] = NULL; + } + + if (replace[i] == NULL) + rlen[i] = 0; + else + rlen[i] = xmlStrlen(replace[i]); + } + + if (i_empty >= 0 && rlen[i_empty] == 0) + i_empty = -1; + + /* replace operation */ + + buf = xmlBufferCreate(); + if (buf == NULL) { + xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); + goto fail_buffer; + } + xmlBufferSetAllocationScheme(buf, XML_BUFFER_ALLOC_DOUBLEIT); + src = string; + start = string; + + while (*src != 0) { + int max_len = 0, i_match = 0; + + for (i=0; i max_len && + xmlStrncmp(src, search[i], slen[i]) == 0) + { + i_match = i; + max_len = slen[i]; + } + } + + if (max_len == 0) { + if (i_empty >= 0 && start < src) { + if (xmlBufferAdd(buf, start, src - start) || + xmlBufferAdd(buf, replace[i_empty], rlen[i_empty])) + { + xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); + goto fail_buffer_add; + } + start = src; + } + + src += xmlUTF8Strsize(src, 1); + } + else { + if ((start < src && + xmlBufferAdd(buf, start, src - start)) || + (rlen[i_match] && + xmlBufferAdd(buf, replace[i_match], rlen[i_match]))) + { + xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); + goto fail_buffer_add; + } + + src += slen[i_match]; + start = src; + } + } + + if (start < src && xmlBufferAdd(buf, start, src - start)) { + xmlXPathSetError(ctxt, XPATH_MEMORY_ERROR); + goto fail_buffer_add; + } + + /* create result node set */ + + exsltStrReturnString(ctxt, xmlBufferContent(buf), xmlBufferLength(buf)); + + /* clean up */ + +fail_buffer_add: + xmlBufferFree(buf); + +fail_buffer: +fail_process_args: + if (search_set != NULL) { + for (i=0; i + +#include +#include +#include +#include +#include +#include +#include "xslt.h" +#include "xsltInternals.h" +#include "xsltutils.h" +#include "attributes.h" +#include "namespaces.h" +#include "templates.h" +#include "imports.h" +#include "transform.h" +#include "preproc.h" + +#define WITH_XSLT_DEBUG_ATTRIBUTES +#ifdef WITH_XSLT_DEBUG +#define WITH_XSLT_DEBUG_ATTRIBUTES +#endif + +/* + * Useful macros + */ +#ifdef IS_BLANK +#undef IS_BLANK +#endif + +#define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \ + ((c) == 0x0D)) + +#define IS_BLANK_NODE(n) \ + (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content))) + +#define ATTRSET_UNRESOLVED 0 +#define ATTRSET_RESOLVING 1 +#define ATTRSET_RESOLVED 2 + + +/* + * The in-memory structure corresponding to an XSLT Attribute in + * an attribute set + */ + + +typedef struct _xsltAttrElem xsltAttrElem; +typedef xsltAttrElem *xsltAttrElemPtr; +struct _xsltAttrElem { + struct _xsltAttrElem *next;/* chained list */ + xmlNodePtr attr; /* the xsl:attribute definition */ +}; + +typedef struct _xsltUseAttrSet xsltUseAttrSet; +typedef xsltUseAttrSet *xsltUseAttrSetPtr; +struct _xsltUseAttrSet { + struct _xsltUseAttrSet *next; /* chained list */ + const xmlChar *ncname; + const xmlChar *ns; +}; + +typedef struct _xsltAttrSet xsltAttrSet; +typedef xsltAttrSet *xsltAttrSetPtr; +struct _xsltAttrSet { + int state; + xsltAttrElemPtr attrs; /* list head */ + xsltUseAttrSetPtr useAttrSets; /* list head */ +}; + +typedef struct _xsltAttrSetContext xsltAttrSetContext; +typedef xsltAttrSetContext *xsltAttrSetContextPtr; +struct _xsltAttrSetContext { + xsltStylesheetPtr topStyle; + xsltStylesheetPtr style; + int error; +}; + +static void +xsltResolveAttrSet(xsltAttrSetPtr set, xsltStylesheetPtr topStyle, + xsltStylesheetPtr style, const xmlChar *name, + const xmlChar *ns, int depth); + +/************************************************************************ + * * + * XSLT Attribute handling * + * * + ************************************************************************/ + +/** + * xsltNewAttrElem: + * @attr: the new xsl:attribute node + * + * Create a new XSLT AttrElem + * + * Returns the newly allocated xsltAttrElemPtr or NULL in case of error + */ +static xsltAttrElemPtr +xsltNewAttrElem(xmlNodePtr attr) { + xsltAttrElemPtr cur; + + cur = (xsltAttrElemPtr) xmlMalloc(sizeof(xsltAttrElem)); + if (cur == NULL) { + xsltGenericError(xsltGenericErrorContext, + "xsltNewAttrElem : malloc failed\n"); + return(NULL); + } + memset(cur, 0, sizeof(xsltAttrElem)); + cur->attr = attr; + return(cur); +} + +/** + * xsltFreeAttrElem: + * @attr: an XSLT AttrElem + * + * Free up the memory allocated by @attr + */ +static void +xsltFreeAttrElem(xsltAttrElemPtr attr) { + xmlFree(attr); +} + +/** + * xsltFreeAttrElemList: + * @list: an XSLT AttrElem list + * + * Free up the memory allocated by @list + */ +static void +xsltFreeAttrElemList(xsltAttrElemPtr list) { + xsltAttrElemPtr next; + + while (list != NULL) { + next = list->next; + xsltFreeAttrElem(list); + list = next; + } +} + +/** + * xsltAddAttrElemList: + * @list: an XSLT AttrElem list + * @attr: the new xsl:attribute node + * + * Add the new attribute to the list. + * + * Returns the new list pointer + */ +static xsltAttrElemPtr +xsltAddAttrElemList(xsltAttrElemPtr list, xmlNodePtr attr) { + xsltAttrElemPtr next, cur; + + if (attr == NULL) + return(list); + if (list == NULL) + return(xsltNewAttrElem(attr)); + cur = list; + while (cur != NULL) { + next = cur->next; + if (next == NULL) { + cur->next = xsltNewAttrElem(attr); + return(list); + } + cur = next; + } + return(list); +} + +/** + * xsltNewUseAttrSet: + * @ncname: local name + * @ns: namespace URI + * + * Create a new XSLT UseAttrSet + * + * Returns the newly allocated xsltUseAttrSetPtr or NULL in case of error. + */ +static xsltUseAttrSetPtr +xsltNewUseAttrSet(const xmlChar *ncname, const xmlChar *ns) { + xsltUseAttrSetPtr cur; + + cur = (xsltUseAttrSetPtr) xmlMalloc(sizeof(xsltUseAttrSet)); + if (cur == NULL) { + xsltGenericError(xsltGenericErrorContext, + "xsltNewUseAttrSet : malloc failed\n"); + return(NULL); + } + memset(cur, 0, sizeof(xsltUseAttrSet)); + cur->ncname = ncname; + cur->ns = ns; + return(cur); +} + +/** + * xsltFreeUseAttrSet: + * @use: an XSLT UseAttrSet + * + * Free up the memory allocated by @use + */ +static void +xsltFreeUseAttrSet(xsltUseAttrSetPtr use) { + xmlFree(use); +} + +/** + * xsltFreeUseAttrSetList: + * @list: an XSLT UseAttrSet list + * + * Free up the memory allocated by @list + */ +static void +xsltFreeUseAttrSetList(xsltUseAttrSetPtr list) { + xsltUseAttrSetPtr next; + + while (list != NULL) { + next = list->next; + xsltFreeUseAttrSet(list); + list = next; + } +} + +/** + * xsltAddUseAttrSetList: + * @list: a xsltUseAttrSet list + * @ncname: local name + * @ns: namespace URI + * + * Add the use-attribute-set name to the list. + * + * Returns the new list pointer. + */ +static xsltUseAttrSetPtr +xsltAddUseAttrSetList(xsltUseAttrSetPtr list, const xmlChar *ncname, + const xmlChar *ns) { + xsltUseAttrSetPtr next, cur; + + if (ncname == NULL) + return(list); + if (list == NULL) + return(xsltNewUseAttrSet(ncname, ns)); + cur = list; + while (cur != NULL) { + if ((cur->ncname == ncname) && (cur->ns == ns)) + return(list); + next = cur->next; + if (next == NULL) { + cur->next = xsltNewUseAttrSet(ncname, ns); + return(list); + } + cur = next; + } + return(list); +} + +/** + * xsltNewAttrSet: + * + * Create a new attribute set. + * + * Returns the newly allocated xsltAttrSetPtr or NULL in case of error. + */ +static xsltAttrSetPtr +xsltNewAttrSet(void) { + xsltAttrSetPtr cur; + + cur = (xsltAttrSetPtr) xmlMalloc(sizeof(xsltAttrSet)); + if (cur == NULL) { + xsltGenericError(xsltGenericErrorContext, + "xsltNewAttrSet : malloc failed\n"); + return(NULL); + } + memset(cur, 0, sizeof(xsltAttrSet)); + return(cur); +} + +/** + * xsltFreeAttrSet: + * @set: an attribute set + * + * Free memory allocated by @set + */ +static void +xsltFreeAttrSet(xsltAttrSetPtr set) { + if (set == NULL) + return; + + xsltFreeAttrElemList(set->attrs); + xsltFreeUseAttrSetList(set->useAttrSets); + xmlFree(set); +} + +/** + * xsltMergeAttrSets: + * @set: an attribute set + * @other: another attribute set + * + * Add all the attributes from @other to @set, + * but drop redefinition of existing values. + */ +static void +xsltMergeAttrSets(xsltAttrSetPtr set, xsltAttrSetPtr other) { + xsltAttrElemPtr cur; + xsltAttrElemPtr old = other->attrs; + int add; + + while (old != NULL) { + /* + * Check that the attribute is not yet in the list + */ + cur = set->attrs; + add = 1; + while (cur != NULL) { + xsltStylePreCompPtr curComp = cur->attr->psvi; + xsltStylePreCompPtr oldComp = old->attr->psvi; + + if ((curComp->name == oldComp->name) && + (curComp->ns == oldComp->ns)) { + add = 0; + break; + } + if (cur->next == NULL) + break; + cur = cur->next; + } + + if (add == 1) { + if (cur == NULL) { + set->attrs = xsltNewAttrElem(old->attr); + } else if (add) { + cur->next = xsltNewAttrElem(old->attr); + } + } + + old = old->next; + } +} + +/************************************************************************ + * * + * Module interfaces * + * * + ************************************************************************/ + +/** + * xsltParseStylesheetAttributeSet: + * @style: the XSLT stylesheet + * @cur: the "attribute-set" element + * + * parse an XSLT stylesheet attribute-set element + */ + +void +xsltParseStylesheetAttributeSet(xsltStylesheetPtr style, xmlNodePtr cur) { + const xmlChar *ncname; + const xmlChar *prefix; + const xmlChar *nsUri = NULL; + xmlChar *value; + xmlNodePtr child; + xsltAttrSetPtr set; + + if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE)) + return; + + value = xmlGetNsProp(cur, (const xmlChar *)"name", NULL); + if ((value == NULL) || (*value == 0)) { + xsltGenericError(xsltGenericErrorContext, + "xsl:attribute-set : name is missing\n"); + if (value) + xmlFree(value); + return; + } + + if (xmlValidateQName(value, 0)) { + xsltTransformError(NULL, style, cur, + "xsl:attribute-set : The name '%s' is not a valid QName.\n", + value); + style->errors++; + xmlFree(value); + return; + } + + ncname = xsltSplitQName(style->dict, value, &prefix); + xmlFree(value); + value = NULL; + if (prefix != NULL) { + xmlNsPtr ns = xmlSearchNs(style->doc, cur, prefix); + if (ns == NULL) { + xsltTransformError(NULL, style, cur, + "xsl:attribute-set : No namespace found for QName '%s:%s'\n", + prefix, ncname); + style->errors++; + return; + } + nsUri = ns->href; + } + + if (style->attributeSets == NULL) { +#ifdef WITH_XSLT_DEBUG_ATTRIBUTES + xsltGenericDebug(xsltGenericDebugContext, + "creating attribute set table\n"); +#endif + style->attributeSets = xmlHashCreate(10); + } + if (style->attributeSets == NULL) + return; + + set = xmlHashLookup2(style->attributeSets, ncname, nsUri); + if (set == NULL) { + set = xsltNewAttrSet(); + if ((set == NULL) || + (xmlHashAddEntry2(style->attributeSets, ncname, nsUri, set) < 0)) { + xsltGenericError(xsltGenericErrorContext, "memory error\n"); + xsltFreeAttrSet(set); + return; + } + } + + /* + * Parse the content. Only xsl:attribute elements are allowed. + */ + child = cur->children; + while (child != NULL) { + /* + * Report invalid nodes. + */ + if ((child->type != XML_ELEMENT_NODE) || + (child->ns == NULL) || + (! IS_XSLT_ELEM(child))) + { + if (child->type == XML_ELEMENT_NODE) + xsltTransformError(NULL, style, child, + "xsl:attribute-set : unexpected child %s\n", + child->name); + else + xsltTransformError(NULL, style, child, + "xsl:attribute-set : child of unexpected type\n"); + } else if (!IS_XSLT_NAME(child, "attribute")) { + xsltTransformError(NULL, style, child, + "xsl:attribute-set : unexpected child xsl:%s\n", + child->name); + } else { +#ifdef WITH_XSLT_DEBUG_ATTRIBUTES + xsltGenericDebug(xsltGenericDebugContext, + "add attribute to list %s\n", ncname); +#endif + xsltStylePreCompute(style, child); + if (child->children != NULL) { +#ifdef XSLT_REFACTORED + xsltParseSequenceConstructor(XSLT_CCTXT(style), + child->children); +#else + xsltParseTemplateContent(style, child); +#endif + } + if (child->psvi == NULL) { + xsltTransformError(NULL, style, child, + "xsl:attribute-set : internal error, attribute %s not " + "compiled\n", child->name); + } + else { + set->attrs = xsltAddAttrElemList(set->attrs, child); + } + } + + child = child->next; + } + + /* + * Process attribute "use-attribute-sets". + */ + value = xmlGetNsProp(cur, BAD_CAST "use-attribute-sets", NULL); + if (value != NULL) { + const xmlChar *curval, *endval; + curval = value; + while (*curval != 0) { + while (IS_BLANK(*curval)) curval++; + if (*curval == 0) + break; + endval = curval; + while ((*endval != 0) && (!IS_BLANK(*endval))) endval++; + curval = xmlDictLookup(style->dict, curval, endval - curval); + if (curval) { + const xmlChar *ncname2 = NULL; + const xmlChar *prefix2 = NULL; + const xmlChar *nsUri2 = NULL; + +#ifdef WITH_XSLT_DEBUG_ATTRIBUTES + xsltGenericDebug(xsltGenericDebugContext, + "xsl:attribute-set : %s adds use %s\n", ncname, curval); +#endif + + if (xmlValidateQName(curval, 0)) { + xsltTransformError(NULL, style, cur, + "xsl:attribute-set : The name '%s' in " + "use-attribute-sets is not a valid QName.\n", curval); + style->errors++; + xmlFree(value); + return; + } + + ncname2 = xsltSplitQName(style->dict, curval, &prefix2); + if (prefix2 != NULL) { + xmlNsPtr ns2 = xmlSearchNs(style->doc, cur, prefix2); + if (ns2 == NULL) { + xsltTransformError(NULL, style, cur, + "xsl:attribute-set : No namespace found for QName " + "'%s:%s' in use-attribute-sets\n", + prefix2, ncname2); + style->errors++; + xmlFree(value); + return; + } + nsUri2 = ns2->href; + } + set->useAttrSets = xsltAddUseAttrSetList(set->useAttrSets, + ncname2, nsUri2); + } + curval = endval; + } + xmlFree(value); + value = NULL; + } + +#ifdef WITH_XSLT_DEBUG_ATTRIBUTES + xsltGenericDebug(xsltGenericDebugContext, + "updated attribute list %s\n", ncname); +#endif +} + +/** + * xsltResolveUseAttrSets: + * @set: the attribute set + * @asctx: the context for attribute set resolution + * @depth: recursion depth + * + * Process "use-attribute-sets". + */ +static void +xsltResolveUseAttrSets(xsltAttrSetPtr set, xsltStylesheetPtr topStyle, + int depth) { + xsltStylesheetPtr cur; + xsltAttrSetPtr other; + xsltUseAttrSetPtr use = set->useAttrSets; + xsltUseAttrSetPtr next; + + while (use != NULL) { + /* + * Iterate top stylesheet and all imports. + */ + cur = topStyle; + while (cur != NULL) { + if (cur->attributeSets) { + other = xmlHashLookup2(cur->attributeSets, use->ncname, + use->ns); + if (other != NULL) { + xsltResolveAttrSet(other, topStyle, cur, use->ncname, + use->ns, depth + 1); + xsltMergeAttrSets(set, other); + break; + } + } + cur = xsltNextImport(cur); + } + + next = use->next; + /* Free useAttrSets early. */ + xsltFreeUseAttrSet(use); + use = next; + } + + set->useAttrSets = NULL; +} + +/** + * xsltResolveAttrSet: + * @set: the attribute set + * @asctx: the context for attribute set resolution + * @name: the local name of the attirbute set + * @ns: the namespace of the attribute set + * @depth: recursion depth + * + * resolve the references in an attribute set. + */ +static void +xsltResolveAttrSet(xsltAttrSetPtr set, xsltStylesheetPtr topStyle, + xsltStylesheetPtr style, const xmlChar *name, + const xmlChar *ns, int depth) { + xsltStylesheetPtr cur; + xsltAttrSetPtr other; + + if (set->state == ATTRSET_RESOLVED) + return; + if (set->state == ATTRSET_RESOLVING) { + xsltTransformError(NULL, topStyle, NULL, + "xsl:attribute-set : use-attribute-sets recursion detected" + " on %s\n", name); + topStyle->errors++; + set->state = ATTRSET_RESOLVED; + return; + } + if (depth > 100) { + xsltTransformError(NULL, topStyle, NULL, + "xsl:attribute-set : use-attribute-sets maximum recursion " + "depth exceeded on %s\n", name); + topStyle->errors++; + return; + } + + set->state = ATTRSET_RESOLVING; + + xsltResolveUseAttrSets(set, topStyle, depth); + + /* Merge imported sets. */ + cur = xsltNextImport(style); + while (cur != NULL) { + if (cur->attributeSets != NULL) { + other = xmlHashLookup2(cur->attributeSets, name, ns); + + if (other != NULL) { +#ifdef WITH_XSLT_DEBUG_ATTRIBUTES + xsltGenericDebug(xsltGenericDebugContext, + "xsl:attribute-set : merging import for %s\n", name); +#endif + xsltResolveUseAttrSets(other, topStyle, depth); + xsltMergeAttrSets(set, other); + xmlHashRemoveEntry2(cur->attributeSets, name, ns, NULL); + xsltFreeAttrSet(other); + } + } + + cur = xsltNextImport(cur); + } + + set->state = ATTRSET_RESOLVED; +} + +/** + * xsltResolveSASCallback: + * @set: the attribute set + * @asctx: the context for attribute set resolution + * @name: the local name of the attirbute set + * @ns: the namespace of the attribute set + * + * resolve the references in an attribute set. + */ +static void +xsltResolveSASCallback(void *payload, void *data, + const xmlChar *name, const xmlChar *ns, + ATTRIBUTE_UNUSED const xmlChar *ignored) { + xsltAttrSetPtr set = (xsltAttrSetPtr) payload; + xsltAttrSetContextPtr asctx = (xsltAttrSetContextPtr) data; + xsltStylesheetPtr topStyle = asctx->topStyle; + xsltStylesheetPtr style = asctx->style; + + if (asctx->error) { + if (style != topStyle) + xsltFreeAttrSet(set); + return; + } + + xsltResolveAttrSet(set, topStyle, style, name, ns, 1); + + /* Move attribute sets to top stylesheet. */ + if (style != topStyle) { + /* + * This imported stylesheet won't be visited anymore. Don't bother + * removing the hash entry. + */ + if (xmlHashAddEntry2(topStyle->attributeSets, name, ns, set) < 0) { + xsltGenericError(xsltGenericErrorContext, + "xsl:attribute-set : internal error, can't move imported " + " attribute set %s\n", name); + asctx->error = 1; + xsltFreeAttrSet(set); + } + } +} + +/** + * xsltResolveStylesheetAttributeSet: + * @style: the XSLT stylesheet + * + * resolve the references between attribute sets. + */ +void +xsltResolveStylesheetAttributeSet(xsltStylesheetPtr style) { + xsltStylesheetPtr cur; + xsltAttrSetContext asctx; + +#ifdef WITH_XSLT_DEBUG_ATTRIBUTES + xsltGenericDebug(xsltGenericDebugContext, + "Resolving attribute sets references\n"); +#endif + asctx.topStyle = style; + asctx.error = 0; + cur = style; + while (cur != NULL) { + if (cur->attributeSets != NULL) { + if (style->attributeSets == NULL) { +#ifdef WITH_XSLT_DEBUG_ATTRIBUTES + xsltGenericDebug(xsltGenericDebugContext, + "creating attribute set table\n"); +#endif + style->attributeSets = xmlHashCreate(10); + } + asctx.style = cur; + xmlHashScanFull(cur->attributeSets, xsltResolveSASCallback, + &asctx); + + if (cur != style) { + /* + * the attribute lists have either been migrated to style + * or freed directly in xsltResolveSASCallback() + */ + xmlHashFree(cur->attributeSets, NULL); + cur->attributeSets = NULL; + } + } + cur = xsltNextImport(cur); + } +} + +/** + * xsltAttribute: + * @ctxt: a XSLT process context + * @contextNode: the current node in the source tree + * @inst: the xsl:attribute element + * @castedComp: precomputed information + * + * Process the xslt attribute node on the source node + */ +void +xsltAttribute(xsltTransformContextPtr ctxt, + xmlNodePtr contextNode, + xmlNodePtr inst, + xsltElemPreCompPtr castedComp) +{ +#ifdef XSLT_REFACTORED + xsltStyleItemAttributePtr comp = + (xsltStyleItemAttributePtr) castedComp; +#else + xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp; +#endif + xmlNodePtr targetElem; + xmlChar *prop = NULL; + const xmlChar *name = NULL, *prefix = NULL, *nsName = NULL; + xmlChar *value = NULL; + xmlNsPtr ns = NULL; + xmlAttrPtr attr; + + if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL) || + (inst->type != XML_ELEMENT_NODE) ) + return; + + /* + * A comp->has_name == 0 indicates that we need to skip this instruction, + * since it was evaluated to be invalid already during compilation. + */ + if (!comp->has_name) + return; + /* + * BIG NOTE: This previously used xsltGetSpecialNamespace() and + * xsltGetNamespace(), but since both are not appropriate, we + * will process namespace lookup here to avoid adding yet another + * ns-lookup function to namespaces.c. + */ + /* + * SPEC XSLT 1.0: Error cases: + * - Creating nodes other than text nodes during the instantiation of + * the content of the xsl:attribute element; implementations may + * either signal the error or ignore the offending nodes." + */ + + if (comp == NULL) { + xsltTransformError(ctxt, NULL, inst, + "Internal error in xsltAttribute(): " + "The XSLT 'attribute' instruction was not compiled.\n"); + return; + } + /* + * TODO: Shouldn't ctxt->insert == NULL be treated as an internal error? + * So report an internal error? + */ + if (ctxt->insert == NULL) + return; + /* + * SPEC XSLT 1.0: + * "Adding an attribute to a node that is not an element; + * implementations may either signal the error or ignore the attribute." + * + * TODO: I think we should signal such errors in the future, and maybe + * provide an option to ignore such errors. + */ + targetElem = ctxt->insert; + if (targetElem->type != XML_ELEMENT_NODE) + return; + + /* + * SPEC XSLT 1.0: + * "Adding an attribute to an element after children have been added + * to it; implementations may either signal the error or ignore the + * attribute." + * + * TODO: We should decide whether not to report such errors or + * to ignore them; note that we *ignore* if the parent is not an + * element, but here we report an error. + */ + if (targetElem->children != NULL) { + /* + * NOTE: Ah! This seems to be intended to support streamed + * result generation!. + */ + xsltTransformError(ctxt, NULL, inst, + "xsl:attribute: Cannot add attributes to an " + "element if children have been already added " + "to the element.\n"); + return; + } + + /* + * Process the name + * ---------------- + */ + +#ifdef WITH_DEBUGGER + if (ctxt->debugStatus != XSLT_DEBUG_NONE) + xslHandleDebugger(inst, contextNode, NULL, ctxt); +#endif + + if (comp->name == NULL) { + /* TODO: fix attr acquisition wrt to the XSLT namespace */ + prop = xsltEvalAttrValueTemplate(ctxt, inst, + (const xmlChar *) "name", XSLT_NAMESPACE); + if (prop == NULL) { + xsltTransformError(ctxt, NULL, inst, + "xsl:attribute: The attribute 'name' is missing.\n"); + goto error; + } + if (xmlValidateQName(prop, 0)) { + xsltTransformError(ctxt, NULL, inst, + "xsl:attribute: The effective name '%s' is not a " + "valid QName.\n", prop); + /* we fall through to catch any further errors, if possible */ + } + + /* + * Reject a name of "xmlns". + */ + if (xmlStrEqual(prop, BAD_CAST "xmlns")) { + xsltTransformError(ctxt, NULL, inst, + "xsl:attribute: The effective name 'xmlns' is not allowed.\n"); + xmlFree(prop); + goto error; + } + + name = xsltSplitQName(ctxt->dict, prop, &prefix); + xmlFree(prop); + } else { + /* + * The "name" value was static. + */ +#ifdef XSLT_REFACTORED + prefix = comp->nsPrefix; + name = comp->name; +#else + name = xsltSplitQName(ctxt->dict, comp->name, &prefix); +#endif + } + + /* + * Process namespace semantics + * --------------------------- + * + * Evaluate the namespace name. + */ + if (comp->has_ns) { + /* + * The "namespace" attribute was existent. + */ + if (comp->ns != NULL) { + /* + * No AVT; just plain text for the namespace name. + */ + if (comp->ns[0] != 0) + nsName = comp->ns; + } else { + xmlChar *tmpNsName; + /* + * Eval the AVT. + */ + /* TODO: check attr acquisition wrt to the XSLT namespace */ + tmpNsName = xsltEvalAttrValueTemplate(ctxt, inst, + (const xmlChar *) "namespace", XSLT_NAMESPACE); + /* + * This fixes bug #302020: The AVT might also evaluate to the + * empty string; this means that the empty string also indicates + * "no namespace". + * SPEC XSLT 1.0: + * "If the string is empty, then the expanded-name of the + * attribute has a null namespace URI." + */ + if ((tmpNsName != NULL) && (tmpNsName[0] != 0)) + nsName = xmlDictLookup(ctxt->dict, BAD_CAST tmpNsName, -1); + xmlFree(tmpNsName); + } + + if (xmlStrEqual(nsName, BAD_CAST "http://www.w3.org/2000/xmlns/")) { + xsltTransformError(ctxt, NULL, inst, + "xsl:attribute: Namespace http://www.w3.org/2000/xmlns/ " + "forbidden.\n"); + goto error; + } + if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) { + prefix = BAD_CAST "xml"; + } else if (xmlStrEqual(prefix, BAD_CAST "xml")) { + prefix = NULL; + } + } else if (prefix != NULL) { + /* + * SPEC XSLT 1.0: + * "If the namespace attribute is not present, then the QName is + * expanded into an expanded-name using the namespace declarations + * in effect for the xsl:attribute element, *not* including any + * default namespace declaration." + */ + ns = xmlSearchNs(inst->doc, inst, prefix); + if (ns == NULL) { + /* + * Note that this is treated as an error now (checked with + * Saxon, Xalan-J and MSXML). + */ + xsltTransformError(ctxt, NULL, inst, + "xsl:attribute: The QName '%s:%s' has no " + "namespace binding in scope in the stylesheet; " + "this is an error, since the namespace was not " + "specified by the instruction itself.\n", prefix, name); + } else + nsName = ns->href; + } + + /* + * Find/create a matching ns-decl in the result tree. + */ + ns = NULL; + +#if 0 + if (0) { + /* + * OPTIMIZE TODO: How do we know if we are adding to a + * fragment or to the result tree? + * + * If we are adding to a result tree fragment (i.e., not to the + * actual result tree), we'll don't bother searching for the + * ns-decl, but just store it in the dummy-doc of the result + * tree fragment. + */ + if (nsName != NULL) { + /* + * TODO: Get the doc of @targetElem. + */ + ns = xsltTreeAcquireStoredNs(some doc, nsName, prefix); + } + } +#endif + + if (nsName != NULL) { + /* + * Something about ns-prefixes: + * SPEC XSLT 1.0: + * "XSLT processors may make use of the prefix of the QName specified + * in the name attribute when selecting the prefix used for outputting + * the created attribute as XML; however, they are not required to do + * so and, if the prefix is xmlns, they must not do so" + */ + /* + * xsl:attribute can produce a scenario where the prefix is NULL, + * so generate a prefix. + */ + if ((prefix == NULL) || xmlStrEqual(prefix, BAD_CAST "xmlns")) { + xmlChar *pref = xmlStrdup(BAD_CAST "ns_1"); + + ns = xsltGetSpecialNamespace(ctxt, inst, nsName, pref, targetElem); + + xmlFree(pref); + } else { + ns = xsltGetSpecialNamespace(ctxt, inst, nsName, prefix, + targetElem); + } + if (ns == NULL) { + xsltTransformError(ctxt, NULL, inst, + "Namespace fixup error: Failed to acquire an in-scope " + "namespace binding for the generated attribute '{%s}%s'.\n", + nsName, name); + goto error; + } + } + /* + * Construction of the value + * ------------------------- + */ + if (inst->children == NULL) { + /* + * No content. + * TODO: Do we need to put the empty string in ? + */ + attr = xmlSetNsProp(ctxt->insert, ns, name, (const xmlChar *) ""); + } else if ((inst->children->next == NULL) && + ((inst->children->type == XML_TEXT_NODE) || + (inst->children->type == XML_CDATA_SECTION_NODE))) + { + xmlNodePtr copyTxt; + + /* + * xmlSetNsProp() will take care of duplicates. + */ + attr = xmlSetNsProp(ctxt->insert, ns, name, NULL); + if (attr == NULL) /* TODO: report error ? */ + goto error; + /* + * This was taken over from xsltCopyText() (transform.c). + */ + if (ctxt->internalized && + (ctxt->insert->doc != NULL) && + (ctxt->insert->doc->dict == ctxt->dict)) + { + copyTxt = xmlNewText(NULL); + if (copyTxt == NULL) /* TODO: report error */ + goto error; + /* + * This is a safe scenario where we don't need to lookup + * the dict. + */ + copyTxt->content = inst->children->content; + /* + * Copy "disable-output-escaping" information. + * TODO: Does this have any effect for attribute values + * anyway? + */ + if (inst->children->name == xmlStringTextNoenc) + copyTxt->name = xmlStringTextNoenc; + } else { + /* + * Copy the value. + */ + copyTxt = xmlNewText(inst->children->content); + if (copyTxt == NULL) /* TODO: report error */ + goto error; + } + attr->children = attr->last = copyTxt; + copyTxt->parent = (xmlNodePtr) attr; + copyTxt->doc = attr->doc; + /* + * Copy "disable-output-escaping" information. + * TODO: Does this have any effect for attribute values + * anyway? + */ + if (inst->children->name == xmlStringTextNoenc) + copyTxt->name = xmlStringTextNoenc; + + /* + * since we create the attribute without content IDness must be + * asserted as a second step + */ + if ((copyTxt->content != NULL) && + (xmlIsID(attr->doc, attr->parent, attr))) + xmlAddID(NULL, attr->doc, copyTxt->content, attr); + } else { + /* + * The sequence constructor might be complex, so instantiate it. + */ + value = xsltEvalTemplateString(ctxt, contextNode, inst); + if (value != NULL) { + attr = xmlSetNsProp(ctxt->insert, ns, name, value); + xmlFree(value); + } else { + /* + * TODO: Do we have to add the empty string to the attr? + * TODO: Does a value of NULL indicate an + * error in xsltEvalTemplateString() ? + */ + attr = xmlSetNsProp(ctxt->insert, ns, name, + (const xmlChar *) ""); + } + } + +error: + return; +} + +/** + * xsltApplyAttributeSet: + * @ctxt: the XSLT stylesheet + * @node: the node in the source tree. + * @inst: the attribute node "xsl:use-attribute-sets" + * @attrSets: the list of QNames of the attribute-sets to be applied + * + * Apply the xsl:use-attribute-sets. + * If @attrSets is NULL, then @inst will be used to exctract this + * value. + * If both, @attrSets and @inst, are NULL, then this will do nothing. + */ +void +xsltApplyAttributeSet(xsltTransformContextPtr ctxt, xmlNodePtr node, + xmlNodePtr inst, + const xmlChar *attrSets) +{ + const xmlChar *ncname = NULL; + const xmlChar *prefix = NULL; + const xmlChar *curstr, *endstr; + xsltAttrSetPtr set; + xsltStylesheetPtr style; + + if (attrSets == NULL) { + if (inst == NULL) + return; + else { + /* + * Extract the value from @inst. + */ + if (inst->type == XML_ATTRIBUTE_NODE) { + if ( ((xmlAttrPtr) inst)->children != NULL) + attrSets = ((xmlAttrPtr) inst)->children->content; + + } + if (attrSets == NULL) { + /* + * TODO: Return an error? + */ + return; + } + } + } + /* + * Parse/apply the list of QNames. + */ + curstr = attrSets; + while (*curstr != 0) { + while (IS_BLANK(*curstr)) + curstr++; + if (*curstr == 0) + break; + endstr = curstr; + while ((*endstr != 0) && (!IS_BLANK(*endstr))) + endstr++; + curstr = xmlDictLookup(ctxt->dict, curstr, endstr - curstr); + if (curstr) { + xmlNsPtr ns; + const xmlChar *nsUri = NULL; + +#ifdef WITH_XSLT_DEBUG_ATTRIBUTES + xsltGenericDebug(xsltGenericDebugContext, + "apply attribute set %s\n", curstr); +#endif + + if (xmlValidateQName(curstr, 0)) { + xsltTransformError(ctxt, NULL, inst, + "The name '%s' in use-attribute-sets is not a valid " + "QName.\n", curstr); + return; + } + + ncname = xsltSplitQName(ctxt->dict, curstr, &prefix); + if (prefix != NULL) { + ns = xmlSearchNs(inst->doc, inst, prefix); + if (ns == NULL) { + xsltTransformError(ctxt, NULL, inst, + "use-attribute-set : No namespace found for QName " + "'%s:%s'\n", prefix, ncname); + return; + } + nsUri = ns->href; + } + + style = ctxt->style; + +#ifdef WITH_DEBUGGER + if ((style != NULL) && + (style->attributeSets != NULL) && + (ctxt->debugStatus != XSLT_DEBUG_NONE)) + { + set = xmlHashLookup2(style->attributeSets, ncname, nsUri); + if ((set != NULL) && (set->attrs != NULL) && + (set->attrs->attr != NULL)) + xslHandleDebugger(set->attrs->attr->parent, node, NULL, + ctxt); + } +#endif + /* + * Lookup the referenced attribute-set. All attribute sets were + * moved to the top stylesheet so there's no need to iterate + * imported stylesheets + */ + set = xmlHashLookup2(style->attributeSets, ncname, nsUri); + if (set != NULL) { + xsltAttrElemPtr cur = set->attrs; + while (cur != NULL) { + if (cur->attr != NULL) { + xsltAttribute(ctxt, node, cur->attr, + cur->attr->psvi); + } + cur = cur->next; + } + } + } + curstr = endstr; + } +} + +static void +xsltFreeAttributeSetsEntry(void *payload, + const xmlChar *name ATTRIBUTE_UNUSED) { + xsltFreeAttrSet((xsltAttrSetPtr) payload); +} + +/** + * xsltFreeAttributeSetsHashes: + * @style: an XSLT stylesheet + * + * Free up the memory used by attribute sets + */ +void +xsltFreeAttributeSetsHashes(xsltStylesheetPtr style) { + if (style->attributeSets != NULL) + xmlHashFree((xmlHashTablePtr) style->attributeSets, + xsltFreeAttributeSetsEntry); + style->attributeSets = NULL; +} diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/attributes.h chromium-145.0.7632.159/third_party/libxslt/src/libxslt/attributes.h --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/attributes.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/attributes.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,39 @@ +/* + * Summary: interface for the XSLT attribute handling + * Description: this module handles the specificities of attribute + * and attribute groups processing. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLT_ATTRIBUTES_H__ +#define __XML_XSLT_ATTRIBUTES_H__ + +#include +#include "xsltexports.h" +#include "xsltInternals.h" + +#ifdef __cplusplus +extern "C" { +#endif + +XSLTPUBFUN void XSLTCALL + xsltParseStylesheetAttributeSet (xsltStylesheetPtr style, + xmlNodePtr cur); +XSLTPUBFUN void XSLTCALL + xsltFreeAttributeSetsHashes (xsltStylesheetPtr style); +XSLTPUBFUN void XSLTCALL + xsltApplyAttributeSet (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + const xmlChar *attributes); +XSLTPUBFUN void XSLTCALL + xsltResolveStylesheetAttributeSet(xsltStylesheetPtr style); +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_ATTRIBUTES_H__ */ + diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/attrvt.c chromium-145.0.7632.159/third_party/libxslt/src/libxslt/attrvt.c --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/attrvt.c 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/attrvt.c 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,405 @@ +/* + * attrvt.c: Implementation of the XSL Transformation 1.0 engine + * attribute value template handling part. + * + * References: + * http://www.w3.org/TR/1999/REC-xslt-19991116 + * + * Michael Kay "XSLT Programmer's Reference" pp 637-643 + * Writing Multiple Output Files + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#define IN_LIBXSLT +#include "libxslt.h" + +#include + +#include +#include +#include +#include +#include "xslt.h" +#include "xsltutils.h" +#include "xsltInternals.h" +#include "templates.h" + +#ifdef WITH_XSLT_DEBUG +#define WITH_XSLT_DEBUG_AVT +#endif + +#define MAX_AVT_SEG 10 + +typedef struct _xsltAttrVT xsltAttrVT; +typedef xsltAttrVT *xsltAttrVTPtr; +struct _xsltAttrVT { + struct _xsltAttrVT *next; /* next xsltAttrVT */ + int nb_seg; /* Number of segments */ + int max_seg; /* max capacity before re-alloc needed */ + int strstart; /* is the start a string */ + /* + * the namespaces in scope + */ + xmlNsPtr *nsList; + int nsNr; + /* + * the content is an alternate of string and xmlXPathCompExprPtr + */ +#if __STDC_VERSION__ >= 199901L + /* Using a C99 flexible array member avoids false positives under UBSan */ + void *segments[]; +#else + void *segments[1]; +#endif +}; + +/** + * xsltNewAttrVT: + * @style: a XSLT process context + * + * Build a new xsltAttrVT structure + * + * Returns the structure or NULL in case of error + */ +static xsltAttrVTPtr +xsltNewAttrVT(xsltStylesheetPtr style) { + xsltAttrVTPtr cur; + size_t size = sizeof(xsltAttrVT) + MAX_AVT_SEG * sizeof(void*); + + cur = (xsltAttrVTPtr) xmlMalloc(size); + if (cur == NULL) { + xsltTransformError(NULL, style, NULL, + "xsltNewAttrVTPtr : malloc failed\n"); + if (style != NULL) style->errors++; + return(NULL); + } + memset(cur, 0, size); + + cur->nb_seg = 0; + cur->max_seg = MAX_AVT_SEG; + cur->strstart = 0; + cur->next = style->attVTs; + /* + * Note: this pointer may be changed by a re-alloc within xsltCompileAttr, + * so that code may change the stylesheet pointer also! + */ + style->attVTs = (xsltAttrVTPtr) cur; + + return(cur); +} + +/** + * xsltFreeAttrVT: + * @avt: pointer to an xsltAttrVT structure + * + * Free up the memory associated to the attribute value template + */ +static void +xsltFreeAttrVT(xsltAttrVTPtr avt) { + int i; + + if (avt == NULL) return; + + if (avt->strstart == 1) { + for (i = 0;i < avt->nb_seg; i += 2) + if (avt->segments[i] != NULL) + xmlFree((xmlChar *) avt->segments[i]); + for (i = 1;i < avt->nb_seg; i += 2) + xmlXPathFreeCompExpr((xmlXPathCompExprPtr) avt->segments[i]); + } else { + for (i = 0;i < avt->nb_seg; i += 2) + xmlXPathFreeCompExpr((xmlXPathCompExprPtr) avt->segments[i]); + for (i = 1;i < avt->nb_seg; i += 2) + if (avt->segments[i] != NULL) + xmlFree((xmlChar *) avt->segments[i]); + } + if (avt->nsList != NULL) + xmlFree(avt->nsList); + xmlFree(avt); +} + +/** + * xsltFreeAVTList: + * @avt: pointer to an list of AVT structures + * + * Free up the memory associated to the attribute value templates + */ +void +xsltFreeAVTList(void *avt) { + xsltAttrVTPtr cur = (xsltAttrVTPtr) avt, next; + + while (cur != NULL) { + next = cur->next; + xsltFreeAttrVT(cur); + cur = next; + } +} +/** + * xsltSetAttrVTsegment: + * @ avt: pointer to an xsltAttrVT structure + * @ val: the value to be set to the next available segment + * + * Within xsltCompileAttr there are several places where a value + * needs to be added to the 'segments' array within the xsltAttrVT + * structure, and at each place the allocated size may have to be + * re-allocated. This routine takes care of that situation. + * + * Returns the avt pointer, which may have been changed by a re-alloc + */ +static xsltAttrVTPtr +xsltSetAttrVTsegment(xsltAttrVTPtr avt, void *val) { + if (avt->nb_seg >= avt->max_seg) { + size_t size = sizeof(xsltAttrVT) + + (avt->max_seg + MAX_AVT_SEG) * sizeof(void *); + avt = (xsltAttrVTPtr) xmlRealloc(avt, size); + if (avt == NULL) + return NULL; + memset(&avt->segments[avt->nb_seg], 0, MAX_AVT_SEG*sizeof(void *)); + avt->max_seg += MAX_AVT_SEG; + } + avt->segments[avt->nb_seg++] = val; + return avt; +} + +/** + * xsltCompileAttr: + * @style: a XSLT process context + * @attr: the attribute coming from the stylesheet. + * + * Precompile an attribute in a stylesheet, basically it checks if it is + * an attribute value template, and if yes, establish some structures needed + * to process it at transformation time. + */ +void +xsltCompileAttr(xsltStylesheetPtr style, xmlAttrPtr attr) { + const xmlChar *str; + const xmlChar *cur; + xmlChar *ret = NULL; + xmlChar *expr = NULL; + xmlXPathCompExprPtr comp = NULL; + xsltAttrVTPtr avt, tmp; + int i = 0, lastavt = 0; + + if ((style == NULL) || (attr == NULL) || (attr->children == NULL)) + return; + if ((attr->children->type != XML_TEXT_NODE) || + (attr->children->next != NULL)) { + xsltTransformError(NULL, style, attr->parent, + "Attribute '%s': The content is expected to be a single text " + "node when compiling an AVT.\n", attr->name); + style->errors++; + return; + } + str = attr->children->content; + if ((xmlStrchr(str, '{') == NULL) && + (xmlStrchr(str, '}') == NULL)) return; + +#ifdef WITH_XSLT_DEBUG_AVT + xsltGenericDebug(xsltGenericDebugContext, + "Found AVT %s: %s\n", attr->name, str); +#endif + if (attr->psvi != NULL) { +#ifdef WITH_XSLT_DEBUG_AVT + xsltGenericDebug(xsltGenericDebugContext, + "AVT %s: already compiled\n", attr->name); +#endif + return; + } + /* + * Create a new AVT object. + */ + avt = xsltNewAttrVT(style); + if (avt == NULL) + return; + attr->psvi = avt; + + avt->nsList = xmlGetNsList(attr->doc, attr->parent); + if (avt->nsList != NULL) { + while (avt->nsList[i] != NULL) + i++; + } + avt->nsNr = i; + + cur = str; + while (*cur != 0) { + if (*cur == '{') { + if (*(cur+1) == '{') { /* escaped '{' */ + cur++; + ret = xmlStrncat(ret, str, cur - str); + cur++; + str = cur; + continue; + } + if (*(cur+1) == '}') { /* skip empty AVT */ + ret = xmlStrncat(ret, str, cur - str); + cur += 2; + str = cur; + continue; + } + if ((ret != NULL) || (cur - str > 0)) { + ret = xmlStrncat(ret, str, cur - str); + str = cur; + if (avt->nb_seg == 0) + avt->strstart = 1; + if ((tmp = xsltSetAttrVTsegment(avt, (void *) ret)) == NULL) + goto error; + avt = tmp; + ret = NULL; + lastavt = 0; + } + + cur++; + while ((*cur != 0) && (*cur != '}')) { + /* Need to check for literal (bug539741) */ + if ((*cur == '\'') || (*cur == '"')) { + char delim = *(cur++); + while ((*cur != 0) && (*cur != delim)) + cur++; + if (*cur != 0) + cur++; /* skip the ending delimiter */ + } else + cur++; + } + if (*cur == 0) { + xsltTransformError(NULL, style, attr->parent, + "Attribute '%s': The AVT has an unmatched '{'.\n", + attr->name); + style->errors++; + goto error; + } + str++; + expr = xmlStrndup(str, cur - str); + if (expr == NULL) { + /* + * TODO: What needs to be done here? + */ + XSLT_TODO + goto error; + } else { + comp = xsltXPathCompile(style, expr); + if (comp == NULL) { + xsltTransformError(NULL, style, attr->parent, + "Attribute '%s': Failed to compile the expression " + "'%s' in the AVT.\n", attr->name, expr); + style->errors++; + goto error; + } + if (avt->nb_seg == 0) + avt->strstart = 0; + if (lastavt == 1) { + if ((tmp = xsltSetAttrVTsegment(avt, NULL)) == NULL) { + xsltTransformError(NULL, style, attr->parent, + "out of memory\n"); + goto error; + } + avt = tmp; + } + if ((tmp = xsltSetAttrVTsegment(avt, (void *) comp)) == NULL) { + xsltTransformError(NULL, style, attr->parent, + "out of memory\n"); + goto error; + } + avt = tmp; + lastavt = 1; + xmlFree(expr); + expr = NULL; + comp = NULL; + } + cur++; + str = cur; + } else if (*cur == '}') { + cur++; + if (*cur == '}') { /* escaped '}' */ + ret = xmlStrncat(ret, str, cur - str); + cur++; + str = cur; + continue; + } else { + xsltTransformError(NULL, style, attr->parent, + "Attribute '%s': The AVT has an unmatched '}'.\n", + attr->name); + goto error; + } + } else + cur++; + } + if ((ret != NULL) || (cur - str > 0)) { + ret = xmlStrncat(ret, str, cur - str); + str = cur; + if (avt->nb_seg == 0) + avt->strstart = 1; + if ((tmp = xsltSetAttrVTsegment(avt, (void *) ret)) == NULL) + goto error; + avt = tmp; + ret = NULL; + } + +error: + if (avt == NULL) { + xsltTransformError(NULL, style, attr->parent, + "xsltCompileAttr: malloc problem\n"); + } else { + if (attr->psvi != avt) { /* may have changed from realloc */ + attr->psvi = avt; + /* + * This is a "hack", but I can't see any clean method of + * doing it. If a re-alloc has taken place, then the pointer + * for this AVT may have changed. style->attVTs was set by + * xsltNewAttrVT, so it needs to be re-set to the new value! + */ + style->attVTs = avt; + } + } + if (ret != NULL) + xmlFree(ret); + if (expr != NULL) + xmlFree(expr); + if (comp != NULL) + xmlXPathFreeCompExpr(comp); +} + + +/** + * xsltEvalAVT: + * @ctxt: the XSLT transformation context + * @avt: the prevompiled attribute value template info + * @node: the node hosting the attribute + * + * Process the given AVT, and return the new string value. + * + * Returns the computed string value or NULL, must be deallocated by the + * caller. + */ +xmlChar * +xsltEvalAVT(xsltTransformContextPtr ctxt, void *avt, xmlNodePtr node) { + xmlChar *ret = NULL, *tmp; + xmlXPathCompExprPtr comp; + xsltAttrVTPtr cur = (xsltAttrVTPtr) avt; + int i; + int str; + + if ((ctxt == NULL) || (avt == NULL) || (node == NULL)) + return(NULL); + str = cur->strstart; + for (i = 0;i < cur->nb_seg;i++) { + if (str) { + ret = xmlStrcat(ret, (const xmlChar *) cur->segments[i]); + } else { + comp = (xmlXPathCompExprPtr) cur->segments[i]; + tmp = xsltEvalXPathStringNs(ctxt, comp, cur->nsNr, cur->nsList); + if (tmp != NULL) { + if (ret != NULL) { + ret = xmlStrcat(ret, tmp); + xmlFree(tmp); + } else { + ret = tmp; + } + } + } + str = !str; + } + return(ret); +} diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/documents.c chromium-145.0.7632.159/third_party/libxslt/src/libxslt/documents.c --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/documents.c 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/documents.c 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,442 @@ +/* + * documents.c: Implementation of the documents handling + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#define IN_LIBXSLT +#include "libxslt.h" + +#include + +#include +#include +#include +#include +#include +#include "xslt.h" +#include "xsltInternals.h" +#include "xsltutils.h" +#include "documents.h" +#include "transform.h" +#include "imports.h" +#include "keys.h" +#include "security.h" + +#ifdef LIBXML_XINCLUDE_ENABLED +#include +#endif + +#define WITH_XSLT_DEBUG_DOCUMENTS + +#ifdef WITH_XSLT_DEBUG +#define WITH_XSLT_DEBUG_DOCUMENTS +#endif + +/************************************************************************ + * * + * Hooks for the document loader * + * * + ************************************************************************/ + +/** + * xsltDocDefaultLoaderFunc: + * @URI: the URI of the document to load + * @dict: the dictionary to use when parsing that document + * @options: parsing options, a set of xmlParserOption + * @ctxt: the context, either a stylesheet or a transformation context + * @type: the xsltLoadType indicating the kind of loading required + * + * Default function to load document not provided by the compilation or + * transformation API themselve, for example when an xsl:import, + * xsl:include is found at compilation time or when a document() + * call is made at runtime. + * + * Returns the pointer to the document (which will be modified and + * freed by the engine later), or NULL in case of error. + */ +static xmlDocPtr +xsltDocDefaultLoaderFunc(const xmlChar * URI, xmlDictPtr dict, int options, + void *ctxt ATTRIBUTE_UNUSED, + xsltLoadType type ATTRIBUTE_UNUSED) +{ + xmlParserCtxtPtr pctxt; + xmlParserInputPtr inputStream; + xmlDocPtr doc; + + pctxt = xmlNewParserCtxt(); + if (pctxt == NULL) + return(NULL); + if ((dict != NULL) && (pctxt->dict != NULL)) { + xmlDictFree(pctxt->dict); + pctxt->dict = NULL; + } + if (dict != NULL) { + pctxt->dict = dict; + xmlDictReference(pctxt->dict); +#ifdef WITH_XSLT_DEBUG + xsltGenericDebug(xsltGenericDebugContext, + "Reusing dictionary for document\n"); +#endif + } + xmlCtxtUseOptions(pctxt, options); + inputStream = xmlLoadExternalEntity((const char *) URI, NULL, pctxt); + if (inputStream == NULL) { + xmlFreeParserCtxt(pctxt); + return(NULL); + } + +#if LIBXML_VERSION >= 21300 + doc = xmlCtxtParseDocument(pctxt, inputStream); +#else + inputPush(pctxt, inputStream); + + xmlParseDocument(pctxt); + + if (pctxt->wellFormed) { + doc = pctxt->myDoc; + } + else { + doc = NULL; + xmlFreeDoc(pctxt->myDoc); + pctxt->myDoc = NULL; + } +#endif + + xmlFreeParserCtxt(pctxt); + + return(doc); +} + + +xsltDocLoaderFunc xsltDocDefaultLoader = xsltDocDefaultLoaderFunc; + +/** + * xsltSetLoaderFunc: + * @f: the new function to handle document loading. + * + * Set the new function to load document, if NULL it resets it to the + * default function. + */ + +void +xsltSetLoaderFunc(xsltDocLoaderFunc f) { + if (f == NULL) + xsltDocDefaultLoader = xsltDocDefaultLoaderFunc; + else + xsltDocDefaultLoader = f; +} + +/************************************************************************ + * * + * Module interfaces * + * * + ************************************************************************/ + +/** + * xsltNewDocument: + * @ctxt: an XSLT transformation context (or NULL) + * @doc: a parsed XML document + * + * Register a new document, apply key computations + * + * Returns a handler to the document + */ +xsltDocumentPtr +xsltNewDocument(xsltTransformContextPtr ctxt, xmlDocPtr doc) { + xsltDocumentPtr cur; + + cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument)); + if (cur == NULL) { + xsltTransformError(ctxt, NULL, (xmlNodePtr) doc, + "xsltNewDocument : malloc failed\n"); + return(NULL); + } + memset(cur, 0, sizeof(xsltDocument)); + cur->doc = doc; + if (ctxt != NULL) { + if (! XSLT_IS_RES_TREE_FRAG(doc)) { + cur->next = ctxt->docList; + ctxt->docList = cur; + } + /* + * A key with a specific name for a specific document + * will only be computed if there's a call to the key() + * function using that specific name for that specific + * document. I.e. computation of keys will be done in + * xsltGetKey() (keys.c) on an on-demand basis. + * + * xsltInitCtxtKeys(ctxt, cur); not called here anymore + */ + } + return(cur); +} + +/** + * xsltNewStyleDocument: + * @style: an XSLT style sheet + * @doc: a parsed XML document + * + * Register a new document, apply key computations + * + * Returns a handler to the document + */ +xsltDocumentPtr +xsltNewStyleDocument(xsltStylesheetPtr style, xmlDocPtr doc) { + xsltDocumentPtr cur; + + cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument)); + if (cur == NULL) { + xsltTransformError(NULL, style, (xmlNodePtr) doc, + "xsltNewStyleDocument : malloc failed\n"); + return(NULL); + } + memset(cur, 0, sizeof(xsltDocument)); + cur->doc = doc; + if (style != NULL) { + cur->next = style->docList; + style->docList = cur; + } + return(cur); +} + +/** + * xsltFreeStyleDocuments: + * @style: an XSLT stylesheet (representing a stylesheet-level) + * + * Frees the node-trees (and xsltDocument structures) of all + * stylesheet-modules of the stylesheet-level represented by + * the given @style. + */ +void +xsltFreeStyleDocuments(xsltStylesheetPtr style) { + xsltDocumentPtr doc, cur; +#ifdef XSLT_REFACTORED_XSLT_NSCOMP + xsltNsMapPtr nsMap; +#endif + + if (style == NULL) + return; + +#ifdef XSLT_REFACTORED_XSLT_NSCOMP + if (XSLT_HAS_INTERNAL_NSMAP(style)) + nsMap = XSLT_GET_INTERNAL_NSMAP(style); + else + nsMap = NULL; +#endif + + cur = style->docList; + while (cur != NULL) { + doc = cur; + cur = cur->next; +#ifdef XSLT_REFACTORED_XSLT_NSCOMP + /* + * Restore all changed namespace URIs of ns-decls. + */ + if (nsMap) + xsltRestoreDocumentNamespaces(nsMap, doc->doc); +#endif + xsltFreeDocumentKeys(doc); + if (!doc->main) + xmlFreeDoc(doc->doc); + xmlFree(doc); + } +} + +/** + * xsltFreeDocuments: + * @ctxt: an XSLT transformation context + * + * Free up all the space used by the loaded documents + */ +void +xsltFreeDocuments(xsltTransformContextPtr ctxt) { + xsltDocumentPtr doc, cur; + + cur = ctxt->docList; + while (cur != NULL) { + doc = cur; + cur = cur->next; + xsltFreeDocumentKeys(doc); + if (!doc->main) + xmlFreeDoc(doc->doc); + xmlFree(doc); + } + cur = ctxt->styleList; + while (cur != NULL) { + doc = cur; + cur = cur->next; + xsltFreeDocumentKeys(doc); + if (!doc->main) + xmlFreeDoc(doc->doc); + xmlFree(doc); + } +} + +/** + * xsltLoadDocument: + * @ctxt: an XSLT transformation context + * @URI: the computed URI of the document + * + * Try to load a document (not a stylesheet) + * within the XSLT transformation context + * + * Returns the new xsltDocumentPtr or NULL in case of error + */ +xsltDocumentPtr +xsltLoadDocument(xsltTransformContextPtr ctxt, const xmlChar *URI) { + xsltDocumentPtr ret; + xmlDocPtr doc; + + if ((ctxt == NULL) || (URI == NULL)) + return(NULL); + + /* + * Security framework check + */ + if (ctxt->sec != NULL) { + int res; + + res = xsltCheckRead(ctxt->sec, ctxt, URI); + if (res <= 0) { + if (res == 0) + xsltTransformError(ctxt, NULL, NULL, + "xsltLoadDocument: read rights for %s denied\n", + URI); + return(NULL); + } + } + + /* + * Walk the context list to find the document if preparsed + */ + ret = ctxt->docList; + while (ret != NULL) { + if ((ret->doc != NULL) && (ret->doc->URL != NULL) && + (xmlStrEqual(ret->doc->URL, URI))) + return(ret); + ret = ret->next; + } + + doc = xsltDocDefaultLoader(URI, ctxt->dict, ctxt->parserOptions, + (void *) ctxt, XSLT_LOAD_DOCUMENT); + + if (doc == NULL) + return(NULL); + + if (ctxt->xinclude != 0) { +#ifdef LIBXML_XINCLUDE_ENABLED +#if LIBXML_VERSION >= 20603 + xmlXIncludeProcessFlags(doc, ctxt->parserOptions); +#else + xmlXIncludeProcess(doc); +#endif +#else + xsltTransformError(ctxt, NULL, NULL, + "xsltLoadDocument(%s) : XInclude processing not compiled in\n", + URI); +#endif + } + /* + * Apply white-space stripping if asked for + */ + if (xsltNeedElemSpaceHandling(ctxt)) + xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc)); + if (ctxt->debugStatus == XSLT_DEBUG_NONE) + xmlXPathOrderDocElems(doc); + + ret = xsltNewDocument(ctxt, doc); + return(ret); +} + +/** + * xsltLoadStyleDocument: + * @style: an XSLT style sheet + * @URI: the computed URI of the document + * + * Try to load a stylesheet document within the XSLT transformation context + * + * Returns the new xsltDocumentPtr or NULL in case of error + */ +xsltDocumentPtr +xsltLoadStyleDocument(xsltStylesheetPtr style, const xmlChar *URI) { + xsltDocumentPtr ret; + xmlDocPtr doc; + xsltSecurityPrefsPtr sec; + + if ((style == NULL) || (URI == NULL)) + return(NULL); + + /* + * Security framework check + */ + sec = xsltGetDefaultSecurityPrefs(); + if (sec != NULL) { + int res; + + res = xsltCheckRead(sec, NULL, URI); + if (res <= 0) { + if (res == 0) + xsltTransformError(NULL, NULL, NULL, + "xsltLoadStyleDocument: read rights for %s denied\n", + URI); + return(NULL); + } + } + + /* + * Walk the context list to find the document if preparsed + */ + ret = style->docList; + while (ret != NULL) { + if ((ret->doc != NULL) && (ret->doc->URL != NULL) && + (xmlStrEqual(ret->doc->URL, URI))) + return(ret); + ret = ret->next; + } + + doc = xsltDocDefaultLoader(URI, style->dict, XSLT_PARSE_OPTIONS, + (void *) style, XSLT_LOAD_STYLESHEET); + if (doc == NULL) + return(NULL); + + ret = xsltNewStyleDocument(style, doc); + if (ret == NULL) + xmlFreeDoc(doc); + return(ret); +} + +/** + * xsltFindDocument: + * @ctxt: an XSLT transformation context + * @doc: a parsed XML document + * + * Try to find a document within the XSLT transformation context. + * This will not find document infos for temporary + * Result Tree Fragments. + * + * Returns the desired xsltDocumentPtr or NULL in case of error + */ +xsltDocumentPtr +xsltFindDocument (xsltTransformContextPtr ctxt, xmlDocPtr doc) { + xsltDocumentPtr ret; + + if ((ctxt == NULL) || (doc == NULL)) + return(NULL); + + /* + * Walk the context list to find the document + */ + ret = ctxt->docList; + while (ret != NULL) { + if (ret->doc == doc) + return(ret); + ret = ret->next; + } + if (doc == ctxt->style->doc) + return(ctxt->document); + return(NULL); +} + diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/documents.h chromium-145.0.7632.159/third_party/libxslt/src/libxslt/documents.h --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/documents.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/documents.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,93 @@ +/* + * Summary: interface for the document handling + * Description: implements document loading and cache (multiple + * document() reference for the same resources must + * be equal. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLT_DOCUMENTS_H__ +#define __XML_XSLT_DOCUMENTS_H__ + +#include +#include "xsltexports.h" +#include "xsltInternals.h" + +#ifdef __cplusplus +extern "C" { +#endif + +XSLTPUBFUN xsltDocumentPtr XSLTCALL + xsltNewDocument (xsltTransformContextPtr ctxt, + xmlDocPtr doc); +XSLTPUBFUN xsltDocumentPtr XSLTCALL + xsltLoadDocument (xsltTransformContextPtr ctxt, + const xmlChar *URI); +XSLTPUBFUN xsltDocumentPtr XSLTCALL + xsltFindDocument (xsltTransformContextPtr ctxt, + xmlDocPtr doc); +XSLTPUBFUN void XSLTCALL + xsltFreeDocuments (xsltTransformContextPtr ctxt); + +XSLTPUBFUN xsltDocumentPtr XSLTCALL + xsltLoadStyleDocument (xsltStylesheetPtr style, + const xmlChar *URI); +XSLTPUBFUN xsltDocumentPtr XSLTCALL + xsltNewStyleDocument (xsltStylesheetPtr style, + xmlDocPtr doc); +XSLTPUBFUN void XSLTCALL + xsltFreeStyleDocuments (xsltStylesheetPtr style); + +/* + * Hooks for document loading + */ + +/** + * xsltLoadType: + * + * Enum defining the kind of loader requirement. + */ +typedef enum { + XSLT_LOAD_START = 0, /* loading for a top stylesheet */ + XSLT_LOAD_STYLESHEET = 1, /* loading for a stylesheet include/import */ + XSLT_LOAD_DOCUMENT = 2 /* loading document at transformation time */ +} xsltLoadType; + +/** + * xsltDocLoaderFunc: + * @URI: the URI of the document to load + * @dict: the dictionary to use when parsing that document + * @options: parsing options, a set of xmlParserOption + * @ctxt: the context, either a stylesheet or a transformation context + * @type: the xsltLoadType indicating the kind of loading required + * + * An xsltDocLoaderFunc is a signature for a function which can be + * registered to load document not provided by the compilation or + * transformation API themselve, for example when an xsl:import, + * xsl:include is found at compilation time or when a document() + * call is made at runtime. + * + * Returns the pointer to the document (which will be modified and + * freed by the engine later), or NULL in case of error. + */ +typedef xmlDocPtr (*xsltDocLoaderFunc) (const xmlChar *URI, + xmlDictPtr dict, + int options, + void *ctxt, + xsltLoadType type); + +XSLTPUBFUN void XSLTCALL + xsltSetLoaderFunc (xsltDocLoaderFunc f); + +/* the loader may be needed by extension libraries so it is exported */ +XSLTPUBVAR xsltDocLoaderFunc xsltDocDefaultLoader; + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_DOCUMENTS_H__ */ + diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/extensions.c chromium-145.0.7632.159/third_party/libxslt/src/libxslt/extensions.c --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/extensions.c 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/extensions.c 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,2403 @@ +/* + * extensions.c: Implemetation of the extensions support + * + * Reference: + * http://www.w3.org/TR/1999/REC-xslt-19991116 + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#define IN_LIBXSLT +#include "libxslt.h" + +#include +#include +#include + +#ifdef WITH_MODULES + #ifdef _WIN32 + #define WIN32_LEAN_AND_MEAN + #include + #else + #include + #endif +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xslt.h" +#include "xsltInternals.h" +#include "xsltlocale.h" +#include "xsltutils.h" +#include "imports.h" +#include "extensions.h" + +#include /* for _MAX_PATH & getenv */ +#ifdef _WIN32 +#ifndef PATH_MAX +#define PATH_MAX _MAX_PATH +#endif +#endif + +#ifdef WITH_XSLT_DEBUG +#define WITH_XSLT_DEBUG_EXTENSIONS +#endif + +/************************************************************************ + * * + * Private Types and Globals * + * * + ************************************************************************/ + +typedef struct _xsltExtDef xsltExtDef; +typedef xsltExtDef *xsltExtDefPtr; +struct _xsltExtDef { + struct _xsltExtDef *next; + xmlChar *prefix; + xmlChar *URI; + void *data; +}; + +typedef struct _xsltExtModule xsltExtModule; +typedef xsltExtModule *xsltExtModulePtr; +struct _xsltExtModule { + xsltExtInitFunction initFunc; + xsltExtShutdownFunction shutdownFunc; + xsltStyleExtInitFunction styleInitFunc; + xsltStyleExtShutdownFunction styleShutdownFunc; +}; + +typedef struct _xsltExtData xsltExtData; +typedef xsltExtData *xsltExtDataPtr; +struct _xsltExtData { + xsltExtModulePtr extModule; + void *extData; +}; + +typedef struct _xsltExtElement xsltExtElement; +typedef xsltExtElement *xsltExtElementPtr; +struct _xsltExtElement { + xsltPreComputeFunction precomp; + xsltTransformFunction transform; +}; + +static xmlHashTablePtr xsltExtensionsHash = NULL; +static xmlHashTablePtr xsltFunctionsHash = NULL; +static xmlHashTablePtr xsltElementsHash = NULL; +static xmlHashTablePtr xsltTopLevelsHash = NULL; +static xmlHashTablePtr xsltModuleHash = NULL; +static xmlMutexPtr xsltExtMutex = NULL; + +/************************************************************************ + * * + * Type functions * + * * + ************************************************************************/ + +/** + * xsltNewExtDef: + * @prefix: the extension prefix + * @URI: the namespace URI + * + * Create a new XSLT ExtDef + * + * Returns the newly allocated xsltExtDefPtr or NULL in case of error + */ +static xsltExtDefPtr +xsltNewExtDef(const xmlChar * prefix, const xmlChar * URI) +{ + xsltExtDefPtr cur; + + cur = (xsltExtDefPtr) xmlMalloc(sizeof(xsltExtDef)); + if (cur == NULL) { + xsltTransformError(NULL, NULL, NULL, + "xsltNewExtDef : malloc failed\n"); + return (NULL); + } + memset(cur, 0, sizeof(xsltExtDef)); + if (prefix != NULL) + cur->prefix = xmlStrdup(prefix); + if (URI != NULL) + cur->URI = xmlStrdup(URI); + return (cur); +} + +/** + * xsltFreeExtDef: + * @extensiond: an XSLT extension definition + * + * Free up the memory allocated by @extensiond + */ +static void +xsltFreeExtDef(xsltExtDefPtr extensiond) +{ + if (extensiond == NULL) + return; + if (extensiond->prefix != NULL) + xmlFree(extensiond->prefix); + if (extensiond->URI != NULL) + xmlFree(extensiond->URI); + xmlFree(extensiond); +} + +/** + * xsltFreeExtDefList: + * @extensiond: an XSLT extension definition list + * + * Free up the memory allocated by all the elements of @extensiond + */ +static void +xsltFreeExtDefList(xsltExtDefPtr extensiond) +{ + xsltExtDefPtr cur; + + while (extensiond != NULL) { + cur = extensiond; + extensiond = extensiond->next; + xsltFreeExtDef(cur); + } +} + +/** + * xsltNewExtModule: + * @initFunc: the module initialization function + * @shutdownFunc: the module shutdown function + * @styleInitFunc: the stylesheet module data allocator function + * @styleShutdownFunc: the stylesheet module data free function + * + * Create a new XSLT extension module + * + * Returns the newly allocated xsltExtModulePtr or NULL in case of error + */ +static xsltExtModulePtr +xsltNewExtModule(xsltExtInitFunction initFunc, + xsltExtShutdownFunction shutdownFunc, + xsltStyleExtInitFunction styleInitFunc, + xsltStyleExtShutdownFunction styleShutdownFunc) +{ + xsltExtModulePtr cur; + + cur = (xsltExtModulePtr) xmlMalloc(sizeof(xsltExtModule)); + if (cur == NULL) { + xsltTransformError(NULL, NULL, NULL, + "xsltNewExtModule : malloc failed\n"); + return (NULL); + } + cur->initFunc = initFunc; + cur->shutdownFunc = shutdownFunc; + cur->styleInitFunc = styleInitFunc; + cur->styleShutdownFunc = styleShutdownFunc; + return (cur); +} + +/** + * xsltFreeExtModule: + * @ext: an XSLT extension module + * + * Free up the memory allocated by @ext + */ +static void +xsltFreeExtModule(xsltExtModulePtr ext) +{ + if (ext == NULL) + return; + xmlFree(ext); +} + +static void +xsltFreeExtModuleEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { + xsltFreeExtModule((xsltExtModulePtr) payload); +} + +/** + * xsltNewExtData: + * @extModule: the module + * @extData: the associated data + * + * Create a new XSLT extension module data wrapper + * + * Returns the newly allocated xsltExtDataPtr or NULL in case of error + */ +static xsltExtDataPtr +xsltNewExtData(xsltExtModulePtr extModule, void *extData) +{ + xsltExtDataPtr cur; + + if (extModule == NULL) + return (NULL); + cur = (xsltExtDataPtr) xmlMalloc(sizeof(xsltExtData)); + if (cur == NULL) { + xsltTransformError(NULL, NULL, NULL, + "xsltNewExtData : malloc failed\n"); + return (NULL); + } + cur->extModule = extModule; + cur->extData = extData; + return (cur); +} + +/** + * xsltFreeExtData: + * @ext: an XSLT extension module data wrapper + * + * Free up the memory allocated by @ext + */ +static void +xsltFreeExtData(xsltExtDataPtr ext) +{ + if (ext == NULL) + return; + xmlFree(ext); +} + +static void +xsltFreeExtDataEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { + xsltFreeExtData((xsltExtDataPtr) payload); +} + +/** + * xsltNewExtElement: + * @precomp: the pre-computation function + * @transform: the transformation function + * + * Create a new XSLT extension element + * + * Returns the newly allocated xsltExtElementPtr or NULL in case of + * error + */ +static xsltExtElementPtr +xsltNewExtElement(xsltPreComputeFunction precomp, + xsltTransformFunction transform) +{ + xsltExtElementPtr cur; + + if (transform == NULL) + return (NULL); + + cur = (xsltExtElementPtr) xmlMalloc(sizeof(xsltExtElement)); + if (cur == NULL) { + xsltTransformError(NULL, NULL, NULL, + "xsltNewExtElement : malloc failed\n"); + return (NULL); + } + cur->precomp = precomp; + cur->transform = transform; + return (cur); +} + +/** + * xsltFreeExtElement: + * @ext: an XSLT extension element + * + * Frees up the memory allocated by @ext + */ +static void +xsltFreeExtElement(xsltExtElementPtr ext) +{ + if (ext == NULL) + return; + xmlFree(ext); +} + +static void +xsltFreeExtElementEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { + xsltFreeExtElement((xsltExtElementPtr) payload); +} + + +#ifdef WITH_MODULES +typedef void (*exsltRegisterFunction) (void); + +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + +/** + * xsltExtModuleRegisterDynamic: + * @URI: the function or element namespace URI + * + * Dynamically loads an extension plugin when available. + * + * The plugin name is derived from the URI by removing the + * initial protocol designation, e.g. "http://", then converting + * the characters ".", "-", "/", and "\" into "_", the removing + * any trailing "/", then concatenating LIBXML_MODULE_EXTENSION. + * + * Plugins are loaded from the directory specified by the + * environment variable LIBXSLT_PLUGINS_PATH, or if NULL, + * by LIBXSLT_DEFAULT_PLUGINS_PATH() which is determined at + * compile time. + * + * Returns 0 if successful, -1 in case of error. + */ + +static int +xsltExtModuleRegisterDynamic(const xmlChar * URI) +{ + void *m; + exsltRegisterFunction regfunc; + xmlChar *ext_name; + char module_filename[PATH_MAX]; + const xmlChar *ext_directory = NULL; + const xmlChar *protocol = NULL; + xmlChar *i, *regfunc_name; + + /* check for bad inputs */ + if (URI == NULL) + return (-1); + + if (NULL == xsltModuleHash) { + xsltModuleHash = xmlHashCreate(5); + if (xsltModuleHash == NULL) + return (-1); + } + + xmlMutexLock(xsltExtMutex); + + /* have we attempted to register this module already? */ + if (xmlHashLookup(xsltModuleHash, URI) != NULL) { + xmlMutexUnlock(xsltExtMutex); + return (-1); + } + xmlMutexUnlock(xsltExtMutex); + + /* transform extension namespace into a module name */ + protocol = xmlStrstr(URI, BAD_CAST "://"); + if (protocol == NULL) { + ext_name = xmlStrdup(URI); + } else { + ext_name = xmlStrdup(protocol + 3); + } + if (ext_name == NULL) { + return (-1); + } + + i = ext_name; + while ('\0' != *i) { + if (('/' == *i) || ('\\' == *i) || ('.' == *i) || ('-' == *i)) + *i = '_'; + i++; + } + + /* Strip underscores from end of string. */ + while (i > ext_name && *(i - 1) == '_') { + i--; + *i = '\0'; + } + + /* determine module directory */ + ext_directory = (xmlChar *) getenv("LIBXSLT_PLUGINS_PATH"); + + if (NULL == ext_directory) { + ext_directory = BAD_CAST LIBXSLT_DEFAULT_PLUGINS_PATH(); + if (NULL == ext_directory) + return (-1); + } +#ifdef WITH_XSLT_DEBUG_EXTENSIONS + else + xsltGenericDebug(xsltGenericDebugContext, + "LIBXSLT_PLUGINS_PATH is %s\n", ext_directory); +#endif + + /* build the module filename, and confirm the module exists */ + xmlStrPrintf((xmlChar *) module_filename, sizeof(module_filename), + "%s/%s%s", ext_directory, ext_name, MODULE_EXTENSION); + +#ifdef WITH_XSLT_DEBUG_EXTENSIONS + xsltGenericDebug(xsltGenericDebugContext, + "Attempting to load plugin: %s for URI: %s\n", + module_filename, URI); +#endif + +#if LIBXML_VERSION < 21300 + if (1 != xmlCheckFilename(module_filename)) { + +#ifdef WITH_XSLT_DEBUG_EXTENSIONS + xsltGenericDebug(xsltGenericDebugContext, + "xmlCheckFilename failed for plugin: %s\n", module_filename); +#endif + + xmlFree(ext_name); + return (-1); + } +#endif + + /* attempt to open the module */ +#ifdef _WIN32 + m = LoadLibraryA(module_filename); +#else + m = dlopen(module_filename, RTLD_LOCAL | RTLD_NOW); +#endif + if (NULL == m) { + +#ifdef WITH_XSLT_DEBUG_EXTENSIONS + xsltGenericDebug(xsltGenericDebugContext, + "dlopen failed for plugin: %s\n", module_filename); +#endif + + xmlFree(ext_name); + return (-1); + } + + /* construct initialization func name */ + regfunc_name = xmlStrdup(ext_name); + regfunc_name = xmlStrcat(regfunc_name, BAD_CAST "_init"); + +#ifdef _WIN32 + regfunc = (void *) GetProcAddress(m, (const char *) regfunc_name); +#else + regfunc = dlsym(m, (const char *) regfunc_name); +#endif + if (regfunc != NULL) { + /* + * Call the module's init function. Note that this function + * calls xsltRegisterExtModuleFull which will add the module + * to xsltExtensionsHash (together with it's entry points). + */ + (*regfunc) (); + + /* register this module in our hash */ + xmlMutexLock(xsltExtMutex); + xmlHashAddEntry(xsltModuleHash, URI, (void *) m); + xmlMutexUnlock(xsltExtMutex); + } else { + +#ifdef WITH_XSLT_DEBUG_EXTENSIONS + xsltGenericDebug(xsltGenericDebugContext, + "dlsym failed for plugin: %s, regfunc: %s\n", + module_filename, regfunc_name); +#endif + + /* if regfunc not found unload the module immediately */ +#ifdef _WIN32 + FreeLibrary(m); +#else + dlclose(m); +#endif + } + + xmlFree(ext_name); + xmlFree(regfunc_name); + return (NULL == regfunc) ? -1 : 0; +} +#else +static int +xsltExtModuleRegisterDynamic(const xmlChar * URI ATTRIBUTE_UNUSED) +{ + return -1; +} +#endif + +/************************************************************************ + * * + * The stylesheet extension prefixes handling * + * * + ************************************************************************/ + + +/** + * xsltFreeExts: + * @style: an XSLT stylesheet + * + * Free up the memory used by XSLT extensions in a stylesheet + */ +void +xsltFreeExts(xsltStylesheetPtr style) +{ + if (style->nsDefs != NULL) + xsltFreeExtDefList((xsltExtDefPtr) style->nsDefs); +} + +/** + * xsltRegisterExtPrefix: + * @style: an XSLT stylesheet + * @prefix: the prefix used (optional) + * @URI: the URI associated to the extension + * + * Registers an extension namespace + * This is called from xslt.c during compile-time. + * The given prefix is not needed. + * Called by: + * xsltParseExtElemPrefixes() (new function) + * xsltRegisterExtPrefix() (old function) + * + * Returns 0 in case of success, 1 if the @URI was already + * registered as an extension namespace and + * -1 in case of failure + */ +int +xsltRegisterExtPrefix(xsltStylesheetPtr style, + const xmlChar * prefix, const xmlChar * URI) +{ + xsltExtDefPtr def, ret; + + if ((style == NULL) || (URI == NULL)) + return (-1); + +#ifdef WITH_XSLT_DEBUG_EXTENSIONS + xsltGenericDebug(xsltGenericDebugContext, + "Registering extension namespace '%s'.\n", URI); +#endif + def = (xsltExtDefPtr) style->nsDefs; +#ifdef XSLT_REFACTORED + /* + * The extension is associated with a namespace name. + */ + while (def != NULL) { + if (xmlStrEqual(URI, def->URI)) + return (1); + def = def->next; + } +#else + while (def != NULL) { + if (xmlStrEqual(prefix, def->prefix)) + return (-1); + def = def->next; + } +#endif + ret = xsltNewExtDef(prefix, URI); + if (ret == NULL) + return (-1); + ret->next = (xsltExtDefPtr) style->nsDefs; + style->nsDefs = ret; + + /* + * check whether there is an extension module with a stylesheet + * initialization function. + */ +#ifdef XSLT_REFACTORED + /* + * Don't initialize modules based on specified namespaces via + * the attribute "[xsl:]extension-element-prefixes". + */ +#else + if (xsltExtensionsHash != NULL) { + xsltExtModulePtr module; + + xmlMutexLock(xsltExtMutex); + module = xmlHashLookup(xsltExtensionsHash, URI); + xmlMutexUnlock(xsltExtMutex); + if (NULL == module) { + if (!xsltExtModuleRegisterDynamic(URI)) { + xmlMutexLock(xsltExtMutex); + module = xmlHashLookup(xsltExtensionsHash, URI); + xmlMutexUnlock(xsltExtMutex); + } + } + if (module != NULL) { + xsltStyleGetExtData(style, URI); + } + } +#endif + return (0); +} + +/************************************************************************ + * * + * The extensions modules interfaces * + * * + ************************************************************************/ + +/** + * xsltRegisterExtFunction: + * @ctxt: an XSLT transformation context + * @name: the name of the element + * @URI: the URI associated to the element + * @function: the actual implementation which should be called + * + * Registers an extension function + * + * Returns 0 in case of success, -1 in case of failure + */ +int +xsltRegisterExtFunction(xsltTransformContextPtr ctxt, const xmlChar * name, + const xmlChar * URI, xmlXPathFunction function) +{ + int ret; + + if ((ctxt == NULL) || (name == NULL) || + (URI == NULL) || (function == NULL)) + return (-1); + if (ctxt->xpathCtxt != NULL) { + xmlXPathRegisterFuncNS(ctxt->xpathCtxt, name, URI, function); + } + if (ctxt->extFunctions == NULL) + ctxt->extFunctions = xmlHashCreate(10); + if (ctxt->extFunctions == NULL) + return (-1); + + ret = xmlHashAddEntry2(ctxt->extFunctions, name, URI, + XML_CAST_FPTR(function)); + + return(ret); +} + +/** + * xsltRegisterExtElement: + * @ctxt: an XSLT transformation context + * @name: the name of the element + * @URI: the URI associated to the element + * @function: the actual implementation which should be called + * + * Registers an extension element + * + * Returns 0 in case of success, -1 in case of failure + */ +int +xsltRegisterExtElement(xsltTransformContextPtr ctxt, const xmlChar * name, + const xmlChar * URI, xsltTransformFunction function) +{ + if ((ctxt == NULL) || (name == NULL) || + (URI == NULL) || (function == NULL)) + return (-1); + if (ctxt->extElements == NULL) + ctxt->extElements = xmlHashCreate(10); + if (ctxt->extElements == NULL) + return (-1); + return (xmlHashAddEntry2 + (ctxt->extElements, name, URI, XML_CAST_FPTR(function))); +} + +/** + * xsltFreeCtxtExts: + * @ctxt: an XSLT transformation context + * + * Free the XSLT extension data + */ +void +xsltFreeCtxtExts(xsltTransformContextPtr ctxt) +{ + if (ctxt->extElements != NULL) + xmlHashFree(ctxt->extElements, NULL); + if (ctxt->extFunctions != NULL) + xmlHashFree(ctxt->extFunctions, NULL); +} + +/** + * xsltStyleGetStylesheetExtData: + * @style: an XSLT stylesheet + * @URI: the URI associated to the exension module + * + * Fires the compile-time initialization callback + * of an extension module and returns a container + * holding the user-data (retrieved via the callback). + * + * Returns the create module-data container + * or NULL if such a module was not registered. + */ +static xsltExtDataPtr +xsltStyleInitializeStylesheetModule(xsltStylesheetPtr style, + const xmlChar * URI) +{ + xsltExtDataPtr dataContainer; + void *userData = NULL; + xsltExtModulePtr module; + + if ((style == NULL) || (URI == NULL)) + return(NULL); + + if (xsltExtensionsHash == NULL) { +#ifdef WITH_XSLT_DEBUG_EXTENSIONS + xsltGenericDebug(xsltGenericDebugContext, + "Not registered extension module: %s\n", URI); +#endif + return(NULL); + } + + xmlMutexLock(xsltExtMutex); + + module = xmlHashLookup(xsltExtensionsHash, URI); + + xmlMutexUnlock(xsltExtMutex); + + if (module == NULL) { +#ifdef WITH_XSLT_DEBUG_EXTENSIONS + xsltGenericDebug(xsltGenericDebugContext, + "Not registered extension module: %s\n", URI); +#endif + return (NULL); + } + /* + * The specified module was registered so initialize it. + */ + if (style->extInfos == NULL) { + style->extInfos = xmlHashCreate(10); + if (style->extInfos == NULL) + return (NULL); + } + /* + * Fire the initialization callback if available. + */ + if (module->styleInitFunc == NULL) { +#ifdef WITH_XSLT_DEBUG_EXTENSIONS + xsltGenericDebug(xsltGenericDebugContext, + "Initializing module with *no* callback: %s\n", URI); +#endif + } else { +#ifdef WITH_XSLT_DEBUG_EXTENSIONS + xsltGenericDebug(xsltGenericDebugContext, + "Initializing module with callback: %s\n", URI); +#endif + /* + * Fire the initialization callback. + */ + userData = module->styleInitFunc(style, URI); + } + /* + * Store the user-data in the context of the given stylesheet. + */ + dataContainer = xsltNewExtData(module, userData); + if (dataContainer == NULL) { + if (module->styleShutdownFunc) + module->styleShutdownFunc(style, URI, userData); + return (NULL); + } + + if (xmlHashAddEntry(style->extInfos, URI, + (void *) dataContainer) < 0) + { + xsltTransformError(NULL, style, NULL, + "Failed to register module '%s'.\n", URI); + style->errors++; + if (module->styleShutdownFunc) + module->styleShutdownFunc(style, URI, userData); + xsltFreeExtData(dataContainer); + return (NULL); + } + + return(dataContainer); +} + +/** + * xsltStyleGetExtData: + * @style: an XSLT stylesheet + * @URI: the URI associated to the exension module + * + * Retrieve the data associated to the extension module + * in this given stylesheet. + * Called by: + * xsltRegisterExtPrefix(), + * ( xsltExtElementPreCompTest(), xsltExtInitTest ) + * + * Returns the pointer or NULL if not present + */ +void * +xsltStyleGetExtData(xsltStylesheetPtr style, const xmlChar * URI) +{ + xsltExtDataPtr dataContainer = NULL; + xsltStylesheetPtr tmpStyle; + + if ((style == NULL) || (URI == NULL) || + (xsltExtensionsHash == NULL)) + return (NULL); + + +#ifdef XSLT_REFACTORED + /* + * This is intended for global storage, so only the main + * stylesheet will hold the data. + */ + tmpStyle = style; + while (tmpStyle->parent != NULL) + tmpStyle = tmpStyle->parent; + if (tmpStyle->extInfos != NULL) { + dataContainer = + (xsltExtDataPtr) xmlHashLookup(tmpStyle->extInfos, URI); + if (dataContainer != NULL) { + /* + * The module was already initialized in the context + * of this stylesheet; just return the user-data that + * comes with it. + */ + return(dataContainer->extData); + } + } +#else + /* + * Old behaviour. + */ + tmpStyle = style; + if (tmpStyle->extInfos != NULL) { + dataContainer = + (xsltExtDataPtr) xmlHashLookup(tmpStyle->extInfos, URI); + if (dataContainer != NULL) { + return(dataContainer->extData); + } + } +#endif + + dataContainer = + xsltStyleInitializeStylesheetModule(tmpStyle, URI); + if (dataContainer != NULL) + return (dataContainer->extData); + return(NULL); +} + +#ifdef XSLT_REFACTORED +/** + * xsltStyleStylesheetLevelGetExtData: + * @style: an XSLT stylesheet + * @URI: the URI associated to the exension module + * + * Retrieve the data associated to the extension module in this given + * stylesheet. + * + * Returns the pointer or NULL if not present + */ +void * +xsltStyleStylesheetLevelGetExtData(xsltStylesheetPtr style, + const xmlChar * URI) +{ + xsltExtDataPtr dataContainer = NULL; + + if ((style == NULL) || (URI == NULL) || + (xsltExtensionsHash == NULL)) + return (NULL); + + if (style->extInfos != NULL) { + dataContainer = (xsltExtDataPtr) xmlHashLookup(style->extInfos, URI); + /* + * The module was already initialized in the context + * of this stylesheet; just return the user-data that + * comes with it. + */ + if (dataContainer) + return(dataContainer->extData); + } + + dataContainer = + xsltStyleInitializeStylesheetModule(style, URI); + if (dataContainer != NULL) + return (dataContainer->extData); + return(NULL); +} +#endif + +/** + * xsltGetExtData: + * @ctxt: an XSLT transformation context + * @URI: the URI associated to the exension module + * + * Retrieve the data associated to the extension module in this given + * transformation. + * + * Returns the pointer or NULL if not present + */ +void * +xsltGetExtData(xsltTransformContextPtr ctxt, const xmlChar * URI) +{ + xsltExtDataPtr data; + + if ((ctxt == NULL) || (URI == NULL)) + return (NULL); + if (ctxt->extInfos == NULL) { + ctxt->extInfos = xmlHashCreate(10); + if (ctxt->extInfos == NULL) + return (NULL); + data = NULL; + } else { + data = (xsltExtDataPtr) xmlHashLookup(ctxt->extInfos, URI); + } + if (data == NULL) { + void *extData; + xsltExtModulePtr module; + + xmlMutexLock(xsltExtMutex); + + module = xmlHashLookup(xsltExtensionsHash, URI); + + xmlMutexUnlock(xsltExtMutex); + + if (module == NULL) { +#ifdef WITH_XSLT_DEBUG_EXTENSIONS + xsltGenericDebug(xsltGenericDebugContext, + "Not registered extension module: %s\n", URI); +#endif + return (NULL); + } else { + if (module->initFunc == NULL) + return (NULL); + +#ifdef WITH_XSLT_DEBUG_EXTENSIONS + xsltGenericDebug(xsltGenericDebugContext, + "Initializing module: %s\n", URI); +#endif + + extData = module->initFunc(ctxt, URI); + if (extData == NULL) + return (NULL); + + data = xsltNewExtData(module, extData); + if ((data == NULL) || + (xmlHashAddEntry(ctxt->extInfos, URI, (void *) data) < 0)) { + xsltTransformError(ctxt, NULL, NULL, + "Failed to register module data: %s\n", + URI); + if (module->shutdownFunc) + module->shutdownFunc(ctxt, URI, extData); + xsltFreeExtData(data); + return (NULL); + } + } + } + return (data->extData); +} + +typedef struct _xsltInitExtCtxt xsltInitExtCtxt; +struct _xsltInitExtCtxt { + xsltTransformContextPtr ctxt; + int ret; +}; + +/** + * xsltInitCtxtExt: + * @styleData: the registered stylesheet data for the module + * @ctxt: the XSLT transformation context + the return value + * @URI: the extension URI + * + * Initializes an extension module + */ +static void +xsltInitCtxtExt(void *payload, void *data, const xmlChar * URI) +{ + xsltExtDataPtr styleData = (xsltExtDataPtr) payload; + xsltInitExtCtxt *ctxt = (xsltInitExtCtxt *) data; + xsltExtModulePtr module; + xsltExtDataPtr ctxtData; + void *extData; + + if ((styleData == NULL) || (ctxt == NULL) || (URI == NULL) || + (ctxt->ret == -1)) { +#ifdef WITH_XSLT_DEBUG_EXTENSIONS + xsltGenericDebug(xsltGenericDebugContext, + "xsltInitCtxtExt: NULL param or error\n"); +#endif + return; + } + module = styleData->extModule; + if ((module == NULL) || (module->initFunc == NULL)) { +#ifdef WITH_XSLT_DEBUG_EXTENSIONS + xsltGenericDebug(xsltGenericDebugContext, + "xsltInitCtxtExt: no module or no initFunc\n"); +#endif + return; + } + + ctxtData = (xsltExtDataPtr) xmlHashLookup(ctxt->ctxt->extInfos, URI); + if (ctxtData != NULL) { +#ifdef WITH_XSLT_DEBUG_EXTENSIONS + xsltGenericDebug(xsltGenericDebugContext, + "xsltInitCtxtExt: already initialized\n"); +#endif + return; + } + + extData = module->initFunc(ctxt->ctxt, URI); + if (extData == NULL) { +#ifdef WITH_XSLT_DEBUG_EXTENSIONS + xsltGenericDebug(xsltGenericDebugContext, + "xsltInitCtxtExt: no extData\n"); +#endif + } + ctxtData = xsltNewExtData(module, extData); + if (ctxtData == NULL) { + if (module->shutdownFunc) + module->shutdownFunc(ctxt->ctxt, URI, extData); + ctxt->ret = -1; + return; + } + + if (ctxt->ctxt->extInfos == NULL) + ctxt->ctxt->extInfos = xmlHashCreate(10); + if (ctxt->ctxt->extInfos == NULL) { + if (module->shutdownFunc) + module->shutdownFunc(ctxt->ctxt, URI, extData); + xsltFreeExtData(ctxtData); + ctxt->ret = -1; + return; + } + + if (xmlHashAddEntry(ctxt->ctxt->extInfos, URI, ctxtData) < 0) { + xsltGenericError(xsltGenericErrorContext, + "Failed to register module data: %s\n", URI); + if (module->shutdownFunc) + module->shutdownFunc(ctxt->ctxt, URI, extData); + xsltFreeExtData(ctxtData); + ctxt->ret = -1; + return; + } +#ifdef WITH_XSLT_DEBUG_EXTENSIONS + xsltGenericDebug(xsltGenericDebugContext, "Registered module %s\n", + URI); +#endif + ctxt->ret++; +} + +/** + * xsltInitCtxtExts: + * @ctxt: an XSLT transformation context + * + * Initialize the set of modules with registered stylesheet data + * + * Returns the number of modules initialized or -1 in case of error + */ +int +xsltInitCtxtExts(xsltTransformContextPtr ctxt) +{ + xsltStylesheetPtr style; + xsltInitExtCtxt ctx; + + if (ctxt == NULL) + return (-1); + + style = ctxt->style; + if (style == NULL) + return (-1); + + ctx.ctxt = ctxt; + ctx.ret = 0; + + while (style != NULL) { + if (style->extInfos != NULL) { + xmlHashScan(style->extInfos, xsltInitCtxtExt, &ctx); + if (ctx.ret == -1) + return (-1); + } + style = xsltNextImport(style); + } +#ifdef WITH_XSLT_DEBUG_EXTENSIONS + xsltGenericDebug(xsltGenericDebugContext, "Registered %d modules\n", + ctx.ret); +#endif + return (ctx.ret); +} + +/** + * xsltShutdownCtxtExt: + * @data: the registered data for the module + * @ctxt: the XSLT transformation context + * @URI: the extension URI + * + * Shutdown an extension module loaded + */ +static void +xsltShutdownCtxtExt(void *payload, void *vctxt, const xmlChar * URI) +{ + xsltExtDataPtr data = (xsltExtDataPtr) payload; + xsltTransformContextPtr ctxt = (xsltTransformContextPtr) vctxt; + xsltExtModulePtr module; + + if ((data == NULL) || (ctxt == NULL) || (URI == NULL)) + return; + module = data->extModule; + if ((module == NULL) || (module->shutdownFunc == NULL)) + return; + +#ifdef WITH_XSLT_DEBUG_EXTENSIONS + xsltGenericDebug(xsltGenericDebugContext, + "Shutting down module : %s\n", URI); +#endif + module->shutdownFunc(ctxt, URI, data->extData); +} + +/** + * xsltShutdownCtxtExts: + * @ctxt: an XSLT transformation context + * + * Shutdown the set of modules loaded + */ +void +xsltShutdownCtxtExts(xsltTransformContextPtr ctxt) +{ + if (ctxt == NULL) + return; + if (ctxt->extInfos == NULL) + return; + xmlHashScan(ctxt->extInfos, xsltShutdownCtxtExt, ctxt); + xmlHashFree(ctxt->extInfos, xsltFreeExtDataEntry); + ctxt->extInfos = NULL; +} + +/** + * xsltShutdownExt: + * @data: the registered data for the module + * @ctxt: the XSLT stylesheet + * @URI: the extension URI + * + * Shutdown an extension module loaded + */ +static void +xsltShutdownExt(void *payload, void *vctxt, const xmlChar * URI) +{ + xsltExtDataPtr data = (xsltExtDataPtr) payload; + xsltStylesheetPtr style = (xsltStylesheetPtr) vctxt; + xsltExtModulePtr module; + + if ((data == NULL) || (style == NULL) || (URI == NULL)) + return; + module = data->extModule; + if ((module == NULL) || (module->styleShutdownFunc == NULL)) + return; + +#ifdef WITH_XSLT_DEBUG_EXTENSIONS + xsltGenericDebug(xsltGenericDebugContext, + "Shutting down module : %s\n", URI); +#endif + module->styleShutdownFunc(style, URI, data->extData); + /* + * Don't remove the entry from the hash table here, since + * this will produce segfaults - this fixes bug #340624. + * + * xmlHashRemoveEntry(style->extInfos, URI, xsltFreeExtDataEntry); + */ +} + +/** + * xsltShutdownExts: + * @style: an XSLT stylesheet + * + * Shutdown the set of modules loaded + */ +void +xsltShutdownExts(xsltStylesheetPtr style) +{ + if (style == NULL) + return; + if (style->extInfos == NULL) + return; + xmlHashScan(style->extInfos, xsltShutdownExt, style); + xmlHashFree(style->extInfos, xsltFreeExtDataEntry); + style->extInfos = NULL; +} + +/** + * xsltCheckExtPrefix: + * @style: the stylesheet + * @URI: the namespace prefix (possibly NULL) + * + * Check if the given prefix is one of the declared extensions. + * This is intended to be called only at compile-time. + * Called by: + * xsltGetInheritedNsList() (xslt.c) + * xsltParseTemplateContent (xslt.c) + * + * Returns 1 if this is an extension, 0 otherwise + */ +int +xsltCheckExtPrefix(xsltStylesheetPtr style, const xmlChar * URI) +{ +#ifdef XSLT_REFACTORED + if ((style == NULL) || (style->compCtxt == NULL) || + (XSLT_CCTXT(style)->inode == NULL) || + (XSLT_CCTXT(style)->inode->extElemNs == NULL)) + return (0); + /* + * Lookup the extension namespaces registered + * at the current node in the stylesheet's tree. + */ + if (XSLT_CCTXT(style)->inode->extElemNs != NULL) { + int i; + xsltPointerListPtr list = XSLT_CCTXT(style)->inode->extElemNs; + + for (i = 0; i < list->number; i++) { + if (xmlStrEqual((const xmlChar *) list->items[i], + URI)) + { + return(1); + } + } + } +#else + xsltExtDefPtr cur; + + if ((style == NULL) || (style->nsDefs == NULL)) + return (0); + if (URI == NULL) + URI = BAD_CAST "#default"; + cur = (xsltExtDefPtr) style->nsDefs; + while (cur != NULL) { + /* + * NOTE: This was change to work on namespace names rather + * than namespace prefixes. This fixes bug #339583. + * TODO: Consider renaming the field "prefix" of xsltExtDef + * to "href". + */ + if (xmlStrEqual(URI, cur->prefix)) + return (1); + cur = cur->next; + } +#endif + return (0); +} + +/** + * xsltCheckExtURI: + * @style: the stylesheet + * @URI: the namespace URI (possibly NULL) + * + * Check if the given prefix is one of the declared extensions. + * This is intended to be called only at compile-time. + * Called by: + * xsltPrecomputeStylesheet() (xslt.c) + * xsltParseTemplateContent (xslt.c) + * + * Returns 1 if this is an extension, 0 otherwise + */ +int +xsltCheckExtURI(xsltStylesheetPtr style, const xmlChar * URI) +{ + xsltExtDefPtr cur; + + if ((style == NULL) || (style->nsDefs == NULL)) + return (0); + if (URI == NULL) + return (0); + cur = (xsltExtDefPtr) style->nsDefs; + while (cur != NULL) { + if (xmlStrEqual(URI, cur->URI)) + return (1); + cur = cur->next; + } + return (0); +} + +/** + * xsltRegisterExtModuleFull: + * @URI: URI associated to this module + * @initFunc: the module initialization function + * @shutdownFunc: the module shutdown function + * @styleInitFunc: the module initialization function + * @styleShutdownFunc: the module shutdown function + * + * Register an XSLT extension module to the library. + * + * Returns 0 if sucessful, -1 in case of error + */ +int +xsltRegisterExtModuleFull(const xmlChar * URI, + xsltExtInitFunction initFunc, + xsltExtShutdownFunction shutdownFunc, + xsltStyleExtInitFunction styleInitFunc, + xsltStyleExtShutdownFunction styleShutdownFunc) +{ + int ret; + xsltExtModulePtr module; + + if ((URI == NULL) || (initFunc == NULL)) + return (-1); + if (xsltExtensionsHash == NULL) + xsltExtensionsHash = xmlHashCreate(10); + + if (xsltExtensionsHash == NULL) + return (-1); + + xmlMutexLock(xsltExtMutex); + + module = xmlHashLookup(xsltExtensionsHash, URI); + if (module != NULL) { + if ((module->initFunc == initFunc) && + (module->shutdownFunc == shutdownFunc)) + ret = 0; + else + ret = -1; + goto done; + } + module = xsltNewExtModule(initFunc, shutdownFunc, + styleInitFunc, styleShutdownFunc); + if (module == NULL) { + ret = -1; + goto done; + } + ret = xmlHashAddEntry(xsltExtensionsHash, URI, (void *) module); + +done: + xmlMutexUnlock(xsltExtMutex); + return (ret); +} + +/** + * xsltRegisterExtModule: + * @URI: URI associated to this module + * @initFunc: the module initialization function + * @shutdownFunc: the module shutdown function + * + * Register an XSLT extension module to the library. + * + * Returns 0 if sucessful, -1 in case of error + */ +int +xsltRegisterExtModule(const xmlChar * URI, + xsltExtInitFunction initFunc, + xsltExtShutdownFunction shutdownFunc) +{ + return xsltRegisterExtModuleFull(URI, initFunc, shutdownFunc, + NULL, NULL); +} + +/** + * xsltUnregisterExtModule: + * @URI: URI associated to this module + * + * Unregister an XSLT extension module from the library. + * + * Returns 0 if sucessful, -1 in case of error + */ +int +xsltUnregisterExtModule(const xmlChar * URI) +{ + int ret; + + if (URI == NULL) + return (-1); + if (xsltExtensionsHash == NULL) + return (-1); + + xmlMutexLock(xsltExtMutex); + + ret = xmlHashRemoveEntry(xsltExtensionsHash, URI, xsltFreeExtModuleEntry); + + xmlMutexUnlock(xsltExtMutex); + + return (ret); +} + +/** + * xsltUnregisterAllExtModules: + * + * Unregister all the XSLT extension module from the library. + */ +static void +xsltUnregisterAllExtModules(void) +{ + if (xsltExtensionsHash == NULL) + return; + + xmlMutexLock(xsltExtMutex); + + xmlHashFree(xsltExtensionsHash, xsltFreeExtModuleEntry); + xsltExtensionsHash = NULL; + + xmlMutexUnlock(xsltExtMutex); +} + +/** + * xsltXPathGetTransformContext: + * @ctxt: an XPath transformation context + * + * Provides the XSLT transformation context from the XPath transformation + * context. This is useful when an XPath function in the extension module + * is called by the XPath interpreter and that the XSLT context is needed + * for example to retrieve the associated data pertaining to this XSLT + * transformation. + * + * Returns the XSLT transformation context or NULL in case of error. + */ +xsltTransformContextPtr +xsltXPathGetTransformContext(xmlXPathParserContextPtr ctxt) +{ + if ((ctxt == NULL) || (ctxt->context == NULL)) + return (NULL); + return (ctxt->context->extra); +} + +/** + * xsltRegisterExtModuleFunction: + * @name: the function name + * @URI: the function namespace URI + * @function: the function callback + * + * Registers an extension module function. + * + * Returns 0 if successful, -1 in case of error. + */ +int +xsltRegisterExtModuleFunction(const xmlChar * name, const xmlChar * URI, + xmlXPathFunction function) +{ + if ((name == NULL) || (URI == NULL) || (function == NULL)) + return (-1); + + if (xsltFunctionsHash == NULL) + xsltFunctionsHash = xmlHashCreate(10); + if (xsltFunctionsHash == NULL) + return (-1); + + xmlMutexLock(xsltExtMutex); + + xmlHashUpdateEntry2(xsltFunctionsHash, name, URI, + XML_CAST_FPTR(function), NULL); + + xmlMutexUnlock(xsltExtMutex); + + return (0); +} + +/** + * xsltExtModuleFunctionLookup: + * @name: the function name + * @URI: the function namespace URI + * + * Looks up an extension module function + * + * Returns the function if found, NULL otherwise. + */ +xmlXPathFunction +xsltExtModuleFunctionLookup(const xmlChar * name, const xmlChar * URI) +{ + xmlXPathFunction ret; + + if ((xsltFunctionsHash == NULL) || (name == NULL) || (URI == NULL)) + return (NULL); + + xmlMutexLock(xsltExtMutex); + + XML_CAST_FPTR(ret) = xmlHashLookup2(xsltFunctionsHash, name, URI); + + xmlMutexUnlock(xsltExtMutex); + + /* if lookup fails, attempt a dynamic load on supported platforms */ + if (NULL == ret) { + if (!xsltExtModuleRegisterDynamic(URI)) { + xmlMutexLock(xsltExtMutex); + + XML_CAST_FPTR(ret) = + xmlHashLookup2(xsltFunctionsHash, name, URI); + + xmlMutexUnlock(xsltExtMutex); + } + } + + return ret; +} + +/** + * xsltUnregisterExtModuleFunction: + * @name: the function name + * @URI: the function namespace URI + * + * Unregisters an extension module function + * + * Returns 0 if successful, -1 in case of error. + */ +int +xsltUnregisterExtModuleFunction(const xmlChar * name, const xmlChar * URI) +{ + int ret; + + if ((xsltFunctionsHash == NULL) || (name == NULL) || (URI == NULL)) + return (-1); + + xmlMutexLock(xsltExtMutex); + + ret = xmlHashRemoveEntry2(xsltFunctionsHash, name, URI, NULL); + + xmlMutexUnlock(xsltExtMutex); + + return(ret); +} + +/** + * xsltUnregisterAllExtModuleFunction: + * + * Unregisters all extension module function + */ +static void +xsltUnregisterAllExtModuleFunction(void) +{ + xmlMutexLock(xsltExtMutex); + + xmlHashFree(xsltFunctionsHash, NULL); + xsltFunctionsHash = NULL; + + xmlMutexUnlock(xsltExtMutex); +} + + +static void +xsltFreeElemPreComp(xsltElemPreCompPtr comp) { + xmlFree(comp); +} + +/** + * xsltNewElemPreComp: + * @style: the XSLT stylesheet + * @inst: the element node + * @function: the transform function + * + * Creates and initializes an #xsltElemPreComp + * + * Returns the new and initialized #xsltElemPreComp + */ +xsltElemPreCompPtr +xsltNewElemPreComp(xsltStylesheetPtr style, xmlNodePtr inst, + xsltTransformFunction function) +{ + xsltElemPreCompPtr cur; + + cur = (xsltElemPreCompPtr) xmlMalloc(sizeof(xsltElemPreComp)); + if (cur == NULL) { + xsltTransformError(NULL, style, NULL, + "xsltNewExtElement : malloc failed\n"); + return (NULL); + } + memset(cur, 0, sizeof(xsltElemPreComp)); + + xsltInitElemPreComp(cur, style, inst, function, xsltFreeElemPreComp); + + return (cur); +} + +/** + * xsltInitElemPreComp: + * @comp: an #xsltElemPreComp (or generally a derived structure) + * @style: the XSLT stylesheet + * @inst: the element node + * @function: the transform function + * @freeFunc: the @comp deallocator + * + * Initializes an existing #xsltElemPreComp structure. This is usefull + * when extending an #xsltElemPreComp to store precomputed data. + * This function MUST be called on any extension element precomputed + * data struct. + */ +void +xsltInitElemPreComp(xsltElemPreCompPtr comp, xsltStylesheetPtr style, + xmlNodePtr inst, xsltTransformFunction function, + xsltElemPreCompDeallocator freeFunc) +{ + comp->type = XSLT_FUNC_EXTENSION; + comp->func = function; + comp->inst = inst; + comp->free = freeFunc; + + comp->next = style->preComps; + style->preComps = comp; +} + +/** + * xsltPreComputeExtModuleElement: + * @style: the stylesheet + * @inst: the element node + * + * Precomputes an extension module element + * + * Returns the precomputed data + */ +xsltElemPreCompPtr +xsltPreComputeExtModuleElement(xsltStylesheetPtr style, xmlNodePtr inst) +{ + xsltExtElementPtr ext; + xsltElemPreCompPtr comp = NULL; + + if ((style == NULL) || (inst == NULL) || + (inst->type != XML_ELEMENT_NODE) || (inst->ns == NULL)) + return (NULL); + + xmlMutexLock(xsltExtMutex); + + ext = (xsltExtElementPtr) + xmlHashLookup2(xsltElementsHash, inst->name, inst->ns->href); + + xmlMutexUnlock(xsltExtMutex); + + /* + * EXT TODO: Now what? + */ + if (ext == NULL) + return (NULL); + + if (ext->precomp != NULL) { + /* + * REVISIT TODO: Check if the text below is correct. + * This will return a xsltElemPreComp structure or NULL. + * 1) If the the author of the extension needs a + * custom structure to hold the specific values of + * this extension, he will derive a structure based on + * xsltElemPreComp; thus we obviously *cannot* refactor + * the xsltElemPreComp structure, since all already derived + * user-defined strucures will break. + * Example: For the extension xsl:document, + * in xsltDocumentComp() (preproc.c), the structure + * xsltStyleItemDocument is allocated, filled with + * specific values and returned. + * 2) If the author needs no values to be stored in + * this structure, then he'll return NULL; + */ + comp = ext->precomp(style, inst, ext->transform); + } + if (comp == NULL) { + /* + * Default creation of a xsltElemPreComp structure, if + * the author of this extension did not create a custom + * structure. + */ + comp = xsltNewElemPreComp(style, inst, ext->transform); + } + + return (comp); +} + +/** + * xsltRegisterExtModuleElement: + * @name: the element name + * @URI: the element namespace URI + * @precomp: the pre-computation callback + * @transform: the transformation callback + * + * Registers an extension module element. + * + * Returns 0 if successful, -1 in case of error. + */ +int +xsltRegisterExtModuleElement(const xmlChar * name, const xmlChar * URI, + xsltPreComputeFunction precomp, + xsltTransformFunction transform) +{ + int ret = 0; + + xsltExtElementPtr ext; + + if ((name == NULL) || (URI == NULL) || (transform == NULL)) + return (-1); + + if (xsltElementsHash == NULL) + xsltElementsHash = xmlHashCreate(10); + if (xsltElementsHash == NULL) + return (-1); + + xmlMutexLock(xsltExtMutex); + + ext = xsltNewExtElement(precomp, transform); + if (ext == NULL) { + ret = -1; + goto done; + } + + xmlHashUpdateEntry2(xsltElementsHash, name, URI, (void *) ext, + xsltFreeExtElementEntry); + +done: + xmlMutexUnlock(xsltExtMutex); + + return (ret); +} + +/** + * xsltExtElementLookup: + * @ctxt: an XSLT process context + * @name: the element name + * @URI: the element namespace URI + * + * Looks up an extension element. @ctxt can be NULL to search only in + * module elements. + * + * Returns the element callback or NULL if not found + */ +xsltTransformFunction +xsltExtElementLookup(xsltTransformContextPtr ctxt, + const xmlChar * name, const xmlChar * URI) +{ + xsltTransformFunction ret; + + if ((name == NULL) || (URI == NULL)) + return (NULL); + + if ((ctxt != NULL) && (ctxt->extElements != NULL)) { + XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->extElements, name, URI); + if (ret != NULL) { + return(ret); + } + } + + ret = xsltExtModuleElementLookup(name, URI); + + return (ret); +} + +/** + * xsltExtModuleElementLookup: + * @name: the element name + * @URI: the element namespace URI + * + * Looks up an extension module element + * + * Returns the callback function if found, NULL otherwise. + */ +xsltTransformFunction +xsltExtModuleElementLookup(const xmlChar * name, const xmlChar * URI) +{ + xsltExtElementPtr ext; + + if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL)) + return (NULL); + + xmlMutexLock(xsltExtMutex); + + ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI); + + xmlMutexUnlock(xsltExtMutex); + + /* + * if function lookup fails, attempt a dynamic load on + * supported platforms + */ + if (NULL == ext) { + if (!xsltExtModuleRegisterDynamic(URI)) { + xmlMutexLock(xsltExtMutex); + + ext = (xsltExtElementPtr) + xmlHashLookup2(xsltElementsHash, name, URI); + + xmlMutexUnlock(xsltExtMutex); + } + } + + if (ext == NULL) + return (NULL); + return (ext->transform); +} + +/** + * xsltExtModuleElementPreComputeLookup: + * @name: the element name + * @URI: the element namespace URI + * + * Looks up an extension module element pre-computation function + * + * Returns the callback function if found, NULL otherwise. + */ +xsltPreComputeFunction +xsltExtModuleElementPreComputeLookup(const xmlChar * name, + const xmlChar * URI) +{ + xsltExtElementPtr ext; + + if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL)) + return (NULL); + + xmlMutexLock(xsltExtMutex); + + ext = (xsltExtElementPtr) xmlHashLookup2(xsltElementsHash, name, URI); + + xmlMutexUnlock(xsltExtMutex); + + if (ext == NULL) { + if (!xsltExtModuleRegisterDynamic(URI)) { + xmlMutexLock(xsltExtMutex); + + ext = (xsltExtElementPtr) + xmlHashLookup2(xsltElementsHash, name, URI); + + xmlMutexUnlock(xsltExtMutex); + } + } + + if (ext == NULL) + return (NULL); + return (ext->precomp); +} + +/** + * xsltUnregisterExtModuleElement: + * @name: the element name + * @URI: the element namespace URI + * + * Unregisters an extension module element + * + * Returns 0 if successful, -1 in case of error. + */ +int +xsltUnregisterExtModuleElement(const xmlChar * name, const xmlChar * URI) +{ + int ret; + + if ((xsltElementsHash == NULL) || (name == NULL) || (URI == NULL)) + return (-1); + + xmlMutexLock(xsltExtMutex); + + ret = xmlHashRemoveEntry2(xsltElementsHash, name, URI, + xsltFreeExtElementEntry); + + xmlMutexUnlock(xsltExtMutex); + + return(ret); +} + +/** + * xsltUnregisterAllExtModuleElement: + * + * Unregisters all extension module element + */ +static void +xsltUnregisterAllExtModuleElement(void) +{ + xmlMutexLock(xsltExtMutex); + + xmlHashFree(xsltElementsHash, xsltFreeExtElementEntry); + xsltElementsHash = NULL; + + xmlMutexUnlock(xsltExtMutex); +} + +/** + * xsltRegisterExtModuleTopLevel: + * @name: the top-level element name + * @URI: the top-level element namespace URI + * @function: the top-level element callback + * + * Registers an extension module top-level element. + * + * Returns 0 if successful, -1 in case of error. + */ +int +xsltRegisterExtModuleTopLevel(const xmlChar * name, const xmlChar * URI, + xsltTopLevelFunction function) +{ + if ((name == NULL) || (URI == NULL) || (function == NULL)) + return (-1); + + if (xsltTopLevelsHash == NULL) + xsltTopLevelsHash = xmlHashCreate(10); + if (xsltTopLevelsHash == NULL) + return (-1); + + xmlMutexLock(xsltExtMutex); + + xmlHashUpdateEntry2(xsltTopLevelsHash, name, URI, + XML_CAST_FPTR(function), NULL); + + xmlMutexUnlock(xsltExtMutex); + + return (0); +} + +/** + * xsltExtModuleTopLevelLookup: + * @name: the top-level element name + * @URI: the top-level element namespace URI + * + * Looks up an extension module top-level element + * + * Returns the callback function if found, NULL otherwise. + */ +xsltTopLevelFunction +xsltExtModuleTopLevelLookup(const xmlChar * name, const xmlChar * URI) +{ + xsltTopLevelFunction ret; + + if ((xsltTopLevelsHash == NULL) || (name == NULL) || (URI == NULL)) + return (NULL); + + xmlMutexLock(xsltExtMutex); + + XML_CAST_FPTR(ret) = xmlHashLookup2(xsltTopLevelsHash, name, URI); + + xmlMutexUnlock(xsltExtMutex); + + /* if lookup fails, attempt a dynamic load on supported platforms */ + if (NULL == ret) { + if (!xsltExtModuleRegisterDynamic(URI)) { + xmlMutexLock(xsltExtMutex); + + XML_CAST_FPTR(ret) = xmlHashLookup2(xsltTopLevelsHash, name, URI); + + xmlMutexUnlock(xsltExtMutex); + } + } + + return (ret); +} + +/** + * xsltUnregisterExtModuleTopLevel: + * @name: the top-level element name + * @URI: the top-level element namespace URI + * + * Unregisters an extension module top-level element + * + * Returns 0 if successful, -1 in case of error. + */ +int +xsltUnregisterExtModuleTopLevel(const xmlChar * name, const xmlChar * URI) +{ + int ret; + + if ((xsltTopLevelsHash == NULL) || (name == NULL) || (URI == NULL)) + return (-1); + + xmlMutexLock(xsltExtMutex); + + ret = xmlHashRemoveEntry2(xsltTopLevelsHash, name, URI, NULL); + + xmlMutexUnlock(xsltExtMutex); + + return(ret); +} + +/** + * xsltUnregisterAllExtModuleTopLevel: + * + * Unregisters all extension module function + */ +static void +xsltUnregisterAllExtModuleTopLevel(void) +{ + xmlMutexLock(xsltExtMutex); + + xmlHashFree(xsltTopLevelsHash, NULL); + xsltTopLevelsHash = NULL; + + xmlMutexUnlock(xsltExtMutex); +} + +/** + * xsltGetExtInfo: + * @style: pointer to a stylesheet + * @URI: the namespace URI desired + * + * looks up URI in extInfos of the stylesheet + * + * returns a pointer to the hash table if found, else NULL + */ +xmlHashTablePtr +xsltGetExtInfo(xsltStylesheetPtr style, const xmlChar * URI) +{ + xsltExtDataPtr data; + + /* + * TODO: Why do we have a return type of xmlHashTablePtr? + * Is the user-allocated data for extension modules expected + * to be a xmlHashTablePtr only? Or is this intended for + * the EXSLT module only? + */ + + if (style != NULL && style->extInfos != NULL) { + data = xmlHashLookup(style->extInfos, URI); + if (data != NULL && data->extData != NULL) + return data->extData; + } + return NULL; +} + +/************************************************************************ + * * + * Test of the extension module API * + * * + ************************************************************************/ + +static xmlChar *testData = NULL; +static xmlChar *testStyleData = NULL; + +/** + * xsltExtFunctionTest: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * function libxslt:test() for testing the extensions support. + */ +static void +xsltExtFunctionTest(xmlXPathParserContextPtr ctxt, + int nargs ATTRIBUTE_UNUSED) +{ + xsltTransformContextPtr tctxt; + void *data = NULL; + + tctxt = xsltXPathGetTransformContext(ctxt); + + if (testData == NULL) { + xsltGenericDebug(xsltGenericDebugContext, + "xsltExtFunctionTest: not initialized," + " calling xsltGetExtData\n"); + data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL); + if (data == NULL) { + xsltTransformError(tctxt, NULL, NULL, + "xsltExtElementTest: not initialized\n"); + return; + } + } + if (tctxt == NULL) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "xsltExtFunctionTest: failed to get the transformation context\n"); + return; + } + if (data == NULL) + data = xsltGetExtData(tctxt, (const xmlChar *) XSLT_DEFAULT_URL); + if (data == NULL) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "xsltExtFunctionTest: failed to get module data\n"); + return; + } + if (data != testData) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "xsltExtFunctionTest: got wrong module data\n"); + return; + } +#ifdef WITH_XSLT_DEBUG_FUNCTION + xsltGenericDebug(xsltGenericDebugContext, + "libxslt:test() called with %d args\n", nargs); +#endif +} + +/** + * xsltExtElementPreCompTest: + * @style: the stylesheet + * @inst: the instruction in the stylesheet + * + * Process a libxslt:test node + */ +static xsltElemPreCompPtr +xsltExtElementPreCompTest(xsltStylesheetPtr style, xmlNodePtr inst, + xsltTransformFunction function) +{ + xsltElemPreCompPtr ret; + + if (style == NULL) { + xsltTransformError(NULL, NULL, inst, + "xsltExtElementTest: no transformation context\n"); + return (NULL); + } + if (testStyleData == NULL) { + xsltGenericDebug(xsltGenericDebugContext, + "xsltExtElementPreCompTest: not initialized," + " calling xsltStyleGetExtData\n"); + xsltStyleGetExtData(style, (const xmlChar *) XSLT_DEFAULT_URL); + if (testStyleData == NULL) { + xsltTransformError(NULL, style, inst, + "xsltExtElementPreCompTest: not initialized\n"); + if (style != NULL) + style->errors++; + return (NULL); + } + } + if (inst == NULL) { + xsltTransformError(NULL, style, inst, + "xsltExtElementPreCompTest: no instruction\n"); + if (style != NULL) + style->errors++; + return (NULL); + } + ret = xsltNewElemPreComp(style, inst, function); + return (ret); +} + +/** + * xsltExtElementTest: + * @ctxt: an XSLT processing context + * @node: The current node + * @inst: the instruction in the stylesheet + * @comp: precomputed information + * + * Process a libxslt:test node + */ +static void +xsltExtElementTest(xsltTransformContextPtr ctxt, xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp ATTRIBUTE_UNUSED) +{ + xmlNodePtr commentNode; + + if (testData == NULL) { + xsltGenericDebug(xsltGenericDebugContext, + "xsltExtElementTest: not initialized," + " calling xsltGetExtData\n"); + xsltGetExtData(ctxt, (const xmlChar *) XSLT_DEFAULT_URL); + if (testData == NULL) { + xsltTransformError(ctxt, NULL, inst, + "xsltExtElementTest: not initialized\n"); + return; + } + } + if (ctxt == NULL) { + xsltTransformError(ctxt, NULL, inst, + "xsltExtElementTest: no transformation context\n"); + return; + } + if (node == NULL) { + xsltTransformError(ctxt, NULL, inst, + "xsltExtElementTest: no current node\n"); + return; + } + if (inst == NULL) { + xsltTransformError(ctxt, NULL, inst, + "xsltExtElementTest: no instruction\n"); + return; + } + if (ctxt->insert == NULL) { + xsltTransformError(ctxt, NULL, inst, + "xsltExtElementTest: no insertion point\n"); + return; + } + commentNode = xmlNewComment((const xmlChar *) + "libxslt:test element test worked"); + xmlAddChild(ctxt->insert, commentNode); +} + +/** + * xsltExtInitTest: + * @ctxt: an XSLT transformation context + * @URI: the namespace URI for the extension + * + * A function called at initialization time of an XSLT extension module + * + * Returns a pointer to the module specific data for this transformation + */ +static void * +xsltExtInitTest(xsltTransformContextPtr ctxt, const xmlChar * URI) +{ + if (testStyleData == NULL) { + xsltGenericDebug(xsltGenericErrorContext, + "xsltExtInitTest: not initialized," + " calling xsltStyleGetExtData\n"); + testStyleData = xsltStyleGetExtData(ctxt->style, URI); + if (testStyleData == NULL) { + xsltTransformError(ctxt, NULL, NULL, + "xsltExtInitTest: not initialized\n"); + return (NULL); + } + } + if (testData != NULL) { + xsltTransformError(ctxt, NULL, NULL, + "xsltExtInitTest: already initialized\n"); + return (NULL); + } + testData = (void *) "test data"; + xsltGenericDebug(xsltGenericDebugContext, + "Registered test module : %s\n", URI); + return (testData); +} + + +/** + * xsltExtShutdownTest: + * @ctxt: an XSLT transformation context + * @URI: the namespace URI for the extension + * @data: the data associated to this module + * + * A function called at shutdown time of an XSLT extension module + */ +static void +xsltExtShutdownTest(xsltTransformContextPtr ctxt, + const xmlChar * URI, void *data) +{ + if (testData == NULL) { + xsltTransformError(ctxt, NULL, NULL, + "xsltExtShutdownTest: not initialized\n"); + return; + } + if (data != testData) { + xsltTransformError(ctxt, NULL, NULL, + "xsltExtShutdownTest: wrong data\n"); + } + testData = NULL; + xsltGenericDebug(xsltGenericDebugContext, + "Unregistered test module : %s\n", URI); +} + +/** + * xsltExtStyleInitTest: + * @style: an XSLT stylesheet + * @URI: the namespace URI for the extension + * + * A function called at initialization time of an XSLT extension module + * + * Returns a pointer to the module specific data for this transformation + */ +static void * +xsltExtStyleInitTest(xsltStylesheetPtr style ATTRIBUTE_UNUSED, + const xmlChar * URI) +{ + if (testStyleData != NULL) { + xsltTransformError(NULL, NULL, NULL, + "xsltExtInitTest: already initialized\n"); + return (NULL); + } + testStyleData = (void *) "test data"; + xsltGenericDebug(xsltGenericDebugContext, + "Registered test module : %s\n", URI); + return (testStyleData); +} + + +/** + * xsltExtStyleShutdownTest: + * @style: an XSLT stylesheet + * @URI: the namespace URI for the extension + * @data: the data associated to this module + * + * A function called at shutdown time of an XSLT extension module + */ +static void +xsltExtStyleShutdownTest(xsltStylesheetPtr style ATTRIBUTE_UNUSED, + const xmlChar * URI, void *data) +{ + if (testStyleData == NULL) { + xsltGenericError(xsltGenericErrorContext, + "xsltExtShutdownTest: not initialized\n"); + return; + } + if (data != testStyleData) { + xsltTransformError(NULL, NULL, NULL, + "xsltExtShutdownTest: wrong data\n"); + } + testStyleData = NULL; + xsltGenericDebug(xsltGenericDebugContext, + "Unregistered test module : %s\n", URI); +} + +/** + * xsltRegisterTestModule: + * + * Registers the test module + */ +void +xsltRegisterTestModule(void) +{ + xsltInitGlobals(); + xsltRegisterExtModuleFull((const xmlChar *) XSLT_DEFAULT_URL, + xsltExtInitTest, xsltExtShutdownTest, + xsltExtStyleInitTest, + xsltExtStyleShutdownTest); + xsltRegisterExtModuleFunction((const xmlChar *) "test", + (const xmlChar *) XSLT_DEFAULT_URL, + xsltExtFunctionTest); + xsltRegisterExtModuleElement((const xmlChar *) "test", + (const xmlChar *) XSLT_DEFAULT_URL, + xsltExtElementPreCompTest, + xsltExtElementTest); +} + +static void +xsltHashScannerModuleFree(void *payload, + void *data ATTRIBUTE_UNUSED, + const xmlChar *name ATTRIBUTE_UNUSED) +{ +#ifdef WITH_MODULES +#ifdef _WIN32 + FreeLibrary(payload); +#else + dlclose(payload); +#endif +#else + (void) payload; +#endif +} + +/** + * xsltInitGlobals: + * + * Initialize the global variables for extensions + */ +void +xsltInitGlobals(void) +{ + if (xsltExtMutex == NULL) { + xsltExtMutex = xmlNewMutex(); + } +} + +/** + * xsltCleanupGlobals: + * + * Unregister all global variables set up by the XSLT library + */ +void +xsltCleanupGlobals(void) +{ + xsltUnregisterAllExtModules(); + xsltUnregisterAllExtModuleFunction(); + xsltUnregisterAllExtModuleElement(); + xsltUnregisterAllExtModuleTopLevel(); + + xmlMutexLock(xsltExtMutex); + /* cleanup dynamic module hash */ + if (NULL != xsltModuleHash) { + xmlHashScan(xsltModuleHash, xsltHashScannerModuleFree, 0); + xmlHashFree(xsltModuleHash, NULL); + xsltModuleHash = NULL; + } + xmlMutexUnlock(xsltExtMutex); + + xmlFreeMutex(xsltExtMutex); + xsltExtMutex = NULL; + xsltFreeLocales(); + xsltUninit(); +} + +static void +xsltDebugDumpExtensionsCallback(void *function ATTRIBUTE_UNUSED, + void *data, const xmlChar * name, + const xmlChar * URI, + const xmlChar * not_used ATTRIBUTE_UNUSED) +{ + FILE *output = (FILE *) data; + if (!name || !URI) + return; + fprintf(output, "{%s}%s\n", URI, name); +} + +static void +xsltDebugDumpExtModulesCallback(void *function ATTRIBUTE_UNUSED, + void *data, const xmlChar * URI, + const xmlChar * not_used ATTRIBUTE_UNUSED, + const xmlChar * not_used2 ATTRIBUTE_UNUSED) +{ + FILE *output = (FILE *) data; + if (!URI) + return; + fprintf(output, "%s\n", URI); +} + +/** + * xsltDebugDumpExtensions: + * @output: the FILE * for the output, if NULL stdout is used + * + * Dumps a list of the registered XSLT extension functions and elements + */ +void +xsltDebugDumpExtensions(FILE * output) +{ + if (output == NULL) + output = stdout; + fprintf(output, + "Registered XSLT Extensions\n--------------------------\n"); + xmlMutexLock(xsltExtMutex); + if (!xsltFunctionsHash) { + fprintf(output, "No registered extension functions\n"); + } else { + fprintf(output, "Registered extension functions:\n"); + xmlHashScanFull(xsltFunctionsHash, xsltDebugDumpExtensionsCallback, + output); + } + if (!xsltTopLevelsHash) { + fprintf(output, "\nNo registered top-level extension elements\n"); + } else { + fprintf(output, "\nRegistered top-level extension elements:\n"); + xmlHashScanFull(xsltTopLevelsHash, xsltDebugDumpExtensionsCallback, + output); + } + if (!xsltElementsHash) { + fprintf(output, "\nNo registered instruction extension elements\n"); + } else { + fprintf(output, "\nRegistered instruction extension elements:\n"); + xmlHashScanFull(xsltElementsHash, xsltDebugDumpExtensionsCallback, + output); + } + if (!xsltExtensionsHash) { + fprintf(output, "\nNo registered extension modules\n"); + } else { + fprintf(output, "\nRegistered extension modules:\n"); + xmlHashScanFull(xsltExtensionsHash, xsltDebugDumpExtModulesCallback, + output); + } + xmlMutexUnlock(xsltExtMutex); +} diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/extensions.h chromium-145.0.7632.159/third_party/libxslt/src/libxslt/extensions.h --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/extensions.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/extensions.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,262 @@ +/* + * Summary: interface for the extension support + * Description: This provide the API needed for simple and module + * extension support. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLT_EXTENSION_H__ +#define __XML_XSLT_EXTENSION_H__ + +#include +#include "xsltexports.h" +#include "xsltInternals.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Extension Modules API. + */ + +/** + * xsltInitGlobals: + * + * Initialize the global variables for extensions + * + */ + +XSLTPUBFUN void XSLTCALL + xsltInitGlobals (void); + +/** + * xsltStyleExtInitFunction: + * @ctxt: an XSLT stylesheet + * @URI: the namespace URI for the extension + * + * A function called at initialization time of an XSLT extension module. + * + * Returns a pointer to the module specific data for this transformation. + */ +typedef void * (*xsltStyleExtInitFunction) (xsltStylesheetPtr style, + const xmlChar *URI); + +/** + * xsltStyleExtShutdownFunction: + * @ctxt: an XSLT stylesheet + * @URI: the namespace URI for the extension + * @data: the data associated to this module + * + * A function called at shutdown time of an XSLT extension module. + */ +typedef void (*xsltStyleExtShutdownFunction) (xsltStylesheetPtr style, + const xmlChar *URI, + void *data); + +/** + * xsltExtInitFunction: + * @ctxt: an XSLT transformation context + * @URI: the namespace URI for the extension + * + * A function called at initialization time of an XSLT extension module. + * + * Returns a pointer to the module specific data for this transformation. + */ +typedef void * (*xsltExtInitFunction) (xsltTransformContextPtr ctxt, + const xmlChar *URI); + +/** + * xsltExtShutdownFunction: + * @ctxt: an XSLT transformation context + * @URI: the namespace URI for the extension + * @data: the data associated to this module + * + * A function called at shutdown time of an XSLT extension module. + */ +typedef void (*xsltExtShutdownFunction) (xsltTransformContextPtr ctxt, + const xmlChar *URI, + void *data); + +XSLTPUBFUN int XSLTCALL + xsltRegisterExtModule (const xmlChar *URI, + xsltExtInitFunction initFunc, + xsltExtShutdownFunction shutdownFunc); +XSLTPUBFUN int XSLTCALL + xsltRegisterExtModuleFull + (const xmlChar * URI, + xsltExtInitFunction initFunc, + xsltExtShutdownFunction shutdownFunc, + xsltStyleExtInitFunction styleInitFunc, + xsltStyleExtShutdownFunction styleShutdownFunc); + +XSLTPUBFUN int XSLTCALL + xsltUnregisterExtModule (const xmlChar * URI); + +XSLTPUBFUN void * XSLTCALL + xsltGetExtData (xsltTransformContextPtr ctxt, + const xmlChar *URI); + +XSLTPUBFUN void * XSLTCALL + xsltStyleGetExtData (xsltStylesheetPtr style, + const xmlChar *URI); +#ifdef XSLT_REFACTORED +XSLTPUBFUN void * XSLTCALL + xsltStyleStylesheetLevelGetExtData( + xsltStylesheetPtr style, + const xmlChar * URI); +#endif +XSLTPUBFUN void XSLTCALL + xsltShutdownCtxtExts (xsltTransformContextPtr ctxt); + +XSLTPUBFUN void XSLTCALL + xsltShutdownExts (xsltStylesheetPtr style); + +XSLTPUBFUN xsltTransformContextPtr XSLTCALL + xsltXPathGetTransformContext + (xmlXPathParserContextPtr ctxt); + +/* + * extension functions +*/ +XSLTPUBFUN int XSLTCALL + xsltRegisterExtModuleFunction + (const xmlChar *name, + const xmlChar *URI, + xmlXPathFunction function); +XSLTPUBFUN xmlXPathFunction XSLTCALL + xsltExtModuleFunctionLookup (const xmlChar *name, + const xmlChar *URI); +XSLTPUBFUN int XSLTCALL + xsltUnregisterExtModuleFunction + (const xmlChar *name, + const xmlChar *URI); + +/* + * extension elements + */ +typedef xsltElemPreCompPtr (*xsltPreComputeFunction) + (xsltStylesheetPtr style, + xmlNodePtr inst, + xsltTransformFunction function); + +XSLTPUBFUN xsltElemPreCompPtr XSLTCALL + xsltNewElemPreComp (xsltStylesheetPtr style, + xmlNodePtr inst, + xsltTransformFunction function); +XSLTPUBFUN void XSLTCALL + xsltInitElemPreComp (xsltElemPreCompPtr comp, + xsltStylesheetPtr style, + xmlNodePtr inst, + xsltTransformFunction function, + xsltElemPreCompDeallocator freeFunc); + +XSLTPUBFUN int XSLTCALL + xsltRegisterExtModuleElement + (const xmlChar *name, + const xmlChar *URI, + xsltPreComputeFunction precomp, + xsltTransformFunction transform); +XSLTPUBFUN xsltTransformFunction XSLTCALL + xsltExtElementLookup (xsltTransformContextPtr ctxt, + const xmlChar *name, + const xmlChar *URI); +XSLTPUBFUN xsltTransformFunction XSLTCALL + xsltExtModuleElementLookup + (const xmlChar *name, + const xmlChar *URI); +XSLTPUBFUN xsltPreComputeFunction XSLTCALL + xsltExtModuleElementPreComputeLookup + (const xmlChar *name, + const xmlChar *URI); +XSLTPUBFUN int XSLTCALL + xsltUnregisterExtModuleElement + (const xmlChar *name, + const xmlChar *URI); + +/* + * top-level elements + */ +typedef void (*xsltTopLevelFunction) (xsltStylesheetPtr style, + xmlNodePtr inst); + +XSLTPUBFUN int XSLTCALL + xsltRegisterExtModuleTopLevel + (const xmlChar *name, + const xmlChar *URI, + xsltTopLevelFunction function); +XSLTPUBFUN xsltTopLevelFunction XSLTCALL + xsltExtModuleTopLevelLookup + (const xmlChar *name, + const xmlChar *URI); +XSLTPUBFUN int XSLTCALL + xsltUnregisterExtModuleTopLevel + (const xmlChar *name, + const xmlChar *URI); + + +/* These 2 functions are deprecated for use within modules. */ +XSLTPUBFUN int XSLTCALL + xsltRegisterExtFunction (xsltTransformContextPtr ctxt, + const xmlChar *name, + const xmlChar *URI, + xmlXPathFunction function); +XSLTPUBFUN int XSLTCALL + xsltRegisterExtElement (xsltTransformContextPtr ctxt, + const xmlChar *name, + const xmlChar *URI, + xsltTransformFunction function); + +/* + * Extension Prefix handling API. + * Those are used by the XSLT (pre)processor. + */ + +XSLTPUBFUN int XSLTCALL + xsltRegisterExtPrefix (xsltStylesheetPtr style, + const xmlChar *prefix, + const xmlChar *URI); +XSLTPUBFUN int XSLTCALL + xsltCheckExtPrefix (xsltStylesheetPtr style, + const xmlChar *URI); +XSLTPUBFUN int XSLTCALL + xsltCheckExtURI (xsltStylesheetPtr style, + const xmlChar *URI); +XSLTPUBFUN int XSLTCALL + xsltInitCtxtExts (xsltTransformContextPtr ctxt); +XSLTPUBFUN void XSLTCALL + xsltFreeCtxtExts (xsltTransformContextPtr ctxt); +XSLTPUBFUN void XSLTCALL + xsltFreeExts (xsltStylesheetPtr style); + +XSLTPUBFUN xsltElemPreCompPtr XSLTCALL + xsltPreComputeExtModuleElement + (xsltStylesheetPtr style, + xmlNodePtr inst); +/* + * Extension Infos access. + * Used by exslt initialisation + */ + +XSLTPUBFUN xmlHashTablePtr XSLTCALL + xsltGetExtInfo (xsltStylesheetPtr style, + const xmlChar *URI); + +/** + * Test of the extension module API + */ +XSLTPUBFUN void XSLTCALL + xsltRegisterTestModule (void); +XSLTPUBFUN void XSLTCALL + xsltDebugDumpExtensions (FILE * output); + + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_EXTENSION_H__ */ + diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/extra.c chromium-145.0.7632.159/third_party/libxslt/src/libxslt/extra.c --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/extra.c 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/extra.c 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,197 @@ +/* + * extra.c: Implementation of non-standard features + * + * Reference: + * Michael Kay "XSLT Programmer's Reference" pp 637-643 + * The node-set() extension function + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#define IN_LIBXSLT +#include "libxslt.h" + +#include +#include + +#include +#include +#include +#include +#include +#include "xslt.h" +#include "xsltInternals.h" +#include "xsltutils.h" +#include "extensions.h" +#include "variables.h" +#include "transform.h" +#include "extra.h" +#include "preproc.h" + +#ifdef WITH_XSLT_DEBUG +#define WITH_XSLT_DEBUG_EXTRA +#endif + +/************************************************************************ + * * + * Handling of XSLT debugging * + * * + ************************************************************************/ + +/** + * xsltDebug: + * @ctxt: an XSLT processing context + * @node: The current node + * @inst: the instruction in the stylesheet + * @comp: precomputed information + * + * Process an debug node + */ +void +xsltDebug(xsltTransformContextPtr ctxt, xmlNodePtr node ATTRIBUTE_UNUSED, + xmlNodePtr inst ATTRIBUTE_UNUSED, + xsltElemPreCompPtr comp ATTRIBUTE_UNUSED) +{ + int i, j; + + xsltGenericError(xsltGenericErrorContext, "Templates:\n"); + for (i = 0, j = ctxt->templNr - 1; ((i < 15) && (j >= 0)); i++, j--) { + xsltGenericError(xsltGenericErrorContext, "#%d ", i); + if (ctxt->templTab[j]->name != NULL) + xsltGenericError(xsltGenericErrorContext, "name %s ", + ctxt->templTab[j]->name); + if (ctxt->templTab[j]->match != NULL) + xsltGenericError(xsltGenericErrorContext, "name %s ", + ctxt->templTab[j]->match); + if (ctxt->templTab[j]->mode != NULL) + xsltGenericError(xsltGenericErrorContext, "name %s ", + ctxt->templTab[j]->mode); + xsltGenericError(xsltGenericErrorContext, "\n"); + } + xsltGenericError(xsltGenericErrorContext, "Variables:\n"); + for (i = 0, j = ctxt->varsNr - 1; ((i < 15) && (j >= 0)); i++, j--) { + xsltStackElemPtr cur; + + if (ctxt->varsTab[j] == NULL) + continue; + xsltGenericError(xsltGenericErrorContext, "#%d\n", i); + cur = ctxt->varsTab[j]; + while (cur != NULL) { + if (cur->comp == NULL) { + xsltGenericError(xsltGenericErrorContext, + "corrupted !!!\n"); + } else if (cur->comp->type == XSLT_FUNC_PARAM) { + xsltGenericError(xsltGenericErrorContext, "param "); + } else if (cur->comp->type == XSLT_FUNC_VARIABLE) { + xsltGenericError(xsltGenericErrorContext, "var "); + } + if (cur->name != NULL) + xsltGenericError(xsltGenericErrorContext, "%s ", + cur->name); + else + xsltGenericError(xsltGenericErrorContext, "noname !!!!"); +#ifdef LIBXML_DEBUG_ENABLED + if (cur->value != NULL) { + if ((xsltGenericDebugContext == stdout) || + (xsltGenericDebugContext == stderr)) + xmlXPathDebugDumpObject((FILE*)xsltGenericDebugContext, + cur->value, 1); + } else { + xsltGenericError(xsltGenericErrorContext, "NULL !!!!"); + } +#endif + xsltGenericError(xsltGenericErrorContext, "\n"); + cur = cur->next; + } + + } +} + +/************************************************************************ + * * + * Classic extensions as described by M. Kay * + * * + ************************************************************************/ + +/** + * xsltFunctionNodeSet: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the node-set() XSLT function + * node-set node-set(result-tree) + * + * This function is available in libxslt, saxon or xt namespace. + */ +void +xsltFunctionNodeSet(xmlXPathParserContextPtr ctxt, int nargs){ + if (nargs != 1) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "node-set() : expects one result-tree arg\n"); + ctxt->error = XPATH_INVALID_ARITY; + return; + } + if ((ctxt->value == NULL) || + ((ctxt->value->type != XPATH_XSLT_TREE) && + (ctxt->value->type != XPATH_NODESET))) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "node-set() invalid arg expecting a result tree\n"); + ctxt->error = XPATH_INVALID_TYPE; + return; + } + if (ctxt->value->type == XPATH_XSLT_TREE) { + ctxt->value->type = XPATH_NODESET; + } +} + +/** + * xsltRegisterExtras: + * @ctxt: a XSLT process context + * + * Registers the built-in extensions. This function is deprecated, use + * xsltRegisterAllExtras instead. + */ +void +xsltRegisterExtras(xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED) { + xsltRegisterAllExtras(); +} + +/** + * xsltRegisterAllExtras: + * + * Registers the built-in extensions + */ +void +xsltRegisterAllExtras (void) { + xsltRegisterExtModuleFunction((const xmlChar *) "node-set", + XSLT_LIBXSLT_NAMESPACE, + xsltFunctionNodeSet); + xsltRegisterExtModuleFunction((const xmlChar *) "node-set", + XSLT_SAXON_NAMESPACE, + xsltFunctionNodeSet); + xsltRegisterExtModuleFunction((const xmlChar *) "node-set", + XSLT_XT_NAMESPACE, + xsltFunctionNodeSet); + xsltRegisterExtModuleElement((const xmlChar *) "debug", + XSLT_LIBXSLT_NAMESPACE, + NULL, + xsltDebug); + xsltRegisterExtModuleElement((const xmlChar *) "output", + XSLT_SAXON_NAMESPACE, + xsltDocumentComp, + xsltDocumentElem); + xsltRegisterExtModuleElement((const xmlChar *) "write", + XSLT_XALAN_NAMESPACE, + xsltDocumentComp, + xsltDocumentElem); + xsltRegisterExtModuleElement((const xmlChar *) "document", + XSLT_XT_NAMESPACE, + xsltDocumentComp, + xsltDocumentElem); + xsltRegisterExtModuleElement((const xmlChar *) "document", + XSLT_NAMESPACE, + xsltDocumentComp, + xsltDocumentElem); +} diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/extra.h chromium-145.0.7632.159/third_party/libxslt/src/libxslt/extra.h --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/extra.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/extra.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,72 @@ +/* + * Summary: interface for the non-standard features + * Description: implement some extension outside the XSLT namespace + * but not EXSLT with is in a different library. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLT_EXTRA_H__ +#define __XML_XSLT_EXTRA_H__ + +#include +#include "xsltexports.h" +#include "xsltInternals.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * XSLT_LIBXSLT_NAMESPACE: + * + * This is the libxslt namespace for specific extensions. + */ +#define XSLT_LIBXSLT_NAMESPACE ((xmlChar *) "http://xmlsoft.org/XSLT/namespace") + +/** + * XSLT_SAXON_NAMESPACE: + * + * This is Michael Kay's Saxon processor namespace for extensions. + */ +#define XSLT_SAXON_NAMESPACE ((xmlChar *) "http://icl.com/saxon") + +/** + * XSLT_XT_NAMESPACE: + * + * This is James Clark's XT processor namespace for extensions. + */ +#define XSLT_XT_NAMESPACE ((xmlChar *) "http://www.jclark.com/xt") + +/** + * XSLT_XALAN_NAMESPACE: + * + * This is the Apache project XALAN processor namespace for extensions. + */ +#define XSLT_XALAN_NAMESPACE ((xmlChar *) \ + "org.apache.xalan.xslt.extensions.Redirect") + + +XSLTPUBFUN void XSLTCALL + xsltFunctionNodeSet (xmlXPathParserContextPtr ctxt, + int nargs); +XSLTPUBFUN void XSLTCALL + xsltDebug (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); + + +XSLTPUBFUN void XSLTCALL + xsltRegisterExtras (xsltTransformContextPtr ctxt); +XSLTPUBFUN void XSLTCALL + xsltRegisterAllExtras (void); + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_EXTRA_H__ */ + diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/functions.c chromium-145.0.7632.159/third_party/libxslt/src/libxslt/functions.c --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/functions.c 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/functions.c 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,1109 @@ +/* + * functions.c: Implementation of the XSLT extra functions + * + * Reference: + * http://www.w3.org/TR/1999/REC-xslt-19991116 + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + * Bjorn Reese for number formatting + */ + +#define IN_LIBXSLT +#include "libxslt.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xslt.h" +#include "xsltInternals.h" +#include "xsltutils.h" +#include "functions.h" +#include "extensions.h" +#include "numbersInternals.h" +#include "keys.h" +#include "documents.h" +#include "transformInternals.h" + +#ifdef WITH_XSLT_DEBUG +#define WITH_XSLT_DEBUG_FUNCTION +#endif + +/* + * Some versions of DocBook XSL use the vendor string to detect + * supporting chunking, this is a workaround to be considered + * in the list of decent XSLT processors + */ +#define DOCBOOK_XSL_HACK + +/** + * xsltXPathFunctionLookup: + * @vctxt: a void * but the XSLT transformation context actually + * @name: the function name + * @ns_uri: the function namespace URI + * + * This is the entry point when a function is needed by the XPath + * interpretor. + * + * Returns the callback function or NULL if not found + */ +xmlXPathFunction +xsltXPathFunctionLookup (void *vctxt, + const xmlChar *name, const xmlChar *ns_uri) { + xmlXPathContextPtr ctxt = (xmlXPathContextPtr) vctxt; + xmlXPathFunction ret; + + if ((ctxt == NULL) || (name == NULL) || (ns_uri == NULL)) + return (NULL); + +#ifdef WITH_XSLT_DEBUG_FUNCTION + xsltGenericDebug(xsltGenericDebugContext, + "Lookup function {%s}%s\n", ns_uri, name); +#endif + + /* give priority to context-level functions */ + /* + ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri); + */ + XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri); + + if (ret == NULL) + ret = xsltExtModuleFunctionLookup(name, ns_uri); + +#ifdef WITH_XSLT_DEBUG_FUNCTION + if (ret != NULL) + xsltGenericDebug(xsltGenericDebugContext, + "found function %s\n", name); +#endif + return(ret); +} + + +/************************************************************************ + * * + * Module interfaces * + * * + ************************************************************************/ + +static void +xsltDocumentFunctionLoadDocument(xmlXPathParserContextPtr ctxt, + const xmlChar* URI, const xmlChar *fragment) +{ + xsltTransformContextPtr tctxt; + xsltDocumentPtr idoc; /* document info */ + xmlDocPtr doc; + xmlXPathContextPtr xptrctxt = NULL; + xmlXPathObjectPtr resObj = NULL; + + (void) xptrctxt; + + tctxt = xsltXPathGetTransformContext(ctxt); + if (tctxt == NULL) { + xsltTransformError(NULL, NULL, NULL, + "document() : internal error tctxt == NULL\n"); + goto out_fragment; + } + + idoc = xsltLoadDocument(tctxt, URI); + + if (idoc == NULL) { + if ((URI == NULL) || + (URI[0] == '#') || + ((tctxt->style->doc != NULL) && + (xmlStrEqual(tctxt->style->doc->URL, URI)))) + { + /* + * This selects the stylesheet's doc itself. + */ + doc = xmlCopyDoc(tctxt->style->doc, 1); + if (doc == NULL) { + xsltTransformError(tctxt, NULL, NULL, + "document() : failed to copy style doc\n"); + goto out_fragment; + } + xsltCleanupSourceDoc(doc); /* Remove psvi fields. */ + idoc = xsltNewDocument(tctxt, doc); + if (idoc == NULL) { + xsltTransformError(tctxt, NULL, NULL, + "document() : failed to create xsltDocument\n"); + xmlFreeDoc(doc); + goto out_fragment; + } + } else { + goto out_fragment; + } + } else + doc = idoc->doc; + + if (fragment == NULL) { + valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr) doc)); + return; + } + + /* use XPointer of HTML location for fragment ID */ +#ifdef LIBXML_XPTR_ENABLED + xptrctxt = xmlXPathNewContext(doc); + if (xptrctxt == NULL) { + xsltTransformError(tctxt, NULL, NULL, + "document() : internal error xptrctxt == NULL\n"); + goto out_fragment; + } + +#if LIBXML_VERSION >= 20911 || \ + defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) + xptrctxt->opLimit = ctxt->context->opLimit; + xptrctxt->opCount = ctxt->context->opCount; + xptrctxt->depth = ctxt->context->depth; + + resObj = xmlXPtrEval(fragment, xptrctxt); + + ctxt->context->opCount = xptrctxt->opCount; +#else + resObj = xmlXPtrEval(fragment, xptrctxt); +#endif + + xmlXPathFreeContext(xptrctxt); +#endif /* LIBXML_XPTR_ENABLED */ + + if ((resObj != NULL) && (resObj->type != XPATH_NODESET)) { + xsltTransformError(tctxt, NULL, NULL, + "document() : XPointer does not select a node set: #%s\n", + fragment); + xmlXPathFreeObject(resObj); + resObj = NULL; + } + +out_fragment: + if (resObj == NULL) + resObj = xmlXPathNewNodeSet(NULL); + valuePush(ctxt, resObj); +} + +/** + * xsltDocumentFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the document() XSLT function + * node-set document(object, node-set?) + */ +void +xsltDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs) +{ + xmlXPathObjectPtr obj, obj2 = NULL; + xmlChar *base = NULL, *URI; + xmlChar *newURI = NULL; + xmlChar *fragment = NULL; + + if ((nargs < 1) || (nargs > 2)) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "document() : invalid number of args %d\n", + nargs); + ctxt->error = XPATH_INVALID_ARITY; + return; + } + if (ctxt->value == NULL) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "document() : invalid arg value\n"); + ctxt->error = XPATH_INVALID_TYPE; + return; + } + + if (nargs == 2) { + if (ctxt->value->type != XPATH_NODESET) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "document() : invalid arg expecting a nodeset\n"); + ctxt->error = XPATH_INVALID_TYPE; + return; + } + + obj2 = valuePop(ctxt); + } + + if ((ctxt->value != NULL) && (ctxt->value->type == XPATH_NODESET)) { + int i; + xmlXPathObjectPtr newobj, ret; + + obj = valuePop(ctxt); + ret = xmlXPathNewNodeSet(NULL); + + if ((obj != NULL) && (obj->nodesetval != NULL) && (ret != NULL)) { + for (i = 0; i < obj->nodesetval->nodeNr; i++) { + valuePush(ctxt, + xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i])); + xmlXPathStringFunction(ctxt, 1); + if (nargs == 2) { + valuePush(ctxt, xmlXPathObjectCopy(obj2)); + } else { + valuePush(ctxt, + xmlXPathNewNodeSet(obj->nodesetval-> + nodeTab[i])); + } + if (ctxt->error) + break; + xsltDocumentFunction(ctxt, 2); + newobj = valuePop(ctxt); + if (newobj != NULL) { + ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval, + newobj->nodesetval); + xmlXPathFreeObject(newobj); + } + } + } + + if (obj != NULL) + xmlXPathFreeObject(obj); + if (obj2 != NULL) + xmlXPathFreeObject(obj2); + valuePush(ctxt, ret); + return; + } + /* + * Make sure it's converted to a string + */ + xmlXPathStringFunction(ctxt, 1); + if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "document() : invalid arg expecting a string\n"); + ctxt->error = XPATH_INVALID_TYPE; + if (obj2 != NULL) + xmlXPathFreeObject(obj2); + return; + } + obj = valuePop(ctxt); + if (obj->stringval == NULL) { + valuePush(ctxt, xmlXPathNewNodeSet(NULL)); + } else { + xsltTransformContextPtr tctxt; + xmlURIPtr uri; + const xmlChar *url; + + tctxt = xsltXPathGetTransformContext(ctxt); + + url = obj->stringval; + + uri = xmlParseURI((const char *) url); + if (uri == NULL) { + xsltTransformError(tctxt, NULL, NULL, + "document() : failed to parse URI '%s'\n", url); + valuePush(ctxt, xmlXPathNewNodeSet(NULL)); + goto error; + } + + /* + * check for and remove fragment identifier + */ + fragment = (xmlChar *)uri->fragment; + if (fragment != NULL) { + uri->fragment = NULL; + newURI = xmlSaveUri(uri); + url = newURI; + } + xmlFreeURI(uri); + + if ((obj2 != NULL) && (obj2->nodesetval != NULL) && + (obj2->nodesetval->nodeNr > 0) && + IS_XSLT_REAL_NODE(obj2->nodesetval->nodeTab[0])) { + xmlNodePtr target; + + target = obj2->nodesetval->nodeTab[0]; + if ((target->type == XML_ATTRIBUTE_NODE) || + (target->type == XML_PI_NODE)) { + target = ((xmlAttrPtr) target)->parent; + } + base = xmlNodeGetBase(target->doc, target); + } else { + if ((tctxt != NULL) && (tctxt->inst != NULL)) { + base = xmlNodeGetBase(tctxt->inst->doc, tctxt->inst); + } else if ((tctxt != NULL) && (tctxt->style != NULL) && + (tctxt->style->doc != NULL)) { + base = xmlNodeGetBase(tctxt->style->doc, + (xmlNodePtr) tctxt->style->doc); + } + } + + URI = xmlBuildURI(url, base); + if (base != NULL) + xmlFree(base); + if (URI == NULL) { + if ((tctxt != NULL) && (tctxt->style != NULL) && + (tctxt->style->doc != NULL) && + (xmlStrEqual(URI, tctxt->style->doc->URL))) { + /* This selects the stylesheet's doc itself. */ + valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr) tctxt->style->doc)); + } else { + valuePush(ctxt, xmlXPathNewNodeSet(NULL)); + } + } else { + xsltDocumentFunctionLoadDocument(ctxt, URI, fragment); + xmlFree(URI); + } + } + +error: + xmlFree(newURI); + xmlFree(fragment); + xmlXPathFreeObject(obj); + if (obj2 != NULL) + xmlXPathFreeObject(obj2); +} + +/** + * xsltKeyFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the key() XSLT function + * node-set key(string, object) + */ +void +xsltKeyFunction(xmlXPathParserContextPtr ctxt, int nargs){ + xmlXPathObjectPtr obj1, obj2; + + if (nargs != 2) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "key() : expects two arguments\n"); + ctxt->error = XPATH_INVALID_ARITY; + return; + } + + /* + * Get the key's value. + */ + obj2 = valuePop(ctxt); + xmlXPathStringFunction(ctxt, 1); + if ((obj2 == NULL) || + (ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "key() : invalid arg expecting a string\n"); + ctxt->error = XPATH_INVALID_TYPE; + xmlXPathFreeObject(obj2); + + return; + } + /* + * Get the key's name. + */ + obj1 = valuePop(ctxt); + + if ((obj2->type == XPATH_NODESET) || (obj2->type == XPATH_XSLT_TREE)) { + int i; + xmlXPathObjectPtr newobj, ret; + + ret = xmlXPathNewNodeSet(NULL); + if (ret == NULL) { + ctxt->error = XPATH_MEMORY_ERROR; + xmlXPathFreeObject(obj1); + xmlXPathFreeObject(obj2); + return; + } + + if (obj2->nodesetval != NULL) { + for (i = 0; i < obj2->nodesetval->nodeNr; i++) { + valuePush(ctxt, xmlXPathObjectCopy(obj1)); + valuePush(ctxt, + xmlXPathNewNodeSet(obj2->nodesetval->nodeTab[i])); + xmlXPathStringFunction(ctxt, 1); + xsltKeyFunction(ctxt, 2); + newobj = valuePop(ctxt); + if (newobj != NULL) + ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval, + newobj->nodesetval); + xmlXPathFreeObject(newobj); + } + } + valuePush(ctxt, ret); + } else { + xmlNodeSetPtr nodelist = NULL; + xmlChar *key = NULL, *value; + const xmlChar *keyURI; + xsltTransformContextPtr tctxt; + xmlChar *qname, *prefix; + xmlXPathContextPtr xpctxt = ctxt->context; + xmlNodePtr tmpNode = NULL; + xsltDocumentPtr oldDocInfo; + + tctxt = xsltXPathGetTransformContext(ctxt); + + oldDocInfo = tctxt->document; + + if (xpctxt->node == NULL) { + xsltTransformError(tctxt, NULL, tctxt->inst, + "Internal error in xsltKeyFunction(): " + "The context node is not set on the XPath context.\n"); + tctxt->state = XSLT_STATE_STOPPED; + goto error; + } + /* + * Get the associated namespace URI if qualified name + */ + qname = obj1->stringval; + key = xmlSplitQName2(qname, &prefix); + if (key == NULL) { + key = xmlStrdup(obj1->stringval); + keyURI = NULL; + if (prefix != NULL) + xmlFree(prefix); + } else { + if (prefix != NULL) { + keyURI = xmlXPathNsLookup(xpctxt, prefix); + if (keyURI == NULL) { + xsltTransformError(tctxt, NULL, tctxt->inst, + "key() : prefix %s is not bound\n", prefix); + /* + * TODO: Shouldn't we stop here? + */ + } + xmlFree(prefix); + } else { + keyURI = NULL; + } + } + + /* + * Force conversion of first arg to string + */ + valuePush(ctxt, obj2); + xmlXPathStringFunction(ctxt, 1); + obj2 = valuePop(ctxt); + if ((obj2 == NULL) || (obj2->type != XPATH_STRING)) { + xsltTransformError(tctxt, NULL, tctxt->inst, + "key() : invalid arg expecting a string\n"); + ctxt->error = XPATH_INVALID_TYPE; + goto error; + } + value = obj2->stringval; + + /* + * We need to ensure that ctxt->document is available for + * xsltGetKey(). + * First find the relevant doc, which is the context node's + * owner doc; using context->doc is not safe, since + * the doc could have been acquired via the document() function, + * or the doc might be a Result Tree Fragment. + * FUTURE INFO: In XSLT 2.0 the key() function takes an additional + * argument indicating the doc to use. + */ + if (xpctxt->node->type == XML_NAMESPACE_DECL) { + /* + * REVISIT: This is a libxml hack! Check xpath.c for details. + * The XPath module sets the owner element of a ns-node on + * the ns->next field. + */ + if ((((xmlNsPtr) xpctxt->node)->next != NULL) && + (((xmlNsPtr) xpctxt->node)->next->type == XML_ELEMENT_NODE)) + { + tmpNode = (xmlNodePtr) ((xmlNsPtr) xpctxt->node)->next; + } + } else + tmpNode = xpctxt->node; + + if ((tmpNode == NULL) || (tmpNode->doc == NULL)) { + xsltTransformError(tctxt, NULL, tctxt->inst, + "Internal error in xsltKeyFunction(): " + "Couldn't get the doc of the XPath context node.\n"); + goto error; + } + + if ((tctxt->document == NULL) || + (tctxt->document->doc != tmpNode->doc)) + { + if (tmpNode->doc->name && (tmpNode->doc->name[0] == ' ')) { + /* + * This is a Result Tree Fragment. + */ + if (tmpNode->doc->_private == NULL) { + tmpNode->doc->_private = xsltNewDocument(tctxt, tmpNode->doc); + if (tmpNode->doc->_private == NULL) + goto error; + } + tctxt->document = (xsltDocumentPtr) tmpNode->doc->_private; + } else { + /* + * May be the initial source doc or a doc acquired via the + * document() function. + */ + tctxt->document = xsltFindDocument(tctxt, tmpNode->doc); + } + if (tctxt->document == NULL) { + xsltTransformError(tctxt, NULL, tctxt->inst, + "Internal error in xsltKeyFunction(): " + "Could not get the document info of a context doc.\n"); + tctxt->state = XSLT_STATE_STOPPED; + goto error; + } + } + /* + * Get/compute the key value. + */ + nodelist = xsltGetKey(tctxt, key, keyURI, value); + +error: + tctxt->document = oldDocInfo; + valuePush(ctxt, xmlXPathWrapNodeSet( + xmlXPathNodeSetMerge(NULL, nodelist))); + if (key != NULL) + xmlFree(key); + } + + if (obj1 != NULL) + xmlXPathFreeObject(obj1); + if (obj2 != NULL) + xmlXPathFreeObject(obj2); +} + +/** + * xsltUnparsedEntityURIFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the unparsed-entity-uri() XSLT function + * string unparsed-entity-uri(string) + */ +void +xsltUnparsedEntityURIFunction(xmlXPathParserContextPtr ctxt, int nargs){ + xmlXPathObjectPtr obj; + xmlChar *str; + + if ((nargs != 1) || (ctxt->value == NULL)) { + xsltGenericError(xsltGenericErrorContext, + "unparsed-entity-uri() : expects one string arg\n"); + ctxt->error = XPATH_INVALID_ARITY; + return; + } + obj = valuePop(ctxt); + if (obj->type != XPATH_STRING) { + obj = xmlXPathConvertString(obj); + if (obj == NULL) { + xmlXPathErr(ctxt, XPATH_MEMORY_ERROR); + return; + } + } + + str = obj->stringval; + if (str == NULL) { + valuePush(ctxt, xmlXPathNewString((const xmlChar *)"")); + } else { + xmlEntityPtr entity; + + entity = xmlGetDocEntity(ctxt->context->doc, str); + if (entity == NULL) { + valuePush(ctxt, xmlXPathNewString((const xmlChar *)"")); + } else { + if (entity->URI != NULL) + valuePush(ctxt, xmlXPathNewString(entity->URI)); + else + valuePush(ctxt, xmlXPathNewString((const xmlChar *)"")); + } + } + xmlXPathFreeObject(obj); +} + +/** + * xsltFormatNumberFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the format-number() XSLT function + * string format-number(number, string, string?) + */ +void +xsltFormatNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) +{ + xmlXPathObjectPtr numberObj = NULL; + xmlXPathObjectPtr formatObj = NULL; + xmlXPathObjectPtr decimalObj = NULL; + xsltStylesheetPtr sheet; + xsltDecimalFormatPtr formatValues = NULL; + xmlChar *result; + const xmlChar *ncname; + const xmlChar *prefix = NULL; + const xmlChar *nsUri = NULL; + xsltTransformContextPtr tctxt; + + tctxt = xsltXPathGetTransformContext(ctxt); + if ((tctxt == NULL) || (tctxt->inst == NULL)) + return; + sheet = tctxt->style; + if (sheet == NULL) + return; + formatValues = sheet->decimalFormat; + + switch (nargs) { + case 3: + if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_STRING)) + xmlXPathStringFunction(ctxt, 1); + decimalObj = valuePop(ctxt); + ncname = xsltSplitQName(sheet->dict, decimalObj->stringval, &prefix); + if (prefix != NULL) { + xmlNsPtr ns = xmlSearchNs(tctxt->inst->doc, tctxt->inst, prefix); + if (ns == NULL) { + xsltTransformError(tctxt, NULL, NULL, + "format-number : No namespace found for QName '%s:%s'\n", + prefix, ncname); + sheet->errors++; + ncname = NULL; + } + else { + nsUri = ns->href; + } + } + if (ncname != NULL) { + formatValues = xsltDecimalFormatGetByQName(sheet, nsUri, ncname); + } + if (formatValues == NULL) { + xsltTransformError(tctxt, NULL, NULL, + "format-number() : undeclared decimal format '%s'\n", + decimalObj->stringval); + } + /* Intentional fall-through */ + case 2: + if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_STRING)) + xmlXPathStringFunction(ctxt, 1); + formatObj = valuePop(ctxt); + if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_NUMBER)) + xmlXPathNumberFunction(ctxt, 1); + numberObj = valuePop(ctxt); + break; + default: + xmlXPathErr(ctxt, XPATH_INVALID_ARITY); + return; + } + + if ((ctxt->error == 0) && + (formatValues != NULL) && (formatObj != NULL) && (numberObj != NULL)) { + if (xsltFormatNumberConversion(formatValues, + formatObj->stringval, + numberObj->floatval, + &result) == XPATH_EXPRESSION_OK) { + valuePush(ctxt, xmlXPathNewString(result)); + xmlFree(result); + } + } + + xmlXPathFreeObject(numberObj); + xmlXPathFreeObject(formatObj); + xmlXPathFreeObject(decimalObj); +} + +/** + * xsltGenerateIdFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the generate-id() XSLT function + * string generate-id(node-set?) + */ +void +xsltGenerateIdFunction(xmlXPathParserContextPtr ctxt, int nargs){ + xsltTransformContextPtr tctxt; + xmlNodePtr cur = NULL; + xmlXPathObjectPtr obj = NULL; + char *str; + const xmlChar *nsPrefix = NULL; + void **psviPtr; + unsigned long id; + size_t size, nsPrefixSize = 0; + + tctxt = xsltXPathGetTransformContext(ctxt); + + if (nargs == 0) { + cur = ctxt->context->node; + } else if (nargs == 1) { + xmlNodeSetPtr nodelist; + int i, ret; + + if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) { + ctxt->error = XPATH_INVALID_TYPE; + xsltTransformError(tctxt, NULL, NULL, + "generate-id() : invalid arg expecting a node-set\n"); + goto out; + } + obj = valuePop(ctxt); + nodelist = obj->nodesetval; + if ((nodelist == NULL) || (nodelist->nodeNr <= 0)) { + valuePush(ctxt, xmlXPathNewCString("")); + goto out; + } + cur = nodelist->nodeTab[0]; + for (i = 1;i < nodelist->nodeNr;i++) { + ret = xmlXPathCmpNodes(cur, nodelist->nodeTab[i]); + if (ret == -1) + cur = nodelist->nodeTab[i]; + } + } else { + xsltTransformError(tctxt, NULL, NULL, + "generate-id() : invalid number of args %d\n", nargs); + ctxt->error = XPATH_INVALID_ARITY; + goto out; + } + + size = 30; /* for "id%lu" */ + + if (cur->type == XML_NAMESPACE_DECL) { + xmlNsPtr ns = (xmlNsPtr) cur; + + nsPrefix = ns->prefix; + if (nsPrefix == NULL) + nsPrefix = BAD_CAST ""; + nsPrefixSize = xmlStrlen(nsPrefix); + /* For "ns" and hex-encoded string */ + size += nsPrefixSize * 2 + 2; + + /* Parent is stored in 'next'. */ + cur = (xmlNodePtr) ns->next; + } + + psviPtr = xsltGetPSVIPtr(cur); + if (psviPtr == NULL) { + xsltTransformError(tctxt, NULL, NULL, + "generate-id(): invalid node type %d\n", cur->type); + ctxt->error = XPATH_INVALID_TYPE; + goto out; + } + + if (xsltGetSourceNodeFlags(cur) & XSLT_SOURCE_NODE_HAS_ID) { + id = (unsigned long) (size_t) *psviPtr; + } else { + if (cur->type == XML_TEXT_NODE && cur->line == USHRT_MAX) { + /* Text nodes store big line numbers in psvi. */ + cur->line = 0; + } else if (*psviPtr != NULL) { + xsltTransformError(tctxt, NULL, NULL, + "generate-id(): psvi already set\n"); + ctxt->error = XPATH_MEMORY_ERROR; + goto out; + } + + if (tctxt->currentId == ULONG_MAX) { + xsltTransformError(tctxt, NULL, NULL, + "generate-id(): id overflow\n"); + ctxt->error = XPATH_MEMORY_ERROR; + goto out; + } + + id = ++tctxt->currentId; + *psviPtr = (void *) (size_t) id; + xsltSetSourceNodeFlags(tctxt, cur, XSLT_SOURCE_NODE_HAS_ID); + } + + str = xmlMalloc(size); + if (str == NULL) { + xsltTransformError(tctxt, NULL, NULL, + "generate-id(): out of memory\n"); + ctxt->error = XPATH_MEMORY_ERROR; + goto out; + } + if (nsPrefix == NULL) { + snprintf(str, size, "id%lu", id); + } else { + size_t i, j; + + snprintf(str, size, "id%luns", id); + + /* + * Only ASCII alphanumerics are allowed, so we hex-encode the prefix. + */ + j = strlen(str); + for (i = 0; i < nsPrefixSize; i++) { + int v; + + v = nsPrefix[i] >> 4; + str[j++] = v < 10 ? '0' + v : 'A' + (v - 10); + v = nsPrefix[i] & 15; + str[j++] = v < 10 ? '0' + v : 'A' + (v - 10); + } + str[j] = '\0'; + } + valuePush(ctxt, xmlXPathWrapString(BAD_CAST str)); + +out: + xmlXPathFreeObject(obj); +} + +/** + * xsltSystemPropertyFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the system-property() XSLT function + * object system-property(string) + */ +void +xsltSystemPropertyFunction(xmlXPathParserContextPtr ctxt, int nargs){ + xmlXPathObjectPtr obj; + xmlChar *prefix, *name; + const xmlChar *nsURI = NULL; + + if (nargs != 1) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "system-property() : expects one string arg\n"); + ctxt->error = XPATH_INVALID_ARITY; + return; + } + if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "system-property() : invalid arg expecting a string\n"); + ctxt->error = XPATH_INVALID_TYPE; + return; + } + obj = valuePop(ctxt); + if (obj->stringval == NULL) { + valuePush(ctxt, xmlXPathNewString((const xmlChar *)"")); + } else { + name = xmlSplitQName2(obj->stringval, &prefix); + if (name == NULL) { + name = xmlStrdup(obj->stringval); + } else { + nsURI = xmlXPathNsLookup(ctxt->context, prefix); + if (nsURI == NULL) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "system-property() : prefix %s is not bound\n", prefix); + } + } + + if (xmlStrEqual(nsURI, XSLT_NAMESPACE)) { +#ifdef DOCBOOK_XSL_HACK + if (xmlStrEqual(name, (const xmlChar *)"vendor")) { + xsltStylesheetPtr sheet; + xsltTransformContextPtr tctxt; + + tctxt = xsltXPathGetTransformContext(ctxt); + if ((tctxt != NULL) && (tctxt->inst != NULL) && + (xmlStrEqual(tctxt->inst->name, BAD_CAST "variable")) && + (tctxt->inst->parent != NULL) && + (xmlStrEqual(tctxt->inst->parent->name, + BAD_CAST "template"))) + sheet = tctxt->style; + else + sheet = NULL; + if ((sheet != NULL) && (sheet->doc != NULL) && + (sheet->doc->URL != NULL) && + (xmlStrstr(sheet->doc->URL, + (const xmlChar *)"chunk") != NULL)) { + valuePush(ctxt, xmlXPathNewString( + (const xmlChar *)"libxslt (SAXON 6.2 compatible)")); + + } else { + valuePush(ctxt, xmlXPathNewString( + (const xmlChar *)XSLT_DEFAULT_VENDOR)); + } + } else +#else + if (xmlStrEqual(name, (const xmlChar *)"vendor")) { + valuePush(ctxt, xmlXPathNewString( + (const xmlChar *)XSLT_DEFAULT_VENDOR)); + } else +#endif + if (xmlStrEqual(name, (const xmlChar *)"version")) { + valuePush(ctxt, xmlXPathNewString( + (const xmlChar *)XSLT_DEFAULT_VERSION)); + } else if (xmlStrEqual(name, (const xmlChar *)"vendor-url")) { + valuePush(ctxt, xmlXPathNewString( + (const xmlChar *)XSLT_DEFAULT_URL)); + } else { + valuePush(ctxt, xmlXPathNewString((const xmlChar *)"")); + } + } else { + valuePush(ctxt, xmlXPathNewString((const xmlChar *)"")); + } + if (name != NULL) + xmlFree(name); + if (prefix != NULL) + xmlFree(prefix); + } + xmlXPathFreeObject(obj); +} + +/** + * xsltElementAvailableFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the element-available() XSLT function + * boolean element-available(string) + */ +void +xsltElementAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){ + xmlXPathObjectPtr obj; + xmlChar *prefix, *name; + const xmlChar *nsURI = NULL; + xsltTransformContextPtr tctxt; + + if (nargs != 1) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "element-available() : expects one string arg\n"); + ctxt->error = XPATH_INVALID_ARITY; + return; + } + xmlXPathStringFunction(ctxt, 1); + if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "element-available() : invalid arg expecting a string\n"); + ctxt->error = XPATH_INVALID_TYPE; + return; + } + obj = valuePop(ctxt); + tctxt = xsltXPathGetTransformContext(ctxt); + if ((tctxt == NULL) || (tctxt->inst == NULL)) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "element-available() : internal error tctxt == NULL\n"); + xmlXPathFreeObject(obj); + valuePush(ctxt, xmlXPathNewBoolean(0)); + return; + } + + + name = xmlSplitQName2(obj->stringval, &prefix); + if (name == NULL) { + xmlNsPtr ns; + + name = xmlStrdup(obj->stringval); + ns = xmlSearchNs(tctxt->inst->doc, tctxt->inst, NULL); + if (ns != NULL) nsURI = ns->href; + } else { + nsURI = xmlXPathNsLookup(ctxt->context, prefix); + if (nsURI == NULL) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "element-available() : prefix %s is not bound\n", prefix); + } + } + + if (xsltExtElementLookup(tctxt, name, nsURI) != NULL) { + valuePush(ctxt, xmlXPathNewBoolean(1)); + } else { + valuePush(ctxt, xmlXPathNewBoolean(0)); + } + + xmlXPathFreeObject(obj); + if (name != NULL) + xmlFree(name); + if (prefix != NULL) + xmlFree(prefix); +} + +/** + * xsltFunctionAvailableFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the function-available() XSLT function + * boolean function-available(string) + */ +void +xsltFunctionAvailableFunction(xmlXPathParserContextPtr ctxt, int nargs){ + xmlXPathObjectPtr obj; + xmlChar *prefix, *name; + const xmlChar *nsURI = NULL; + + if (nargs != 1) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "function-available() : expects one string arg\n"); + ctxt->error = XPATH_INVALID_ARITY; + return; + } + xmlXPathStringFunction(ctxt, 1); + if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "function-available() : invalid arg expecting a string\n"); + ctxt->error = XPATH_INVALID_TYPE; + return; + } + obj = valuePop(ctxt); + + name = xmlSplitQName2(obj->stringval, &prefix); + if (name == NULL) { + name = xmlStrdup(obj->stringval); + } else { + nsURI = xmlXPathNsLookup(ctxt->context, prefix); + if (nsURI == NULL) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "function-available() : prefix %s is not bound\n", prefix); + } + } + + if (xmlXPathFunctionLookupNS(ctxt->context, name, nsURI) != NULL) { + valuePush(ctxt, xmlXPathNewBoolean(1)); + } else { + valuePush(ctxt, xmlXPathNewBoolean(0)); + } + + xmlXPathFreeObject(obj); + if (name != NULL) + xmlFree(name); + if (prefix != NULL) + xmlFree(prefix); +} + +/** + * xsltCurrentFunction: + * @ctxt: the XPath Parser context + * @nargs: the number of arguments + * + * Implement the current() XSLT function + * node-set current() + */ +static void +xsltCurrentFunction(xmlXPathParserContextPtr ctxt, int nargs){ + xsltTransformContextPtr tctxt; + + if (nargs != 0) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "current() : function uses no argument\n"); + ctxt->error = XPATH_INVALID_ARITY; + return; + } + tctxt = xsltXPathGetTransformContext(ctxt); + if (tctxt == NULL) { + xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL, + "current() : internal error tctxt == NULL\n"); + valuePush(ctxt, xmlXPathNewNodeSet(NULL)); + } else { + valuePush(ctxt, xmlXPathNewNodeSet(tctxt->node)); /* current */ + } +} + +/************************************************************************ + * * + * Registration of XSLT and libxslt functions * + * * + ************************************************************************/ + +/** + * xsltRegisterAllFunctions: + * @ctxt: the XPath context + * + * Registers all default XSLT functions in this context + */ +void +xsltRegisterAllFunctions(xmlXPathContextPtr ctxt) +{ + xmlXPathRegisterFunc(ctxt, (const xmlChar *) "current", + xsltCurrentFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *) "document", + xsltDocumentFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *) "key", xsltKeyFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *) "unparsed-entity-uri", + xsltUnparsedEntityURIFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *) "format-number", + xsltFormatNumberFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *) "generate-id", + xsltGenerateIdFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *) "system-property", + xsltSystemPropertyFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *) "element-available", + xsltElementAvailableFunction); + xmlXPathRegisterFunc(ctxt, (const xmlChar *) "function-available", + xsltFunctionAvailableFunction); +} diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/functions.h chromium-145.0.7632.159/third_party/libxslt/src/libxslt/functions.h --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/functions.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/functions.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,78 @@ +/* + * Summary: interface for the XSLT functions not from XPath + * Description: a set of extra functions coming from XSLT but not in XPath + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard and Bjorn Reese + */ + +#ifndef __XML_XSLT_FUNCTIONS_H__ +#define __XML_XSLT_FUNCTIONS_H__ + +#include +#include +#include "xsltexports.h" +#include "xsltInternals.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * XSLT_REGISTER_FUNCTION_LOOKUP: + * + * Registering macro, not general purpose at all but used in different modules. + */ +#define XSLT_REGISTER_FUNCTION_LOOKUP(ctxt) \ + xmlXPathRegisterFuncLookup((ctxt)->xpathCtxt, \ + xsltXPathFunctionLookup, \ + (void *)(ctxt->xpathCtxt)); + +XSLTPUBFUN xmlXPathFunction XSLTCALL + xsltXPathFunctionLookup (void *vctxt, + const xmlChar *name, + const xmlChar *ns_uri); + +/* + * Interfaces for the functions implementations. + */ + +XSLTPUBFUN void XSLTCALL + xsltDocumentFunction (xmlXPathParserContextPtr ctxt, + int nargs); +XSLTPUBFUN void XSLTCALL + xsltKeyFunction (xmlXPathParserContextPtr ctxt, + int nargs); +XSLTPUBFUN void XSLTCALL + xsltUnparsedEntityURIFunction (xmlXPathParserContextPtr ctxt, + int nargs); +XSLTPUBFUN void XSLTCALL + xsltFormatNumberFunction (xmlXPathParserContextPtr ctxt, + int nargs); +XSLTPUBFUN void XSLTCALL + xsltGenerateIdFunction (xmlXPathParserContextPtr ctxt, + int nargs); +XSLTPUBFUN void XSLTCALL + xsltSystemPropertyFunction (xmlXPathParserContextPtr ctxt, + int nargs); +XSLTPUBFUN void XSLTCALL + xsltElementAvailableFunction (xmlXPathParserContextPtr ctxt, + int nargs); +XSLTPUBFUN void XSLTCALL + xsltFunctionAvailableFunction (xmlXPathParserContextPtr ctxt, + int nargs); + +/* + * And the registration + */ + +XSLTPUBFUN void XSLTCALL + xsltRegisterAllFunctions (xmlXPathContextPtr ctxt); + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_FUNCTIONS_H__ */ + diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/imports.c chromium-145.0.7632.159/third_party/libxslt/src/libxslt/imports.c --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/imports.c 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/imports.c 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,423 @@ +/* + * imports.c: Implementation of the XSLT imports + * + * Reference: + * http://www.w3.org/TR/1999/REC-xslt-19991116 + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#define IN_LIBXSLT +#include "libxslt.h" + +#include + +#include +#include +#include +#include +#include +#include "xslt.h" +#include "xsltInternals.h" +#include "xsltutils.h" +#include "preproc.h" +#include "imports.h" +#include "documents.h" +#include "security.h" +#include "pattern.h" + + +/************************************************************************ + * * + * Module interfaces * + * * + ************************************************************************/ +/** + * xsltFixImportedCompSteps: + * @master: the "master" stylesheet + * @style: the stylesheet being imported by the master + * + * normalize the comp steps for the stylesheet being imported + * by the master, together with any imports within that. + * + */ +static void xsltFixImportedCompSteps(xsltStylesheetPtr master, + xsltStylesheetPtr style) { + xsltStylesheetPtr res; + xmlHashScan(style->templatesHash, xsltNormalizeCompSteps, master); + master->extrasNr += style->extrasNr; + for (res = style->imports; res != NULL; res = res->next) { + xsltFixImportedCompSteps(master, res); + } +} + +#define XSLT_MAX_NESTING 40 + +static int +xsltCheckCycle(xsltStylesheetPtr style, xmlNodePtr cur, const xmlChar *URI) { + xsltStylesheetPtr ancestor; + xsltDocumentPtr docptr; + int depth; + + /* + * Check imported stylesheets. + */ + depth = 0; + ancestor = style; + while (ancestor != NULL) { + if (++depth >= XSLT_MAX_NESTING) { + xsltTransformError(NULL, style, cur, + "maximum nesting depth exceeded: %s\n", URI); + return(-1); + } + if (xmlStrEqual(ancestor->doc->URL, URI)) { + xsltTransformError(NULL, style, cur, + "recursion detected on imported URL %s\n", URI); + return(-1); + } + + /* + * Check included stylesheets. + */ + docptr = ancestor->includes; + while (docptr != NULL) { + if (++depth >= XSLT_MAX_NESTING) { + xsltTransformError(NULL, style, cur, + "maximum nesting depth exceeded: %s\n", URI); + return(-1); + } + if (xmlStrEqual(docptr->doc->URL, URI)) { + xsltTransformError(NULL, style, cur, + "recursion detected on included URL %s\n", URI); + return(-1); + } + docptr = docptr->includes; + } + + ancestor = ancestor->parent; + } + + return(0); +} + +/** + * xsltParseStylesheetImport: + * @style: the XSLT stylesheet + * @cur: the import element + * + * parse an XSLT stylesheet import element + * + * Returns 0 in case of success -1 in case of failure. + */ + +int +xsltParseStylesheetImport(xsltStylesheetPtr style, xmlNodePtr cur) { + int ret = -1; + xmlDocPtr import = NULL; + xmlChar *base = NULL; + xmlChar *uriRef = NULL; + xmlChar *URI = NULL; + xsltStylesheetPtr res; + xsltSecurityPrefsPtr sec; + + if ((cur == NULL) || (style == NULL)) + return (ret); + + uriRef = xmlGetNsProp(cur, (const xmlChar *)"href", NULL); + if (uriRef == NULL) { + xsltTransformError(NULL, style, cur, + "xsl:import : missing href attribute\n"); + goto error; + } + + base = xmlNodeGetBase(style->doc, cur); + URI = xmlBuildURI(uriRef, base); + if (URI == NULL) { + xsltTransformError(NULL, style, cur, + "xsl:import : invalid URI reference %s\n", uriRef); + goto error; + } + + if (xsltCheckCycle(style, cur, URI) < 0) + goto error; + + /* + * Security framework check + */ + sec = xsltGetDefaultSecurityPrefs(); + if (sec != NULL) { + int secres; + + secres = xsltCheckRead(sec, NULL, URI); + if (secres <= 0) { + if (secres == 0) + xsltTransformError(NULL, NULL, NULL, + "xsl:import: read rights for %s denied\n", + URI); + goto error; + } + } + + import = xsltDocDefaultLoader(URI, style->dict, XSLT_PARSE_OPTIONS, + (void *) style, XSLT_LOAD_STYLESHEET); + if (import == NULL) { + xsltTransformError(NULL, style, cur, + "xsl:import : unable to load %s\n", URI); + goto error; + } + + res = xsltParseStylesheetImportedDoc(import, style); + if (res != NULL) { + res->next = style->imports; + style->imports = res; + if (style->parent == NULL) { + xsltFixImportedCompSteps(style, res); + } + ret = 0; + } else { + xmlFreeDoc(import); + } + +error: + if (uriRef != NULL) + xmlFree(uriRef); + if (base != NULL) + xmlFree(base); + if (URI != NULL) + xmlFree(URI); + + return (ret); +} + +/** + * xsltParseStylesheetInclude: + * @style: the XSLT stylesheet + * @cur: the include node + * + * parse an XSLT stylesheet include element + * + * Returns 0 in case of success -1 in case of failure + */ + +int +xsltParseStylesheetInclude(xsltStylesheetPtr style, xmlNodePtr cur) { + int ret = -1; + xmlDocPtr oldDoc; + xmlChar *base = NULL; + xmlChar *uriRef = NULL; + xmlChar *URI = NULL; + xsltStylesheetPtr result; + xsltDocumentPtr include; + int oldNopreproc; + + if ((cur == NULL) || (style == NULL)) + return (ret); + + uriRef = xmlGetNsProp(cur, (const xmlChar *)"href", NULL); + if (uriRef == NULL) { + xsltTransformError(NULL, style, cur, + "xsl:include : missing href attribute\n"); + goto error; + } + + base = xmlNodeGetBase(style->doc, cur); + URI = xmlBuildURI(uriRef, base); + if (URI == NULL) { + xsltTransformError(NULL, style, cur, + "xsl:include : invalid URI reference %s\n", uriRef); + goto error; + } + + if (xsltCheckCycle(style, cur, URI) < 0) + goto error; + + include = xsltLoadStyleDocument(style, URI); + if (include == NULL) { + xsltTransformError(NULL, style, cur, + "xsl:include : unable to load %s\n", URI); + goto error; + } +#ifdef XSLT_REFACTORED + if (IS_XSLT_ELEM_FAST(cur) && (cur->psvi != NULL)) { + ((xsltStyleItemIncludePtr) cur->psvi)->include = include; + } else { + xsltTransformError(NULL, style, cur, + "Internal error: (xsltParseStylesheetInclude) " + "The xsl:include element was not compiled.\n", URI); + style->errors++; + } +#endif + oldDoc = style->doc; + style->doc = include->doc; + /* chain to stylesheet for recursion checking */ + include->includes = style->includes; + style->includes = include; + oldNopreproc = style->nopreproc; + style->nopreproc = include->preproc; + /* + * TODO: This will change some values of the + * including stylesheet with every included module + * (e.g. excluded-result-prefixes) + * We need to strictly seperate such stylesheet-owned values. + */ + result = xsltParseStylesheetProcess(style, include->doc); + style->nopreproc = oldNopreproc; + include->preproc = 1; + style->includes = include->includes; + style->doc = oldDoc; + if (result == NULL) { + ret = -1; + goto error; + } + ret = 0; + +error: + if (uriRef != NULL) + xmlFree(uriRef); + if (base != NULL) + xmlFree(base); + if (URI != NULL) + xmlFree(URI); + + return (ret); +} + +/** + * xsltNextImport: + * @cur: the current XSLT stylesheet + * + * Find the next stylesheet in import precedence. + * + * Returns the next stylesheet or NULL if it was the last one + */ + +xsltStylesheetPtr +xsltNextImport(xsltStylesheetPtr cur) { + if (cur == NULL) + return(NULL); + if (cur->imports != NULL) + return(cur->imports); + if (cur->next != NULL) + return(cur->next) ; + do { + cur = cur->parent; + if (cur == NULL) break; + if (cur->next != NULL) return(cur->next); + } while (cur != NULL); + return(cur); +} + +/** + * xsltNeedElemSpaceHandling: + * @ctxt: an XSLT transformation context + * + * Checks whether that stylesheet requires white-space stripping + * + * Returns 1 if space should be stripped, 0 if not + */ + +int +xsltNeedElemSpaceHandling(xsltTransformContextPtr ctxt) { + xsltStylesheetPtr style; + + if (ctxt == NULL) + return(0); + style = ctxt->style; + while (style != NULL) { + if (style->stripSpaces != NULL) + return(1); + style = xsltNextImport(style); + } + return(0); +} + +/** + * xsltFindElemSpaceHandling: + * @ctxt: an XSLT transformation context + * @node: an XML node + * + * Find strip-space or preserve-space information for an element + * respect the import precedence or the wildcards + * + * Returns 1 if space should be stripped, 0 if not, and 2 if everything + * should be CDTATA wrapped. + */ + +int +xsltFindElemSpaceHandling(xsltTransformContextPtr ctxt, xmlNodePtr node) { + xsltStylesheetPtr style; + const xmlChar *val; + + if ((ctxt == NULL) || (node == NULL)) + return(0); + style = ctxt->style; + while (style != NULL) { + if (node->ns != NULL) { + val = (const xmlChar *) + xmlHashLookup2(style->stripSpaces, node->name, node->ns->href); + if (val == NULL) { + val = (const xmlChar *) + xmlHashLookup2(style->stripSpaces, BAD_CAST "*", + node->ns->href); + } + } else { + val = (const xmlChar *) + xmlHashLookup2(style->stripSpaces, node->name, NULL); + } + if (val != NULL) { + if (xmlStrEqual(val, (xmlChar *) "strip")) + return(1); + if (xmlStrEqual(val, (xmlChar *) "preserve")) + return(0); + } + if (style->stripAll == 1) + return(1); + if (style->stripAll == -1) + return(0); + + style = xsltNextImport(style); + } + return(0); +} + +/** + * xsltFindTemplate: + * @ctxt: an XSLT transformation context + * @name: the template name + * @nameURI: the template name URI + * + * Finds the named template, apply import precedence rule. + * REVISIT TODO: We'll change the nameURI fields of + * templates to be in the string dict, so if the + * specified @nameURI is in the same dict, then use pointer + * comparison. Check if this can be done in a sane way. + * Maybe this function is not needed internally at + * transformation-time if we hard-wire the called templates + * to the caller. + * + * Returns the xsltTemplatePtr or NULL if not found + */ +xsltTemplatePtr +xsltFindTemplate(xsltTransformContextPtr ctxt, const xmlChar *name, + const xmlChar *nameURI) { + xsltTemplatePtr cur; + xsltStylesheetPtr style; + + if ((ctxt == NULL) || (name == NULL)) + return(NULL); + style = ctxt->style; + while (style != NULL) { + if (style->namedTemplates != NULL) { + cur = (xsltTemplatePtr) + xmlHashLookup2(style->namedTemplates, name, nameURI); + if (cur != NULL) + return(cur); + } + + style = xsltNextImport(style); + } + return(NULL); +} + diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/imports.h chromium-145.0.7632.159/third_party/libxslt/src/libxslt/imports.h --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/imports.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/imports.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,75 @@ +/* + * Summary: interface for the XSLT import support + * Description: macros and fuctions needed to implement and + * access the import tree + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLT_IMPORTS_H__ +#define __XML_XSLT_IMPORTS_H__ + +#include +#include "xsltexports.h" +#include "xsltInternals.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * XSLT_GET_IMPORT_PTR: + * + * A macro to import pointers from the stylesheet cascading order. + */ +#define XSLT_GET_IMPORT_PTR(res, style, name) { \ + xsltStylesheetPtr st = style; \ + res = NULL; \ + while (st != NULL) { \ + if (st->name != NULL) { res = st->name; break; } \ + st = xsltNextImport(st); \ + }} + +/** + * XSLT_GET_IMPORT_INT: + * + * A macro to import intergers from the stylesheet cascading order. + */ +#define XSLT_GET_IMPORT_INT(res, style, name) { \ + xsltStylesheetPtr st = style; \ + res = -1; \ + while (st != NULL) { \ + if (st->name != -1) { res = st->name; break; } \ + st = xsltNextImport(st); \ + }} + +/* + * Module interfaces + */ +XSLTPUBFUN int XSLTCALL + xsltParseStylesheetImport(xsltStylesheetPtr style, + xmlNodePtr cur); +XSLTPUBFUN int XSLTCALL + xsltParseStylesheetInclude + (xsltStylesheetPtr style, + xmlNodePtr cur); +XSLTPUBFUN xsltStylesheetPtr XSLTCALL + xsltNextImport (xsltStylesheetPtr style); +XSLTPUBFUN int XSLTCALL + xsltNeedElemSpaceHandling(xsltTransformContextPtr ctxt); +XSLTPUBFUN int XSLTCALL + xsltFindElemSpaceHandling(xsltTransformContextPtr ctxt, + xmlNodePtr node); +XSLTPUBFUN xsltTemplatePtr XSLTCALL + xsltFindTemplate (xsltTransformContextPtr ctxt, + const xmlChar *name, + const xmlChar *nameURI); + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_IMPORTS_H__ */ + diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/keys.c chromium-145.0.7632.159/third_party/libxslt/src/libxslt/keys.c --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/keys.c 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/keys.c 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,935 @@ +/* + * keys.c: Implemetation of the keys support + * + * Reference: + * http://www.w3.org/TR/1999/REC-xslt-19991116 + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#define IN_LIBXSLT +#include "libxslt.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "xslt.h" +#include "xsltInternals.h" +#include "xsltutils.h" +#include "imports.h" +#include "templates.h" +#include "keys.h" + +#ifdef WITH_XSLT_DEBUG +#define WITH_XSLT_DEBUG_KEYS +#endif + +static int +xsltInitDocKeyTable(xsltTransformContextPtr ctxt, const xmlChar *name, + const xmlChar *nameURI); + +/************************************************************************ + * * + * Type functions * + * * + ************************************************************************/ + +/** + * xsltNewKeyDef: + * @name: the key name or NULL + * @nameURI: the name URI or NULL + * + * Create a new XSLT KeyDef + * + * Returns the newly allocated xsltKeyDefPtr or NULL in case of error + */ +static xsltKeyDefPtr +xsltNewKeyDef(const xmlChar *name, const xmlChar *nameURI) { + xsltKeyDefPtr cur; + + cur = (xsltKeyDefPtr) xmlMalloc(sizeof(xsltKeyDef)); + if (cur == NULL) { + xsltTransformError(NULL, NULL, NULL, + "xsltNewKeyDef : malloc failed\n"); + return(NULL); + } + memset(cur, 0, sizeof(xsltKeyDef)); + if (name != NULL) + cur->name = xmlStrdup(name); + if (nameURI != NULL) + cur->nameURI = xmlStrdup(nameURI); + cur->nsList = NULL; + return(cur); +} + +/** + * xsltFreeKeyDef: + * @keyd: an XSLT key definition + * + * Free up the memory allocated by @keyd + */ +static void +xsltFreeKeyDef(xsltKeyDefPtr keyd) { + if (keyd == NULL) + return; + if (keyd->comp != NULL) + xmlXPathFreeCompExpr(keyd->comp); + if (keyd->usecomp != NULL) + xmlXPathFreeCompExpr(keyd->usecomp); + if (keyd->name != NULL) + xmlFree(keyd->name); + if (keyd->nameURI != NULL) + xmlFree(keyd->nameURI); + if (keyd->match != NULL) + xmlFree(keyd->match); + if (keyd->use != NULL) + xmlFree(keyd->use); + if (keyd->nsList != NULL) + xmlFree(keyd->nsList); + memset(keyd, -1, sizeof(xsltKeyDef)); + xmlFree(keyd); +} + +/** + * xsltFreeKeyDefList: + * @keyd: an XSLT key definition list + * + * Free up the memory allocated by all the elements of @keyd + */ +static void +xsltFreeKeyDefList(xsltKeyDefPtr keyd) { + xsltKeyDefPtr cur; + + while (keyd != NULL) { + cur = keyd; + keyd = keyd->next; + xsltFreeKeyDef(cur); + } +} + +/** + * xsltNewKeyTable: + * @name: the key name or NULL + * @nameURI: the name URI or NULL + * + * Create a new XSLT KeyTable + * + * Returns the newly allocated xsltKeyTablePtr or NULL in case of error + */ +static xsltKeyTablePtr +xsltNewKeyTable(const xmlChar *name, const xmlChar *nameURI) { + xsltKeyTablePtr cur; + + cur = (xsltKeyTablePtr) xmlMalloc(sizeof(xsltKeyTable)); + if (cur == NULL) { + xsltTransformError(NULL, NULL, NULL, + "xsltNewKeyTable : malloc failed\n"); + return(NULL); + } + memset(cur, 0, sizeof(xsltKeyTable)); + if (name != NULL) + cur->name = xmlStrdup(name); + if (nameURI != NULL) + cur->nameURI = xmlStrdup(nameURI); + cur->keys = xmlHashCreate(0); + return(cur); +} + +static void +xsltFreeNodeSetEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { + xmlXPathFreeNodeSet((xmlNodeSetPtr) payload); +} + +/** + * xsltFreeKeyTable: + * @keyt: an XSLT key table + * + * Free up the memory allocated by @keyt + */ +static void +xsltFreeKeyTable(xsltKeyTablePtr keyt) { + if (keyt == NULL) + return; + if (keyt->name != NULL) + xmlFree(keyt->name); + if (keyt->nameURI != NULL) + xmlFree(keyt->nameURI); + if (keyt->keys != NULL) + xmlHashFree(keyt->keys, xsltFreeNodeSetEntry); + memset(keyt, -1, sizeof(xsltKeyTable)); + xmlFree(keyt); +} + +/** + * xsltFreeKeyTableList: + * @keyt: an XSLT key table list + * + * Free up the memory allocated by all the elements of @keyt + */ +static void +xsltFreeKeyTableList(xsltKeyTablePtr keyt) { + xsltKeyTablePtr cur; + + while (keyt != NULL) { + cur = keyt; + keyt = keyt->next; + xsltFreeKeyTable(cur); + } +} + +/************************************************************************ + * * + * The interpreter for the precompiled patterns * + * * + ************************************************************************/ + + +/** + * xsltFreeKeys: + * @style: an XSLT stylesheet + * + * Free up the memory used by XSLT keys in a stylesheet + */ +void +xsltFreeKeys(xsltStylesheetPtr style) { + if (style->keys) + xsltFreeKeyDefList((xsltKeyDefPtr) style->keys); +} + +/** + * skipString: + * @cur: the current pointer + * @end: the current offset + * + * skip a string delimited by " or ' + * + * Returns the byte after the string or -1 in case of error + */ +static int +skipString(const xmlChar *cur, int end) { + xmlChar limit; + + if ((cur == NULL) || (end < 0)) return(-1); + if ((cur[end] == '\'') || (cur[end] == '"')) limit = cur[end]; + else return(end); + end++; + while (cur[end] != 0) { + if (cur[end] == limit) + return(end + 1); + end++; + } + return(-1); +} + +/** + * skipPredicate: + * @cur: the current pointer + * @end: the current offset + * + * skip a predicate + * + * Returns the byte after the predicate or -1 in case of error + */ +static int +skipPredicate(const xmlChar *cur, int end) { + int level = 0; + + if ((cur == NULL) || (end < 0)) return(-1); + if (cur[end] != '[') return(end); + end++; + while (cur[end] != 0) { + if ((cur[end] == '\'') || (cur[end] == '"')) { + end = skipString(cur, end); + if (end <= 0) + return(-1); + continue; + } else if (cur[end] == '[') { + level += 1; + } else if (cur[end] == ']') { + if (level == 0) + return(end + 1); + level -= 1; + } + end++; + } + return(-1); +} + +/** + * xsltAddKey: + * @style: an XSLT stylesheet + * @name: the key name or NULL + * @nameURI: the name URI or NULL + * @match: the match value + * @use: the use value + * @inst: the key instruction + * + * add a key definition to a stylesheet + * + * Returns 0 in case of success, and -1 in case of failure. + */ +int +xsltAddKey(xsltStylesheetPtr style, const xmlChar *name, + const xmlChar *nameURI, const xmlChar *match, + const xmlChar *use, xmlNodePtr inst) { + xsltKeyDefPtr key; + xmlChar *pattern = NULL; + int current, end, start, i = 0; + + if ((style == NULL) || (name == NULL) || (match == NULL) || (use == NULL)) + return(-1); + +#ifdef WITH_XSLT_DEBUG_KEYS + xsltGenericDebug(xsltGenericDebugContext, + "Add key %s, match %s, use %s\n", name, match, use); +#endif + + key = xsltNewKeyDef(name, nameURI); + if (key == NULL) + return(-1); + key->match = xmlStrdup(match); + key->use = xmlStrdup(use); + key->inst = inst; + key->nsList = xmlGetNsList(inst->doc, inst); + if (key->nsList != NULL) { + while (key->nsList[i] != NULL) + i++; + } + key->nsNr = i; + + /* + * Split the | and register it as as many keys + */ + current = end = 0; + while (match[current] != 0) { + start = current; + while (xmlIsBlank_ch(match[current])) + current++; + end = current; + while ((match[end] != 0) && (match[end] != '|')) { + if (match[end] == '[') { + end = skipPredicate(match, end); + if (end <= 0) { + xsltTransformError(NULL, style, inst, + "xsl:key : 'match' pattern is malformed: %s", + key->match); + if (style != NULL) style->errors++; + goto error; + } + } else + end++; + } + if (current == end) { + xsltTransformError(NULL, style, inst, + "xsl:key : 'match' pattern is empty\n"); + if (style != NULL) style->errors++; + goto error; + } + if (match[start] != '/') { + pattern = xmlStrcat(pattern, (xmlChar *)"//"); + if (pattern == NULL) { + if (style != NULL) style->errors++; + goto error; + } + } + pattern = xmlStrncat(pattern, &match[start], end - start); + if (pattern == NULL) { + if (style != NULL) style->errors++; + goto error; + } + + if (match[end] == '|') { + pattern = xmlStrcat(pattern, (xmlChar *)"|"); + end++; + } + current = end; + } + if (pattern == NULL) { + xsltTransformError(NULL, style, inst, + "xsl:key : 'match' pattern is empty\n"); + if (style != NULL) style->errors++; + goto error; + } +#ifdef WITH_XSLT_DEBUG_KEYS + xsltGenericDebug(xsltGenericDebugContext, + " resulting pattern %s\n", pattern); +#endif + /* + * XSLT-1: "It is an error for the value of either the use + * attribute or the match attribute to contain a + * VariableReference." + * TODO: We should report a variable-reference at compile-time. + * Maybe a search for "$", if it occurs outside of quotation + * marks, could be sufficient. + */ +#ifdef XML_XPATH_NOVAR + key->comp = xsltXPathCompileFlags(style, pattern, XML_XPATH_NOVAR); +#else + key->comp = xsltXPathCompile(style, pattern); +#endif + if (key->comp == NULL) { + xsltTransformError(NULL, style, inst, + "xsl:key : 'match' pattern compilation failed '%s'\n", + pattern); + if (style != NULL) style->errors++; + } +#ifdef XML_XPATH_NOVAR + key->usecomp = xsltXPathCompileFlags(style, use, XML_XPATH_NOVAR); +#else + key->usecomp = xsltXPathCompile(style, use); +#endif + if (key->usecomp == NULL) { + xsltTransformError(NULL, style, inst, + "xsl:key : 'use' expression compilation failed '%s'\n", + use); + if (style != NULL) style->errors++; + } + + /* + * Sometimes the stylesheet writer use the order to ease the + * resolution of keys when they are dependant, keep the provided + * order so add the new one at the end. + */ + if (style->keys == NULL) { + style->keys = key; + } else { + xsltKeyDefPtr prev = style->keys; + + while (prev->next != NULL) + prev = prev->next; + + prev->next = key; + } + key->next = NULL; + key = NULL; + +error: + if (pattern != NULL) + xmlFree(pattern); + if (key != NULL) + xsltFreeKeyDef(key); + return(0); +} + +/** + * xsltGetKey: + * @ctxt: an XSLT transformation context + * @name: the key name or NULL + * @nameURI: the name URI or NULL + * @value: the key value to look for + * + * Looks up a key of the in current source doc (the document info + * on @ctxt->document). Computes the key if not already done + * for the current source doc. + * + * Returns the nodeset resulting from the query or NULL + */ +xmlNodeSetPtr +xsltGetKey(xsltTransformContextPtr ctxt, const xmlChar *name, + const xmlChar *nameURI, const xmlChar *value) { + xmlNodeSetPtr ret; + xsltKeyTablePtr table; + int init_table = 0; + + if ((ctxt == NULL) || (name == NULL) || (value == NULL) || + (ctxt->document == NULL)) + return(NULL); + +#ifdef WITH_XSLT_DEBUG_KEYS + xsltGenericDebug(xsltGenericDebugContext, + "Get key %s, value %s\n", name, value); +#endif + + /* + * keys are computed only on-demand on first key access for a document + */ + if ((ctxt->document->nbKeysComputed < ctxt->nbKeys) && + (ctxt->keyInitLevel == 0)) { + /* + * If non-recursive behaviour, just try to initialize all keys + */ + if (xsltInitAllDocKeys(ctxt)) + return(NULL); + } + +retry: + table = (xsltKeyTablePtr) ctxt->document->keys; + while (table != NULL) { + if (((nameURI != NULL) == (table->nameURI != NULL)) && + xmlStrEqual(table->name, name) && + xmlStrEqual(table->nameURI, nameURI)) + { + ret = (xmlNodeSetPtr)xmlHashLookup(table->keys, value); + return(ret); + } + table = table->next; + } + + if ((ctxt->keyInitLevel != 0) && (init_table == 0)) { + /* + * Apparently one key is recursive and this one is needed, + * initialize just it, that time and retry + */ + xsltInitDocKeyTable(ctxt, name, nameURI); + init_table = 1; + goto retry; + } + + return(NULL); +} + + +/** + * xsltInitDocKeyTable: + * + * INTERNAL ROUTINE ONLY + * + * Check if any keys on the current document need to be computed + */ +static int +xsltInitDocKeyTable(xsltTransformContextPtr ctxt, const xmlChar *name, + const xmlChar *nameURI) +{ + xsltStylesheetPtr style; + xsltKeyDefPtr keyd = NULL; + int found = 0; + +#ifdef KEY_INIT_DEBUG +fprintf(stderr, "xsltInitDocKeyTable %s\n", name); +#endif + + style = ctxt->style; + while (style != NULL) { + keyd = (xsltKeyDefPtr) style->keys; + while (keyd != NULL) { + if (((keyd->nameURI != NULL) == + (nameURI != NULL)) && + xmlStrEqual(keyd->name, name) && + xmlStrEqual(keyd->nameURI, nameURI)) + { + xsltInitCtxtKey(ctxt, ctxt->document, keyd); + if (ctxt->document->nbKeysComputed == ctxt->nbKeys) + return(0); + found = 1; + } + keyd = keyd->next; + } + style = xsltNextImport(style); + } + if (found == 0) { +#ifdef WITH_XSLT_DEBUG_KEYS + XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext, + "xsltInitDocKeyTable: did not found %s\n", name)); +#endif + xsltTransformError(ctxt, NULL, keyd? keyd->inst : NULL, + "Failed to find key definition for %s\n", name); + ctxt->state = XSLT_STATE_STOPPED; + return(-1); + } +#ifdef KEY_INIT_DEBUG +fprintf(stderr, "xsltInitDocKeyTable %s done\n", name); +#endif + return(0); +} + +/** + * xsltInitAllDocKeys: + * @ctxt: transformation context + * + * INTERNAL ROUTINE ONLY + * + * Check if any keys on the current document need to be computed + * + * Returns 0 in case of success, -1 in case of failure + */ +int +xsltInitAllDocKeys(xsltTransformContextPtr ctxt) +{ + xsltStylesheetPtr style; + xsltKeyDefPtr keyd; + xsltKeyTablePtr table; + + if (ctxt == NULL) + return(-1); + +#ifdef KEY_INIT_DEBUG +fprintf(stderr, "xsltInitAllDocKeys %d %d\n", + ctxt->document->nbKeysComputed, ctxt->nbKeys); +#endif + + if (ctxt->document->nbKeysComputed == ctxt->nbKeys) + return(0); + + + /* + * TODO: This could be further optimized + */ + style = ctxt->style; + while (style) { + keyd = (xsltKeyDefPtr) style->keys; + while (keyd != NULL) { +#ifdef KEY_INIT_DEBUG +fprintf(stderr, "Init key %s\n", keyd->name); +#endif + /* + * Check if keys with this QName have been already + * computed. + */ + table = (xsltKeyTablePtr) ctxt->document->keys; + while (table) { + if (((keyd->nameURI != NULL) == (table->nameURI != NULL)) && + xmlStrEqual(keyd->name, table->name) && + xmlStrEqual(keyd->nameURI, table->nameURI)) + { + break; + } + table = table->next; + } + if (table == NULL) { + /* + * Keys with this QName have not been yet computed. + */ + xsltInitDocKeyTable(ctxt, keyd->name, keyd->nameURI); + } + keyd = keyd->next; + } + style = xsltNextImport(style); + } +#ifdef KEY_INIT_DEBUG +fprintf(stderr, "xsltInitAllDocKeys: done\n"); +#endif + return(0); +} + +/** + * xsltInitCtxtKey: + * @ctxt: an XSLT transformation context + * @idoc: the document information (holds key values) + * @keyDef: the key definition + * + * Computes the key tables this key and for the current input document. + * + * Returns: 0 on success, -1 on error + */ +int +xsltInitCtxtKey(xsltTransformContextPtr ctxt, xsltDocumentPtr idoc, + xsltKeyDefPtr keyDef) +{ + int i, len, k; + xmlNodeSetPtr matchList = NULL, keylist; + xmlXPathObjectPtr matchRes = NULL, useRes = NULL; + xmlChar *str = NULL; + xsltKeyTablePtr table; + xmlNodePtr oldInst, cur; + xmlNodePtr oldContextNode; + xsltDocumentPtr oldDocInfo; + int oldXPPos, oldXPSize; + xmlNodePtr oldXPNode; + xmlDocPtr oldXPDoc; + int oldXPNsNr; + xmlNsPtr *oldXPNamespaces; + xmlXPathContextPtr xpctxt; + +#ifdef KEY_INIT_DEBUG +fprintf(stderr, "xsltInitCtxtKey %s : %d\n", keyDef->name, ctxt->keyInitLevel); +#endif + + if ((keyDef->comp == NULL) || (keyDef->usecomp == NULL)) + return(-1); + + /* + * Detect recursive keys + */ + if (ctxt->keyInitLevel > ctxt->nbKeys) { +#ifdef WITH_XSLT_DEBUG_KEYS + XSLT_TRACE(ctxt,XSLT_TRACE_KEYS, + xsltGenericDebug(xsltGenericDebugContext, + "xsltInitCtxtKey: key definition of %s is recursive\n", + keyDef->name)); +#endif + xsltTransformError(ctxt, NULL, keyDef->inst, + "Key definition for %s is recursive\n", keyDef->name); + ctxt->state = XSLT_STATE_STOPPED; + return(-1); + } + ctxt->keyInitLevel++; + + xpctxt = ctxt->xpathCtxt; + idoc->nbKeysComputed++; + /* + * Save context state. + */ + oldInst = ctxt->inst; + oldDocInfo = ctxt->document; + oldContextNode = ctxt->node; + + oldXPNode = xpctxt->node; + oldXPDoc = xpctxt->doc; + oldXPPos = xpctxt->proximityPosition; + oldXPSize = xpctxt->contextSize; + oldXPNsNr = xpctxt->nsNr; + oldXPNamespaces = xpctxt->namespaces; + + /* + * Set up contexts. + */ + ctxt->document = idoc; + ctxt->node = (xmlNodePtr) idoc->doc; + ctxt->inst = keyDef->inst; + + xpctxt->doc = idoc->doc; + xpctxt->node = (xmlNodePtr) idoc->doc; + /* TODO : clarify the use of namespaces in keys evaluation */ + xpctxt->namespaces = keyDef->nsList; + xpctxt->nsNr = keyDef->nsNr; + + /* + * Evaluate the 'match' expression of the xsl:key. + * TODO: The 'match' is a *pattern*. + */ + matchRes = xmlXPathCompiledEval(keyDef->comp, xpctxt); + if (matchRes == NULL) { + +#ifdef WITH_XSLT_DEBUG_KEYS + XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext, + "xsltInitCtxtKey: %s evaluation failed\n", keyDef->match)); +#endif + xsltTransformError(ctxt, NULL, keyDef->inst, + "Failed to evaluate the 'match' expression.\n"); + ctxt->state = XSLT_STATE_STOPPED; + goto error; + } else { + if (matchRes->type == XPATH_NODESET) { + matchList = matchRes->nodesetval; + +#ifdef WITH_XSLT_DEBUG_KEYS + if (matchList != NULL) + XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext, + "xsltInitCtxtKey: %s evaluates to %d nodes\n", + keyDef->match, matchList->nodeNr)); +#endif + } else { + /* + * Is not a node set, but must be. + */ +#ifdef WITH_XSLT_DEBUG_KEYS + XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext, + "xsltInitCtxtKey: %s is not a node set\n", keyDef->match)); +#endif + xsltTransformError(ctxt, NULL, keyDef->inst, + "The 'match' expression did not evaluate to a node set.\n"); + ctxt->state = XSLT_STATE_STOPPED; + goto error; + } + } + if ((matchList == NULL) || (matchList->nodeNr <= 0)) + goto exit; + + /** + * Multiple key definitions for the same name are allowed, so + * we must check if the key is already present for this doc + */ + table = (xsltKeyTablePtr) idoc->keys; + while (table != NULL) { + if (xmlStrEqual(table->name, keyDef->name) && + (((keyDef->nameURI == NULL) && (table->nameURI == NULL)) || + ((keyDef->nameURI != NULL) && (table->nameURI != NULL) && + (xmlStrEqual(table->nameURI, keyDef->nameURI))))) + break; + table = table->next; + } + /** + * If the key was not previously defined, create it now and + * chain it to the list of keys for the doc + */ + if (table == NULL) { + table = xsltNewKeyTable(keyDef->name, keyDef->nameURI); + if (table == NULL) + goto error; + table->next = idoc->keys; + idoc->keys = table; + } + + /* + * SPEC XSLT 1.0 (XSLT 2.0 does not clarify the context size!) + * "...the use attribute of the xsl:key element is evaluated with x as + " the current node and with a node list containing just x as the + * current node list" + */ + xpctxt->contextSize = 1; + xpctxt->proximityPosition = 1; + + for (i = 0; i < matchList->nodeNr; i++) { + cur = matchList->nodeTab[i]; + if (! IS_XSLT_REAL_NODE(cur)) + continue; + ctxt->node = cur; + xpctxt->node = cur; + /* + * Process the 'use' of the xsl:key. + * SPEC XSLT 1.0: + * "The use attribute is an expression specifying the values of + * the key; the expression is evaluated once for each node that + * matches the pattern." + */ + if (useRes != NULL) + xmlXPathFreeObject(useRes); + useRes = xmlXPathCompiledEval(keyDef->usecomp, xpctxt); + if (useRes == NULL) { + xsltTransformError(ctxt, NULL, keyDef->inst, + "Failed to evaluate the 'use' expression.\n"); + ctxt->state = XSLT_STATE_STOPPED; + break; + } + if (useRes->type == XPATH_NODESET) { + if ((useRes->nodesetval != NULL) && + (useRes->nodesetval->nodeNr != 0)) + { + len = useRes->nodesetval->nodeNr; + str = xmlXPathCastNodeToString(useRes->nodesetval->nodeTab[0]); + } else { + continue; + } + } else { + len = 1; + if (useRes->type == XPATH_STRING) { + /* + * Consume the string value. + */ + str = useRes->stringval; + useRes->stringval = NULL; + } else { + str = xmlXPathCastToString(useRes); + } + } + /* + * Process all strings. + */ + k = 0; + while (1) { + if (str == NULL) + goto next_string; + +#ifdef WITH_XSLT_DEBUG_KEYS + XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext, + "xsl:key : node associated to ('%s', '%s')\n", keyDef->name, str)); +#endif + + keylist = xmlHashLookup(table->keys, str); + if (keylist == NULL) { + keylist = xmlXPathNodeSetCreate(cur); + if (keylist == NULL) + goto error; + if (xmlHashAddEntry(table->keys, str, keylist) < 0) { + xmlXPathFreeNodeSet(keylist); + goto error; + } + } else { + /* + * TODO: How do we know if this function failed? + */ + xmlXPathNodeSetAdd(keylist, cur); + } + xsltSetSourceNodeFlags(ctxt, cur, XSLT_SOURCE_NODE_HAS_KEY); + xmlFree(str); + str = NULL; + +next_string: + k++; + if (k >= len) + break; + str = xmlXPathCastNodeToString(useRes->nodesetval->nodeTab[k]); + } + } + +exit: +error: + ctxt->keyInitLevel--; + /* + * Restore context state. + */ + xpctxt->node = oldXPNode; + xpctxt->doc = oldXPDoc; + xpctxt->nsNr = oldXPNsNr; + xpctxt->namespaces = oldXPNamespaces; + xpctxt->proximityPosition = oldXPPos; + xpctxt->contextSize = oldXPSize; + + ctxt->node = oldContextNode; + ctxt->document = oldDocInfo; + ctxt->inst = oldInst; + + if (str) + xmlFree(str); + if (useRes != NULL) + xmlXPathFreeObject(useRes); + if (matchRes != NULL) + xmlXPathFreeObject(matchRes); + return(0); +} + +/** + * xsltInitCtxtKeys: + * @ctxt: an XSLT transformation context + * @idoc: a document info + * + * Computes all the keys tables for the current input document. + * Should be done before global varibales are initialized. + * NOTE: Not used anymore in the refactored code. + */ +void +xsltInitCtxtKeys(xsltTransformContextPtr ctxt, xsltDocumentPtr idoc) { + xsltStylesheetPtr style; + xsltKeyDefPtr keyDef; + + if ((ctxt == NULL) || (idoc == NULL)) + return; + +#ifdef KEY_INIT_DEBUG +fprintf(stderr, "xsltInitCtxtKeys on document\n"); +#endif + +#ifdef WITH_XSLT_DEBUG_KEYS + if ((idoc->doc != NULL) && (idoc->doc->URL != NULL)) + XSLT_TRACE(ctxt,XSLT_TRACE_KEYS,xsltGenericDebug(xsltGenericDebugContext, "Initializing keys on %s\n", + idoc->doc->URL)); +#endif + style = ctxt->style; + while (style != NULL) { + keyDef = (xsltKeyDefPtr) style->keys; + while (keyDef != NULL) { + xsltInitCtxtKey(ctxt, idoc, keyDef); + + keyDef = keyDef->next; + } + + style = xsltNextImport(style); + } + +#ifdef KEY_INIT_DEBUG +fprintf(stderr, "xsltInitCtxtKeys on document: done\n"); +#endif + +} + +/** + * xsltFreeDocumentKeys: + * @idoc: a XSLT document + * + * Free the keys associated to a document + */ +void +xsltFreeDocumentKeys(xsltDocumentPtr idoc) { + if (idoc != NULL) + xsltFreeKeyTableList(idoc->keys); +} + diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/keys.h chromium-145.0.7632.159/third_party/libxslt/src/libxslt/keys.h --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/keys.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/keys.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,53 @@ +/* + * Summary: interface for the key matching used in key() and template matches. + * Description: implementation of the key mechanims. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLT_KEY_H__ +#define __XML_XSLT_KEY_H__ + +#include +#include "xsltexports.h" +#include "xsltInternals.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * NODE_IS_KEYED: + * + * check for bit 15 set + */ +#define NODE_IS_KEYED (1 >> 15) + +XSLTPUBFUN int XSLTCALL + xsltAddKey (xsltStylesheetPtr style, + const xmlChar *name, + const xmlChar *nameURI, + const xmlChar *match, + const xmlChar *use, + xmlNodePtr inst); +XSLTPUBFUN xmlNodeSetPtr XSLTCALL + xsltGetKey (xsltTransformContextPtr ctxt, + const xmlChar *name, + const xmlChar *nameURI, + const xmlChar *value); +XSLTPUBFUN void XSLTCALL + xsltInitCtxtKeys (xsltTransformContextPtr ctxt, + xsltDocumentPtr doc); +XSLTPUBFUN void XSLTCALL + xsltFreeKeys (xsltStylesheetPtr style); +XSLTPUBFUN void XSLTCALL + xsltFreeDocumentKeys (xsltDocumentPtr doc); + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_H__ */ + diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/libxslt.3 chromium-145.0.7632.159/third_party/libxslt/src/libxslt/libxslt.3 --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/libxslt.3 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/libxslt.3 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,31 @@ +.TH libxslt 3 "30 August 2001" +.SH NAME +libxslt \- library used to do XSL transformations on XML documents +.SH DESCRIPTION +The +.I libxslt +library is used to do XSL transformations on XML documents that +have been loaded into memory with functions from +.I libxml. +.LP +.SH FILES +.TP 2.2i +.B /usr/lib/libxslt_1.0.0/libxslt.a +static library +.TP +.B /usr/lib/libxslt_1.0.0/libxslt.so +sharable library +.TP +.B /usr/package/libxslt_1.0.0/bin/xsltproc +binary application to do XSL transformations on the command line +.SH AUTHORS +Daniel Veillard (daniel@veillard.com). +If you download and install this package look at instructions on the +Web site https://gitlab.gnome.org/GNOME/libxslt . +Manual page by Heiko W. Rupp (hwr@pilhuhn.de) +.SH SEE ALSO +.IR libexslt (3), +.IR libxml (3), +.IR xsltproc (1), +.IR xmllint (1) +.\" end of manual page diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/libxslt.h chromium-145.0.7632.159/third_party/libxslt/src/libxslt/libxslt.h --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/libxslt.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/libxslt.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,55 @@ +/* + * Summary: internal header only used during the compilation of libxslt + * Description: internal header only used during the compilation of libxslt + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XSLT_LIBXSLT_H__ +#define __XSLT_LIBXSLT_H__ + +/* + * These macros must be defined before including system headers. + * Do not add any #include directives above this block. + */ +#ifndef NO_LARGEFILE_SOURCE + #ifndef _LARGEFILE_SOURCE + #define _LARGEFILE_SOURCE + #endif + #ifndef _FILE_OFFSET_BITS + #define _FILE_OFFSET_BITS 64 + #endif +#endif + +#if defined(_WIN32) && !defined (__MINGW32__) +#include +#else +#include "config.h" +#endif + +#include +#include + +#if !defined LIBXSLT_PUBLIC +#if (defined (__CYGWIN__) || defined _MSC_VER) && !defined IN_LIBXSLT && !defined LIBXSLT_STATIC +#define LIBXSLT_PUBLIC __declspec(dllimport) +#else +#define LIBXSLT_PUBLIC +#endif +#endif + +#if defined(_MSC_VER) || defined(__MINGW32__) +#include +#include +#define mkdir(p,m) _mkdir(p) +#endif + +#ifdef __GNUC__ +#define ATTRIBUTE_UNUSED __attribute__((unused)) +#else +#define ATTRIBUTE_UNUSED +#endif + +#endif /* ! __XSLT_LIBXSLT_H__ */ diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/namespaces.c chromium-145.0.7632.159/third_party/libxslt/src/libxslt/namespaces.c --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/namespaces.c 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/namespaces.c 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,835 @@ +/* + * namespaces.c: Implementation of the XSLT namespaces handling + * + * Reference: + * http://www.w3.org/TR/1999/REC-xslt-19991116 + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#define IN_LIBXSLT +#include "libxslt.h" + +#include + +#ifndef XSLT_NEED_TRIO +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +#include "xslt.h" +#include "xsltInternals.h" +#include "xsltutils.h" +#include "namespaces.h" +#include "imports.h" + +/************************************************************************ + * * + * Module interfaces * + * * + ************************************************************************/ + +#ifdef XSLT_REFACTORED +static xsltNsAliasPtr +xsltNewNsAlias(xsltCompilerCtxtPtr cctxt) +{ + xsltNsAliasPtr ret; + + if (cctxt == NULL) + return(NULL); + + ret = (xsltNsAliasPtr) xmlMalloc(sizeof(xsltNsAlias)); + if (ret == NULL) { + xsltTransformError(NULL, cctxt->style, NULL, + "Internal error in xsltNewNsAlias(): Memory allocation failed.\n"); + cctxt->style->errors++; + return(NULL); + } + memset(ret, 0, sizeof(xsltNsAlias)); + /* + * TODO: Store the item at current stylesheet-level. + */ + ret->next = cctxt->nsAliases; + cctxt->nsAliases = ret; + + return(ret); +} +#endif /* XSLT_REFACTORED */ +/** + * xsltNamespaceAlias: + * @style: the XSLT stylesheet + * @node: the xsl:namespace-alias node + * + * Read the stylesheet-prefix and result-prefix attributes, register + * them as well as the corresponding namespace. + */ +void +xsltNamespaceAlias(xsltStylesheetPtr style, xmlNodePtr node) +{ + xmlChar *resultPrefix = NULL; + xmlChar *stylePrefix = NULL; + xmlNsPtr literalNs = NULL; + xmlNsPtr targetNs = NULL; + +#ifdef XSLT_REFACTORED + xsltNsAliasPtr alias; + + if ((style == NULL) || (node == NULL)) + return; + + /* + * SPEC XSLT 1.0: + * "If a namespace URI is declared to be an alias for multiple + * different namespace URIs, then the declaration with the highest + * import precedence is used. It is an error if there is more than + * one such declaration. An XSLT processor may signal the error; + * if it does not signal the error, it must recover by choosing, + * from amongst the declarations with the highest import precedence, + * the one that occurs last in the stylesheet." + * + * SPEC TODO: Check for the errors mentioned above. + */ + /* + * NOTE that the XSLT 2.0 also *does* use the NULL namespace if + * "#default" is used and there's no default namespace is scope. + * I.e., this is *not* an error. + * Most XSLT 1.0 implementations work this way. + * The XSLT 1.0 spec has nothing to say on the subject. + */ + /* + * Attribute "stylesheet-prefix". + */ + stylePrefix = xmlGetNsProp(node, (const xmlChar *)"stylesheet-prefix", NULL); + if (stylePrefix == NULL) { + xsltTransformError(NULL, style, node, + "The attribute 'stylesheet-prefix' is missing.\n"); + return; + } + if (xmlStrEqual(stylePrefix, (const xmlChar *)"#default")) + literalNs = xmlSearchNs(node->doc, node, NULL); + else { + literalNs = xmlSearchNs(node->doc, node, stylePrefix); + if (literalNs == NULL) { + xsltTransformError(NULL, style, node, + "Attribute 'stylesheet-prefix': There's no namespace " + "declaration in scope for the prefix '%s'.\n", + stylePrefix); + goto error; + } + } + /* + * Attribute "result-prefix". + */ + resultPrefix = xmlGetNsProp(node, (const xmlChar *)"result-prefix", NULL); + if (resultPrefix == NULL) { + xsltTransformError(NULL, style, node, + "The attribute 'result-prefix' is missing.\n"); + goto error; + } + if (xmlStrEqual(resultPrefix, (const xmlChar *)"#default")) + targetNs = xmlSearchNs(node->doc, node, NULL); + else { + targetNs = xmlSearchNs(node->doc, node, resultPrefix); + + if (targetNs == NULL) { + xsltTransformError(NULL, style, node, + "Attribute 'result-prefix': There's no namespace " + "declaration in scope for the prefix '%s'.\n", + stylePrefix); + goto error; + } + } + /* + * + * Same alias for multiple different target namespace URIs: + * TODO: The one with the highest import precedence is used. + * Example: + * + * + * + * + * Same target namespace URI for multiple different aliases: + * All alias-definitions will be used. + * Example: + * + * + * + * Cases using #default: + * + * TODO: Has this an effect at all? + * + * + * From namespace to no namespace. + * + * + * From no namespace to namespace. + */ + + + /* + * Store the ns-node in the alias-object. + */ + alias = xsltNewNsAlias(XSLT_CCTXT(style)); + if (alias == NULL) + return; + alias->literalNs = literalNs; + alias->targetNs = targetNs; + XSLT_CCTXT(style)->hasNsAliases = 1; + + +#else /* XSLT_REFACTORED */ + const xmlChar *literalNsName; + const xmlChar *targetNsName; + + + if ((style == NULL) || (node == NULL)) + return; + + stylePrefix = xmlGetNsProp(node, (const xmlChar *)"stylesheet-prefix", NULL); + if (stylePrefix == NULL) { + xsltTransformError(NULL, style, node, + "namespace-alias: stylesheet-prefix attribute missing\n"); + return; + } + resultPrefix = xmlGetNsProp(node, (const xmlChar *)"result-prefix", NULL); + if (resultPrefix == NULL) { + xsltTransformError(NULL, style, node, + "namespace-alias: result-prefix attribute missing\n"); + goto error; + } + + if (xmlStrEqual(stylePrefix, (const xmlChar *)"#default")) { + literalNs = xmlSearchNs(node->doc, node, NULL); + if (literalNs == NULL) { + literalNsName = NULL; + } else + literalNsName = literalNs->href; /* Yes - set for nsAlias table */ + } else { + literalNs = xmlSearchNs(node->doc, node, stylePrefix); + + if ((literalNs == NULL) || (literalNs->href == NULL)) { + xsltTransformError(NULL, style, node, + "namespace-alias: prefix %s not bound to any namespace\n", + stylePrefix); + goto error; + } else + literalNsName = literalNs->href; + } + + /* + * When "#default" is used for result, if a default namespace has not + * been explicitly declared the special value UNDEFINED_DEFAULT_NS is + * put into the nsAliases table + */ + if (xmlStrEqual(resultPrefix, (const xmlChar *)"#default")) { + targetNs = xmlSearchNs(node->doc, node, NULL); + if (targetNs == NULL) { + targetNsName = UNDEFINED_DEFAULT_NS; + } else + targetNsName = targetNs->href; + } else { + targetNs = xmlSearchNs(node->doc, node, resultPrefix); + + if ((targetNs == NULL) || (targetNs->href == NULL)) { + xsltTransformError(NULL, style, node, + "namespace-alias: prefix %s not bound to any namespace\n", + resultPrefix); + goto error; + } else + targetNsName = targetNs->href; + } + /* + * Special case: if #default is used for + * the stylesheet-prefix (literal namespace) and there's no default + * namespace in scope, we'll use style->defaultAlias for this. + */ + if (literalNsName == NULL) { + if (targetNs != NULL) { + /* + * BUG TODO: Is it not sufficient to have only 1 field for + * this, since subsequently alias declarations will + * overwrite this. + * Example: + * + * + * The mapping for "foo" won't be visible anymore. + */ + style->defaultAlias = targetNs->href; + } + } else { + if (style->nsAliases == NULL) + style->nsAliases = xmlHashCreate(10); + if (style->nsAliases == NULL) { + xsltTransformError(NULL, style, node, + "namespace-alias: cannot create hash table\n"); + goto error; + } + xmlHashAddEntry((xmlHashTablePtr) style->nsAliases, + literalNsName, (void *) targetNsName); + } +#endif /* else of XSLT_REFACTORED */ + +error: + if (stylePrefix != NULL) + xmlFree(stylePrefix); + if (resultPrefix != NULL) + xmlFree(resultPrefix); +} + +/** + * xsltGetSpecialNamespace: + * @ctxt: the transformation context + * @invocNode: the invoking node; e.g. a literal result element/attr; + * only used for error reports + * @nsName: the namespace name (or NULL) + * @nsPrefix: the suggested namespace prefix (or NULL) + * @target: the result element on which to anchor a namespace + * + * Find a matching (prefix and ns-name) ns-declaration + * for the requested @nsName and @nsPrefix in the result tree. + * If none is found then a new ns-declaration will be + * added to @resultElem. If, in this case, the given prefix is + * already in use, then a ns-declaration with a modified ns-prefix + * be we created. Note that this function's priority is to + * preserve ns-prefixes; it will only change a prefix if there's + * a namespace clash. + * If both @nsName and @nsPrefix are NULL, then this will try to + * "undeclare" a default namespace by declaring an xmlns="". + * + * Returns a namespace declaration or NULL. + */ +xmlNsPtr +xsltGetSpecialNamespace(xsltTransformContextPtr ctxt, xmlNodePtr invocNode, + const xmlChar *nsName, const xmlChar *nsPrefix, + xmlNodePtr target) +{ + xmlNsPtr ns; + int prefixOccupied = 0; + + if ((ctxt == NULL) || (target == NULL) || + (target->type != XML_ELEMENT_NODE)) + return(NULL); + + /* + * NOTE: Namespace exclusion and ns-aliasing is performed at + * compilation-time in the refactored code; so this need not be done + * here (it was in the old code). + * NOTE: @invocNode was named @cur in the old code and was documented to + * be an input node; since it was only used to anchor an error report + * somewhere, we can safely change this to @invocNode, which now + * will be the XSLT instruction (also a literal result element/attribute), + * which was responsible for this call. + */ + /* + * OPTIMIZE TODO: This all could be optimized by keeping track of + * the ns-decls currently in-scope via a specialized context. + */ + if ((nsPrefix == NULL) && ((nsName == NULL) || (nsName[0] == 0))) { + /* + * NOTE: the "undeclaration" of the default namespace was + * part of the logic of the old xsltGetSpecialNamespace() code, + * so we'll keep that mechanism. + * Related to the old code: bug #302020: + */ + /* + * OPTIMIZE TODO: This all could be optimized by keeping track of + * the ns-decls currently in-scope via a specialized context. + */ + /* + * Search on the result element itself. + */ + if (target->nsDef != NULL) { + ns = target->nsDef; + do { + if (ns->prefix == NULL) { + if ((ns->href != NULL) && (ns->href[0] != 0)) { + /* + * Raise a namespace normalization error. + */ + xsltTransformError(ctxt, NULL, invocNode, + "Namespace normalization error: Cannot undeclare " + "the default namespace, since the default namespace " + "'%s' is already declared on the result element " + "'%s'.\n", ns->href, target->name); + return(NULL); + } else { + /* + * The default namespace was undeclared on the + * result element. + */ + return(NULL); + } + break; + } + ns = ns->next; + } while (ns != NULL); + } + if ((target->parent != NULL) && + (target->parent->type == XML_ELEMENT_NODE)) + { + /* + * The parent element is in no namespace, so assume + * that there is no default namespace in scope. + */ + if (target->parent->ns == NULL) + return(NULL); + + ns = xmlSearchNs(target->doc, target->parent, + NULL); + /* + * Fine if there's no default ns is scope, or if the + * default ns was undeclared. + */ + if ((ns == NULL) || (ns->href == NULL) || (ns->href[0] == 0)) + return(NULL); + + /* + * Undeclare the default namespace. + */ + xmlNewNs(target, BAD_CAST "", NULL); + /* TODO: Check result */ + return(NULL); + } + return(NULL); + } + /* + * Handle the XML namespace. + * QUESTION: Is this faster than using xmlStrEqual() anyway? + */ + if ((nsPrefix != NULL) && + (nsPrefix[0] == 'x') && (nsPrefix[1] == 'm') && + (nsPrefix[2] == 'l') && (nsPrefix[3] == 0)) + { + return(xmlSearchNs(target->doc, target, nsPrefix)); + } + /* + * First: search on the result element itself. + */ + if (target->nsDef != NULL) { + ns = target->nsDef; + do { + if ((ns->prefix == NULL) == (nsPrefix == NULL)) { + if (ns->prefix == nsPrefix) { + if (xmlStrEqual(ns->href, nsName)) + return(ns); + prefixOccupied = 1; + break; + } else if (xmlStrEqual(ns->prefix, nsPrefix)) { + if (xmlStrEqual(ns->href, nsName)) + return(ns); + prefixOccupied = 1; + break; + } + } + ns = ns->next; + } while (ns != NULL); + } + if (prefixOccupied) { + /* + * If the ns-prefix is occupied by an other ns-decl on the + * result element, then this means: + * 1) The desired prefix is shadowed + * 2) There's no way around changing the prefix + * + * Try a desperate search for an in-scope ns-decl + * with a matching ns-name before we use the last option, + * which is to recreate the ns-decl with a modified prefix. + */ + ns = xmlSearchNsByHref(target->doc, target, nsName); + if (ns != NULL) + return(ns); + + /* + * Fallback to changing the prefix. + */ + } else if ((target->parent != NULL) && + (target->parent->type == XML_ELEMENT_NODE)) + { + /* + * Try to find a matching ns-decl in the ancestor-axis. + * + * Check the common case: The parent element of the current + * result element is in the same namespace (with an equal ns-prefix). + */ + if ((target->parent->ns != NULL) && + ((target->parent->ns->prefix != NULL) == (nsPrefix != NULL))) + { + ns = target->parent->ns; + + if (nsPrefix == NULL) { + if (xmlStrEqual(ns->href, nsName)) + return(ns); + } else if (xmlStrEqual(ns->prefix, nsPrefix) && + xmlStrEqual(ns->href, nsName)) + { + return(ns); + } + } + /* + * Lookup the remaining in-scope namespaces. + */ + ns = xmlSearchNs(target->doc, target->parent, nsPrefix); + if (ns != NULL) { + if (xmlStrEqual(ns->href, nsName)) + return(ns); + /* + * Now check for a nasty case: We need to ensure that the new + * ns-decl won't shadow a prefix in-use by an existing attribute. + * + * + * + * val-b + * + * + */ + if (target->properties) { + xmlAttrPtr attr = target->properties; + do { + if ((attr->ns) && + xmlStrEqual(attr->ns->prefix, nsPrefix)) + { + /* + * Bad, this prefix is already in use. + * Since we'll change the prefix anyway, try + * a search for a matching ns-decl based on the + * namespace name. + */ + ns = xmlSearchNsByHref(target->doc, target, nsName); + if (ns != NULL) + return(ns); + goto declare_new_prefix; + } + attr = attr->next; + } while (attr != NULL); + } + } else { + /* + * Either no matching ns-prefix was found or the namespace is + * shadowed. + * Create a new ns-decl on the current result element. + * + * Hmm, we could also try to reuse an in-scope + * namespace with a matching ns-name but a different + * ns-prefix. + * What has higher priority? + * 1) If keeping the prefix: create a new ns-decl. + * 2) If reusal: first lookup ns-names; then fallback + * to creation of a new ns-decl. + * REVISIT: this currently uses case 1) although + * the old way was use xmlSearchNsByHref() and to let change + * the prefix. + */ +#if 0 + ns = xmlSearchNsByHref(target->doc, target, nsName); + if (ns != NULL) + return(ns); +#endif + } + /* + * Create the ns-decl on the current result element. + */ + ns = xmlNewNs(target, nsName, nsPrefix); + /* TODO: check errors */ + return(ns); + } else { + /* + * This is either the root of the tree or something weird is going on. + */ + ns = xmlNewNs(target, nsName, nsPrefix); + /* TODO: Check result */ + return(ns); + } + +declare_new_prefix: + /* + * Fallback: we need to generate a new prefix and declare the namespace + * on the result element. + */ + { + xmlChar pref[30]; + int counter = 1; + + if (nsPrefix == NULL) { + nsPrefix = BAD_CAST "ns"; + } + + do { + snprintf((char *) pref, 30, "%s_%d", nsPrefix, counter++); + ns = xmlSearchNs(target->doc, target, BAD_CAST pref); + if (counter > 1000) { + xsltTransformError(ctxt, NULL, invocNode, + "Internal error in xsltAcquireResultInScopeNs(): " + "Failed to compute a unique ns-prefix for the " + "generated element"); + return(NULL); + } + } while (ns != NULL); + ns = xmlNewNs(target, nsName, BAD_CAST pref); + /* TODO: Check result */ + return(ns); + } + return(NULL); +} + +/** + * xsltGetNamespace: + * @ctxt: a transformation context + * @cur: the input node + * @ns: the namespace + * @out: the output node (or its parent) + * + * Find a matching (prefix and ns-name) ns-declaration + * for the requested @ns->prefix and @ns->href in the result tree. + * If none is found then a new ns-declaration will be + * added to @resultElem. If, in this case, the given prefix is + * already in use, then a ns-declaration with a modified ns-prefix + * be we created. + * + * Called by: + * - xsltCopyPropList() (*not* anymore) + * - xsltShallowCopyElement() + * - xsltCopyTreeInternal() (*not* anymore) + * - xsltApplySequenceConstructor() (*not* in the refactored code), + * - xsltElement() (*not* anymore) + * + * Returns a namespace declaration or NULL in case of + * namespace fixup failures or API or internal errors. + */ +xmlNsPtr +xsltGetNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur, xmlNsPtr ns, + xmlNodePtr out) +{ + + if (ns == NULL) + return(NULL); + +#ifdef XSLT_REFACTORED + /* + * Namespace exclusion and ns-aliasing is performed at + * compilation-time in the refactored code. + * Additionally, aliasing is not intended for non Literal + * Result Elements. + */ + return(xsltGetSpecialNamespace(ctxt, cur, ns->href, ns->prefix, out)); +#else + { + xsltStylesheetPtr style; + const xmlChar *URI = NULL; /* the replacement URI */ + + if ((ctxt == NULL) || (cur == NULL) || (out == NULL)) + return(NULL); + + style = ctxt->style; + while (style != NULL) { + if (style->nsAliases != NULL) + URI = (const xmlChar *) + xmlHashLookup(style->nsAliases, ns->href); + if (URI != NULL) + break; + + style = xsltNextImport(style); + } + + + if (URI == UNDEFINED_DEFAULT_NS) { + return(xsltGetSpecialNamespace(ctxt, cur, NULL, NULL, out)); +#if 0 + /* + * TODO: Removed, since wrong. If there was no default + * namespace in the stylesheet then this must resolve to + * the NULL namespace. + */ + xmlNsPtr dflt; + dflt = xmlSearchNs(cur->doc, cur, NULL); + if (dflt != NULL) + URI = dflt->href; + else + return NULL; +#endif + } else if (URI == NULL) + URI = ns->href; + + return(xsltGetSpecialNamespace(ctxt, cur, URI, ns->prefix, out)); + } +#endif +} + +/** + * xsltGetPlainNamespace: + * @ctxt: a transformation context + * @cur: the input node + * @ns: the namespace + * @out: the result element + * + * Obsolete. + * *Not* called by any Libxslt/Libexslt function. + * Exaclty the same as xsltGetNamespace(). + * + * Returns a namespace declaration or NULL in case of + * namespace fixup failures or API or internal errors. + */ +xmlNsPtr +xsltGetPlainNamespace(xsltTransformContextPtr ctxt, xmlNodePtr cur, + xmlNsPtr ns, xmlNodePtr out) +{ + return(xsltGetNamespace(ctxt, cur, ns, out)); +} + +/** + * xsltCopyNamespaceList: + * @ctxt: a transformation context + * @node: the target node + * @cur: the first namespace + * + * Do a copy of an namespace list. If @node is non-NULL the + * new namespaces are added automatically. This handles namespaces + * aliases. + * This function is intended only for *internal* use at + * transformation-time for copying ns-declarations of Literal + * Result Elements. + * + * Called by: + * xsltCopyTreeInternal() (transform.c) + * xsltShallowCopyElem() (transform.c) + * + * REVISIT: This function won't be used in the refactored code. + * + * Returns: a new xmlNsPtr, or NULL in case of error. + */ +xmlNsPtr +xsltCopyNamespaceList(xsltTransformContextPtr ctxt, xmlNodePtr node, + xmlNsPtr cur) { + xmlNsPtr ret = NULL, tmp; + xmlNsPtr p = NULL,q; + + if (cur == NULL) + return(NULL); + if (cur->type != XML_NAMESPACE_DECL) + return(NULL); + + /* + * One can add namespaces only on element nodes + */ + if ((node != NULL) && (node->type != XML_ELEMENT_NODE)) + node = NULL; + + while (cur != NULL) { + if (cur->type != XML_NAMESPACE_DECL) + break; + + /* + * Avoid duplicating namespace declarations in the tree if + * a matching declaration is in scope. + */ + if (node != NULL) { + if ((node->ns != NULL) && + (xmlStrEqual(node->ns->prefix, cur->prefix)) && + (xmlStrEqual(node->ns->href, cur->href))) { + cur = cur->next; + continue; + } + tmp = xmlSearchNs(node->doc, node, cur->prefix); + if ((tmp != NULL) && (xmlStrEqual(tmp->href, cur->href))) { + cur = cur->next; + continue; + } + } +#ifdef XSLT_REFACTORED + /* + * Namespace exclusion and ns-aliasing is performed at + * compilation-time in the refactored code. + */ + q = xmlNewNs(node, cur->href, cur->prefix); + if (p == NULL) { + ret = p = q; + } else { + p->next = q; + p = q; + } +#else + /* + * TODO: Remove this if the refactored code gets enabled. + */ + if (!xmlStrEqual(cur->href, XSLT_NAMESPACE)) { + const xmlChar *URI; + /* TODO apply cascading */ + URI = (const xmlChar *) xmlHashLookup(ctxt->style->nsAliases, + cur->href); + if (URI == UNDEFINED_DEFAULT_NS) { + cur = cur->next; + continue; + } + if (URI != NULL) { + q = xmlNewNs(node, URI, cur->prefix); + } else { + q = xmlNewNs(node, cur->href, cur->prefix); + } + if (p == NULL) { + ret = p = q; + } else { + p->next = q; + p = q; + } + } +#endif + cur = cur->next; + } + return(ret); +} + +/** + * xsltCopyNamespace: + * @ctxt: a transformation context + * @elem: the target element node + * @ns: the namespace node + * + * Copies a namespace node (declaration). If @elem is not NULL, + * then the new namespace will be declared on @elem. + * + * Returns: a new xmlNsPtr, or NULL in case of an error. + */ +xmlNsPtr +xsltCopyNamespace(xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, + xmlNodePtr elem, xmlNsPtr ns) +{ + if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) + return(NULL); + /* + * One can add namespaces only on element nodes + */ + if ((elem != NULL) && (elem->type != XML_ELEMENT_NODE)) + return(xmlNewNs(NULL, ns->href, ns->prefix)); + else + return(xmlNewNs(elem, ns->href, ns->prefix)); +} + + +/** + * xsltFreeNamespaceAliasHashes: + * @style: an XSLT stylesheet + * + * Free up the memory used by namespaces aliases + */ +void +xsltFreeNamespaceAliasHashes(xsltStylesheetPtr style) { + if (style->nsAliases != NULL) + xmlHashFree((xmlHashTablePtr) style->nsAliases, NULL); + style->nsAliases = NULL; +} diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/namespaces.h chromium-145.0.7632.159/third_party/libxslt/src/libxslt/namespaces.h --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/namespaces.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/namespaces.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,68 @@ +/* + * Summary: interface for the XSLT namespace handling + * Description: set of function easing the processing and generation + * of namespace nodes in XSLT. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLT_NAMESPACES_H__ +#define __XML_XSLT_NAMESPACES_H__ + +#include +#include "xsltexports.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Used within nsAliases hashtable when the default namespace is required + * but it's not been explicitly defined + */ +/** + * UNDEFINED_DEFAULT_NS: + * + * Special value for undefined namespace, internal + */ +#define UNDEFINED_DEFAULT_NS (const xmlChar *) -1L + +XSLTPUBFUN void XSLTCALL + xsltNamespaceAlias (xsltStylesheetPtr style, + xmlNodePtr node); +XSLTPUBFUN xmlNsPtr XSLTCALL + xsltGetNamespace (xsltTransformContextPtr ctxt, + xmlNodePtr cur, + xmlNsPtr ns, + xmlNodePtr out); +XSLTPUBFUN xmlNsPtr XSLTCALL + xsltGetPlainNamespace (xsltTransformContextPtr ctxt, + xmlNodePtr cur, + xmlNsPtr ns, + xmlNodePtr out); +XSLTPUBFUN xmlNsPtr XSLTCALL + xsltGetSpecialNamespace (xsltTransformContextPtr ctxt, + xmlNodePtr cur, + const xmlChar *URI, + const xmlChar *prefix, + xmlNodePtr out); +XSLTPUBFUN xmlNsPtr XSLTCALL + xsltCopyNamespace (xsltTransformContextPtr ctxt, + xmlNodePtr elem, + xmlNsPtr ns); +XSLTPUBFUN xmlNsPtr XSLTCALL + xsltCopyNamespaceList (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNsPtr cur); +XSLTPUBFUN void XSLTCALL + xsltFreeNamespaceAliasHashes + (xsltStylesheetPtr style); + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_NAMESPACES_H__ */ + diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/numbers.c chromium-145.0.7632.159/third_party/libxslt/src/libxslt/numbers.c --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/numbers.c 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/numbers.c 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,1412 @@ +/* + * numbers.c: Implementation of the XSLT number functions + * + * Reference: + * http://www.w3.org/TR/1999/REC-xslt-19991116 + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + * Bjorn Reese + */ + +#define IN_LIBXSLT +#include "libxslt.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "xsltutils.h" +#include "pattern.h" +#include "templates.h" +#include "transform.h" +#include "numbersInternals.h" + +#ifndef FALSE +# define FALSE (0 == 1) +# define TRUE (1 == 1) +#endif + +#define SYMBOL_QUOTE ((xmlChar)'\'') + +#define DEFAULT_TOKEN '0' +#define DEFAULT_SEPARATOR "." + +#define MAX_TOKENS 1024 + +typedef struct _xsltFormatToken xsltFormatToken; +typedef xsltFormatToken *xsltFormatTokenPtr; +struct _xsltFormatToken { + xmlChar *separator; + int token; + int width; +}; + +typedef struct _xsltFormat xsltFormat; +typedef xsltFormat *xsltFormatPtr; +struct _xsltFormat { + xmlChar *start; + xsltFormatToken tokens[MAX_TOKENS]; + int nTokens; + xmlChar *end; +}; + +static const char alpha_upper_list[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; +static const char alpha_lower_list[] = "abcdefghijklmnopqrstuvwxyz"; +static const xsltFormatToken default_token = { + BAD_CAST(DEFAULT_SEPARATOR), + DEFAULT_TOKEN, + 1 +}; + +/* + * Helper functions copied from libxml2 + */ + +/** + * xsltCopyCharMultiByte: + * @out: pointer to an array of xmlChar + * @val: the char value + * + * append the char value in the array + * + * Returns the number of xmlChar written + */ +static int +xsltCopyCharMultiByte(xmlChar *out, int val) { + if ((out == NULL) || (val < 0)) return(0); + if (val >= 0x80) { + xmlChar *savedout = out; + int bits; + if (val < 0x800) { *out++= (val >> 6) | 0xC0; bits= 0; } + else if (val < 0x10000) { *out++= (val >> 12) | 0xE0; bits= 6;} + else if (val < 0x110000) { *out++= (val >> 18) | 0xF0; bits= 12; } + else { + return(0); + } + for ( ; bits >= 0; bits-= 6) + *out++= ((val >> bits) & 0x3F) | 0x80 ; + return (out - savedout); + } + *out = val; + return 1; +} + +/** + * xsltUTF8Charcmp + * @utf1: pointer to first UTF8 char + * @utf2: pointer to second UTF8 char + * + * returns result of comparing the two UCS4 values + * as with xmlStrncmp + */ +static int +xsltUTF8Charcmp(xmlChar *utf1, xmlChar *utf2) { + int len = xmlUTF8Strsize(utf1, 1); + + if (len < 1) + return -1; + if (utf1 == NULL ) { + if (utf2 == NULL) + return 0; + return -1; + } + return xmlStrncmp(utf1, utf2, len); +} + +static int +xsltIsLetterDigit(int val) { + return xmlIsBaseCharQ(val) || xmlIsIdeographicQ(val) || + xmlIsDigitQ(val); +} + +/************************************************************************ + * * + * Utility functions * + * * + ************************************************************************/ + +#define IS_SPECIAL(self,letter) \ + ((xsltUTF8Charcmp((letter), (self)->zeroDigit) == 0) || \ + (xsltUTF8Charcmp((letter), (self)->digit) == 0) || \ + (xsltUTF8Charcmp((letter), (self)->decimalPoint) == 0) || \ + (xsltUTF8Charcmp((letter), (self)->grouping) == 0) || \ + (xsltUTF8Charcmp((letter), (self)->patternSeparator) == 0)) + +#define IS_DIGIT_ZERO(x) xsltIsDigitZero(x) +#define IS_DIGIT_ONE(x) xsltIsDigitZero((x)-1) + +static int +xsltIsDigitZero(int ch) +{ + /* + * Reference: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt + * + * There a many more digit ranges in newer Unicode versions. These + * are only the zeros that match Digit in XML 1.0 (IS_DIGIT macro). + */ + switch (ch) { + case 0x0030: case 0x0660: case 0x06F0: case 0x0966: + case 0x09E6: case 0x0A66: case 0x0AE6: case 0x0B66: + case 0x0C66: case 0x0CE6: case 0x0D66: case 0x0E50: + case 0x0ED0: case 0x0F20: + return TRUE; + default: + return FALSE; + } +} + +static void +xsltNumberFormatDecimal(xmlBufferPtr buffer, + double number, + int digit_zero, + int width, + int digitsPerGroup, + int groupingCharacter, + int groupingCharacterLen) +{ + /* + * This used to be + * xmlChar temp_string[sizeof(double) * CHAR_BIT * sizeof(xmlChar) + 4]; + * which would be length 68 on x86 arch. It was changed to be a longer, + * fixed length in order to try to cater for (reasonable) UTF8 + * separators and numeric characters. The max UTF8 char size will be + * 6 or less, so the value used [500] should be *much* larger than needed + */ + xmlChar temp_string[500]; + xmlChar *pointer; + xmlChar temp_char[6]; + int i; + int val; + int len; + + /* Build buffer from back */ + pointer = &temp_string[sizeof(temp_string)] - 1; /* last char */ + *pointer = 0; + i = 0; + while (pointer > temp_string) { + if ((i >= width) && (fabs(number) < 1.0)) + break; /* for */ + if ((i > 0) && (groupingCharacter != 0) && + (digitsPerGroup > 0) && + ((i % digitsPerGroup) == 0)) { + if (pointer - groupingCharacterLen < temp_string) { + i = -1; /* flag error */ + break; + } + pointer -= groupingCharacterLen; + xsltCopyCharMultiByte(pointer, groupingCharacter); + } + + val = digit_zero + (int)fmod(number, 10.0); + if (val < 0x80) { /* shortcut if ASCII */ + if (pointer <= temp_string) { /* Check enough room */ + i = -1; + break; + } + *(--pointer) = val; + } + else { + /* + * Here we have a multibyte character. It's a little messy, + * because until we generate the char we don't know how long + * it is. So, we generate it into the buffer temp_char, then + * copy from there into temp_string. + */ + len = xsltCopyCharMultiByte(temp_char, val); + if ( (pointer - len) < temp_string ) { + i = -1; + break; + } + pointer -= len; + memcpy(pointer, temp_char, len); + } + number /= 10.0; + ++i; + } + if (i < 0) + xsltGenericError(xsltGenericErrorContext, + "xsltNumberFormatDecimal: Internal buffer size exceeded\n"); + xmlBufferCat(buffer, pointer); +} + +static void +xsltNumberFormatAlpha(xsltNumberDataPtr data, + xmlBufferPtr buffer, + double number, + int is_upper) +{ + char temp_string[sizeof(double) * CHAR_BIT * sizeof(xmlChar) + 1]; + char *pointer; + int i; + const char *alpha_list; + double alpha_size = (double)(sizeof(alpha_upper_list) - 1); + + /* + * XSLT 1.0 isn't clear on how to handle zero, but XSLT 2.0 says: + * + * For all format tokens other than the first kind above (one that + * consists of decimal digits), there may be implementation-defined + * lower and upper bounds on the range of numbers that can be + * formatted using this format token; indeed, for some numbering + * sequences there may be intrinsic limits. [...] Numbers that fall + * outside this range must be formatted using the format token 1. + * + * The "a" token has an intrinsic lower limit of 1. + */ + if (number < 1.0) { + xsltNumberFormatDecimal(buffer, number, '0', 1, + data->digitsPerGroup, + data->groupingCharacter, + data->groupingCharacterLen); + return; + } + + /* Build buffer from back */ + pointer = &temp_string[sizeof(temp_string)]; + *(--pointer) = 0; + alpha_list = (is_upper) ? alpha_upper_list : alpha_lower_list; + + for (i = 1; i < (int)sizeof(temp_string); i++) { + number--; + *(--pointer) = alpha_list[((int)fmod(number, alpha_size))]; + number /= alpha_size; + if (number < 1.0) + break; /* for */ + } + xmlBufferCCat(buffer, pointer); +} + +static void +xsltNumberFormatRoman(xsltNumberDataPtr data, + xmlBufferPtr buffer, + double number, + int is_upper) +{ + /* + * See discussion in xsltNumberFormatAlpha. Also use a reasonable upper + * bound to avoid denial of service. + */ + if (number < 1.0 || number > 5000.0) { + xsltNumberFormatDecimal(buffer, number, '0', 1, + data->digitsPerGroup, + data->groupingCharacter, + data->groupingCharacterLen); + return; + } + + /* + * Based on an example by Jim Walsh + */ + while (number >= 1000.0) { + xmlBufferCCat(buffer, (is_upper) ? "M" : "m"); + number -= 1000.0; + } + if (number >= 900.0) { + xmlBufferCCat(buffer, (is_upper) ? "CM" : "cm"); + number -= 900.0; + } + while (number >= 500.0) { + xmlBufferCCat(buffer, (is_upper) ? "D" : "d"); + number -= 500.0; + } + if (number >= 400.0) { + xmlBufferCCat(buffer, (is_upper) ? "CD" : "cd"); + number -= 400.0; + } + while (number >= 100.0) { + xmlBufferCCat(buffer, (is_upper) ? "C" : "c"); + number -= 100.0; + } + if (number >= 90.0) { + xmlBufferCCat(buffer, (is_upper) ? "XC" : "xc"); + number -= 90.0; + } + while (number >= 50.0) { + xmlBufferCCat(buffer, (is_upper) ? "L" : "l"); + number -= 50.0; + } + if (number >= 40.0) { + xmlBufferCCat(buffer, (is_upper) ? "XL" : "xl"); + number -= 40.0; + } + while (number >= 10.0) { + xmlBufferCCat(buffer, (is_upper) ? "X" : "x"); + number -= 10.0; + } + if (number >= 9.0) { + xmlBufferCCat(buffer, (is_upper) ? "IX" : "ix"); + number -= 9.0; + } + while (number >= 5.0) { + xmlBufferCCat(buffer, (is_upper) ? "V" : "v"); + number -= 5.0; + } + if (number >= 4.0) { + xmlBufferCCat(buffer, (is_upper) ? "IV" : "iv"); + number -= 4.0; + } + while (number >= 1.0) { + xmlBufferCCat(buffer, (is_upper) ? "I" : "i"); + number--; + } +} + +static void +xsltNumberFormatTokenize(const xmlChar *format, + xsltFormatPtr tokens) +{ + int ix = 0; + int j; + int val; + int len; + + tokens->start = NULL; + tokens->tokens[0].separator = NULL; + tokens->end = NULL; + + /* + * Insert initial non-alphanumeric token. + * There is always such a token in the list, even if NULL + */ + while (!xsltIsLetterDigit(val = xsltGetUTF8CharZ(format+ix, &len))) { + if (format[ix] == 0) /* if end of format string */ + break; /* while */ + ix += len; + } + if (ix > 0) + tokens->start = xmlStrndup(format, ix); + + + for (tokens->nTokens = 0; tokens->nTokens < MAX_TOKENS; + tokens->nTokens++) { + if (format[ix] == 0) + break; /* for */ + + /* + * separator has already been parsed (except for the first + * number) in tokens->end, recover it. + */ + if (tokens->nTokens > 0) { + tokens->tokens[tokens->nTokens].separator = tokens->end; + tokens->end = NULL; + } + + val = xsltGetUTF8CharZ(format+ix, &len); + if (IS_DIGIT_ONE(val) || + IS_DIGIT_ZERO(val)) { + tokens->tokens[tokens->nTokens].width = 1; + while (IS_DIGIT_ZERO(val)) { + tokens->tokens[tokens->nTokens].width++; + ix += len; + val = xsltGetUTF8CharZ(format+ix, &len); + } + if (IS_DIGIT_ONE(val)) { + tokens->tokens[tokens->nTokens].token = val - 1; + ix += len; + val = xsltGetUTF8CharZ(format+ix, &len); + } else { + tokens->tokens[tokens->nTokens].token = '0'; + tokens->tokens[tokens->nTokens].width = 1; + } + } else if ( (val == 'A') || + (val == 'a') || + (val == 'I') || + (val == 'i') ) { + tokens->tokens[tokens->nTokens].token = val; + ix += len; + val = xsltGetUTF8CharZ(format+ix, &len); + } else { + /* XSLT section 7.7 + * "Any other format token indicates a numbering sequence + * that starts with that token. If an implementation does + * not support a numbering sequence that starts with that + * token, it must use a format token of 1." + */ + tokens->tokens[tokens->nTokens].token = '0'; + tokens->tokens[tokens->nTokens].width = 1; + } + /* + * Skip over remaining alphanumeric characters from the Nd + * (Number, decimal digit), Nl (Number, letter), No (Number, + * other), Lu (Letter, uppercase), Ll (Letter, lowercase), Lt + * (Letters, titlecase), Lm (Letters, modifiers), and Lo + * (Letters, other (uncased)) Unicode categories. This happens + * to correspond to the Letter and Digit classes from XML (and + * one wonders why XSLT doesn't refer to these instead). + */ + while (xsltIsLetterDigit(val)) { + ix += len; + val = xsltGetUTF8CharZ(format+ix, &len); + } + + /* + * Insert temporary non-alphanumeric final tooken. + */ + j = ix; + while (!xsltIsLetterDigit(val)) { + if (val == 0) + break; /* while */ + ix += len; + val = xsltGetUTF8CharZ(format+ix, &len); + } + if (ix > j) + tokens->end = xmlStrndup(&format[j], ix - j); + } +} + +static void +xsltNumberFormatInsertNumbers(xsltNumberDataPtr data, + double *numbers, + int numbers_max, + xsltFormatPtr tokens, + xmlBufferPtr buffer) +{ + int i = 0; + double number; + const xsltFormatToken *token; + + /* + * Handle initial non-alphanumeric token + */ + if (tokens->start != NULL) + xmlBufferCat(buffer, tokens->start); + + for (i = 0; i < numbers_max; i++) { + /* Insert number */ + number = numbers[(numbers_max - 1) - i]; + /* Round to nearest like XSLT 2.0 */ + number = floor(number + 0.5); + /* + * XSLT 1.0 isn't clear on how to handle negative numbers, but XSLT + * 2.0 says: + * + * It is a non-recoverable dynamic error if any undiscarded item + * in the atomized sequence supplied as the value of the value + * attribute of xsl:number cannot be converted to an integer, or + * if the resulting integer is less than 0 (zero). + */ + if (number < 0.0) { + xsltTransformError(NULL, NULL, NULL, + "xsl-number : negative value\n"); + /* Recover by treating negative values as zero. */ + number = 0.0; + } + if (i < tokens->nTokens) { + /* + * The "n"th format token will be used to format the "n"th + * number in the list + */ + token = &(tokens->tokens[i]); + } else if (tokens->nTokens > 0) { + /* + * If there are more numbers than format tokens, then the + * last format token will be used to format the remaining + * numbers. + */ + token = &(tokens->tokens[tokens->nTokens - 1]); + } else { + /* + * If there are no format tokens, then a format token of + * 1 is used to format all numbers. + */ + token = &default_token; + } + + /* Print separator, except for the first number */ + if (i > 0) { + if (token->separator != NULL) + xmlBufferCat(buffer, token->separator); + else + xmlBufferCCat(buffer, DEFAULT_SEPARATOR); + } + + switch (xmlXPathIsInf(number)) { + case -1: + xmlBufferCCat(buffer, "-Infinity"); + break; + case 1: + xmlBufferCCat(buffer, "Infinity"); + break; + default: + if (xmlXPathIsNaN(number)) { + xmlBufferCCat(buffer, "NaN"); + } else { + + switch (token->token) { + case 'A': + xsltNumberFormatAlpha(data, buffer, number, TRUE); + break; + case 'a': + xsltNumberFormatAlpha(data, buffer, number, FALSE); + break; + case 'I': + xsltNumberFormatRoman(data, buffer, number, TRUE); + break; + case 'i': + xsltNumberFormatRoman(data, buffer, number, FALSE); + break; + default: + if (IS_DIGIT_ZERO(token->token)) { + xsltNumberFormatDecimal(buffer, + number, + token->token, + token->width, + data->digitsPerGroup, + data->groupingCharacter, + data->groupingCharacterLen); + } + break; + } + } + + } + } + + /* + * Handle final non-alphanumeric token + */ + if (tokens->end != NULL) + xmlBufferCat(buffer, tokens->end); + +} + +static int +xsltTestCompMatchCount(xsltTransformContextPtr context, + xmlNodePtr node, + xsltCompMatchPtr countPat, + xmlNodePtr cur) +{ + if (countPat != NULL) { + return xsltTestCompMatchList(context, node, countPat); + } + else { + /* + * 7.7 Numbering + * + * If count attribute is not specified, then it defaults to the + * pattern that matches any node with the same node type as the + * current node and, if the current node has an expanded-name, with + * the same expanded-name as the current node. + */ + if (node->type != cur->type) + return 0; + if (node->type == XML_NAMESPACE_DECL) + /* + * Namespace nodes have no preceding siblings and no parents + * that are namespace nodes. This means that node == cur. + */ + return 1; + /* TODO: Skip node types without expanded names like text nodes. */ + if (!xmlStrEqual(node->name, cur->name)) + return 0; + if (node->ns == cur->ns) + return 1; + if ((node->ns == NULL) || (cur->ns == NULL)) + return 0; + return (xmlStrEqual(node->ns->href, cur->ns->href)); + } +} + +static int +xsltNumberFormatGetAnyLevel(xsltTransformContextPtr context, + xmlNodePtr node, + xsltCompMatchPtr countPat, + xsltCompMatchPtr fromPat, + double *array) +{ + int amount = 0; + int cnt = 0; + xmlNodePtr cur = node; + + while (cur != NULL) { + /* process current node */ + if (xsltTestCompMatchCount(context, cur, countPat, node)) + cnt++; + if ((fromPat != NULL) && + xsltTestCompMatchList(context, cur, fromPat)) { + break; /* while */ + } + + /* Skip to next preceding or ancestor */ + if ((cur->type == XML_DOCUMENT_NODE) || +#ifdef LIBXML_DOCB_ENABLED + (cur->type == XML_DOCB_DOCUMENT_NODE) || +#endif + (cur->type == XML_HTML_DOCUMENT_NODE)) + break; /* while */ + + if (cur->type == XML_NAMESPACE_DECL) { + /* + * The XPath module stores the parent of a namespace node in + * the ns->next field. + */ + cur = (xmlNodePtr) ((xmlNsPtr) cur)->next; + } else if (cur->type == XML_ATTRIBUTE_NODE) { + cur = cur->parent; + } else { + while ((cur->prev != NULL) && ((cur->prev->type == XML_DTD_NODE) || + (cur->prev->type == XML_XINCLUDE_START) || + (cur->prev->type == XML_XINCLUDE_END))) + cur = cur->prev; + if (cur->prev != NULL) { + for (cur = cur->prev; cur->last != NULL; cur = cur->last); + } else { + cur = cur->parent; + } + } + } + + array[amount++] = (double) cnt; + + return(amount); +} + +static int +xsltNumberFormatGetMultipleLevel(xsltTransformContextPtr context, + xmlNodePtr node, + xsltCompMatchPtr countPat, + xsltCompMatchPtr fromPat, + double *array, + int max) +{ + int amount = 0; + int cnt; + xmlNodePtr ancestor; + xmlNodePtr preceding; + + /* ancestor-or-self::*[count] */ + ancestor = node; + + while ((ancestor != NULL) && (ancestor->type != XML_DOCUMENT_NODE)) { + if ((fromPat != NULL) && + xsltTestCompMatchList(context, ancestor, fromPat)) + break; + + if (xsltTestCompMatchCount(context, ancestor, countPat, node)) { + /* count(preceding-sibling::*) */ + cnt = 1; + if (ancestor->type != XML_NAMESPACE_DECL) + preceding = ancestor->prev; + else + preceding = NULL; + while (preceding != NULL) { + if (xsltTestCompMatchCount(context, preceding, countPat, + node)) + cnt++; + preceding = preceding->prev; + } + array[amount++] = (double)cnt; + if (amount >= max) + break; + } + + if ((ancestor != NULL) && (ancestor->type == XML_NAMESPACE_DECL)) { + xmlNsPtr ns = (xmlNsPtr) ancestor; + + if ((ns->next != NULL) && + (ns->next->type != XML_NAMESPACE_DECL)) + ancestor = (xmlNodePtr) ns->next; + else + ancestor = NULL; + } else { + ancestor = ancestor->parent; + } + } + + return amount; +} + +static int +xsltNumberFormatGetValue(xmlXPathContextPtr context, + xmlNodePtr node, + const xmlChar *value, + double *number) +{ + int amount = 0; + xmlBufferPtr pattern; + xmlXPathObjectPtr obj; + xmlNodePtr oldNode; + + pattern = xmlBufferCreate(); + if (pattern != NULL) { + oldNode = context->node; + + xmlBufferCCat(pattern, "number("); + xmlBufferCat(pattern, value); + xmlBufferCCat(pattern, ")"); + context->node = node; + obj = xmlXPathEvalExpression(xmlBufferContent(pattern), + context); + if (obj != NULL) { + *number = obj->floatval; + amount++; + xmlXPathFreeObject(obj); + } + xmlBufferFree(pattern); + + context->node = oldNode; + } + return amount; +} + +/** + * xsltNumberFormat: + * @ctxt: the XSLT transformation context + * @data: the formatting information + * @node: the data to format + * + * Convert one number. + */ +void +xsltNumberFormat(xsltTransformContextPtr ctxt, + xsltNumberDataPtr data, + xmlNodePtr node) +{ + xmlBufferPtr output = NULL; + int amount, i; + double number; + xsltFormat tokens; + + if (data->format != NULL) { + xsltNumberFormatTokenize(data->format, &tokens); + } + else { + xmlChar *format; + + /* The format needs to be recomputed each time */ + if (data->has_format == 0) + return; + format = xsltEvalAttrValueTemplate(ctxt, data->node, + (const xmlChar *) "format", + XSLT_NAMESPACE); + if (format == NULL) + return; + xsltNumberFormatTokenize(format, &tokens); + xmlFree(format); + } + + output = xmlBufferCreate(); + if (output == NULL) + goto XSLT_NUMBER_FORMAT_END; + + /* + * Evaluate the XPath expression to find the value(s) + */ + if (data->value) { + amount = xsltNumberFormatGetValue(ctxt->xpathCtxt, + node, + data->value, + &number); + if (amount == 1) { + xsltNumberFormatInsertNumbers(data, + &number, + 1, + &tokens, + output); + } + + } else if (data->level) { + + if (xmlStrEqual(data->level, (const xmlChar *) "single")) { + amount = xsltNumberFormatGetMultipleLevel(ctxt, + node, + data->countPat, + data->fromPat, + &number, + 1); + if (amount == 1) { + xsltNumberFormatInsertNumbers(data, + &number, + 1, + &tokens, + output); + } + } else if (xmlStrEqual(data->level, (const xmlChar *) "multiple")) { + double numarray[1024]; + int max = sizeof(numarray)/sizeof(numarray[0]); + amount = xsltNumberFormatGetMultipleLevel(ctxt, + node, + data->countPat, + data->fromPat, + numarray, + max); + if (amount > 0) { + xsltNumberFormatInsertNumbers(data, + numarray, + amount, + &tokens, + output); + } + } else if (xmlStrEqual(data->level, (const xmlChar *) "any")) { + amount = xsltNumberFormatGetAnyLevel(ctxt, + node, + data->countPat, + data->fromPat, + &number); + if (amount > 0) { + xsltNumberFormatInsertNumbers(data, + &number, + 1, + &tokens, + output); + } + } + + /* + * Unlike `match` patterns, `count` and `from` patterns can contain + * variable references, so we have to clear the pattern match + * cache if the "direct" matching algorithm was used. + */ + if (data->countPat != NULL) + xsltCompMatchClearCache(ctxt, data->countPat); + if (data->fromPat != NULL) + xsltCompMatchClearCache(ctxt, data->fromPat); + } + /* Insert number as text node */ + xsltCopyTextString(ctxt, ctxt->insert, xmlBufferContent(output), 0); + + xmlBufferFree(output); + +XSLT_NUMBER_FORMAT_END: + if (tokens.start != NULL) + xmlFree(tokens.start); + if (tokens.end != NULL) + xmlFree(tokens.end); + for (i = 0;i < tokens.nTokens;i++) { + if (tokens.tokens[i].separator != NULL) + xmlFree(tokens.tokens[i].separator); + } +} + +static int +xsltFormatNumberPreSuffix(xsltDecimalFormatPtr self, xmlChar **format, xsltFormatNumberInfoPtr info) +{ + /* will hold total length of prefix/suffix without quote characters */ + int count=0; + int len; + + while (1) { + /* + * prefix / suffix ends at end of string or at + * first 'special' character + */ + if (**format == 0) + return count; + /* if next character 'escaped' just count it */ + if (**format == SYMBOL_QUOTE) { + if (*++(*format) == 0) + return -1; + } + else if (IS_SPECIAL(self, *format)) + return count; + /* + * else treat percent/per-mille as special cases, + * depending on whether +ve or -ve + */ + else { + /* + * for +ve prefix/suffix, allow only a + * single occurence of either + */ + if (xsltUTF8Charcmp(*format, self->percent) == 0) { + if (info->is_multiplier_set) + return -1; + info->multiplier = 100; + info->is_multiplier_set = TRUE; + } else if (xsltUTF8Charcmp(*format, self->permille) == 0) { + if (info->is_multiplier_set) + return -1; + info->multiplier = 1000; + info->is_multiplier_set = TRUE; + } + } + + if ((len=xmlUTF8Strsize(*format, 1)) < 1) + return -1; + count += len; + *format += len; + } +} + +/** + * xsltFormatNumberConversion: + * @self: the decimal format + * @format: the format requested + * @number: the value to format + * @result: the place to output the result + * + * format-number() uses the JDK 1.1 DecimalFormat class: + * + * http://java.sun.com/products/jdk/1.1/docs/api/java.text.DecimalFormat.html + * + * Structure: + * + * pattern := subpattern{;subpattern} + * subpattern := {prefix}integer{.fraction}{suffix} + * prefix := '\\u0000'..'\\uFFFD' - specialCharacters + * suffix := '\\u0000'..'\\uFFFD' - specialCharacters + * integer := '#'* '0'* '0' + * fraction := '0'* '#'* + * + * Notation: + * X* 0 or more instances of X + * (X | Y) either X or Y. + * X..Y any character from X up to Y, inclusive. + * S - T characters in S, except those in T + * + * Special Characters: + * + * Symbol Meaning + * 0 a digit + * # a digit, zero shows as absent + * . placeholder for decimal separator + * , placeholder for grouping separator. + * ; separates formats. + * - default negative prefix. + * % multiply by 100 and show as percentage + * ? multiply by 1000 and show as per mille + * X any other characters can be used in the prefix or suffix + * ' used to quote special characters in a prefix or suffix. + * + * Returns a possible XPath error + */ +xmlXPathError +xsltFormatNumberConversion(xsltDecimalFormatPtr self, + xmlChar *format, + double number, + xmlChar **result) +{ + xmlXPathError status = XPATH_EXPRESSION_OK; + xmlBufferPtr buffer; + xmlChar *the_format, *prefix = NULL, *suffix = NULL; + xmlChar *nprefix, *nsuffix = NULL; + int prefix_length, suffix_length = 0, nprefix_length, nsuffix_length; + int exp10; + double scale; + int j, len = 0; + int self_grouping_len; + xsltFormatNumberInfo format_info; + /* + * delayed_multiplier allows a 'trailing' percent or + * permille to be treated as suffix + */ + int delayed_multiplier = 0; + /* flag to show no -ve format present for -ve number */ + char default_sign = 0; + /* flag to show error found, should use default format */ + char found_error = 0; + + if (xmlStrlen(format) <= 0) { + xsltTransformError(NULL, NULL, NULL, + "xsltFormatNumberConversion : " + "Invalid format (0-length)\n"); + } + *result = NULL; + if (xmlXPathIsNaN(number)) { + if ((self == NULL) || (self->noNumber == NULL)) + *result = xmlStrdup(BAD_CAST "NaN"); + else + *result = xmlStrdup(self->noNumber); + return(status); + } + + format_info.integer_hash = 0; + format_info.integer_digits = 0; + format_info.frac_digits = 0; + format_info.frac_hash = 0; + format_info.group = -1; + format_info.multiplier = 1; + format_info.add_decimal = FALSE; + format_info.is_multiplier_set = FALSE; + format_info.is_negative_pattern = FALSE; + + the_format = format; + + /* + * First we process the +ve pattern to get percent / permille, + * as well as main format + */ + prefix = the_format; + prefix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info); + if (prefix_length < 0) { + found_error = 1; + goto OUTPUT_NUMBER; + } + + /* + * Here we process the "number" part of the format. It gets + * a little messy because of the percent/per-mille - if that + * appears at the end, it may be part of the suffix instead + * of part of the number, so the variable delayed_multiplier + * is used to handle it + */ + self_grouping_len = xmlStrlen(self->grouping); + while ((*the_format != 0) && + (xsltUTF8Charcmp(the_format, self->decimalPoint) != 0) && + (xsltUTF8Charcmp(the_format, self->patternSeparator) != 0)) { + + if (delayed_multiplier != 0) { + format_info.multiplier = delayed_multiplier; + format_info.is_multiplier_set = TRUE; + delayed_multiplier = 0; + } + if (xsltUTF8Charcmp(the_format, self->digit) == 0) { + if (format_info.integer_digits > 0) { + found_error = 1; + goto OUTPUT_NUMBER; + } + format_info.integer_hash++; + if (format_info.group >= 0) + format_info.group++; + } else if (xsltUTF8Charcmp(the_format, self->zeroDigit) == 0) { + format_info.integer_digits++; + if (format_info.group >= 0) + format_info.group++; + } else if ((self_grouping_len > 0) && + (!xmlStrncmp(the_format, self->grouping, self_grouping_len))) { + /* Reset group count */ + format_info.group = 0; + the_format += self_grouping_len; + continue; + } else if (xsltUTF8Charcmp(the_format, self->percent) == 0) { + if (format_info.is_multiplier_set) { + found_error = 1; + goto OUTPUT_NUMBER; + } + delayed_multiplier = 100; + } else if (xsltUTF8Charcmp(the_format, self->permille) == 0) { + if (format_info.is_multiplier_set) { + found_error = 1; + goto OUTPUT_NUMBER; + } + delayed_multiplier = 1000; + } else + break; /* while */ + + if ((len=xmlUTF8Strsize(the_format, 1)) < 1) { + found_error = 1; + goto OUTPUT_NUMBER; + } + the_format += len; + + } + + /* We have finished the integer part, now work on fraction */ + if ( (*the_format != 0) && + (xsltUTF8Charcmp(the_format, self->decimalPoint) == 0) ) { + format_info.add_decimal = TRUE; + if ((len = xmlUTF8Strsize(the_format, 1)) < 1) { + found_error = 1; + goto OUTPUT_NUMBER; + } + the_format += len; /* Skip over the decimal */ + } + + while (*the_format != 0) { + + if (xsltUTF8Charcmp(the_format, self->zeroDigit) == 0) { + if (format_info.frac_hash != 0) { + found_error = 1; + goto OUTPUT_NUMBER; + } + format_info.frac_digits++; + } else if (xsltUTF8Charcmp(the_format, self->digit) == 0) { + format_info.frac_hash++; + } else if (xsltUTF8Charcmp(the_format, self->percent) == 0) { + if (format_info.is_multiplier_set) { + found_error = 1; + goto OUTPUT_NUMBER; + } + delayed_multiplier = 100; + if ((len = xmlUTF8Strsize(the_format, 1)) < 1) { + found_error = 1; + goto OUTPUT_NUMBER; + } + the_format += len; + continue; /* while */ + } else if (xsltUTF8Charcmp(the_format, self->permille) == 0) { + if (format_info.is_multiplier_set) { + found_error = 1; + goto OUTPUT_NUMBER; + } + delayed_multiplier = 1000; + if ((len = xmlUTF8Strsize(the_format, 1)) < 1) { + found_error = 1; + goto OUTPUT_NUMBER; + } + the_format += len; + continue; /* while */ + } else if (xsltUTF8Charcmp(the_format, self->grouping) != 0) { + break; /* while */ + } + if ((len = xmlUTF8Strsize(the_format, 1)) < 1) { + found_error = 1; + goto OUTPUT_NUMBER; + } + the_format += len; + if (delayed_multiplier != 0) { + format_info.multiplier = delayed_multiplier; + delayed_multiplier = 0; + format_info.is_multiplier_set = TRUE; + } + } + + /* + * If delayed_multiplier is set after processing the + * "number" part, should be in suffix + */ + if (delayed_multiplier != 0) { + the_format -= len; + delayed_multiplier = 0; + } + + suffix = the_format; + suffix_length = xsltFormatNumberPreSuffix(self, &the_format, &format_info); + if ( (suffix_length < 0) || + ((*the_format != 0) && + (xsltUTF8Charcmp(the_format, self->patternSeparator) != 0)) ) { + found_error = 1; + goto OUTPUT_NUMBER; + } + + /* + * We have processed the +ve prefix, number part and +ve suffix. + * If the number is -ve, we must substitute the -ve prefix / suffix + */ + if (number < 0) { + /* + * Note that j is the number of UTF8 chars before the separator, + * not the number of bytes! (bug 151975) + */ + j = xmlUTF8Strloc(format, self->patternSeparator); + if (j < 0) { + /* No -ve pattern present, so use default signing */ + default_sign = 1; + } + else { + /* Skip over pattern separator (accounting for UTF8) */ + the_format = (xmlChar *)xmlUTF8Strpos(format, j + 1); + /* + * Flag changes interpretation of percent/permille + * in -ve pattern + */ + format_info.is_negative_pattern = TRUE; + format_info.is_multiplier_set = FALSE; + + /* First do the -ve prefix */ + nprefix = the_format; + nprefix_length = xsltFormatNumberPreSuffix(self, + &the_format, &format_info); + if (nprefix_length<0) { + found_error = 1; + goto OUTPUT_NUMBER; + } + + while (*the_format != 0) { + if ( (xsltUTF8Charcmp(the_format, (self)->percent) == 0) || + (xsltUTF8Charcmp(the_format, (self)->permille)== 0) ) { + if (format_info.is_multiplier_set) { + found_error = 1; + goto OUTPUT_NUMBER; + } + format_info.is_multiplier_set = TRUE; + delayed_multiplier = 1; + } + else if (IS_SPECIAL(self, the_format)) + delayed_multiplier = 0; + else + break; /* while */ + if ((len = xmlUTF8Strsize(the_format, 1)) < 1) { + found_error = 1; + goto OUTPUT_NUMBER; + } + the_format += len; + } + if (delayed_multiplier != 0) { + format_info.is_multiplier_set = FALSE; + the_format -= len; + } + + /* Finally do the -ve suffix */ + if (*the_format != 0) { + nsuffix = the_format; + nsuffix_length = xsltFormatNumberPreSuffix(self, + &the_format, &format_info); + if (nsuffix_length < 0) { + found_error = 1; + goto OUTPUT_NUMBER; + } + } + else + nsuffix_length = 0; + if (*the_format != 0) { + found_error = 1; + goto OUTPUT_NUMBER; + } + /* + * Here's another Java peculiarity: + * if -ve prefix/suffix == +ve ones, discard & use default + */ + if ((nprefix_length != prefix_length) || + (nsuffix_length != suffix_length) || + ((nprefix_length > 0) && + (xmlStrncmp(nprefix, prefix, prefix_length) !=0 )) || + ((nsuffix_length > 0) && + (xmlStrncmp(nsuffix, suffix, suffix_length) !=0 ))) { + prefix = nprefix; + prefix_length = nprefix_length; + suffix = nsuffix; + suffix_length = nsuffix_length; + } /* else { + default_sign = 1; + } + */ + } + } + +OUTPUT_NUMBER: + if (found_error != 0) { + xsltTransformError(NULL, NULL, NULL, + "xsltFormatNumberConversion : " + "error in format string '%s', using default\n", format); + default_sign = (number < 0.0) ? 1 : 0; + prefix_length = suffix_length = 0; + format_info.integer_hash = 0; + format_info.integer_digits = 1; + format_info.frac_digits = 1; + format_info.frac_hash = 4; + format_info.group = -1; + format_info.multiplier = 1; + format_info.add_decimal = TRUE; + } + + /* Apply multiplier */ + number *= (double)format_info.multiplier; + switch (xmlXPathIsInf(number)) { + case -1: + if (self->minusSign == NULL) + *result = xmlStrdup(BAD_CAST "-"); + else + *result = xmlStrdup(self->minusSign); + /* Intentional fall-through */ + case 1: + if ((self == NULL) || (self->infinity == NULL)) + *result = xmlStrcat(*result, BAD_CAST "Infinity"); + else + *result = xmlStrcat(*result, self->infinity); + return(status); + default: + break; + } + + buffer = xmlBufferCreate(); + if (buffer == NULL) { + return XPATH_MEMORY_ERROR; + } + + /* Ready to output our number. First see if "default sign" is required */ + if (default_sign != 0) + xmlBufferAdd(buffer, self->minusSign, xmlUTF8Strsize(self->minusSign, 1)); + + /* Put the prefix into the buffer */ + for (j = 0; j < prefix_length; ) { + if (*prefix == SYMBOL_QUOTE) + prefix++; + len = xmlUTF8Strsize(prefix, 1); + xmlBufferAdd(buffer, prefix, len); + prefix += len; + j += len; + } + + /* Round to n digits */ + number = fabs(number); + exp10 = format_info.frac_digits + format_info.frac_hash; + /* DBL_MAX_10_EXP should be 308 on IEEE platforms. */ + if (exp10 > DBL_MAX_10_EXP) { + if (format_info.frac_digits > DBL_MAX_10_EXP) { + format_info.frac_digits = DBL_MAX_10_EXP; + format_info.frac_hash = 0; + } else { + format_info.frac_hash = DBL_MAX_10_EXP - format_info.frac_digits; + } + exp10 = DBL_MAX_10_EXP; + } + scale = pow(10.0, (double) exp10); + number += .5 / scale; + number -= fmod(number, 1 / scale); + + /* Next do the integer part of the number */ + if ((self->grouping != NULL) && + (self->grouping[0] != 0)) { + int gchar; + + len = xmlStrlen(self->grouping); + gchar = xsltGetUTF8Char(self->grouping, &len); + xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0], + format_info.integer_digits, + format_info.group, + gchar, len); + } else + xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0], + format_info.integer_digits, + format_info.group, + ',', 1); + + /* Special case: java treats '.#' like '.0', '.##' like '.0#', etc. */ + if ((format_info.integer_digits + format_info.integer_hash + + format_info.frac_digits == 0) && (format_info.frac_hash > 0)) { + ++format_info.frac_digits; + --format_info.frac_hash; + } + + /* Add leading zero, if required */ + if ((floor(number) == 0) && + (format_info.integer_digits + format_info.frac_digits == 0)) { + xmlBufferAdd(buffer, self->zeroDigit, xmlUTF8Strsize(self->zeroDigit, 1)); + } + + /* Next the fractional part, if required */ + if (format_info.frac_digits + format_info.frac_hash == 0) { + if (format_info.add_decimal) + xmlBufferAdd(buffer, self->decimalPoint, + xmlUTF8Strsize(self->decimalPoint, 1)); + } + else { + number -= floor(number); + if ((number != 0) || (format_info.frac_digits != 0)) { + xmlBufferAdd(buffer, self->decimalPoint, + xmlUTF8Strsize(self->decimalPoint, 1)); + number = floor(scale * number + 0.5); + for (j = format_info.frac_hash; j > 0; j--) { + if (fmod(number, 10.0) >= 1.0) + break; /* for */ + number /= 10.0; + } + xsltNumberFormatDecimal(buffer, floor(number), self->zeroDigit[0], + format_info.frac_digits + j, + 0, 0, 0); + } + } + /* Put the suffix into the buffer */ + for (j = 0; j < suffix_length; ) { + if (*suffix == SYMBOL_QUOTE) + suffix++; + len = xmlUTF8Strsize(suffix, 1); + xmlBufferAdd(buffer, suffix, len); + suffix += len; + j += len; + } + + *result = xmlStrdup(xmlBufferContent(buffer)); + xmlBufferFree(buffer); + return status; +} + diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/numbersInternals.h chromium-145.0.7632.159/third_party/libxslt/src/libxslt/numbersInternals.h --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/numbersInternals.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/numbersInternals.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,73 @@ +/* + * Summary: Implementation of the XSLT number functions + * Description: Implementation of the XSLT number functions + * + * Copy: See Copyright for the status of this software. + * + * Author: Bjorn Reese and Daniel Veillard + */ + +#ifndef __XML_XSLT_NUMBERSINTERNALS_H__ +#define __XML_XSLT_NUMBERSINTERNALS_H__ + +#include +#include "xsltexports.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct _xsltCompMatch; + +/** + * xsltNumberData: + * + * This data structure is just a wrapper to pass xsl:number data in. + */ +typedef struct _xsltNumberData xsltNumberData; +typedef xsltNumberData *xsltNumberDataPtr; + +struct _xsltNumberData { + const xmlChar *level; + const xmlChar *count; + const xmlChar *from; + const xmlChar *value; + const xmlChar *format; + int has_format; + int digitsPerGroup; + int groupingCharacter; + int groupingCharacterLen; + xmlDocPtr doc; + xmlNodePtr node; + struct _xsltCompMatch *countPat; + struct _xsltCompMatch *fromPat; + + /* + * accelerators + */ +}; + +/** + * xsltFormatNumberInfo,: + * + * This data structure lists the various parameters needed to format numbers. + */ +typedef struct _xsltFormatNumberInfo xsltFormatNumberInfo; +typedef xsltFormatNumberInfo *xsltFormatNumberInfoPtr; + +struct _xsltFormatNumberInfo { + int integer_hash; /* Number of '#' in integer part */ + int integer_digits; /* Number of '0' in integer part */ + int frac_digits; /* Number of '0' in fractional part */ + int frac_hash; /* Number of '#' in fractional part */ + int group; /* Number of chars per display 'group' */ + int multiplier; /* Scaling for percent or permille */ + char add_decimal; /* Flag for whether decimal point appears in pattern */ + char is_multiplier_set; /* Flag to catch multiple occurences of percent/permille */ + char is_negative_pattern;/* Flag for processing -ve prefix/suffix */ +}; + +#ifdef __cplusplus +} +#endif +#endif /* __XML_XSLT_NUMBERSINTERNALS_H__ */ diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/pattern.c chromium-145.0.7632.159/third_party/libxslt/src/libxslt/pattern.c --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/pattern.c 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/pattern.c 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,2534 @@ +/* + * pattern.c: Implemetation of the template match compilation and lookup + * + * Reference: + * http://www.w3.org/TR/1999/REC-xslt-19991116 + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +/* + * TODO: handle pathological cases like *[*[@a="b"]] + * TODO: detect [number] at compilation, optimize accordingly + */ + +#define IN_LIBXSLT +#include "libxslt.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include "xslt.h" +#include "xsltInternals.h" +#include "xsltutils.h" +#include "imports.h" +#include "templates.h" +#include "keys.h" +#include "pattern.h" +#include "documents.h" + +#ifdef WITH_XSLT_DEBUG +#define WITH_XSLT_DEBUG_PATTERN +#endif + +/* + * Types are private: + */ + +typedef enum { + XSLT_OP_END=0, + XSLT_OP_ROOT, + XSLT_OP_ELEM, + XSLT_OP_ATTR, + XSLT_OP_PARENT, + XSLT_OP_ANCESTOR, + XSLT_OP_ID, + XSLT_OP_KEY, + XSLT_OP_NS, + XSLT_OP_ALL, + XSLT_OP_PI, + XSLT_OP_COMMENT, + XSLT_OP_TEXT, + XSLT_OP_NODE, + XSLT_OP_PREDICATE +} xsltOp; + +typedef enum { + AXIS_CHILD=1, + AXIS_ATTRIBUTE +} xsltAxis; + +typedef struct _xsltStepState xsltStepState; +typedef xsltStepState *xsltStepStatePtr; +struct _xsltStepState { + int step; + xmlNodePtr node; +}; + +typedef struct _xsltStepStates xsltStepStates; +typedef xsltStepStates *xsltStepStatesPtr; +struct _xsltStepStates { + int nbstates; + int maxstates; + xsltStepStatePtr states; +}; + +typedef struct _xsltStepOp xsltStepOp; +typedef xsltStepOp *xsltStepOpPtr; +struct _xsltStepOp { + xsltOp op; + xmlChar *value; + xmlChar *value2; + xmlChar *value3; + xmlXPathCompExprPtr comp; + /* + * Optimisations for count + */ + int previousExtra; + int indexExtra; + int lenExtra; +}; + +struct _xsltCompMatch { + struct _xsltCompMatch *next; /* siblings in the name hash */ + float priority; /* the priority */ + const xmlChar *pattern; /* the pattern */ + const xmlChar *mode; /* the mode */ + const xmlChar *modeURI; /* the mode URI */ + xsltTemplatePtr template; /* the associated template */ + xmlNodePtr node; /* the containing element */ + + int direct; + /* TODO fix the statically allocated size steps[] */ + int nbStep; + int maxStep; + xmlNsPtr *nsList; /* the namespaces in scope */ + int nsNr; /* the number of namespaces in scope */ + xsltStepOpPtr steps; /* ops for computation */ +}; + +typedef struct _xsltParserContext xsltParserContext; +typedef xsltParserContext *xsltParserContextPtr; +struct _xsltParserContext { + xsltStylesheetPtr style; /* the stylesheet */ + xsltTransformContextPtr ctxt; /* the transformation or NULL */ + const xmlChar *cur; /* the current char being parsed */ + const xmlChar *base; /* the full expression */ + xmlDocPtr doc; /* the source document */ + xmlNodePtr elem; /* the source element */ + int error; /* error code */ + xsltCompMatchPtr comp; /* the result */ +}; + +/************************************************************************ + * * + * Type functions * + * * + ************************************************************************/ + +/** + * xsltNewCompMatch: + * + * Create a new XSLT CompMatch + * + * Returns the newly allocated xsltCompMatchPtr or NULL in case of error + */ +static xsltCompMatchPtr +xsltNewCompMatch(void) { + xsltCompMatchPtr cur; + + cur = (xsltCompMatchPtr) xmlMalloc(sizeof(xsltCompMatch)); + if (cur == NULL) { + xsltTransformError(NULL, NULL, NULL, + "xsltNewCompMatch : out of memory error\n"); + return(NULL); + } + memset(cur, 0, sizeof(xsltCompMatch)); + cur->maxStep = 10; + cur->nbStep = 0; + cur-> steps = (xsltStepOpPtr) xmlMalloc(sizeof(xsltStepOp) * + cur->maxStep); + if (cur->steps == NULL) { + xsltTransformError(NULL, NULL, NULL, + "xsltNewCompMatch : out of memory error\n"); + xmlFree(cur); + return(NULL); + } + cur->nsNr = 0; + cur->nsList = NULL; + cur->direct = 0; + return(cur); +} + +/** + * xsltFreeCompMatch: + * @comp: an XSLT comp + * + * Free up the memory allocated by @comp + */ +static void +xsltFreeCompMatch(xsltCompMatchPtr comp) { + xsltStepOpPtr op; + int i; + + if (comp == NULL) + return; + if (comp->pattern != NULL) + xmlFree((xmlChar *)comp->pattern); + if (comp->nsList != NULL) + xmlFree(comp->nsList); + for (i = 0;i < comp->nbStep;i++) { + op = &comp->steps[i]; + if (op->value != NULL) + xmlFree(op->value); + if (op->value2 != NULL) + xmlFree(op->value2); + if (op->value3 != NULL) + xmlFree(op->value3); + if (op->comp != NULL) + xmlXPathFreeCompExpr(op->comp); + } + xmlFree(comp->steps); + memset(comp, -1, sizeof(xsltCompMatch)); + xmlFree(comp); +} + +/** + * xsltFreeCompMatchList: + * @comp: an XSLT comp list + * + * Free up the memory allocated by all the elements of @comp + */ +void +xsltFreeCompMatchList(xsltCompMatchPtr comp) { + xsltCompMatchPtr cur; + + while (comp != NULL) { + cur = comp; + comp = comp->next; + xsltFreeCompMatch(cur); + } +} + +static void +xsltFreeCompMatchListEntry(void *payload, + const xmlChar *name ATTRIBUTE_UNUSED) { + xsltFreeCompMatchList((xsltCompMatchPtr) payload); +} + +/** + * xsltNormalizeCompSteps: + * @payload: pointer to template hash table entry + * @data: pointer to the stylesheet + * @name: template match name + * + * This is a hashtable scanner function to normalize the compiled + * steps of an imported stylesheet. + */ +void xsltNormalizeCompSteps(void *payload, + void *data, const xmlChar *name ATTRIBUTE_UNUSED) { + xsltCompMatchPtr comp = payload; + xsltStylesheetPtr style = data; + int ix; + + for (ix = 0; ix < comp->nbStep; ix++) { + comp->steps[ix].previousExtra += style->extrasNr; + comp->steps[ix].indexExtra += style->extrasNr; + comp->steps[ix].lenExtra += style->extrasNr; + } +} + +/** + * xsltNewParserContext: + * @style: the stylesheet + * @ctxt: the transformation context, if done at run-time + * + * Create a new XSLT ParserContext + * + * Returns the newly allocated xsltParserContextPtr or NULL in case of error + */ +static xsltParserContextPtr +xsltNewParserContext(xsltStylesheetPtr style, xsltTransformContextPtr ctxt) { + xsltParserContextPtr cur; + + cur = (xsltParserContextPtr) xmlMalloc(sizeof(xsltParserContext)); + if (cur == NULL) { + xsltTransformError(NULL, NULL, NULL, + "xsltNewParserContext : malloc failed\n"); + return(NULL); + } + memset(cur, 0, sizeof(xsltParserContext)); + cur->style = style; + cur->ctxt = ctxt; + return(cur); +} + +/** + * xsltFreeParserContext: + * @ctxt: an XSLT parser context + * + * Free up the memory allocated by @ctxt + */ +static void +xsltFreeParserContext(xsltParserContextPtr ctxt) { + if (ctxt == NULL) + return; + memset(ctxt, -1, sizeof(xsltParserContext)); + xmlFree(ctxt); +} + +/** + * xsltCompMatchAdd: + * @comp: the compiled match expression + * @op: an op + * @value: the first value + * @value2: the second value + * @novar: flag to set XML_XPATH_NOVAR + * + * Add an step to an XSLT Compiled Match + * + * Returns -1 in case of failure, 0 otherwise. + */ +static int +xsltCompMatchAdd(xsltParserContextPtr ctxt, xsltCompMatchPtr comp, + xsltOp op, xmlChar * value, xmlChar * value2, int novar) +{ + if (comp->nbStep >= comp->maxStep) { + xsltStepOpPtr tmp; + + tmp = (xsltStepOpPtr) xmlRealloc(comp->steps, comp->maxStep * 2 * + sizeof(xsltStepOp)); + if (tmp == NULL) { + xsltGenericError(xsltGenericErrorContext, + "xsltCompMatchAdd: memory re-allocation failure.\n"); + if (ctxt->style != NULL) + ctxt->style->errors++; + return (-1); + } + comp->maxStep *= 2; + comp->steps = tmp; + } + comp->steps[comp->nbStep].op = op; + comp->steps[comp->nbStep].value = value; + comp->steps[comp->nbStep].value2 = value2; + comp->steps[comp->nbStep].value3 = NULL; + comp->steps[comp->nbStep].comp = NULL; + if (ctxt->ctxt != NULL) { + comp->steps[comp->nbStep].previousExtra = + xsltAllocateExtraCtxt(ctxt->ctxt); + comp->steps[comp->nbStep].indexExtra = + xsltAllocateExtraCtxt(ctxt->ctxt); + comp->steps[comp->nbStep].lenExtra = + xsltAllocateExtraCtxt(ctxt->ctxt); + } else { + comp->steps[comp->nbStep].previousExtra = + xsltAllocateExtra(ctxt->style); + comp->steps[comp->nbStep].indexExtra = + xsltAllocateExtra(ctxt->style); + comp->steps[comp->nbStep].lenExtra = + xsltAllocateExtra(ctxt->style); + } + if (op == XSLT_OP_PREDICATE) { + int flags = 0; + +#ifdef XML_XPATH_NOVAR + if (novar != 0) + flags = XML_XPATH_NOVAR; +#endif + comp->steps[comp->nbStep].comp = xsltXPathCompileFlags(ctxt->style, + value, flags); + if (comp->steps[comp->nbStep].comp == NULL) { + xsltTransformError(NULL, ctxt->style, ctxt->elem, + "Failed to compile predicate\n"); + if (ctxt->style != NULL) + ctxt->style->errors++; + } + } + comp->nbStep++; + return (0); +} + +/** + * xsltSwapTopCompMatch: + * @comp: the compiled match expression + * + * reverse the two top steps. + */ +static void +xsltSwapTopCompMatch(xsltCompMatchPtr comp) { + int i; + int j = comp->nbStep - 1; + + if (j > 0) { + register xmlChar *tmp; + register xsltOp op; + register xmlXPathCompExprPtr expr; + register int t; + i = j - 1; + tmp = comp->steps[i].value; + comp->steps[i].value = comp->steps[j].value; + comp->steps[j].value = tmp; + tmp = comp->steps[i].value2; + comp->steps[i].value2 = comp->steps[j].value2; + comp->steps[j].value2 = tmp; + tmp = comp->steps[i].value3; + comp->steps[i].value3 = comp->steps[j].value3; + comp->steps[j].value3 = tmp; + op = comp->steps[i].op; + comp->steps[i].op = comp->steps[j].op; + comp->steps[j].op = op; + expr = comp->steps[i].comp; + comp->steps[i].comp = comp->steps[j].comp; + comp->steps[j].comp = expr; + t = comp->steps[i].previousExtra; + comp->steps[i].previousExtra = comp->steps[j].previousExtra; + comp->steps[j].previousExtra = t; + t = comp->steps[i].indexExtra; + comp->steps[i].indexExtra = comp->steps[j].indexExtra; + comp->steps[j].indexExtra = t; + t = comp->steps[i].lenExtra; + comp->steps[i].lenExtra = comp->steps[j].lenExtra; + comp->steps[j].lenExtra = t; + } +} + +/** + * xsltReverseCompMatch: + * @ctxt: the parser context + * @comp: the compiled match expression + * + * reverse all the stack of expressions + */ +static void +xsltReverseCompMatch(xsltParserContextPtr ctxt, xsltCompMatchPtr comp) { + int i = 0; + int j = comp->nbStep - 1; + + while (j > i) { + register xmlChar *tmp; + register xsltOp op; + register xmlXPathCompExprPtr expr; + register int t; + + tmp = comp->steps[i].value; + comp->steps[i].value = comp->steps[j].value; + comp->steps[j].value = tmp; + tmp = comp->steps[i].value2; + comp->steps[i].value2 = comp->steps[j].value2; + comp->steps[j].value2 = tmp; + tmp = comp->steps[i].value3; + comp->steps[i].value3 = comp->steps[j].value3; + comp->steps[j].value3 = tmp; + op = comp->steps[i].op; + comp->steps[i].op = comp->steps[j].op; + comp->steps[j].op = op; + expr = comp->steps[i].comp; + comp->steps[i].comp = comp->steps[j].comp; + comp->steps[j].comp = expr; + t = comp->steps[i].previousExtra; + comp->steps[i].previousExtra = comp->steps[j].previousExtra; + comp->steps[j].previousExtra = t; + t = comp->steps[i].indexExtra; + comp->steps[i].indexExtra = comp->steps[j].indexExtra; + comp->steps[j].indexExtra = t; + t = comp->steps[i].lenExtra; + comp->steps[i].lenExtra = comp->steps[j].lenExtra; + comp->steps[j].lenExtra = t; + j--; + i++; + } + xsltCompMatchAdd(ctxt, comp, XSLT_OP_END, NULL, NULL, 0); + + /* + * Detect consecutive XSLT_OP_PREDICATE indicating a direct matching + * should be done. + */ + for (i = 0;i < comp->nbStep - 1;i++) { + if ((comp->steps[i].op == XSLT_OP_PREDICATE) && + (comp->steps[i + 1].op == XSLT_OP_PREDICATE)) { + + comp->direct = 1; + if (comp->pattern[0] != '/') { + xmlChar *query; + + query = xmlStrdup((const xmlChar *)"//"); + query = xmlStrcat(query, comp->pattern); + + xmlFree((xmlChar *) comp->pattern); + comp->pattern = query; + } + break; + } + } +} + +/************************************************************************ + * * + * The interpreter for the precompiled patterns * + * * + ************************************************************************/ + +static int +xsltPatPushState(xsltTransformContextPtr ctxt, xsltStepStates *states, + int step, xmlNodePtr node) { + if (states->maxstates <= states->nbstates) { + xsltStepState *tmp; + int newMax = states->maxstates == 0 ? 4 : 2 * states->maxstates; + + tmp = (xsltStepStatePtr) xmlRealloc(states->states, + newMax * sizeof(xsltStepState)); + if (tmp == NULL) { + xsltGenericError(xsltGenericErrorContext, + "xsltPatPushState: memory re-allocation failure.\n"); + ctxt->state = XSLT_STATE_STOPPED; + return(-1); + } + states->states = tmp; + states->maxstates = newMax; + } + states->states[states->nbstates].step = step; + states->states[states->nbstates++].node = node; +#if 0 + fprintf(stderr, "Push: %d, %s\n", step, node->name); +#endif + return(0); +} + +static void +xmlXPathFreeObjectWrapper(void *obj) { + xmlXPathFreeObject((xmlXPathObjectPtr) obj); +} + +/** + * xsltTestCompMatchDirect: + * @ctxt: a XSLT process context + * @comp: the precompiled pattern + * @node: a node + * @nsList: the namespaces in scope + * @nsNr: the number of namespaces in scope + * + * Test whether the node matches the pattern, do a direct evalutation + * and not a step by step evaluation. + * + * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure + */ +static int +xsltTestCompMatchDirect(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp, + xmlNodePtr node, xmlNsPtr *nsList, int nsNr) { + xsltStepOpPtr sel = NULL; + xmlDocPtr prevdoc; + xmlDocPtr doc; + xmlXPathObjectPtr list; + int ix, j; + int nocache = 0; + int isRVT; + + doc = node->doc; + if (XSLT_IS_RES_TREE_FRAG(doc)) + isRVT = 1; + else + isRVT = 0; + sel = &comp->steps[0]; /* store extra in first step arbitrarily */ + + prevdoc = (xmlDocPtr) + XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr); + ix = XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival); + list = (xmlXPathObjectPtr) + XSLT_RUNTIME_EXTRA_LST(ctxt, sel->lenExtra); + + if ((list == NULL) || (prevdoc != doc)) { + xmlXPathObjectPtr newlist; + xmlNodePtr parent = node->parent; + xmlDocPtr olddoc; + xmlNodePtr oldnode; + int oldNsNr, oldContextSize, oldProximityPosition; + xmlNsPtr *oldNamespaces; + + oldnode = ctxt->xpathCtxt->node; + olddoc = ctxt->xpathCtxt->doc; + oldNsNr = ctxt->xpathCtxt->nsNr; + oldNamespaces = ctxt->xpathCtxt->namespaces; + oldContextSize = ctxt->xpathCtxt->contextSize; + oldProximityPosition = ctxt->xpathCtxt->proximityPosition; + ctxt->xpathCtxt->node = node; + ctxt->xpathCtxt->doc = doc; + ctxt->xpathCtxt->namespaces = nsList; + ctxt->xpathCtxt->nsNr = nsNr; + newlist = xmlXPathEval(comp->pattern, ctxt->xpathCtxt); + ctxt->xpathCtxt->node = oldnode; + ctxt->xpathCtxt->doc = olddoc; + ctxt->xpathCtxt->namespaces = oldNamespaces; + ctxt->xpathCtxt->nsNr = oldNsNr; + ctxt->xpathCtxt->contextSize = oldContextSize; + ctxt->xpathCtxt->proximityPosition = oldProximityPosition; + if (newlist == NULL) + return(-1); + if (newlist->type != XPATH_NODESET) { + xmlXPathFreeObject(newlist); + return(-1); + } + ix = 0; + + if ((parent == NULL) || (node->doc == NULL) || isRVT) + nocache = 1; + + if (nocache == 0) { + if (list != NULL) + xmlXPathFreeObject(list); + list = newlist; + + XSLT_RUNTIME_EXTRA_LST(ctxt, sel->lenExtra) = + (void *) list; + XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) = + (void *) doc; + XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = + 0; + XSLT_RUNTIME_EXTRA_FREE(ctxt, sel->lenExtra) = + xmlXPathFreeObjectWrapper; + } else + list = newlist; + } + if ((list->nodesetval == NULL) || + (list->nodesetval->nodeNr <= 0)) { + if (nocache == 1) + xmlXPathFreeObject(list); + return(0); + } + /* TODO: store the index and use it for the scan */ + if (ix == 0) { + for (j = 0;j < list->nodesetval->nodeNr;j++) { + if (list->nodesetval->nodeTab[j] == node) { + if (nocache == 1) + xmlXPathFreeObject(list); + return(1); + } + } + } else { + } + if (nocache == 1) + xmlXPathFreeObject(list); + return(0); +} + +/** + * xsltTestStepMatch: + * @ctxt: a XSLT process context + * @node: a node + * @step: the step + * + * Test whether the node matches the step. + * + * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure + */ +static int +xsltTestStepMatch(xsltTransformContextPtr ctxt, xmlNodePtr node, + xsltStepOpPtr step) { + switch (step->op) { + case XSLT_OP_ROOT: + if ((node->type == XML_DOCUMENT_NODE) || +#ifdef LIBXML_DOCB_ENABLED + (node->type == XML_DOCB_DOCUMENT_NODE) || +#endif + (node->type == XML_HTML_DOCUMENT_NODE)) + return(1); + if ((node->type == XML_ELEMENT_NODE) && (node->name[0] == ' ')) + return(1); + return(0); + case XSLT_OP_ELEM: + if (node->type != XML_ELEMENT_NODE) + return(0); + if (step->value == NULL) + return(1); + if (step->value[0] != node->name[0]) + return(0); + if (!xmlStrEqual(step->value, node->name)) + return(0); + + /* Namespace test */ + if (node->ns == NULL) { + if (step->value2 != NULL) + return(0); + } else if (node->ns->href != NULL) { + if (step->value2 == NULL) + return(0); + if (!xmlStrEqual(step->value2, node->ns->href)) + return(0); + } + return(1); + case XSLT_OP_ATTR: + if (node->type != XML_ATTRIBUTE_NODE) + return(0); + if (step->value != NULL) { + if (step->value[0] != node->name[0]) + return(0); + if (!xmlStrEqual(step->value, node->name)) + return(0); + } + /* Namespace test */ + if (node->ns == NULL) { + if (step->value2 != NULL) + return(0); + } else if (step->value2 != NULL) { + if (!xmlStrEqual(step->value2, node->ns->href)) + return(0); + } + return(1); + case XSLT_OP_ID: { + /* TODO Handle IDs decently, must be done differently */ + xmlAttrPtr id; + + if (node->type != XML_ELEMENT_NODE) + return(0); + + id = xmlGetID(node->doc, step->value); + if ((id == NULL) || (id->parent != node)) + return(0); + break; + } + case XSLT_OP_KEY: { + xmlNodeSetPtr list; + int indx; + + list = xsltGetKey(ctxt, step->value, + step->value3, step->value2); + if (list == NULL) + return(0); + for (indx = 0;indx < list->nodeNr;indx++) + if (list->nodeTab[indx] == node) + break; + if (indx >= list->nodeNr) + return(0); + break; + } + case XSLT_OP_NS: + if (node->type != XML_ELEMENT_NODE) + return(0); + if (node->ns == NULL) { + if (step->value != NULL) + return(0); + } else if (node->ns->href != NULL) { + if (step->value == NULL) + return(0); + if (!xmlStrEqual(step->value, node->ns->href)) + return(0); + } + break; + case XSLT_OP_ALL: + if (node->type != XML_ELEMENT_NODE) + return(0); + break; + case XSLT_OP_PI: + if (node->type != XML_PI_NODE) + return(0); + if (step->value != NULL) { + if (!xmlStrEqual(step->value, node->name)) + return(0); + } + break; + case XSLT_OP_COMMENT: + if (node->type != XML_COMMENT_NODE) + return(0); + break; + case XSLT_OP_TEXT: + if ((node->type != XML_TEXT_NODE) && + (node->type != XML_CDATA_SECTION_NODE)) + return(0); + break; + case XSLT_OP_NODE: + switch (node->type) { + case XML_ELEMENT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_PI_NODE: + case XML_COMMENT_NODE: + case XML_TEXT_NODE: + break; + default: + return(0); + } + break; + default: + xsltTransformError(ctxt, NULL, node, + "xsltTestStepMatch: unexpected step op %d\n", + step->op); + return(-1); + } + + return(1); +} + +/** + * xsltTestPredicateMatch: + * @ctxt: a XSLT process context + * @comp: the precompiled pattern + * @node: a node + * @step: the predicate step + * @sel: the previous step + * + * Test whether the node matches the predicate + * + * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure + */ +static int +xsltTestPredicateMatch(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp, + xmlNodePtr node, xsltStepOpPtr step, + xsltStepOpPtr sel) { + xmlNodePtr oldNode; + xmlDocPtr doc; + int oldCS, oldCP; + int pos = 0, len = 0; + int isRVT; + int match; + + if (step->value == NULL) + return(0); + if (step->comp == NULL) + return(0); + if (sel == NULL) + return(0); + + doc = node->doc; + if (XSLT_IS_RES_TREE_FRAG(doc)) + isRVT = 1; + else + isRVT = 0; + + /* + * Recompute contextSize and proximityPosition. + * + * This could be improved in the following ways: + * + * - Skip recomputation if predicates don't use position() or last() + * - Keep data for multiple parents. This would require a hash table + * or an unused member in xmlNode. + * - Store node test results in a bitmap to avoid computing them twice. + */ + oldCS = ctxt->xpathCtxt->contextSize; + oldCP = ctxt->xpathCtxt->proximityPosition; + { + xmlNodePtr previous; + int nocache = 0; + + previous = (xmlNodePtr) + XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr); + if ((previous != NULL) && + (previous->parent == node->parent)) { + /* + * just walk back to adjust the index + */ + int indx = 0; + xmlNodePtr sibling = node; + + while (sibling != NULL) { + if (sibling == previous) + break; + if (xsltTestStepMatch(ctxt, sibling, sel)) + indx++; + sibling = sibling->prev; + } + if (sibling == NULL) { + /* hum going backward in document order ... */ + indx = 0; + sibling = node; + while (sibling != NULL) { + if (sibling == previous) + break; + if (xsltTestStepMatch(ctxt, sibling, sel)) + indx--; + sibling = sibling->next; + } + } + if (sibling != NULL) { + pos = XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) + indx; + /* + * If the node is in a Value Tree we need to + * save len, but cannot cache the node! + * (bugs 153137 and 158840) + */ + if (node->doc != NULL) { + len = XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival); + if (!isRVT) { + XSLT_RUNTIME_EXTRA(ctxt, + sel->previousExtra, ptr) = node; + XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = pos; + } + } + } else + pos = 0; + } else { + /* + * recompute the index + */ + xmlNodePtr parent = node->parent; + xmlNodePtr siblings = NULL; + + if (parent) siblings = parent->children; + + while (siblings != NULL) { + if (siblings == node) { + len++; + pos = len; + } else if (xsltTestStepMatch(ctxt, siblings, sel)) { + len++; + } + siblings = siblings->next; + } + if ((parent == NULL) || (node->doc == NULL)) + nocache = 1; + else { + while (parent->parent != NULL) + parent = parent->parent; + if (((parent->type != XML_DOCUMENT_NODE) && + (parent->type != XML_HTML_DOCUMENT_NODE)) || + (parent != (xmlNodePtr) node->doc)) + nocache = 1; + } + } + if (pos != 0) { + ctxt->xpathCtxt->contextSize = len; + ctxt->xpathCtxt->proximityPosition = pos; + /* + * If the node is in a Value Tree we cannot + * cache it ! + */ + if ((!isRVT) && (node->doc != NULL) && + (nocache == 0)) { + XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) = node; + XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = pos; + XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival) = len; + } + } + } + + oldNode = ctxt->node; + ctxt->node = node; + + match = xsltEvalXPathPredicate(ctxt, step->comp, comp->nsList, comp->nsNr); + + if (pos != 0) { + ctxt->xpathCtxt->contextSize = oldCS; + ctxt->xpathCtxt->proximityPosition = oldCP; + } + ctxt->node = oldNode; + + return match; +} + +/** + * xsltTestCompMatch: + * @ctxt: a XSLT process context + * @comp: the precompiled pattern + * @node: a node + * @mode: the mode name or NULL + * @modeURI: the mode URI or NULL + * + * Test whether the node matches the pattern + * + * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure + */ +static int +xsltTestCompMatch(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp, + xmlNodePtr matchNode, const xmlChar *mode, + const xmlChar *modeURI) { + int i; + int found = 0; + xmlNodePtr node = matchNode; + xmlNodePtr oldInst; + xsltStepOpPtr step, sel = NULL; + xsltStepStates states = {0, 0, NULL}; /* // may require backtrack */ + + if ((comp == NULL) || (node == NULL) || (ctxt == NULL)) { + xsltTransformError(ctxt, NULL, node, + "xsltTestCompMatch: null arg\n"); + return(-1); + } + if (mode != NULL) { + if (comp->mode == NULL) + return(0); + /* + * both mode strings must be interned on the stylesheet dictionary + */ + if (comp->mode != mode) + return(0); + } else { + if (comp->mode != NULL) + return(0); + } + if (modeURI != NULL) { + if (comp->modeURI == NULL) + return(0); + /* + * both modeURI strings must be interned on the stylesheet dictionary + */ + if (comp->modeURI != modeURI) + return(0); + } else { + if (comp->modeURI != NULL) + return(0); + } + + /* Some XPath functions rely on inst being set correctly. */ + oldInst = ctxt->inst; + ctxt->inst = comp->node; + + i = 0; +restart: + for (;i < comp->nbStep;i++) { + step = &comp->steps[i]; + if (step->op != XSLT_OP_PREDICATE) + sel = step; + switch (step->op) { + case XSLT_OP_END: + goto found; + case XSLT_OP_PARENT: + if ((node->type == XML_DOCUMENT_NODE) || + (node->type == XML_HTML_DOCUMENT_NODE) || +#ifdef LIBXML_DOCB_ENABLED + (node->type == XML_DOCB_DOCUMENT_NODE) || +#endif + (node->type == XML_NAMESPACE_DECL)) + goto rollback; + node = node->parent; + if (node == NULL) + goto rollback; + if (step->value == NULL) + continue; + if (step->value[0] != node->name[0]) + goto rollback; + if (!xmlStrEqual(step->value, node->name)) + goto rollback; + /* Namespace test */ + if (node->ns == NULL) { + if (step->value2 != NULL) + goto rollback; + } else if (node->ns->href != NULL) { + if (step->value2 == NULL) + goto rollback; + if (!xmlStrEqual(step->value2, node->ns->href)) + goto rollback; + } + continue; + case XSLT_OP_ANCESTOR: + /* TODO: implement coalescing of ANCESTOR/NODE ops */ + if (step->value == NULL) { + step = &comp->steps[i+1]; + if (step->op == XSLT_OP_ROOT) + goto found; + /* added NS, ID and KEY as a result of bug 168208 */ + if ((step->op != XSLT_OP_ELEM) && + (step->op != XSLT_OP_ALL) && + (step->op != XSLT_OP_NS) && + (step->op != XSLT_OP_ID) && + (step->op != XSLT_OP_KEY)) + goto rollback; + } + if (node == NULL) + goto rollback; + if ((node->type == XML_DOCUMENT_NODE) || + (node->type == XML_HTML_DOCUMENT_NODE) || +#ifdef LIBXML_DOCB_ENABLED + (node->type == XML_DOCB_DOCUMENT_NODE) || +#endif + (node->type == XML_NAMESPACE_DECL)) + goto rollback; + node = node->parent; + if ((step->op != XSLT_OP_ELEM) && step->op != XSLT_OP_ALL) { + xsltPatPushState(ctxt, &states, i, node); + continue; + } + i++; + sel = step; + if (step->value == NULL) { + xsltPatPushState(ctxt, &states, i - 1, node); + continue; + } + while (node != NULL) { + if ((node->type == XML_ELEMENT_NODE) && + (step->value[0] == node->name[0]) && + (xmlStrEqual(step->value, node->name))) { + /* Namespace test */ + if (node->ns == NULL) { + if (step->value2 == NULL) + break; + } else if (node->ns->href != NULL) { + if ((step->value2 != NULL) && + (xmlStrEqual(step->value2, node->ns->href))) + break; + } + } + node = node->parent; + } + if (node == NULL) + goto rollback; + xsltPatPushState(ctxt, &states, i - 1, node); + continue; + case XSLT_OP_PREDICATE: { + /* + * When there is cascading XSLT_OP_PREDICATE or a predicate + * after an op which hasn't been optimized yet, then use a + * direct computation approach. It's not done directly + * at the beginning of the routine to filter out as much + * as possible this costly computation. + */ + if (comp->direct) { + found = xsltTestCompMatchDirect(ctxt, comp, matchNode, + comp->nsList, comp->nsNr); + goto exit; + } + + if (!xsltTestPredicateMatch(ctxt, comp, node, step, sel)) + goto rollback; + + break; + } + default: + if (xsltTestStepMatch(ctxt, node, step) != 1) + goto rollback; + break; + } + } +found: + found = 1; +exit: + ctxt->inst = oldInst; + if (states.states != NULL) { + /* Free the rollback states */ + xmlFree(states.states); + } + return found; +rollback: + /* got an error try to rollback */ + if (states.states == NULL || states.nbstates <= 0) { + found = 0; + goto exit; + } + states.nbstates--; + i = states.states[states.nbstates].step; + node = states.states[states.nbstates].node; +#if 0 + fprintf(stderr, "Pop: %d, %s\n", i, node->name); +#endif + goto restart; +} + +/** + * xsltTestCompMatchList: + * @ctxt: a XSLT process context + * @node: a node + * @comp: the precompiled pattern list + * + * Test whether the node matches one of the patterns in the list + * + * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure + */ +int +xsltTestCompMatchList(xsltTransformContextPtr ctxt, xmlNodePtr node, + xsltCompMatchPtr comp) { + int ret; + + if ((ctxt == NULL) || (node == NULL)) + return(-1); + while (comp != NULL) { + ret = xsltTestCompMatch(ctxt, comp, node, NULL, NULL); + if (ret == 1) + return(1); + comp = comp->next; + } + return(0); +} + +/** + * xsltCompMatchClearCache: + * @ctxt: a XSLT process context + * @comp: the precompiled pattern list + * + * Clear pattern match cache. + */ +void +xsltCompMatchClearCache(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp) { + xsltStepOpPtr sel; + xmlXPathObjectPtr list; + + if ((ctxt == NULL) || (comp == NULL)) + return; + + sel = &comp->steps[0]; + list = (xmlXPathObjectPtr) XSLT_RUNTIME_EXTRA_LST(ctxt, sel->lenExtra); + + if (list != NULL) { + xmlXPathFreeObject(list); + + XSLT_RUNTIME_EXTRA_LST(ctxt, sel->lenExtra) = NULL; + XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) = NULL; + XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = 0; + XSLT_RUNTIME_EXTRA_FREE(ctxt, sel->lenExtra) = NULL; + } +} + +/************************************************************************ + * * + * Dedicated parser for templates * + * * + ************************************************************************/ + +#define CUR (*ctxt->cur) +#define SKIP(val) ctxt->cur += (val) +#define NXT(val) ctxt->cur[(val)] +#define CUR_PTR ctxt->cur + +#define SKIP_BLANKS \ + while (xmlIsBlank_ch(CUR)) NEXT + +#define CURRENT (*ctxt->cur) +#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur) + + +#define PUSH(op, val, val2, novar) \ + if (xsltCompMatchAdd(ctxt, ctxt->comp, (op), (val), (val2), (novar))) goto error; + +#define SWAP() \ + xsltSwapTopCompMatch(ctxt->comp); + +#define XSLT_ERROR(X) \ + { xsltError(ctxt, __FILE__, __LINE__, X); \ + ctxt->error = (X); return; } + +#define XSLT_ERROR0(X) \ + { xsltError(ctxt, __FILE__, __LINE__, X); \ + ctxt->error = (X); return(0); } + +/** + * xsltScanLiteral: + * @ctxt: the XPath Parser context + * + * Parse an XPath Litteral: + * + * [29] Literal ::= '"' [^"]* '"' + * | "'" [^']* "'" + * + * Returns the Literal parsed or NULL + */ + +static xmlChar * +xsltScanLiteral(xsltParserContextPtr ctxt) { + const xmlChar *q, *cur; + xmlChar *ret = NULL; + int val, len; + + SKIP_BLANKS; + if (CUR == '"') { + NEXT; + cur = q = CUR_PTR; + val = xsltGetUTF8CharZ(cur, &len); + while ((xmlIsCharQ(val)) && (val != '"')) { + cur += len; + val = xsltGetUTF8CharZ(cur, &len); + } + if (!xmlIsCharQ(val)) { + ctxt->error = 1; + return(NULL); + } else { + ret = xmlStrndup(q, cur - q); + } + cur += len; + CUR_PTR = cur; + } else if (CUR == '\'') { + NEXT; + cur = q = CUR_PTR; + val = xsltGetUTF8CharZ(cur, &len); + while ((xmlIsCharQ(val)) && (val != '\'')) { + cur += len; + val = xsltGetUTF8CharZ(cur, &len); + } + if (!xmlIsCharQ(val)) { + ctxt->error = 1; + return(NULL); + } else { + ret = xmlStrndup(q, cur - q); + } + cur += len; + CUR_PTR = cur; + } else { + ctxt->error = 1; + return(NULL); + } + return(ret); +} + +/** + * xsltScanNCName: + * @ctxt: the XPath Parser context + * + * Parses a non qualified name + * + * Returns the Name parsed or NULL + */ + +static xmlChar * +xsltScanNCName(xsltParserContextPtr ctxt) { + const xmlChar *q, *cur; + xmlChar *ret = NULL; + int val, len; + + SKIP_BLANKS; + + cur = q = CUR_PTR; + val = xsltGetUTF8CharZ(cur, &len); + if (!xmlIsBaseCharQ(val) && !xmlIsIdeographicQ(val) && (val != '_')) + return(NULL); + + while (xmlIsBaseCharQ(val) || xmlIsIdeographicQ(val) || + xmlIsDigitQ(val) || + (val == '.') || (val == '-') || + (val == '_') || + xmlIsCombiningQ(val) || + xmlIsExtenderQ(val)) { + cur += len; + val = xsltGetUTF8CharZ(cur, &len); + } + ret = xmlStrndup(q, cur - q); + CUR_PTR = cur; + return(ret); +} + +/* + * xsltCompileIdKeyPattern: + * @ctxt: the compilation context + * @name: a preparsed name + * @aid: whether id/key are allowed there + * @novar: flag to prohibit xslt var + * + * Compile the XSLT LocationIdKeyPattern + * [3] IdKeyPattern ::= 'id' '(' Literal ')' + * | 'key' '(' Literal ',' Literal ')' + * + * also handle NodeType and PI from: + * + * [7] NodeTest ::= NameTest + * | NodeType '(' ')' + * | 'processing-instruction' '(' Literal ')' + */ +static void +xsltCompileIdKeyPattern(xsltParserContextPtr ctxt, xmlChar *name, + int aid, int novar, xsltAxis axis) { + xmlChar *lit = NULL; + xmlChar *lit2 = NULL; + + if (CUR != '(') { + xsltTransformError(NULL, NULL, NULL, + "xsltCompileIdKeyPattern : ( expected\n"); + ctxt->error = 1; + return; + } + if ((aid) && (xmlStrEqual(name, (const xmlChar *)"id"))) { + if (axis != 0) { + xsltTransformError(NULL, NULL, NULL, + "xsltCompileIdKeyPattern : NodeTest expected\n"); + ctxt->error = 1; + return; + } + NEXT; + SKIP_BLANKS; + lit = xsltScanLiteral(ctxt); + if (ctxt->error) { + xsltTransformError(NULL, NULL, NULL, + "xsltCompileIdKeyPattern : Literal expected\n"); + xmlFree(lit); + return; + } + SKIP_BLANKS; + if (CUR != ')') { + xsltTransformError(NULL, NULL, NULL, + "xsltCompileIdKeyPattern : ) expected\n"); + xmlFree(lit); + ctxt->error = 1; + return; + } + NEXT; + PUSH(XSLT_OP_ID, lit, NULL, novar); + lit = NULL; + } else if ((aid) && (xmlStrEqual(name, (const xmlChar *)"key"))) { + if (axis != 0) { + xsltTransformError(NULL, NULL, NULL, + "xsltCompileIdKeyPattern : NodeTest expected\n"); + ctxt->error = 1; + return; + } + NEXT; + SKIP_BLANKS; + lit = xsltScanLiteral(ctxt); + if (ctxt->error) { + xsltTransformError(NULL, NULL, NULL, + "xsltCompileIdKeyPattern : Literal expected\n"); + xmlFree(lit); + return; + } + SKIP_BLANKS; + if (CUR != ',') { + xsltTransformError(NULL, NULL, NULL, + "xsltCompileIdKeyPattern : , expected\n"); + xmlFree(lit); + ctxt->error = 1; + return; + } + NEXT; + SKIP_BLANKS; + lit2 = xsltScanLiteral(ctxt); + if (ctxt->error) { + xsltTransformError(NULL, NULL, NULL, + "xsltCompileIdKeyPattern : Literal expected\n"); + xmlFree(lit); + return; + } + SKIP_BLANKS; + if (CUR != ')') { + xsltTransformError(NULL, NULL, NULL, + "xsltCompileIdKeyPattern : ) expected\n"); + xmlFree(lit); + xmlFree(lit2); + ctxt->error = 1; + return; + } + NEXT; + /* URGENT TODO: support namespace in keys */ + PUSH(XSLT_OP_KEY, lit, lit2, novar); + lit = NULL; + lit2 = NULL; + } else if (xmlStrEqual(name, (const xmlChar *)"processing-instruction")) { + NEXT; + SKIP_BLANKS; + if (CUR != ')') { + lit = xsltScanLiteral(ctxt); + if (ctxt->error) { + xsltTransformError(NULL, NULL, NULL, + "xsltCompileIdKeyPattern : Literal expected\n"); + xmlFree(lit); + return; + } + SKIP_BLANKS; + if (CUR != ')') { + xsltTransformError(NULL, NULL, NULL, + "xsltCompileIdKeyPattern : ) expected\n"); + ctxt->error = 1; + xmlFree(lit); + return; + } + } + NEXT; + PUSH(XSLT_OP_PI, lit, NULL, novar); + lit = NULL; + } else if (xmlStrEqual(name, (const xmlChar *)"text")) { + NEXT; + SKIP_BLANKS; + if (CUR != ')') { + xsltTransformError(NULL, NULL, NULL, + "xsltCompileIdKeyPattern : ) expected\n"); + ctxt->error = 1; + return; + } + NEXT; + PUSH(XSLT_OP_TEXT, NULL, NULL, novar); + } else if (xmlStrEqual(name, (const xmlChar *)"comment")) { + NEXT; + SKIP_BLANKS; + if (CUR != ')') { + xsltTransformError(NULL, NULL, NULL, + "xsltCompileIdKeyPattern : ) expected\n"); + ctxt->error = 1; + return; + } + NEXT; + PUSH(XSLT_OP_COMMENT, NULL, NULL, novar); + } else if (xmlStrEqual(name, (const xmlChar *)"node")) { + NEXT; + SKIP_BLANKS; + if (CUR != ')') { + xsltTransformError(NULL, NULL, NULL, + "xsltCompileIdKeyPattern : ) expected\n"); + ctxt->error = 1; + return; + } + NEXT; + if (axis == AXIS_ATTRIBUTE) { + PUSH(XSLT_OP_ATTR, NULL, NULL, novar); + } + else { + PUSH(XSLT_OP_NODE, NULL, NULL, novar); + } + } else if (aid) { + xsltTransformError(NULL, NULL, NULL, + "xsltCompileIdKeyPattern : expecting 'key' or 'id' or node type\n"); + ctxt->error = 1; + return; + } else { + xsltTransformError(NULL, NULL, NULL, + "xsltCompileIdKeyPattern : node type\n"); + ctxt->error = 1; + return; + } +error: + return; +} + +/** + * xsltCompileStepPattern: + * @ctxt: the compilation context + * @token: a posible precompiled name + * @novar: flag to prohibit xslt variables from pattern + * + * Compile the XSLT StepPattern and generates a precompiled + * form suitable for fast matching. + * + * [5] StepPattern ::= ChildOrAttributeAxisSpecifier NodeTest Predicate* + * [6] ChildOrAttributeAxisSpecifier ::= AbbreviatedAxisSpecifier + * | ('child' | 'attribute') '::' + * from XPath + * [7] NodeTest ::= NameTest + * | NodeType '(' ')' + * | 'processing-instruction' '(' Literal ')' + * [8] Predicate ::= '[' PredicateExpr ']' + * [9] PredicateExpr ::= Expr + * [13] AbbreviatedAxisSpecifier ::= '@'? + * [37] NameTest ::= '*' | NCName ':' '*' | QName + */ + +static void +xsltCompileStepPattern(xsltParserContextPtr ctxt, xmlChar *token, int novar) { + xmlChar *name = NULL; + const xmlChar *URI = NULL; + xmlChar *URL = NULL; + xmlChar *ret = NULL; + int level; + xsltAxis axis = 0; + + SKIP_BLANKS; + if ((token == NULL) && (CUR == '@')) { + NEXT; + axis = AXIS_ATTRIBUTE; + } +parse_node_test: + if (token == NULL) + token = xsltScanNCName(ctxt); + if (token == NULL) { + if (CUR == '*') { + NEXT; + if (axis == AXIS_ATTRIBUTE) { + PUSH(XSLT_OP_ATTR, NULL, NULL, novar); + } + else { + PUSH(XSLT_OP_ALL, NULL, NULL, novar); + } + goto parse_predicate; + } else { + xsltTransformError(NULL, NULL, NULL, + "xsltCompileStepPattern : Name expected\n"); + ctxt->error = 1; + goto error; + } + } + + + SKIP_BLANKS; + if (CUR == '(') { + xsltCompileIdKeyPattern(ctxt, token, 0, novar, axis); + xmlFree(token); + token = NULL; + if (ctxt->error) + goto error; + } else if (CUR == ':') { + NEXT; + if (CUR != ':') { + xmlChar *prefix = token; + xmlNsPtr ns; + + /* + * This is a namespace match + */ + token = xsltScanNCName(ctxt); + ns = xmlSearchNs(ctxt->doc, ctxt->elem, prefix); + if (ns == NULL) { + xsltTransformError(NULL, NULL, NULL, + "xsltCompileStepPattern : no namespace bound to prefix %s\n", + prefix); + xmlFree(prefix); + prefix=NULL; + ctxt->error = 1; + goto error; + } else { + URL = xmlStrdup(ns->href); + } + xmlFree(prefix); + prefix=NULL; + if (token == NULL) { + if (CUR == '*') { + NEXT; + if (axis == AXIS_ATTRIBUTE) { + PUSH(XSLT_OP_ATTR, NULL, URL, novar); + URL = NULL; + } + else { + PUSH(XSLT_OP_NS, URL, NULL, novar); + URL = NULL; + } + } else { + xsltTransformError(NULL, NULL, NULL, + "xsltCompileStepPattern : Name expected\n"); + ctxt->error = 1; + goto error; + } + } else { + if (axis == AXIS_ATTRIBUTE) { + PUSH(XSLT_OP_ATTR, token, URL, novar); + token = NULL; + URL = NULL; + } + else { + PUSH(XSLT_OP_ELEM, token, URL, novar); + token = NULL; + URL = NULL; + } + } + } else { + if (axis != 0) { + xsltTransformError(NULL, NULL, NULL, + "xsltCompileStepPattern : NodeTest expected\n"); + ctxt->error = 1; + goto error; + } + NEXT; + if (xmlStrEqual(token, (const xmlChar *) "child")) { + axis = AXIS_CHILD; + } else if (xmlStrEqual(token, (const xmlChar *) "attribute")) { + axis = AXIS_ATTRIBUTE; + } else { + xsltTransformError(NULL, NULL, NULL, + "xsltCompileStepPattern : 'child' or 'attribute' expected\n"); + ctxt->error = 1; + goto error; + } + xmlFree(token); + token = NULL; + SKIP_BLANKS; + token = xsltScanNCName(ctxt); + goto parse_node_test; + } + } else { + URI = xsltGetQNameURI(ctxt->elem, &token); + if (token == NULL) { + ctxt->error = 1; + goto error; + } + if (URI != NULL) + URL = xmlStrdup(URI); + if (axis == AXIS_ATTRIBUTE) { + PUSH(XSLT_OP_ATTR, token, URL, novar); + token = NULL; + URL = NULL; + } + else { + PUSH(XSLT_OP_ELEM, token, URL, novar); + token = NULL; + URL = NULL; + } + } +parse_predicate: + SKIP_BLANKS; + level = 0; + while (CUR == '[') { + const xmlChar *q; + + level++; + NEXT; + q = CUR_PTR; + while (CUR != 0) { + /* Skip over nested predicates */ + if (CUR == '[') + level++; + else if (CUR == ']') { + level--; + if (level == 0) + break; + } else if (CUR == '"') { + NEXT; + while ((CUR != 0) && (CUR != '"')) + NEXT; + } else if (CUR == '\'') { + NEXT; + while ((CUR != 0) && (CUR != '\'')) + NEXT; + } + NEXT; + } + if (CUR == 0) { + xsltTransformError(NULL, NULL, NULL, + "xsltCompileStepPattern : ']' expected\n"); + ctxt->error = 1; + return; + } + ret = xmlStrndup(q, CUR_PTR - q); + PUSH(XSLT_OP_PREDICATE, ret, NULL, novar); + ret = NULL; + /* push the predicate lower than local test */ + SWAP(); + NEXT; + SKIP_BLANKS; + } + return; +error: + if (token != NULL) + xmlFree(token); + if (name != NULL) + xmlFree(name); + if (URL != NULL) + xmlFree(URL); + if (ret != NULL) + xmlFree(ret); +} + +/** + * xsltCompileRelativePathPattern: + * @comp: the compilation context + * @token: a posible precompiled name + * @novar: flag to prohibit xslt variables + * + * Compile the XSLT RelativePathPattern and generates a precompiled + * form suitable for fast matching. + * + * [4] RelativePathPattern ::= StepPattern + * | RelativePathPattern '/' StepPattern + * | RelativePathPattern '//' StepPattern + */ +static void +xsltCompileRelativePathPattern(xsltParserContextPtr ctxt, xmlChar *token, int novar) { + xsltCompileStepPattern(ctxt, token, novar); + if (ctxt->error) + goto error; + SKIP_BLANKS; + while ((CUR != 0) && (CUR != '|')) { + if ((CUR == '/') && (NXT(1) == '/')) { + PUSH(XSLT_OP_ANCESTOR, NULL, NULL, novar); + NEXT; + NEXT; + SKIP_BLANKS; + xsltCompileStepPattern(ctxt, NULL, novar); + } else if (CUR == '/') { + PUSH(XSLT_OP_PARENT, NULL, NULL, novar); + NEXT; + SKIP_BLANKS; + xsltCompileStepPattern(ctxt, NULL, novar); + } else { + ctxt->error = 1; + } + if (ctxt->error) + goto error; + SKIP_BLANKS; + } +error: + return; +} + +/** + * xsltCompileLocationPathPattern: + * @ctxt: the compilation context + * @novar: flag to prohibit xslt variables + * + * Compile the XSLT LocationPathPattern and generates a precompiled + * form suitable for fast matching. + * + * [2] LocationPathPattern ::= '/' RelativePathPattern? + * | IdKeyPattern (('/' | '//') RelativePathPattern)? + * | '//'? RelativePathPattern + */ +static void +xsltCompileLocationPathPattern(xsltParserContextPtr ctxt, int novar) { + SKIP_BLANKS; + if ((CUR == '/') && (NXT(1) == '/')) { + /* + * since we reverse the query + * a leading // can be safely ignored + */ + NEXT; + NEXT; + ctxt->comp->priority = 0.5; /* '//' means not 0 priority */ + xsltCompileRelativePathPattern(ctxt, NULL, novar); + } else if (CUR == '/') { + /* + * We need to find root as the parent + */ + NEXT; + SKIP_BLANKS; + PUSH(XSLT_OP_ROOT, NULL, NULL, novar); + if ((CUR != 0) && (CUR != '|')) { + PUSH(XSLT_OP_PARENT, NULL, NULL, novar); + xsltCompileRelativePathPattern(ctxt, NULL, novar); + } + } else if (CUR == '*') { + xsltCompileRelativePathPattern(ctxt, NULL, novar); + } else if (CUR == '@') { + xsltCompileRelativePathPattern(ctxt, NULL, novar); + } else { + xmlChar *name; + name = xsltScanNCName(ctxt); + if (name == NULL) { + xsltTransformError(NULL, NULL, NULL, + "xsltCompileLocationPathPattern : Name expected\n"); + ctxt->error = 1; + return; + } + SKIP_BLANKS; + if ((CUR == '(') && !xmlXPathIsNodeType(name)) { + xsltCompileIdKeyPattern(ctxt, name, 1, novar, 0); + xmlFree(name); + name = NULL; + if (ctxt->error) + return; + if ((CUR == '/') && (NXT(1) == '/')) { + PUSH(XSLT_OP_ANCESTOR, NULL, NULL, novar); + NEXT; + NEXT; + SKIP_BLANKS; + xsltCompileRelativePathPattern(ctxt, NULL, novar); + } else if (CUR == '/') { + PUSH(XSLT_OP_PARENT, NULL, NULL, novar); + NEXT; + SKIP_BLANKS; + xsltCompileRelativePathPattern(ctxt, NULL, novar); + } + return; + } + xsltCompileRelativePathPattern(ctxt, name, novar); + } +error: + return; +} + +/** + * xsltCompilePatternInternal: + * @pattern: an XSLT pattern + * @doc: the containing document + * @node: the containing element + * @style: the stylesheet + * @runtime: the transformation context, if done at run-time + * @novar: flag to prohibit xslt variables + * + * Compile the XSLT pattern and generates a list of precompiled form suitable + * for fast matching. + * + * [1] Pattern ::= LocationPathPattern | Pattern '|' LocationPathPattern + * + * Returns the generated pattern list or NULL in case of failure + */ + +static xsltCompMatchPtr +xsltCompilePatternInternal(const xmlChar *pattern, xmlDocPtr doc, + xmlNodePtr node, xsltStylesheetPtr style, + xsltTransformContextPtr runtime, int novar) { + xsltParserContextPtr ctxt = NULL; + xsltCompMatchPtr element, first = NULL, previous = NULL; + int current, start, end, level, j; + + if (pattern == NULL) { + xsltTransformError(NULL, NULL, node, + "xsltCompilePattern : NULL pattern\n"); + return(NULL); + } + + ctxt = xsltNewParserContext(style, runtime); + if (ctxt == NULL) + return(NULL); + ctxt->doc = doc; + ctxt->elem = node; + current = end = 0; + while (pattern[current] != 0) { + start = current; + while (xmlIsBlank_ch(pattern[current])) + current++; + end = current; + level = 0; + while ((pattern[end] != 0) && ((pattern[end] != '|') || (level != 0))) { + if (pattern[end] == '[') + level++; + else if (pattern[end] == ']') + level--; + else if (pattern[end] == '\'') { + end++; + while ((pattern[end] != 0) && (pattern[end] != '\'')) + end++; + } else if (pattern[end] == '"') { + end++; + while ((pattern[end] != 0) && (pattern[end] != '"')) + end++; + } + if (pattern[end] == 0) + break; + end++; + } + if (current == end) { + xsltTransformError(NULL, NULL, node, + "xsltCompilePattern : NULL pattern\n"); + goto error; + } + element = xsltNewCompMatch(); + if (element == NULL) { + goto error; + } + if (first == NULL) + first = element; + else if (previous != NULL) + previous->next = element; + previous = element; + + ctxt->comp = element; + ctxt->base = xmlStrndup(&pattern[start], end - start); + if (ctxt->base == NULL) + goto error; + ctxt->cur = &(ctxt->base)[current - start]; + element->pattern = ctxt->base; + element->node = node; + element->nsList = xmlGetNsList(doc, node); + j = 0; + if (element->nsList != NULL) { + while (element->nsList[j] != NULL) + j++; + } + element->nsNr = j; + + +#ifdef WITH_XSLT_DEBUG_PATTERN + xsltGenericDebug(xsltGenericDebugContext, + "xsltCompilePattern : parsing '%s'\n", + element->pattern); +#endif + /* + Preset default priority to be zero. + This may be changed by xsltCompileLocationPathPattern. + */ + element->priority = 0; + xsltCompileLocationPathPattern(ctxt, novar); + if (ctxt->error) { + xsltTransformError(NULL, style, node, + "xsltCompilePattern : failed to compile '%s'\n", + element->pattern); + if (style != NULL) style->errors++; + goto error; + } + + /* + * Reverse for faster interpretation. + */ + xsltReverseCompMatch(ctxt, element); + + /* + * Set-up the priority + */ + if (element->priority == 0) { /* if not yet determined */ + if (((element->steps[0].op == XSLT_OP_ELEM) || + (element->steps[0].op == XSLT_OP_ATTR) || + (element->steps[0].op == XSLT_OP_PI)) && + (element->steps[0].value != NULL) && + (element->steps[1].op == XSLT_OP_END)) { + ; /* previously preset */ + } else if ((element->steps[0].op == XSLT_OP_ATTR) && + (element->steps[0].value2 != NULL) && + (element->steps[1].op == XSLT_OP_END)) { + element->priority = -0.25; + } else if ((element->steps[0].op == XSLT_OP_NS) && + (element->steps[0].value != NULL) && + (element->steps[1].op == XSLT_OP_END)) { + element->priority = -0.25; + } else if ((element->steps[0].op == XSLT_OP_ATTR) && + (element->steps[0].value == NULL) && + (element->steps[0].value2 == NULL) && + (element->steps[1].op == XSLT_OP_END)) { + element->priority = -0.5; + } else if (((element->steps[0].op == XSLT_OP_PI) || + (element->steps[0].op == XSLT_OP_TEXT) || + (element->steps[0].op == XSLT_OP_ALL) || + (element->steps[0].op == XSLT_OP_NODE) || + (element->steps[0].op == XSLT_OP_COMMENT)) && + (element->steps[1].op == XSLT_OP_END)) { + element->priority = -0.5; + } else { + element->priority = 0.5; + } + } +#ifdef WITH_XSLT_DEBUG_PATTERN + xsltGenericDebug(xsltGenericDebugContext, + "xsltCompilePattern : parsed %s, default priority %f\n", + element->pattern, element->priority); +#endif + if (pattern[end] == '|') + end++; + current = end; + } + if (end == 0) { + xsltTransformError(NULL, style, node, + "xsltCompilePattern : NULL pattern\n"); + if (style != NULL) style->errors++; + goto error; + } + + xsltFreeParserContext(ctxt); + return(first); + +error: + if (ctxt != NULL) + xsltFreeParserContext(ctxt); + if (first != NULL) + xsltFreeCompMatchList(first); + return(NULL); +} + +/** + * xsltCompilePattern: + * @pattern: an XSLT pattern + * @doc: the containing document + * @node: the containing element + * @style: the stylesheet + * @runtime: the transformation context, if done at run-time + * + * Compile the XSLT pattern and generates a list of precompiled form suitable + * for fast matching. + * + * [1] Pattern ::= LocationPathPattern | Pattern '|' LocationPathPattern + * + * Returns the generated pattern list or NULL in case of failure + */ + +xsltCompMatchPtr +xsltCompilePattern(const xmlChar *pattern, xmlDocPtr doc, + xmlNodePtr node, xsltStylesheetPtr style, + xsltTransformContextPtr runtime) { + return (xsltCompilePatternInternal(pattern, doc, node, style, runtime, 0)); +} + +/************************************************************************ + * * + * Module interfaces * + * * + ************************************************************************/ + +/** + * xsltAddTemplate: + * @style: an XSLT stylesheet + * @cur: an XSLT template + * @mode: the mode name or NULL + * @modeURI: the mode URI or NULL + * + * Register the XSLT pattern associated to @cur + * + * Returns -1 in case of error, 0 otherwise + */ +int +xsltAddTemplate(xsltStylesheetPtr style, xsltTemplatePtr cur, + const xmlChar *mode, const xmlChar *modeURI) { + xsltCompMatchPtr pat, list, next; + /* + * 'top' will point to style->xxxMatch ptr - declaring as 'void' + * avoids gcc 'type-punned pointer' warning. + */ + xsltCompMatchPtr *top = NULL; + const xmlChar *name = NULL; + float priority; /* the priority */ + + if ((style == NULL) || (cur == NULL)) + return(-1); + + if (cur->next != NULL) + cur->position = cur->next->position + 1; + + /* Register named template */ + if (cur->name != NULL) { + if (style->namedTemplates == NULL) { + style->namedTemplates = xmlHashCreate(10); + if (style->namedTemplates == NULL) + return(-1); + } + else { + void *dup = xmlHashLookup2(style->namedTemplates, cur->name, + cur->nameURI); + if (dup != NULL) { + xsltTransformError(NULL, style, cur->elem, + "xsl:template: error duplicate name '%s'\n", + cur->name); + style->errors++; + return(-1); + } + } + + xmlHashAddEntry2(style->namedTemplates, cur->name, cur->nameURI, cur); + } + + if (cur->match == NULL) { + if (cur->name == NULL) { + xsltTransformError(NULL, style, cur->elem, + "xsl:template: need to specify match or name attribute\n"); + style->errors++; + return(-1); + } + return(0); + } + + priority = cur->priority; + pat = xsltCompilePatternInternal(cur->match, style->doc, cur->elem, + style, NULL, 1); + if (pat == NULL) + return(-1); + while (pat) { + int success = 0; + + next = pat->next; + pat->next = NULL; + name = NULL; + + pat->template = cur; + if (mode != NULL) + pat->mode = xmlDictLookup(style->dict, mode, -1); + if (modeURI != NULL) + pat->modeURI = xmlDictLookup(style->dict, modeURI, -1); + if (priority != XSLT_PAT_NO_PRIORITY) + pat->priority = priority; + + /* + * insert it in the hash table list corresponding to its lookup name + */ + switch (pat->steps[0].op) { + case XSLT_OP_ATTR: + if (pat->steps[0].value != NULL) + name = pat->steps[0].value; + else + top = &(style->attrMatch); + break; + case XSLT_OP_PARENT: + case XSLT_OP_ANCESTOR: + top = &(style->elemMatch); + break; + case XSLT_OP_ROOT: + top = &(style->rootMatch); + break; + case XSLT_OP_KEY: + top = &(style->keyMatch); + break; + case XSLT_OP_ID: + /* TODO optimize ID !!! */ + case XSLT_OP_NS: + case XSLT_OP_ALL: + top = &(style->elemMatch); + break; + case XSLT_OP_END: + case XSLT_OP_PREDICATE: + xsltTransformError(NULL, style, NULL, + "xsltAddTemplate: invalid compiled pattern\n"); + xsltFreeCompMatch(pat); + return(-1); + /* + * TODO: some flags at the top level about type based patterns + * would be faster than inclusion in the hash table. + */ + case XSLT_OP_PI: + if (pat->steps[0].value != NULL) + name = pat->steps[0].value; + else + top = &(style->piMatch); + break; + case XSLT_OP_COMMENT: + top = &(style->commentMatch); + break; + case XSLT_OP_TEXT: + top = &(style->textMatch); + break; + case XSLT_OP_ELEM: + case XSLT_OP_NODE: + if (pat->steps[0].value != NULL) + name = pat->steps[0].value; + else + top = &(style->elemMatch); + break; + } + if (name != NULL) { + if (style->templatesHash == NULL) { + style->templatesHash = xmlHashCreate(1024); + success = (style->templatesHash != NULL) && + (xmlHashAddEntry3(style->templatesHash, name, mode, + modeURI, pat) >= 0); + } else { + list = (xsltCompMatchPtr) xmlHashLookup3(style->templatesHash, + name, mode, modeURI); + if (list == NULL) { + success = (xmlHashAddEntry3(style->templatesHash, name, + mode, modeURI, pat) >= 0); + } else { + /* + * Note '<=' since one must choose among the matching + * template rules that are left, the one that occurs + * last in the stylesheet + */ + if (list->priority <= pat->priority) { + pat->next = list; + xmlHashUpdateEntry3(style->templatesHash, name, + mode, modeURI, pat, NULL); + } else { + while (list->next != NULL) { + if (list->next->priority <= pat->priority) + break; + list = list->next; + } + pat->next = list->next; + list->next = pat; + } + success = 1; + } + } + } else if (top != NULL) { + list = *top; + if (list == NULL) { + *top = pat; + pat->next = NULL; + } else if (list->priority <= pat->priority) { + pat->next = list; + *top = pat; + } else { + while (list->next != NULL) { + if (list->next->priority <= pat->priority) + break; + list = list->next; + } + pat->next = list->next; + list->next = pat; + } + success = 1; + } + if (success == 0) { + xsltTransformError(NULL, style, NULL, + "xsltAddTemplate: invalid compiled pattern\n"); + xsltFreeCompMatch(pat); + xsltFreeCompMatchList(next); + return(-1); + } +#ifdef WITH_XSLT_DEBUG_PATTERN + if (mode) + xsltGenericDebug(xsltGenericDebugContext, + "added pattern : '%s' mode '%s' priority %f\n", + pat->pattern, pat->mode, pat->priority); + else + xsltGenericDebug(xsltGenericDebugContext, + "added pattern : '%s' priority %f\n", + pat->pattern, pat->priority); +#endif + + pat = next; + } + return(0); +} + +static int +xsltComputeAllKeys(xsltTransformContextPtr ctxt, xmlNodePtr contextNode) +{ + if ((ctxt == NULL) || (contextNode == NULL)) { + xsltTransformError(ctxt, NULL, ctxt->inst, + "Internal error in xsltComputeAllKeys(): " + "Bad arguments.\n"); + return(-1); + } + + if (ctxt->document == NULL) { + /* + * The document info will only be NULL if we have a RTF. + */ + if (contextNode->doc->_private != NULL) + goto doc_info_mismatch; + /* + * On-demand creation of the document info (needed for keys). + */ + ctxt->document = xsltNewDocument(ctxt, contextNode->doc); + if (ctxt->document == NULL) + return(-1); + } + return xsltInitAllDocKeys(ctxt); + +doc_info_mismatch: + xsltTransformError(ctxt, NULL, ctxt->inst, + "Internal error in xsltComputeAllKeys(): " + "The context's document info doesn't match the " + "document info of the current result tree.\n"); + ctxt->state = XSLT_STATE_STOPPED; + return(-1); +} + +/** + * xsltGetTemplate: + * @ctxt: a XSLT process context + * @node: the node being processed + * @style: the current style + * + * Finds the template applying to this node, if @style is non-NULL + * it means one needs to look for the next imported template in scope. + * + * Returns the xsltTemplatePtr or NULL if not found + */ +xsltTemplatePtr +xsltGetTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node, + xsltStylesheetPtr style) +{ + xsltStylesheetPtr curstyle; + xsltTemplatePtr ret = NULL; + const xmlChar *name = NULL; + xsltCompMatchPtr list = NULL; + float priority; + + if ((ctxt == NULL) || (node == NULL)) + return(NULL); + + if (style == NULL) { + curstyle = ctxt->style; + } else { + curstyle = xsltNextImport(style); + } + + while ((curstyle != NULL) && (curstyle != style)) { + priority = XSLT_PAT_NO_PRIORITY; + /* TODO : handle IDs/keys here ! */ + if (curstyle->templatesHash != NULL) { + /* + * Use the top name as selector + */ + switch (node->type) { + case XML_ELEMENT_NODE: + if (node->name[0] == ' ') + break; + /* Intentional fall-through */ + case XML_ATTRIBUTE_NODE: + case XML_PI_NODE: + name = node->name; + break; + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_COMMENT_NODE: + case XML_ENTITY_REF_NODE: + case XML_ENTITY_NODE: + case XML_DOCUMENT_TYPE_NODE: + case XML_DOCUMENT_FRAG_NODE: + case XML_NOTATION_NODE: + case XML_DTD_NODE: + case XML_ELEMENT_DECL: + case XML_ATTRIBUTE_DECL: + case XML_ENTITY_DECL: + case XML_NAMESPACE_DECL: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: + break; + default: + return(NULL); + + } + } + if (name != NULL) { + /* + * find the list of applicable expressions based on the name + */ + list = (xsltCompMatchPtr) xmlHashLookup3(curstyle->templatesHash, + name, ctxt->mode, ctxt->modeURI); + } else + list = NULL; + while (list != NULL) { + if (xsltTestCompMatch(ctxt, list, node, + ctxt->mode, ctxt->modeURI) == 1) { + ret = list->template; + priority = list->priority; + break; + } + list = list->next; + } + list = NULL; + + /* + * find alternate generic matches + */ + switch (node->type) { + case XML_ELEMENT_NODE: + if (node->name[0] == ' ') + list = curstyle->rootMatch; + else + list = curstyle->elemMatch; + break; + case XML_ATTRIBUTE_NODE: { + list = curstyle->attrMatch; + break; + } + case XML_PI_NODE: + list = curstyle->piMatch; + break; + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: { + list = curstyle->rootMatch; + break; + } + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + list = curstyle->textMatch; + break; + case XML_COMMENT_NODE: + list = curstyle->commentMatch; + break; + case XML_ENTITY_REF_NODE: + case XML_ENTITY_NODE: + case XML_DOCUMENT_TYPE_NODE: + case XML_DOCUMENT_FRAG_NODE: + case XML_NOTATION_NODE: + case XML_DTD_NODE: + case XML_ELEMENT_DECL: + case XML_ATTRIBUTE_DECL: + case XML_ENTITY_DECL: + case XML_NAMESPACE_DECL: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: + break; + default: + break; + } + while ((list != NULL) && + ((ret == NULL) || + (list->priority > priority) || + ((list->priority == priority) && + (list->template->position > ret->position)))) { + if (xsltTestCompMatch(ctxt, list, node, + ctxt->mode, ctxt->modeURI) == 1) { + ret = list->template; + priority = list->priority; + break; + } + list = list->next; + } + /* + * Some of the tests for elements can also apply to documents + */ + if ((node->type == XML_DOCUMENT_NODE) || + (node->type == XML_HTML_DOCUMENT_NODE) || + (node->type == XML_TEXT_NODE)) { + list = curstyle->elemMatch; + while ((list != NULL) && + ((ret == NULL) || + (list->priority > priority) || + ((list->priority == priority) && + (list->template->position > ret->position)))) { + if (xsltTestCompMatch(ctxt, list, node, + ctxt->mode, ctxt->modeURI) == 1) { + ret = list->template; + priority = list->priority; + break; + } + list = list->next; + } + } else if ((node->type == XML_PI_NODE) || + (node->type == XML_COMMENT_NODE)) { + list = curstyle->elemMatch; + while ((list != NULL) && + ((ret == NULL) || + (list->priority > priority) || + ((list->priority == priority) && + (list->template->position > ret->position)))) { + if (xsltTestCompMatch(ctxt, list, node, + ctxt->mode, ctxt->modeURI) == 1) { + ret = list->template; + priority = list->priority; + break; + } + list = list->next; + } + } + +keyed_match: + if (xsltGetSourceNodeFlags(node) & XSLT_SOURCE_NODE_HAS_KEY) { + list = curstyle->keyMatch; + while ((list != NULL) && + ((ret == NULL) || + (list->priority > priority) || + ((list->priority == priority) && + (list->template->position > ret->position)))) { + if (xsltTestCompMatch(ctxt, list, node, + ctxt->mode, ctxt->modeURI) == 1) { + ret = list->template; + priority = list->priority; + break; + } + list = list->next; + } + } + else if (ctxt->hasTemplKeyPatterns && + ((ctxt->document == NULL) || + (ctxt->document->nbKeysComputed < ctxt->nbKeys))) + { + /* + * Compute all remaining keys for this document. + * + * REVISIT TODO: I think this could be further optimized. + */ + if (xsltComputeAllKeys(ctxt, node) == -1) + goto error; + + if (xsltGetSourceNodeFlags(node) & XSLT_SOURCE_NODE_HAS_KEY) + goto keyed_match; + } + if (ret != NULL) + return(ret); + + /* + * Cycle on next curstylesheet import. + */ + curstyle = xsltNextImport(curstyle); + } + +error: + return(NULL); +} + +/** + * xsltCleanupTemplates: + * @style: an XSLT stylesheet + * + * Cleanup the state of the templates used by the stylesheet and + * the ones it imports. + */ +void +xsltCleanupTemplates(xsltStylesheetPtr style ATTRIBUTE_UNUSED) { +} + +/** + * xsltFreeTemplateHashes: + * @style: an XSLT stylesheet + * + * Free up the memory used by xsltAddTemplate/xsltGetTemplate mechanism + */ +void +xsltFreeTemplateHashes(xsltStylesheetPtr style) { + if (style->templatesHash != NULL) + xmlHashFree(style->templatesHash, xsltFreeCompMatchListEntry); + if (style->rootMatch != NULL) + xsltFreeCompMatchList(style->rootMatch); + if (style->keyMatch != NULL) + xsltFreeCompMatchList(style->keyMatch); + if (style->elemMatch != NULL) + xsltFreeCompMatchList(style->elemMatch); + if (style->attrMatch != NULL) + xsltFreeCompMatchList(style->attrMatch); + if (style->parentMatch != NULL) + xsltFreeCompMatchList(style->parentMatch); + if (style->textMatch != NULL) + xsltFreeCompMatchList(style->textMatch); + if (style->piMatch != NULL) + xsltFreeCompMatchList(style->piMatch); + if (style->commentMatch != NULL) + xsltFreeCompMatchList(style->commentMatch); + if (style->namedTemplates != NULL) + xmlHashFree(style->namedTemplates, NULL); +} + diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/pattern.h chromium-145.0.7632.159/third_party/libxslt/src/libxslt/pattern.h --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/pattern.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/pattern.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,84 @@ +/* + * Summary: interface for the pattern matching used in template matches. + * Description: the implementation of the lookup of the right template + * for a given node must be really fast in order to keep + * decent performances. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLT_PATTERN_H__ +#define __XML_XSLT_PATTERN_H__ + +#include "xsltInternals.h" +#include "xsltexports.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xsltCompMatch: + * + * Data structure used for the implementation of patterns. + * It is kept private (in pattern.c). + */ +typedef struct _xsltCompMatch xsltCompMatch; +typedef xsltCompMatch *xsltCompMatchPtr; + +/* + * Pattern related interfaces. + */ + +XSLTPUBFUN xsltCompMatchPtr XSLTCALL + xsltCompilePattern (const xmlChar *pattern, + xmlDocPtr doc, + xmlNodePtr node, + xsltStylesheetPtr style, + xsltTransformContextPtr runtime); +XSLTPUBFUN void XSLTCALL + xsltFreeCompMatchList (xsltCompMatchPtr comp); +XSLTPUBFUN int XSLTCALL + xsltTestCompMatchList (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xsltCompMatchPtr comp); +XSLTPUBFUN void XSLTCALL + xsltCompMatchClearCache (xsltTransformContextPtr ctxt, + xsltCompMatchPtr comp); +XSLTPUBFUN void XSLTCALL + xsltNormalizeCompSteps (void *payload, + void *data, + const xmlChar *name); + +/* + * Template related interfaces. + */ +XSLTPUBFUN int XSLTCALL + xsltAddTemplate (xsltStylesheetPtr style, + xsltTemplatePtr cur, + const xmlChar *mode, + const xmlChar *modeURI); +XSLTPUBFUN xsltTemplatePtr XSLTCALL + xsltGetTemplate (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xsltStylesheetPtr style); +XSLTPUBFUN void XSLTCALL + xsltFreeTemplateHashes (xsltStylesheetPtr style); +XSLTPUBFUN void XSLTCALL + xsltCleanupTemplates (xsltStylesheetPtr style); + +#if 0 +int xsltMatchPattern (xsltTransformContextPtr ctxt, + xmlNodePtr node, + const xmlChar *pattern, + xmlDocPtr ctxtdoc, + xmlNodePtr ctxtnode); +#endif +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_PATTERN_H__ */ + diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/preproc.c chromium-145.0.7632.159/third_party/libxslt/src/libxslt/preproc.c --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/preproc.c 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/preproc.c 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,2368 @@ +/* + * preproc.c: Preprocessing of style operations + * + * References: + * http://www.w3.org/TR/1999/REC-xslt-19991116 + * + * Michael Kay "XSLT Programmer's Reference" pp 637-643 + * Writing Multiple Output Files + * + * XSLT-1.1 Working Draft + * http://www.w3.org/TR/xslt11#multiple-output + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#define IN_LIBXSLT +#include "libxslt.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "xslt.h" +#include "xsltutils.h" +#include "xsltInternals.h" +#include "transform.h" +#include "templates.h" +#include "variables.h" +#include "numbersInternals.h" +#include "preproc.h" +#include "extra.h" +#include "imports.h" +#include "extensions.h" +#include "pattern.h" + +#ifdef WITH_XSLT_DEBUG +#define WITH_XSLT_DEBUG_PREPROC +#endif + +const xmlChar *xsltExtMarker = (const xmlChar *) "Extension Element"; + +/************************************************************************ + * * + * Grammar checks * + * * + ************************************************************************/ + +#ifdef XSLT_REFACTORED + /* + * Grammar checks are now performed in xslt.c. + */ +#else +/** + * xsltCheckTopLevelElement: + * @style: the XSLT stylesheet + * @inst: the XSLT instruction + * @err: raise an error or not + * + * Check that the instruction is instanciated as a top level element. + * + * Returns -1 in case of error, 0 if failed and 1 in case of success + */ +static int +xsltCheckTopLevelElement(xsltStylesheetPtr style, xmlNodePtr inst, int err) { + xmlNodePtr parent; + if ((style == NULL) || (inst == NULL) || (inst->ns == NULL)) + return(-1); + + parent = inst->parent; + if (parent == NULL) { + if (err) { + xsltTransformError(NULL, style, inst, + "internal problem: element has no parent\n"); + style->errors++; + } + return(0); + } + if ((parent->ns == NULL) || (parent->type != XML_ELEMENT_NODE) || + ((parent->ns != inst->ns) && + (!xmlStrEqual(parent->ns->href, inst->ns->href))) || + ((!xmlStrEqual(parent->name, BAD_CAST "stylesheet")) && + (!xmlStrEqual(parent->name, BAD_CAST "transform")))) { + if (err) { + xsltTransformError(NULL, style, inst, + "element %s only allowed as child of stylesheet\n", + inst->name); + style->errors++; + } + return(0); + } + return(1); +} + +/** + * xsltCheckInstructionElement: + * @style: the XSLT stylesheet + * @inst: the XSLT instruction + * + * Check that the instruction is instanciated as an instruction element. + */ +static void +xsltCheckInstructionElement(xsltStylesheetPtr style, xmlNodePtr inst) { + xmlNodePtr parent; + int has_ext; + + if ((style == NULL) || (inst == NULL) || (inst->ns == NULL) || + (style->literal_result)) + return; + + has_ext = (style->extInfos != NULL); + + parent = inst->parent; + if (parent == NULL) { + xsltTransformError(NULL, style, inst, + "internal problem: element has no parent\n"); + style->errors++; + return; + } + while ((parent != NULL) && (parent->type != XML_DOCUMENT_NODE)) { + if (((parent->ns == inst->ns) || + ((parent->ns != NULL) && + (xmlStrEqual(parent->ns->href, inst->ns->href)))) && + ((xmlStrEqual(parent->name, BAD_CAST "template")) || + (xmlStrEqual(parent->name, BAD_CAST "param")) || + (xmlStrEqual(parent->name, BAD_CAST "attribute")) || + (xmlStrEqual(parent->name, BAD_CAST "variable")))) { + return; + } + + /* + * if we are within an extension element all bets are off + * about the semantic there e.g. xsl:param within func:function + */ + if ((has_ext) && (parent->ns != NULL) && + (xmlHashLookup(style->extInfos, parent->ns->href) != NULL)) + return; + + parent = parent->parent; + } + xsltTransformError(NULL, style, inst, + "element %s only allowed within a template, variable or param\n", + inst->name); + style->errors++; +} + +/** + * xsltCheckParentElement: + * @style: the XSLT stylesheet + * @inst: the XSLT instruction + * @allow1: allowed parent1 + * @allow2: allowed parent2 + * + * Check that the instruction is instanciated as the childre of one of the + * possible parents. + */ +static void +xsltCheckParentElement(xsltStylesheetPtr style, xmlNodePtr inst, + const xmlChar *allow1, const xmlChar *allow2) { + xmlNodePtr parent; + + if ((style == NULL) || (inst == NULL) || (inst->ns == NULL) || + (style->literal_result)) + return; + + parent = inst->parent; + if (parent == NULL) { + xsltTransformError(NULL, style, inst, + "internal problem: element has no parent\n"); + style->errors++; + return; + } + if (((parent->ns == inst->ns) || + ((parent->ns != NULL) && + (xmlStrEqual(parent->ns->href, inst->ns->href)))) && + ((xmlStrEqual(parent->name, allow1)) || + (xmlStrEqual(parent->name, allow2)))) { + return; + } + + if (style->extInfos != NULL) { + while ((parent != NULL) && (parent->type != XML_DOCUMENT_NODE)) { + /* + * if we are within an extension element all bets are off + * about the semantic there e.g. xsl:param within func:function + */ + if ((parent->ns != NULL) && + (xmlHashLookup(style->extInfos, parent->ns->href) != NULL)) + return; + + parent = parent->parent; + } + } + xsltTransformError(NULL, style, inst, + "element %s is not allowed within that context\n", + inst->name); + style->errors++; +} +#endif + +/************************************************************************ + * * + * handling of precomputed data * + * * + ************************************************************************/ + +/** + * xsltNewStylePreComp: + * @style: the XSLT stylesheet + * @type: the construct type + * + * Create a new XSLT Style precomputed block + * + * Returns the newly allocated specialized structure + * or NULL in case of error + */ +static xsltStylePreCompPtr +xsltNewStylePreComp(xsltStylesheetPtr style, xsltStyleType type) { + xsltStylePreCompPtr cur; +#ifdef XSLT_REFACTORED + size_t size; +#endif + + if (style == NULL) + return(NULL); + +#ifdef XSLT_REFACTORED + /* + * URGENT TODO: Use specialized factory functions in order + * to avoid this ugliness. + */ + switch (type) { + case XSLT_FUNC_COPY: + size = sizeof(xsltStyleItemCopy); break; + case XSLT_FUNC_SORT: + size = sizeof(xsltStyleItemSort); break; + case XSLT_FUNC_TEXT: + size = sizeof(xsltStyleItemText); break; + case XSLT_FUNC_ELEMENT: + size = sizeof(xsltStyleItemElement); break; + case XSLT_FUNC_ATTRIBUTE: + size = sizeof(xsltStyleItemAttribute); break; + case XSLT_FUNC_COMMENT: + size = sizeof(xsltStyleItemComment); break; + case XSLT_FUNC_PI: + size = sizeof(xsltStyleItemPI); break; + case XSLT_FUNC_COPYOF: + size = sizeof(xsltStyleItemCopyOf); break; + case XSLT_FUNC_VALUEOF: + size = sizeof(xsltStyleItemValueOf); break;; + case XSLT_FUNC_NUMBER: + size = sizeof(xsltStyleItemNumber); break; + case XSLT_FUNC_APPLYIMPORTS: + size = sizeof(xsltStyleItemApplyImports); break; + case XSLT_FUNC_CALLTEMPLATE: + size = sizeof(xsltStyleItemCallTemplate); break; + case XSLT_FUNC_APPLYTEMPLATES: + size = sizeof(xsltStyleItemApplyTemplates); break; + case XSLT_FUNC_CHOOSE: + size = sizeof(xsltStyleItemChoose); break; + case XSLT_FUNC_IF: + size = sizeof(xsltStyleItemIf); break; + case XSLT_FUNC_FOREACH: + size = sizeof(xsltStyleItemForEach); break; + case XSLT_FUNC_DOCUMENT: + size = sizeof(xsltStyleItemDocument); break; + case XSLT_FUNC_WITHPARAM: + size = sizeof(xsltStyleItemWithParam); break; + case XSLT_FUNC_PARAM: + size = sizeof(xsltStyleItemParam); break; + case XSLT_FUNC_VARIABLE: + size = sizeof(xsltStyleItemVariable); break; + case XSLT_FUNC_WHEN: + size = sizeof(xsltStyleItemWhen); break; + case XSLT_FUNC_OTHERWISE: + size = sizeof(xsltStyleItemOtherwise); break; + default: + xsltTransformError(NULL, style, NULL, + "xsltNewStylePreComp : invalid type %d\n", type); + style->errors++; + return(NULL); + } + /* + * Create the structure. + */ + cur = (xsltStylePreCompPtr) xmlMalloc(size); + if (cur == NULL) { + xsltTransformError(NULL, style, NULL, + "xsltNewStylePreComp : malloc failed\n"); + style->errors++; + return(NULL); + } + memset(cur, 0, size); + +#else /* XSLT_REFACTORED */ + /* + * Old behaviour. + */ + cur = (xsltStylePreCompPtr) xmlMalloc(sizeof(xsltStylePreComp)); + if (cur == NULL) { + xsltTransformError(NULL, style, NULL, + "xsltNewStylePreComp : malloc failed\n"); + style->errors++; + return(NULL); + } + memset(cur, 0, sizeof(xsltStylePreComp)); +#endif /* XSLT_REFACTORED */ + + /* + * URGENT TODO: Better to move this to spezialized factory functions. + */ + cur->type = type; + switch (cur->type) { + case XSLT_FUNC_COPY: + cur->func = xsltCopy;break; + case XSLT_FUNC_SORT: + cur->func = xsltSort;break; + case XSLT_FUNC_TEXT: + cur->func = xsltText;break; + case XSLT_FUNC_ELEMENT: + cur->func = xsltElement;break; + case XSLT_FUNC_ATTRIBUTE: + cur->func = xsltAttribute;break; + case XSLT_FUNC_COMMENT: + cur->func = xsltComment;break; + case XSLT_FUNC_PI: + cur->func = xsltProcessingInstruction; + break; + case XSLT_FUNC_COPYOF: + cur->func = xsltCopyOf;break; + case XSLT_FUNC_VALUEOF: + cur->func = xsltValueOf;break; + case XSLT_FUNC_NUMBER: + cur->func = xsltNumber;break; + case XSLT_FUNC_APPLYIMPORTS: + cur->func = xsltApplyImports;break; + case XSLT_FUNC_CALLTEMPLATE: + cur->func = xsltCallTemplate;break; + case XSLT_FUNC_APPLYTEMPLATES: + cur->func = xsltApplyTemplates;break; + case XSLT_FUNC_CHOOSE: + cur->func = xsltChoose;break; + case XSLT_FUNC_IF: + cur->func = xsltIf;break; + case XSLT_FUNC_FOREACH: + cur->func = xsltForEach;break; + case XSLT_FUNC_DOCUMENT: + cur->func = xsltDocumentElem;break; + case XSLT_FUNC_WITHPARAM: + case XSLT_FUNC_PARAM: + case XSLT_FUNC_VARIABLE: + case XSLT_FUNC_WHEN: + break; + default: + if (cur->func == NULL) { + xsltTransformError(NULL, style, NULL, + "xsltNewStylePreComp : no function for type %d\n", type); + style->errors++; + } + } + cur->next = style->preComps; + style->preComps = (xsltElemPreCompPtr) cur; + + return(cur); +} + +/** + * xsltFreeStylePreComp: + * @comp: an XSLT Style precomputed block + * + * Free up the memory allocated by @comp + */ +static void +xsltFreeStylePreComp(xsltStylePreCompPtr comp) { + if (comp == NULL) + return; +#ifdef XSLT_REFACTORED + /* + * URGENT TODO: Implement destructors. + */ + switch (comp->type) { + case XSLT_FUNC_LITERAL_RESULT_ELEMENT: + break; + case XSLT_FUNC_COPY: + break; + case XSLT_FUNC_SORT: { + xsltStyleItemSortPtr item = (xsltStyleItemSortPtr) comp; + if (item->comp != NULL) + xmlXPathFreeCompExpr(item->comp); + } + break; + case XSLT_FUNC_TEXT: + break; + case XSLT_FUNC_ELEMENT: + break; + case XSLT_FUNC_ATTRIBUTE: + break; + case XSLT_FUNC_COMMENT: + break; + case XSLT_FUNC_PI: + break; + case XSLT_FUNC_COPYOF: { + xsltStyleItemCopyOfPtr item = (xsltStyleItemCopyOfPtr) comp; + if (item->comp != NULL) + xmlXPathFreeCompExpr(item->comp); + } + break; + case XSLT_FUNC_VALUEOF: { + xsltStyleItemValueOfPtr item = (xsltStyleItemValueOfPtr) comp; + if (item->comp != NULL) + xmlXPathFreeCompExpr(item->comp); + } + break; + case XSLT_FUNC_NUMBER: { + xsltStyleItemNumberPtr item = (xsltStyleItemNumberPtr) comp; + if (item->numdata.countPat != NULL) + xsltFreeCompMatchList(item->numdata.countPat); + if (item->numdata.fromPat != NULL) + xsltFreeCompMatchList(item->numdata.fromPat); + } + break; + case XSLT_FUNC_APPLYIMPORTS: + break; + case XSLT_FUNC_CALLTEMPLATE: + break; + case XSLT_FUNC_APPLYTEMPLATES: { + xsltStyleItemApplyTemplatesPtr item = + (xsltStyleItemApplyTemplatesPtr) comp; + if (item->comp != NULL) + xmlXPathFreeCompExpr(item->comp); + } + break; + case XSLT_FUNC_CHOOSE: + break; + case XSLT_FUNC_IF: { + xsltStyleItemIfPtr item = (xsltStyleItemIfPtr) comp; + if (item->comp != NULL) + xmlXPathFreeCompExpr(item->comp); + } + break; + case XSLT_FUNC_FOREACH: { + xsltStyleItemForEachPtr item = + (xsltStyleItemForEachPtr) comp; + if (item->comp != NULL) + xmlXPathFreeCompExpr(item->comp); + } + break; + case XSLT_FUNC_DOCUMENT: + break; + case XSLT_FUNC_WITHPARAM: { + xsltStyleItemWithParamPtr item = + (xsltStyleItemWithParamPtr) comp; + if (item->comp != NULL) + xmlXPathFreeCompExpr(item->comp); + } + break; + case XSLT_FUNC_PARAM: { + xsltStyleItemParamPtr item = + (xsltStyleItemParamPtr) comp; + if (item->comp != NULL) + xmlXPathFreeCompExpr(item->comp); + } + break; + case XSLT_FUNC_VARIABLE: { + xsltStyleItemVariablePtr item = + (xsltStyleItemVariablePtr) comp; + if (item->comp != NULL) + xmlXPathFreeCompExpr(item->comp); + } + break; + case XSLT_FUNC_WHEN: { + xsltStyleItemWhenPtr item = + (xsltStyleItemWhenPtr) comp; + if (item->comp != NULL) + xmlXPathFreeCompExpr(item->comp); + } + break; + case XSLT_FUNC_OTHERWISE: + case XSLT_FUNC_FALLBACK: + case XSLT_FUNC_MESSAGE: + case XSLT_FUNC_INCLUDE: + case XSLT_FUNC_ATTRSET: + + break; + default: + /* TODO: Raise error. */ + break; + } +#else + if (comp->comp != NULL) + xmlXPathFreeCompExpr(comp->comp); + if (comp->numdata.countPat != NULL) + xsltFreeCompMatchList(comp->numdata.countPat); + if (comp->numdata.fromPat != NULL) + xsltFreeCompMatchList(comp->numdata.fromPat); + if (comp->nsList != NULL) + xmlFree(comp->nsList); +#endif + + xmlFree(comp); +} + + +/************************************************************************ + * * + * XSLT-1.1 extensions * + * * + ************************************************************************/ + +/** + * xsltDocumentComp: + * @style: the XSLT stylesheet + * @inst: the instruction in the stylesheet + * @function: unused + * + * Pre process an XSLT-1.1 document element + * + * Returns a precompiled data structure for the element + */ +xsltElemPreCompPtr +xsltDocumentComp(xsltStylesheetPtr style, xmlNodePtr inst, + xsltTransformFunction function ATTRIBUTE_UNUSED) { +#ifdef XSLT_REFACTORED + xsltStyleItemDocumentPtr comp; +#else + xsltStylePreCompPtr comp; +#endif + const xmlChar *filename = NULL; + + /* + * As of 2006-03-30, this function is currently defined in Libxslt + * to be used for: + * (in libxslt/extra.c) + * "output" in XSLT_SAXON_NAMESPACE + * "write" XSLT_XALAN_NAMESPACE + * "document" XSLT_XT_NAMESPACE + * "document" XSLT_NAMESPACE (from the abandoned old working + * draft of XSLT 1.1) + * (in libexslt/common.c) + * "document" in EXSLT_COMMON_NAMESPACE + */ +#ifdef XSLT_REFACTORED + comp = (xsltStyleItemDocumentPtr) + xsltNewStylePreComp(style, XSLT_FUNC_DOCUMENT); +#else + comp = xsltNewStylePreComp(style, XSLT_FUNC_DOCUMENT); +#endif + + if (comp == NULL) + return (NULL); + comp->inst = inst; + comp->ver11 = 0; + + if (xmlStrEqual(inst->name, (const xmlChar *) "output")) { +#ifdef WITH_XSLT_DEBUG_EXTRA + xsltGenericDebug(xsltGenericDebugContext, + "Found saxon:output extension\n"); +#endif + /* + * The element "output" is in the namespace XSLT_SAXON_NAMESPACE + * (http://icl.com/saxon) + * The @file is in no namespace; it is an AVT. + * (http://www.computerwizards.com/saxon/doc/extensions.html#saxon:output) + * + * TODO: Do we need not to check the namespace here? + */ + filename = xsltEvalStaticAttrValueTemplate(style, inst, + (const xmlChar *)"file", + NULL, &comp->has_filename); + } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) { +#ifdef WITH_XSLT_DEBUG_EXTRA + xsltGenericDebug(xsltGenericDebugContext, + "Found xalan:write extension\n"); +#endif + /* the filename need to be interpreted */ + /* + * TODO: Is "filename need to be interpreted" meant to be a todo? + * Where will be the filename of xalan:write be processed? + * + * TODO: Do we need not to check the namespace here? + * The extension ns is "http://xml.apache.org/xalan/redirect". + * See http://xml.apache.org/xalan-j/extensionslib.html. + */ + } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) { + if (inst->ns != NULL) { + if (xmlStrEqual(inst->ns->href, XSLT_NAMESPACE)) { + /* + * Mark the instruction as being of + * XSLT version 1.1 (abandoned). + */ + comp->ver11 = 1; +#ifdef WITH_XSLT_DEBUG_EXTRA + xsltGenericDebug(xsltGenericDebugContext, + "Found xslt11:document construct\n"); +#endif + } else { + if (xmlStrEqual(inst->ns->href, + (const xmlChar *)"http://exslt.org/common")) { + /* EXSLT. */ +#ifdef WITH_XSLT_DEBUG_EXTRA + xsltGenericDebug(xsltGenericDebugContext, + "Found exslt:document extension\n"); +#endif + } else if (xmlStrEqual(inst->ns->href, XSLT_XT_NAMESPACE)) { + /* James Clark's XT. */ +#ifdef WITH_XSLT_DEBUG_EXTRA + xsltGenericDebug(xsltGenericDebugContext, + "Found xt:document extension\n"); +#endif + } + } + } + /* + * The element "document" is used in conjunction with the + * following namespaces: + * + * 1) XSLT_NAMESPACE (http://www.w3.org/1999/XSL/Transform version 1.1) + * + * + * TODO: is @href is an AVT? + * + * In all cases @href is in no namespace. + */ + filename = xsltEvalStaticAttrValueTemplate(style, inst, + (const xmlChar *)"href", NULL, &comp->has_filename); + } + if (!comp->has_filename) { + goto error; + } + comp->filename = filename; + +error: + return ((xsltElemPreCompPtr) comp); +} + +/************************************************************************ + * * + * Most of the XSLT-1.0 transformations * + * * + ************************************************************************/ + +/** + * xsltSortComp: + * @style: the XSLT stylesheet + * @inst: the xslt sort node + * + * Process the xslt sort node on the source node + */ +static void +xsltSortComp(xsltStylesheetPtr style, xmlNodePtr inst) { +#ifdef XSLT_REFACTORED + xsltStyleItemSortPtr comp; +#else + xsltStylePreCompPtr comp; +#endif + if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) + return; + +#ifdef XSLT_REFACTORED + comp = (xsltStyleItemSortPtr) xsltNewStylePreComp(style, XSLT_FUNC_SORT); +#else + comp = xsltNewStylePreComp(style, XSLT_FUNC_SORT); +#endif + + if (comp == NULL) + return; + inst->psvi = comp; + comp->inst = inst; + + comp->stype = xsltEvalStaticAttrValueTemplate(style, inst, + (const xmlChar *)"data-type", + NULL, &comp->has_stype); + if (comp->stype != NULL) { + if (xmlStrEqual(comp->stype, (const xmlChar *) "text")) + comp->number = 0; + else if (xmlStrEqual(comp->stype, (const xmlChar *) "number")) + comp->number = 1; + else { + xsltTransformError(NULL, style, inst, + "xsltSortComp: no support for data-type = %s\n", comp->stype); + comp->number = 0; /* use default */ + if (style != NULL) style->warnings++; + } + } + comp->order = xsltEvalStaticAttrValueTemplate(style, inst, + (const xmlChar *)"order", + NULL, &comp->has_order); + if (comp->order != NULL) { + if (xmlStrEqual(comp->order, (const xmlChar *) "ascending")) + comp->descending = 0; + else if (xmlStrEqual(comp->order, (const xmlChar *) "descending")) + comp->descending = 1; + else { + xsltTransformError(NULL, style, inst, + "xsltSortComp: invalid value %s for order\n", comp->order); + comp->descending = 0; /* use default */ + if (style != NULL) style->warnings++; + } + } + comp->case_order = xsltEvalStaticAttrValueTemplate(style, inst, + (const xmlChar *)"case-order", + NULL, &comp->has_use); + if (comp->case_order != NULL) { + if (xmlStrEqual(comp->case_order, (const xmlChar *) "upper-first")) + comp->lower_first = 0; + else if (xmlStrEqual(comp->case_order, (const xmlChar *) "lower-first")) + comp->lower_first = 1; + else { + xsltTransformError(NULL, style, inst, + "xsltSortComp: invalid value %s for order\n", comp->order); + comp->lower_first = 0; /* use default */ + if (style != NULL) style->warnings++; + } + } + + comp->lang = xsltEvalStaticAttrValueTemplate(style, inst, + (const xmlChar *)"lang", + NULL, &comp->has_lang); + + comp->select = xsltGetCNsProp(style, inst,(const xmlChar *)"select", XSLT_NAMESPACE); + if (comp->select == NULL) { + /* + * The default value of the select attribute is ., which will + * cause the string-value of the current node to be used as + * the sort key. + */ + comp->select = xmlDictLookup(style->dict, BAD_CAST ".", 1); + } + comp->comp = xsltXPathCompile(style, comp->select); + if (comp->comp == NULL) { + xsltTransformError(NULL, style, inst, + "xsltSortComp: could not compile select expression '%s'\n", + comp->select); + if (style != NULL) style->errors++; + } + if (inst->children != NULL) { + xsltTransformError(NULL, style, inst, + "xsl:sort : is not empty\n"); + if (style != NULL) style->errors++; + } +} + +/** + * xsltCopyComp: + * @style: the XSLT stylesheet + * @inst: the xslt copy node + * + * Process the xslt copy node on the source node + */ +static void +xsltCopyComp(xsltStylesheetPtr style, xmlNodePtr inst) { +#ifdef XSLT_REFACTORED + xsltStyleItemCopyPtr comp; +#else + xsltStylePreCompPtr comp; +#endif + + if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) + return; +#ifdef XSLT_REFACTORED + comp = (xsltStyleItemCopyPtr) xsltNewStylePreComp(style, XSLT_FUNC_COPY); +#else + comp = xsltNewStylePreComp(style, XSLT_FUNC_COPY); +#endif + + if (comp == NULL) + return; + inst->psvi = comp; + comp->inst = inst; + + + comp->use = xsltGetCNsProp(style, inst, (const xmlChar *)"use-attribute-sets", + XSLT_NAMESPACE); + if (comp->use == NULL) + comp->has_use = 0; + else + comp->has_use = 1; +} + +#ifdef XSLT_REFACTORED + /* Enable if ever needed for xsl:text. */ +#else +/** + * xsltTextComp: + * @style: an XSLT compiled stylesheet + * @inst: the xslt text node + * + * TODO: This function is obsolete, since xsl:text won't + * be compiled, but removed from the tree. + * + * Process the xslt text node on the source node + */ +static void +xsltTextComp(xsltStylesheetPtr style, xmlNodePtr inst) { +#ifdef XSLT_REFACTORED + xsltStyleItemTextPtr comp; +#else + xsltStylePreCompPtr comp; +#endif + const xmlChar *prop; + + if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) + return; + +#ifdef XSLT_REFACTORED + comp = (xsltStyleItemTextPtr) xsltNewStylePreComp(style, XSLT_FUNC_TEXT); +#else + comp = xsltNewStylePreComp(style, XSLT_FUNC_TEXT); +#endif + if (comp == NULL) + return; + inst->psvi = comp; + comp->inst = inst; + comp->noescape = 0; + + prop = xsltGetCNsProp(style, inst, + (const xmlChar *)"disable-output-escaping", + XSLT_NAMESPACE); + if (prop != NULL) { + if (xmlStrEqual(prop, (const xmlChar *)"yes")) { + comp->noescape = 1; + } else if (!xmlStrEqual(prop, + (const xmlChar *)"no")){ + xsltTransformError(NULL, style, inst, + "xsl:text: disable-output-escaping allows only yes or no\n"); + if (style != NULL) style->warnings++; + } + } +} +#endif /* else of XSLT_REFACTORED */ + +/** + * xsltElementComp: + * @style: an XSLT compiled stylesheet + * @inst: the xslt element node + * + * Process the xslt element node on the source node + */ +static void +xsltElementComp(xsltStylesheetPtr style, xmlNodePtr inst) { +#ifdef XSLT_REFACTORED + xsltStyleItemElementPtr comp; +#else + xsltStylePreCompPtr comp; +#endif + + /* + * + * + * + */ + if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) + return; + +#ifdef XSLT_REFACTORED + comp = (xsltStyleItemElementPtr) xsltNewStylePreComp(style, XSLT_FUNC_ELEMENT); +#else + comp = xsltNewStylePreComp(style, XSLT_FUNC_ELEMENT); +#endif + + if (comp == NULL) + return; + inst->psvi = comp; + comp->inst = inst; + + /* + * Attribute "name". + */ + /* + * TODO: Precompile the AVT. See bug #344894. + */ + comp->name = xsltEvalStaticAttrValueTemplate(style, inst, + (const xmlChar *)"name", NULL, &comp->has_name); + if (! comp->has_name) { + xsltTransformError(NULL, style, inst, + "xsl:element: The attribute 'name' is missing.\n"); + style->errors++; + goto error; + } + /* + * Attribute "namespace". + */ + /* + * TODO: Precompile the AVT. See bug #344894. + */ + comp->ns = xsltEvalStaticAttrValueTemplate(style, inst, + (const xmlChar *)"namespace", NULL, &comp->has_ns); + + if (comp->name != NULL) { + if (xmlValidateQName(comp->name, 0)) { + xsltTransformError(NULL, style, inst, + "xsl:element: The value '%s' of the attribute 'name' is " + "not a valid QName.\n", comp->name); + style->errors++; + } else { + const xmlChar *prefix = NULL, *name; + + name = xsltSplitQName(style->dict, comp->name, &prefix); + if (comp->has_ns == 0) { + xmlNsPtr ns; + + /* + * SPEC XSLT 1.0: + * "If the namespace attribute is not present, then the QName is + * expanded into an expanded-name using the namespace declarations + * in effect for the xsl:element element, including any default + * namespace declaration. + */ + ns = xmlSearchNs(inst->doc, inst, prefix); + if (ns != NULL) { + comp->ns = xmlDictLookup(style->dict, ns->href, -1); + comp->has_ns = 1; +#ifdef XSLT_REFACTORED + comp->nsPrefix = prefix; + comp->name = name; +#else + (void)name; /* Suppress unused variable warning. */ +#endif + } else if (prefix != NULL) { + xsltTransformError(NULL, style, inst, + "xsl:element: The prefixed QName '%s' " + "has no namespace binding in scope in the " + "stylesheet; this is an error, since the namespace was " + "not specified by the instruction itself.\n", comp->name); + style->errors++; + } + } + if ((prefix != NULL) && + (!xmlStrncasecmp(prefix, (xmlChar *)"xml", 3))) + { + /* + * Mark is to be skipped. + */ + comp->has_name = 0; + } + } + } + /* + * Attribute "use-attribute-sets", + */ + comp->use = xsltEvalStaticAttrValueTemplate(style, inst, + (const xmlChar *)"use-attribute-sets", + NULL, &comp->has_use); + +error: + return; +} + +/** + * xsltAttributeComp: + * @style: an XSLT compiled stylesheet + * @inst: the xslt attribute node + * + * Process the xslt attribute node on the source node + */ +static void +xsltAttributeComp(xsltStylesheetPtr style, xmlNodePtr inst) { +#ifdef XSLT_REFACTORED + xsltStyleItemAttributePtr comp; +#else + xsltStylePreCompPtr comp; +#endif + + /* + * + * + * + */ + if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) + return; + +#ifdef XSLT_REFACTORED + comp = (xsltStyleItemAttributePtr) xsltNewStylePreComp(style, + XSLT_FUNC_ATTRIBUTE); +#else + comp = xsltNewStylePreComp(style, XSLT_FUNC_ATTRIBUTE); +#endif + + if (comp == NULL) + return; + inst->psvi = comp; + comp->inst = inst; + + /* + * Attribute "name". + */ + /* + * TODO: Precompile the AVT. See bug #344894. + */ + comp->name = xsltEvalStaticAttrValueTemplate(style, inst, + (const xmlChar *)"name", + NULL, &comp->has_name); + if (! comp->has_name) { + xsltTransformError(NULL, style, inst, + "XSLT-attribute: The attribute 'name' is missing.\n"); + style->errors++; + return; + } + /* + * Attribute "namespace". + */ + /* + * TODO: Precompile the AVT. See bug #344894. + */ + comp->ns = xsltEvalStaticAttrValueTemplate(style, inst, + (const xmlChar *)"namespace", + NULL, &comp->has_ns); + + if (comp->name != NULL) { + if (xmlValidateQName(comp->name, 0)) { + xsltTransformError(NULL, style, inst, + "xsl:attribute: The value '%s' of the attribute 'name' is " + "not a valid QName.\n", comp->name); + style->errors++; + } else if (xmlStrEqual(comp->name, BAD_CAST "xmlns")) { + xsltTransformError(NULL, style, inst, + "xsl:attribute: The attribute name 'xmlns' is not allowed.\n"); + style->errors++; + } else { + const xmlChar *prefix = NULL, *name; + + name = xsltSplitQName(style->dict, comp->name, &prefix); + if (prefix != NULL) { + if (comp->has_ns == 0) { + xmlNsPtr ns; + + /* + * SPEC XSLT 1.0: + * "If the namespace attribute is not present, then the + * QName is expanded into an expanded-name using the + * namespace declarations in effect for the xsl:element + * element, including any default namespace declaration. + */ + ns = xmlSearchNs(inst->doc, inst, prefix); + if (ns != NULL) { + comp->ns = xmlDictLookup(style->dict, ns->href, -1); + comp->has_ns = 1; +#ifdef XSLT_REFACTORED + comp->nsPrefix = prefix; + comp->name = name; +#else + (void)name; /* Suppress unused variable warning. */ +#endif + } else { + xsltTransformError(NULL, style, inst, + "xsl:attribute: The prefixed QName '%s' " + "has no namespace binding in scope in the " + "stylesheet; this is an error, since the " + "namespace was not specified by the instruction " + "itself.\n", comp->name); + style->errors++; + } + } + } + } + } +} + +/** + * xsltCommentComp: + * @style: an XSLT compiled stylesheet + * @inst: the xslt comment node + * + * Process the xslt comment node on the source node + */ +static void +xsltCommentComp(xsltStylesheetPtr style, xmlNodePtr inst) { +#ifdef XSLT_REFACTORED + xsltStyleItemCommentPtr comp; +#else + xsltStylePreCompPtr comp; +#endif + + if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) + return; + +#ifdef XSLT_REFACTORED + comp = (xsltStyleItemCommentPtr) xsltNewStylePreComp(style, XSLT_FUNC_COMMENT); +#else + comp = xsltNewStylePreComp(style, XSLT_FUNC_COMMENT); +#endif + + if (comp == NULL) + return; + inst->psvi = comp; + comp->inst = inst; +} + +/** + * xsltProcessingInstructionComp: + * @style: an XSLT compiled stylesheet + * @inst: the xslt processing-instruction node + * + * Process the xslt processing-instruction node on the source node + */ +static void +xsltProcessingInstructionComp(xsltStylesheetPtr style, xmlNodePtr inst) { +#ifdef XSLT_REFACTORED + xsltStyleItemPIPtr comp; +#else + xsltStylePreCompPtr comp; +#endif + + if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) + return; + +#ifdef XSLT_REFACTORED + comp = (xsltStyleItemPIPtr) xsltNewStylePreComp(style, XSLT_FUNC_PI); +#else + comp = xsltNewStylePreComp(style, XSLT_FUNC_PI); +#endif + + if (comp == NULL) + return; + inst->psvi = comp; + comp->inst = inst; + + comp->name = xsltEvalStaticAttrValueTemplate(style, inst, + (const xmlChar *)"name", + XSLT_NAMESPACE, &comp->has_name); +} + +/** + * xsltCopyOfComp: + * @style: an XSLT compiled stylesheet + * @inst: the xslt copy-of node + * + * Process the xslt copy-of node on the source node + */ +static void +xsltCopyOfComp(xsltStylesheetPtr style, xmlNodePtr inst) { +#ifdef XSLT_REFACTORED + xsltStyleItemCopyOfPtr comp; +#else + xsltStylePreCompPtr comp; +#endif + + if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) + return; + +#ifdef XSLT_REFACTORED + comp = (xsltStyleItemCopyOfPtr) xsltNewStylePreComp(style, XSLT_FUNC_COPYOF); +#else + comp = xsltNewStylePreComp(style, XSLT_FUNC_COPYOF); +#endif + + if (comp == NULL) + return; + inst->psvi = comp; + comp->inst = inst; + + comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", + XSLT_NAMESPACE); + if (comp->select == NULL) { + xsltTransformError(NULL, style, inst, + "xsl:copy-of : select is missing\n"); + if (style != NULL) style->errors++; + return; + } + comp->comp = xsltXPathCompile(style, comp->select); + if (comp->comp == NULL) { + xsltTransformError(NULL, style, inst, + "xsl:copy-of : could not compile select expression '%s'\n", + comp->select); + if (style != NULL) style->errors++; + } +} + +/** + * xsltValueOfComp: + * @style: an XSLT compiled stylesheet + * @inst: the xslt value-of node + * + * Process the xslt value-of node on the source node + */ +static void +xsltValueOfComp(xsltStylesheetPtr style, xmlNodePtr inst) { +#ifdef XSLT_REFACTORED + xsltStyleItemValueOfPtr comp; +#else + xsltStylePreCompPtr comp; +#endif + const xmlChar *prop; + + if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) + return; + +#ifdef XSLT_REFACTORED + comp = (xsltStyleItemValueOfPtr) xsltNewStylePreComp(style, XSLT_FUNC_VALUEOF); +#else + comp = xsltNewStylePreComp(style, XSLT_FUNC_VALUEOF); +#endif + + if (comp == NULL) + return; + inst->psvi = comp; + comp->inst = inst; + + prop = xsltGetCNsProp(style, inst, + (const xmlChar *)"disable-output-escaping", + XSLT_NAMESPACE); + if (prop != NULL) { + if (xmlStrEqual(prop, (const xmlChar *)"yes")) { + comp->noescape = 1; + } else if (!xmlStrEqual(prop, + (const xmlChar *)"no")){ + xsltTransformError(NULL, style, inst, +"xsl:value-of : disable-output-escaping allows only yes or no\n"); + if (style != NULL) style->warnings++; + } + } + comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", + XSLT_NAMESPACE); + if (comp->select == NULL) { + xsltTransformError(NULL, style, inst, + "xsl:value-of : select is missing\n"); + if (style != NULL) style->errors++; + return; + } + comp->comp = xsltXPathCompile(style, comp->select); + if (comp->comp == NULL) { + xsltTransformError(NULL, style, inst, + "xsl:value-of : could not compile select expression '%s'\n", + comp->select); + if (style != NULL) style->errors++; + } +} + +static void +xsltGetQNameProperty(xsltStylesheetPtr style, xmlNodePtr inst, + const xmlChar *propName, + int mandatory, + int *hasProp, const xmlChar **nsName, + const xmlChar** localName) +{ + const xmlChar *prop; + + if (nsName) + *nsName = NULL; + if (localName) + *localName = NULL; + if (hasProp) + *hasProp = 0; + + prop = xsltGetCNsProp(style, inst, propName, XSLT_NAMESPACE); + if (prop == NULL) { + if (mandatory) { + xsltTransformError(NULL, style, inst, + "The attribute '%s' is missing.\n", propName); + style->errors++; + return; + } + } else { + const xmlChar *URI; + + if (xmlValidateQName(prop, 0)) { + xsltTransformError(NULL, style, inst, + "The value '%s' of the attribute " + "'%s' is not a valid QName.\n", prop, propName); + style->errors++; + return; + } else { + /* + * @prop will be in the string dict afterwards, @URI not. + */ + URI = xsltGetQNameURI2(style, inst, &prop); + if (prop == NULL) { + style->errors++; + } else { + if (localName) + *localName = prop; + if (hasProp) + *hasProp = 1; + if (URI != NULL) { + /* + * Fixes bug #308441: Put the ns-name in the dict + * in order to pointer compare names during XPath's + * variable lookup. + */ + if (nsName) + *nsName = xmlDictLookup(style->dict, URI, -1); + /* comp->has_ns = 1; */ + } + } + } + } + return; +} + +/** + * xsltWithParamComp: + * @style: an XSLT compiled stylesheet + * @inst: the xslt with-param node + * + * Process the xslt with-param node on the source node + * Allowed parents: xsl:call-template, xsl:apply-templates. + * + * + * + */ +static void +xsltWithParamComp(xsltStylesheetPtr style, xmlNodePtr inst) { +#ifdef XSLT_REFACTORED + xsltStyleItemWithParamPtr comp; +#else + xsltStylePreCompPtr comp; +#endif + + if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) + return; + +#ifdef XSLT_REFACTORED + comp = (xsltStyleItemWithParamPtr) xsltNewStylePreComp(style, XSLT_FUNC_WITHPARAM); +#else + comp = xsltNewStylePreComp(style, XSLT_FUNC_WITHPARAM); +#endif + + if (comp == NULL) + return; + inst->psvi = comp; + comp->inst = inst; + + /* + * Attribute "name". + */ + xsltGetQNameProperty(style, inst, BAD_CAST "name", + 1, &(comp->has_name), &(comp->ns), &(comp->name)); + if (comp->ns) + comp->has_ns = 1; + /* + * Attribute "select". + */ + comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", + XSLT_NAMESPACE); + if (comp->select != NULL) { + comp->comp = xsltXPathCompile(style, comp->select); + if (comp->comp == NULL) { + xsltTransformError(NULL, style, inst, + "XSLT-with-param: Failed to compile select " + "expression '%s'\n", comp->select); + style->errors++; + } + if (inst->children != NULL) { + xsltTransformError(NULL, style, inst, + "XSLT-with-param: The content should be empty since " + "the attribute select is present.\n"); + style->warnings++; + } + } +} + +/** + * xsltNumberComp: + * @style: an XSLT compiled stylesheet + * @cur: the xslt number node + * + * Process the xslt number node on the source node + */ +static void +xsltNumberComp(xsltStylesheetPtr style, xmlNodePtr cur) { +#ifdef XSLT_REFACTORED + xsltStyleItemNumberPtr comp; +#else + xsltStylePreCompPtr comp; +#endif + const xmlChar *prop; + + if ((style == NULL) || (cur == NULL) || (cur->type != XML_ELEMENT_NODE)) + return; + +#ifdef XSLT_REFACTORED + comp = (xsltStyleItemNumberPtr) xsltNewStylePreComp(style, XSLT_FUNC_NUMBER); +#else + comp = xsltNewStylePreComp(style, XSLT_FUNC_NUMBER); +#endif + + if (comp == NULL) + return; + cur->psvi = comp; + + comp->numdata.doc = cur->doc; + comp->numdata.node = cur; + comp->numdata.value = xsltGetCNsProp(style, cur, (const xmlChar *)"value", + XSLT_NAMESPACE); + + prop = xsltEvalStaticAttrValueTemplate(style, cur, + (const xmlChar *)"format", + XSLT_NAMESPACE, &comp->numdata.has_format); + if (comp->numdata.has_format == 0) { + comp->numdata.format = xmlDictLookup(style->dict, BAD_CAST "" , 0); + } else { + comp->numdata.format = prop; + } + + comp->numdata.count = xsltGetCNsProp(style, cur, (const xmlChar *)"count", + XSLT_NAMESPACE); + comp->numdata.from = xsltGetCNsProp(style, cur, (const xmlChar *)"from", + XSLT_NAMESPACE); + + prop = xsltGetCNsProp(style, cur, (const xmlChar *)"count", XSLT_NAMESPACE); + if (prop != NULL) { + comp->numdata.countPat = xsltCompilePattern(prop, cur->doc, cur, style, + NULL); + } + + prop = xsltGetCNsProp(style, cur, (const xmlChar *)"from", XSLT_NAMESPACE); + if (prop != NULL) { + comp->numdata.fromPat = xsltCompilePattern(prop, cur->doc, cur, style, + NULL); + } + + prop = xsltGetCNsProp(style, cur, (const xmlChar *)"level", XSLT_NAMESPACE); + if (prop != NULL) { + if (xmlStrEqual(prop, BAD_CAST("single")) || + xmlStrEqual(prop, BAD_CAST("multiple")) || + xmlStrEqual(prop, BAD_CAST("any"))) { + comp->numdata.level = prop; + } else { + xsltTransformError(NULL, style, cur, + "xsl:number : invalid value %s for level\n", prop); + if (style != NULL) style->warnings++; + } + } + + prop = xsltGetCNsProp(style, cur, (const xmlChar *)"lang", XSLT_NAMESPACE); + if (prop != NULL) { + xsltTransformError(NULL, style, cur, + "xsl:number : lang attribute not implemented\n"); + XSLT_TODO; /* xsl:number lang attribute */ + } + + prop = xsltGetCNsProp(style, cur, (const xmlChar *)"letter-value", XSLT_NAMESPACE); + if (prop != NULL) { + if (xmlStrEqual(prop, BAD_CAST("alphabetic"))) { + xsltTransformError(NULL, style, cur, + "xsl:number : letter-value 'alphabetic' not implemented\n"); + if (style != NULL) style->warnings++; + XSLT_TODO; /* xsl:number letter-value attribute alphabetic */ + } else if (xmlStrEqual(prop, BAD_CAST("traditional"))) { + xsltTransformError(NULL, style, cur, + "xsl:number : letter-value 'traditional' not implemented\n"); + if (style != NULL) style->warnings++; + XSLT_TODO; /* xsl:number letter-value attribute traditional */ + } else { + xsltTransformError(NULL, style, cur, + "xsl:number : invalid value %s for letter-value\n", prop); + if (style != NULL) style->warnings++; + } + } + + prop = xsltGetCNsProp(style, cur, (const xmlChar *)"grouping-separator", + XSLT_NAMESPACE); + if (prop != NULL) { + comp->numdata.groupingCharacterLen = xmlStrlen(prop); + comp->numdata.groupingCharacter = + xsltGetUTF8Char(prop, &(comp->numdata.groupingCharacterLen)); + if (comp->numdata.groupingCharacter < 0) + comp->numdata.groupingCharacter = 0; + } + + prop = xsltGetCNsProp(style, cur, (const xmlChar *)"grouping-size", XSLT_NAMESPACE); + if (prop != NULL) { + sscanf((char *)prop, "%d", &comp->numdata.digitsPerGroup); + } else { + comp->numdata.groupingCharacter = 0; + } + + /* Set default values */ + if (comp->numdata.value == NULL) { + if (comp->numdata.level == NULL) { + comp->numdata.level = xmlDictLookup(style->dict, + BAD_CAST"single", 6); + } + } + +} + +/** + * xsltApplyImportsComp: + * @style: an XSLT compiled stylesheet + * @inst: the xslt apply-imports node + * + * Process the xslt apply-imports node on the source node + */ +static void +xsltApplyImportsComp(xsltStylesheetPtr style, xmlNodePtr inst) { +#ifdef XSLT_REFACTORED + xsltStyleItemApplyImportsPtr comp; +#else + xsltStylePreCompPtr comp; +#endif + + if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) + return; + +#ifdef XSLT_REFACTORED + comp = (xsltStyleItemApplyImportsPtr) xsltNewStylePreComp(style, XSLT_FUNC_APPLYIMPORTS); +#else + comp = xsltNewStylePreComp(style, XSLT_FUNC_APPLYIMPORTS); +#endif + + if (comp == NULL) + return; + inst->psvi = comp; + comp->inst = inst; +} + +/** + * xsltCallTemplateComp: + * @style: an XSLT compiled stylesheet + * @inst: the xslt call-template node + * + * Process the xslt call-template node on the source node + */ +static void +xsltCallTemplateComp(xsltStylesheetPtr style, xmlNodePtr inst) { +#ifdef XSLT_REFACTORED + xsltStyleItemCallTemplatePtr comp; +#else + xsltStylePreCompPtr comp; +#endif + + if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) + return; + +#ifdef XSLT_REFACTORED + comp = (xsltStyleItemCallTemplatePtr) + xsltNewStylePreComp(style, XSLT_FUNC_CALLTEMPLATE); +#else + comp = xsltNewStylePreComp(style, XSLT_FUNC_CALLTEMPLATE); +#endif + + if (comp == NULL) + return; + inst->psvi = comp; + comp->inst = inst; + + /* + * Attribute "name". + */ + xsltGetQNameProperty(style, inst, BAD_CAST "name", + 1, &(comp->has_name), &(comp->ns), &(comp->name)); + if (comp->ns) + comp->has_ns = 1; +} + +/** + * xsltApplyTemplatesComp: + * @style: an XSLT compiled stylesheet + * @inst: the apply-templates node + * + * Process the apply-templates node on the source node + */ +static void +xsltApplyTemplatesComp(xsltStylesheetPtr style, xmlNodePtr inst) { +#ifdef XSLT_REFACTORED + xsltStyleItemApplyTemplatesPtr comp; +#else + xsltStylePreCompPtr comp; +#endif + + if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) + return; + +#ifdef XSLT_REFACTORED + comp = (xsltStyleItemApplyTemplatesPtr) + xsltNewStylePreComp(style, XSLT_FUNC_APPLYTEMPLATES); +#else + comp = xsltNewStylePreComp(style, XSLT_FUNC_APPLYTEMPLATES); +#endif + + if (comp == NULL) + return; + inst->psvi = comp; + comp->inst = inst; + + /* + * Attribute "mode". + */ + xsltGetQNameProperty(style, inst, BAD_CAST "mode", + 0, NULL, &(comp->modeURI), &(comp->mode)); + /* + * Attribute "select". + */ + comp->select = xsltGetCNsProp(style, inst, BAD_CAST "select", + XSLT_NAMESPACE); + if (comp->select != NULL) { + comp->comp = xsltXPathCompile(style, comp->select); + if (comp->comp == NULL) { + xsltTransformError(NULL, style, inst, + "XSLT-apply-templates: could not compile select " + "expression '%s'\n", comp->select); + style->errors++; + } + } + /* TODO: handle (or skip) the xsl:sort and xsl:with-param */ +} + +/** + * xsltChooseComp: + * @style: an XSLT compiled stylesheet + * @inst: the xslt choose node + * + * Process the xslt choose node on the source node + */ +static void +xsltChooseComp(xsltStylesheetPtr style, xmlNodePtr inst) { +#ifdef XSLT_REFACTORED + xsltStyleItemChoosePtr comp; +#else + xsltStylePreCompPtr comp; +#endif + + if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) + return; + +#ifdef XSLT_REFACTORED + comp = (xsltStyleItemChoosePtr) + xsltNewStylePreComp(style, XSLT_FUNC_CHOOSE); +#else + comp = xsltNewStylePreComp(style, XSLT_FUNC_CHOOSE); +#endif + + if (comp == NULL) + return; + inst->psvi = comp; + comp->inst = inst; +} + +/** + * xsltIfComp: + * @style: an XSLT compiled stylesheet + * @inst: the xslt if node + * + * Process the xslt if node on the source node + */ +static void +xsltIfComp(xsltStylesheetPtr style, xmlNodePtr inst) { +#ifdef XSLT_REFACTORED + xsltStyleItemIfPtr comp; +#else + xsltStylePreCompPtr comp; +#endif + + if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) + return; + +#ifdef XSLT_REFACTORED + comp = (xsltStyleItemIfPtr) + xsltNewStylePreComp(style, XSLT_FUNC_IF); +#else + comp = xsltNewStylePreComp(style, XSLT_FUNC_IF); +#endif + + if (comp == NULL) + return; + inst->psvi = comp; + comp->inst = inst; + + comp->test = xsltGetCNsProp(style, inst, (const xmlChar *)"test", XSLT_NAMESPACE); + if (comp->test == NULL) { + xsltTransformError(NULL, style, inst, + "xsl:if : test is not defined\n"); + if (style != NULL) style->errors++; + return; + } + comp->comp = xsltXPathCompile(style, comp->test); + if (comp->comp == NULL) { + xsltTransformError(NULL, style, inst, + "xsl:if : could not compile test expression '%s'\n", + comp->test); + if (style != NULL) style->errors++; + } +} + +/** + * xsltWhenComp: + * @style: an XSLT compiled stylesheet + * @inst: the xslt if node + * + * Process the xslt if node on the source node + */ +static void +xsltWhenComp(xsltStylesheetPtr style, xmlNodePtr inst) { +#ifdef XSLT_REFACTORED + xsltStyleItemWhenPtr comp; +#else + xsltStylePreCompPtr comp; +#endif + + if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) + return; + +#ifdef XSLT_REFACTORED + comp = (xsltStyleItemWhenPtr) + xsltNewStylePreComp(style, XSLT_FUNC_WHEN); +#else + comp = xsltNewStylePreComp(style, XSLT_FUNC_WHEN); +#endif + + if (comp == NULL) + return; + inst->psvi = comp; + comp->inst = inst; + + comp->test = xsltGetCNsProp(style, inst, (const xmlChar *)"test", XSLT_NAMESPACE); + if (comp->test == NULL) { + xsltTransformError(NULL, style, inst, + "xsl:when : test is not defined\n"); + if (style != NULL) style->errors++; + return; + } + comp->comp = xsltXPathCompile(style, comp->test); + if (comp->comp == NULL) { + xsltTransformError(NULL, style, inst, + "xsl:when : could not compile test expression '%s'\n", + comp->test); + if (style != NULL) style->errors++; + } +} + +/** + * xsltForEachComp: + * @style: an XSLT compiled stylesheet + * @inst: the xslt for-each node + * + * Process the xslt for-each node on the source node + */ +static void +xsltForEachComp(xsltStylesheetPtr style, xmlNodePtr inst) { +#ifdef XSLT_REFACTORED + xsltStyleItemForEachPtr comp; +#else + xsltStylePreCompPtr comp; +#endif + + if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) + return; + +#ifdef XSLT_REFACTORED + comp = (xsltStyleItemForEachPtr) + xsltNewStylePreComp(style, XSLT_FUNC_FOREACH); +#else + comp = xsltNewStylePreComp(style, XSLT_FUNC_FOREACH); +#endif + + if (comp == NULL) + return; + inst->psvi = comp; + comp->inst = inst; + + comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", + XSLT_NAMESPACE); + if (comp->select == NULL) { + xsltTransformError(NULL, style, inst, + "xsl:for-each : select is missing\n"); + if (style != NULL) style->errors++; + } else { + comp->comp = xsltXPathCompile(style, comp->select); + if (comp->comp == NULL) { + xsltTransformError(NULL, style, inst, + "xsl:for-each : could not compile select expression '%s'\n", + comp->select); + if (style != NULL) style->errors++; + } + } + /* TODO: handle and skip the xsl:sort */ +} + +/** + * xsltVariableComp: + * @style: an XSLT compiled stylesheet + * @inst: the xslt variable node + * + * Process the xslt variable node on the source node + */ +static void +xsltVariableComp(xsltStylesheetPtr style, xmlNodePtr inst) { +#ifdef XSLT_REFACTORED + xsltStyleItemVariablePtr comp; +#else + xsltStylePreCompPtr comp; +#endif + + if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) + return; + +#ifdef XSLT_REFACTORED + comp = (xsltStyleItemVariablePtr) + xsltNewStylePreComp(style, XSLT_FUNC_VARIABLE); +#else + comp = xsltNewStylePreComp(style, XSLT_FUNC_VARIABLE); +#endif + + if (comp == NULL) + return; + + inst->psvi = comp; + comp->inst = inst; + /* + * The full template resolution can be done statically + */ + + /* + * Attribute "name". + */ + xsltGetQNameProperty(style, inst, BAD_CAST "name", + 1, &(comp->has_name), &(comp->ns), &(comp->name)); + if (comp->ns) + comp->has_ns = 1; + /* + * Attribute "select". + */ + comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", + XSLT_NAMESPACE); + if (comp->select != NULL) { +#ifndef XSLT_REFACTORED + xmlNodePtr cur; +#endif + comp->comp = xsltXPathCompile(style, comp->select); + if (comp->comp == NULL) { + xsltTransformError(NULL, style, inst, + "XSLT-variable: Failed to compile the XPath expression '%s'.\n", + comp->select); + style->errors++; + } +#ifdef XSLT_REFACTORED + if (inst->children != NULL) { + xsltTransformError(NULL, style, inst, + "XSLT-variable: There must be no child nodes, since the " + "attribute 'select' was specified.\n"); + style->errors++; + } +#else + for (cur = inst->children; cur != NULL; cur = cur->next) { + if (cur->type != XML_COMMENT_NODE && + (cur->type != XML_TEXT_NODE || !xsltIsBlank(cur->content))) + { + xsltTransformError(NULL, style, inst, + "XSLT-variable: There must be no child nodes, since the " + "attribute 'select' was specified.\n"); + style->errors++; + } + } +#endif + } +} + +/** + * xsltParamComp: + * @style: an XSLT compiled stylesheet + * @inst: the xslt param node + * + * Process the xslt param node on the source node + */ +static void +xsltParamComp(xsltStylesheetPtr style, xmlNodePtr inst) { +#ifdef XSLT_REFACTORED + xsltStyleItemParamPtr comp; +#else + xsltStylePreCompPtr comp; +#endif + + if ((style == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) + return; + +#ifdef XSLT_REFACTORED + comp = (xsltStyleItemParamPtr) + xsltNewStylePreComp(style, XSLT_FUNC_PARAM); +#else + comp = xsltNewStylePreComp(style, XSLT_FUNC_PARAM); +#endif + + if (comp == NULL) + return; + inst->psvi = comp; + comp->inst = inst; + + /* + * Attribute "name". + */ + xsltGetQNameProperty(style, inst, BAD_CAST "name", + 1, &(comp->has_name), &(comp->ns), &(comp->name)); + if (comp->ns) + comp->has_ns = 1; + /* + * Attribute "select". + */ + comp->select = xsltGetCNsProp(style, inst, (const xmlChar *)"select", + XSLT_NAMESPACE); + if (comp->select != NULL) { + comp->comp = xsltXPathCompile(style, comp->select); + if (comp->comp == NULL) { + xsltTransformError(NULL, style, inst, + "XSLT-param: could not compile select expression '%s'.\n", + comp->select); + style->errors++; + } + if (inst->children != NULL) { + xsltTransformError(NULL, style, inst, + "XSLT-param: The content should be empty since the " + "attribute 'select' is present.\n"); + style->warnings++; + } + } +} + +/************************************************************************ + * * + * Generic interface * + * * + ************************************************************************/ + +/** + * xsltFreeStylePreComps: + * @style: an XSLT transformation context + * + * Free up the memory allocated by all precomputed blocks + */ +void +xsltFreeStylePreComps(xsltStylesheetPtr style) { + xsltElemPreCompPtr cur, next; + + if (style == NULL) + return; + + cur = style->preComps; + while (cur != NULL) { + next = cur->next; + if (cur->type == XSLT_FUNC_EXTENSION) + cur->free(cur); + else + xsltFreeStylePreComp((xsltStylePreCompPtr) cur); + cur = next; + } +} + +#ifdef XSLT_REFACTORED + +/** + * xsltStylePreCompute: + * @style: the XSLT stylesheet + * @node: the element in the XSLT namespace + * + * Precompute an XSLT element. + * This expects the type of the element to be already + * set in style->compCtxt->inode->type; + */ +void +xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr node) { + /* + * The xsltXSLTElemMarker marker was set beforehand by + * the parsing mechanism for all elements in the XSLT namespace. + */ + if (style == NULL) { + if ((node != NULL) && (node->type == XML_ELEMENT_NODE)) + node->psvi = NULL; + return; + } + if (node == NULL) + return; + if (! IS_XSLT_ELEM_FAST(node)) + return; + + node->psvi = NULL; + if (XSLT_CCTXT(style)->inode->type != 0) { + switch (XSLT_CCTXT(style)->inode->type) { + case XSLT_FUNC_APPLYTEMPLATES: + xsltApplyTemplatesComp(style, node); + break; + case XSLT_FUNC_WITHPARAM: + xsltWithParamComp(style, node); + break; + case XSLT_FUNC_VALUEOF: + xsltValueOfComp(style, node); + break; + case XSLT_FUNC_COPY: + xsltCopyComp(style, node); + break; + case XSLT_FUNC_COPYOF: + xsltCopyOfComp(style, node); + break; + case XSLT_FUNC_IF: + xsltIfComp(style, node); + break; + case XSLT_FUNC_CHOOSE: + xsltChooseComp(style, node); + break; + case XSLT_FUNC_WHEN: + xsltWhenComp(style, node); + break; + case XSLT_FUNC_OTHERWISE: + /* NOP yet */ + return; + case XSLT_FUNC_FOREACH: + xsltForEachComp(style, node); + break; + case XSLT_FUNC_APPLYIMPORTS: + xsltApplyImportsComp(style, node); + break; + case XSLT_FUNC_ATTRIBUTE: + xsltAttributeComp(style, node); + break; + case XSLT_FUNC_ELEMENT: + xsltElementComp(style, node); + break; + case XSLT_FUNC_SORT: + xsltSortComp(style, node); + break; + case XSLT_FUNC_COMMENT: + xsltCommentComp(style, node); + break; + case XSLT_FUNC_NUMBER: + xsltNumberComp(style, node); + break; + case XSLT_FUNC_PI: + xsltProcessingInstructionComp(style, node); + break; + case XSLT_FUNC_CALLTEMPLATE: + xsltCallTemplateComp(style, node); + break; + case XSLT_FUNC_PARAM: + xsltParamComp(style, node); + break; + case XSLT_FUNC_VARIABLE: + xsltVariableComp(style, node); + break; + case XSLT_FUNC_FALLBACK: + /* NOP yet */ + return; + case XSLT_FUNC_DOCUMENT: + /* The extra one */ + node->psvi = (void *) xsltDocumentComp(style, node, + xsltDocumentElem); + break; + case XSLT_FUNC_MESSAGE: + /* NOP yet */ + return; + default: + /* + * NOTE that xsl:text, xsl:template, xsl:stylesheet, + * xsl:transform, xsl:import, xsl:include are not expected + * to be handed over to this function. + */ + xsltTransformError(NULL, style, node, + "Internal error: (xsltStylePreCompute) cannot handle " + "the XSLT element '%s'.\n", node->name); + style->errors++; + return; + } + } else { + /* + * Fallback to string comparison. + */ + if (IS_XSLT_NAME(node, "apply-templates")) { + xsltApplyTemplatesComp(style, node); + } else if (IS_XSLT_NAME(node, "with-param")) { + xsltWithParamComp(style, node); + } else if (IS_XSLT_NAME(node, "value-of")) { + xsltValueOfComp(style, node); + } else if (IS_XSLT_NAME(node, "copy")) { + xsltCopyComp(style, node); + } else if (IS_XSLT_NAME(node, "copy-of")) { + xsltCopyOfComp(style, node); + } else if (IS_XSLT_NAME(node, "if")) { + xsltIfComp(style, node); + } else if (IS_XSLT_NAME(node, "choose")) { + xsltChooseComp(style, node); + } else if (IS_XSLT_NAME(node, "when")) { + xsltWhenComp(style, node); + } else if (IS_XSLT_NAME(node, "otherwise")) { + /* NOP yet */ + return; + } else if (IS_XSLT_NAME(node, "for-each")) { + xsltForEachComp(style, node); + } else if (IS_XSLT_NAME(node, "apply-imports")) { + xsltApplyImportsComp(style, node); + } else if (IS_XSLT_NAME(node, "attribute")) { + xsltAttributeComp(style, node); + } else if (IS_XSLT_NAME(node, "element")) { + xsltElementComp(style, node); + } else if (IS_XSLT_NAME(node, "sort")) { + xsltSortComp(style, node); + } else if (IS_XSLT_NAME(node, "comment")) { + xsltCommentComp(style, node); + } else if (IS_XSLT_NAME(node, "number")) { + xsltNumberComp(style, node); + } else if (IS_XSLT_NAME(node, "processing-instruction")) { + xsltProcessingInstructionComp(style, node); + } else if (IS_XSLT_NAME(node, "call-template")) { + xsltCallTemplateComp(style, node); + } else if (IS_XSLT_NAME(node, "param")) { + xsltParamComp(style, node); + } else if (IS_XSLT_NAME(node, "variable")) { + xsltVariableComp(style, node); + } else if (IS_XSLT_NAME(node, "fallback")) { + /* NOP yet */ + return; + } else if (IS_XSLT_NAME(node, "document")) { + /* The extra one */ + node->psvi = (void *) xsltDocumentComp(style, node, + xsltDocumentElem); + } else if (IS_XSLT_NAME(node, "output")) { + /* Top-level */ + return; + } else if (IS_XSLT_NAME(node, "preserve-space")) { + /* Top-level */ + return; + } else if (IS_XSLT_NAME(node, "strip-space")) { + /* Top-level */ + return; + } else if (IS_XSLT_NAME(node, "key")) { + /* Top-level */ + return; + } else if (IS_XSLT_NAME(node, "message")) { + return; + } else if (IS_XSLT_NAME(node, "attribute-set")) { + /* Top-level */ + return; + } else if (IS_XSLT_NAME(node, "namespace-alias")) { + /* Top-level */ + return; + } else if (IS_XSLT_NAME(node, "decimal-format")) { + /* Top-level */ + return; + } else if (IS_XSLT_NAME(node, "include")) { + /* Top-level */ + } else { + /* + * NOTE that xsl:text, xsl:template, xsl:stylesheet, + * xsl:transform, xsl:import, xsl:include are not expected + * to be handed over to this function. + */ + xsltTransformError(NULL, style, node, + "Internal error: (xsltStylePreCompute) cannot handle " + "the XSLT element '%s'.\n", node->name); + style->errors++; + return; + } + } + /* + * Assign the current list of in-scope namespaces to the + * item. This is needed for XPath expressions. + */ + if (node->psvi != NULL) { + ((xsltStylePreCompPtr) node->psvi)->inScopeNs = + XSLT_CCTXT(style)->inode->inScopeNs; + } +} + +#else + +/** + * xsltStylePreCompute: + * @style: the XSLT stylesheet + * @inst: the instruction in the stylesheet + * + * Precompute an XSLT stylesheet element + */ +void +xsltStylePreCompute(xsltStylesheetPtr style, xmlNodePtr inst) { + /* + * URGENT TODO: Normally inst->psvi Should never be reserved here, + * BUT: since if we include the same stylesheet from + * multiple imports, then the stylesheet will be parsed + * again. We simply must not try to compute the stylesheet again. + * TODO: Get to the point where we don't need to query the + * namespace- and local-name of the node, but can evaluate this + * using cctxt->style->inode->category; + */ + if ((inst == NULL) || (inst->type != XML_ELEMENT_NODE) || + (inst->psvi != NULL)) + return; + + if (IS_XSLT_ELEM(inst)) { + xsltStylePreCompPtr cur; + + if (IS_XSLT_NAME(inst, "apply-templates")) { + xsltCheckInstructionElement(style, inst); + xsltApplyTemplatesComp(style, inst); + } else if (IS_XSLT_NAME(inst, "with-param")) { + xsltCheckParentElement(style, inst, BAD_CAST "apply-templates", + BAD_CAST "call-template"); + xsltWithParamComp(style, inst); + } else if (IS_XSLT_NAME(inst, "value-of")) { + xsltCheckInstructionElement(style, inst); + xsltValueOfComp(style, inst); + } else if (IS_XSLT_NAME(inst, "copy")) { + xsltCheckInstructionElement(style, inst); + xsltCopyComp(style, inst); + } else if (IS_XSLT_NAME(inst, "copy-of")) { + xsltCheckInstructionElement(style, inst); + xsltCopyOfComp(style, inst); + } else if (IS_XSLT_NAME(inst, "if")) { + xsltCheckInstructionElement(style, inst); + xsltIfComp(style, inst); + } else if (IS_XSLT_NAME(inst, "when")) { + xsltCheckParentElement(style, inst, BAD_CAST "choose", NULL); + xsltWhenComp(style, inst); + } else if (IS_XSLT_NAME(inst, "choose")) { + xsltCheckInstructionElement(style, inst); + xsltChooseComp(style, inst); + } else if (IS_XSLT_NAME(inst, "for-each")) { + xsltCheckInstructionElement(style, inst); + xsltForEachComp(style, inst); + } else if (IS_XSLT_NAME(inst, "apply-imports")) { + xsltCheckInstructionElement(style, inst); + xsltApplyImportsComp(style, inst); + } else if (IS_XSLT_NAME(inst, "attribute")) { + xmlNodePtr parent = inst->parent; + + if ((parent == NULL) || + (parent->type != XML_ELEMENT_NODE) || (parent->ns == NULL) || + ((parent->ns != inst->ns) && + (!xmlStrEqual(parent->ns->href, inst->ns->href))) || + (!xmlStrEqual(parent->name, BAD_CAST "attribute-set"))) { + xsltCheckInstructionElement(style, inst); + } + xsltAttributeComp(style, inst); + } else if (IS_XSLT_NAME(inst, "element")) { + xsltCheckInstructionElement(style, inst); + xsltElementComp(style, inst); + } else if (IS_XSLT_NAME(inst, "text")) { + xsltCheckInstructionElement(style, inst); + xsltTextComp(style, inst); + } else if (IS_XSLT_NAME(inst, "sort")) { + xsltCheckParentElement(style, inst, BAD_CAST "apply-templates", + BAD_CAST "for-each"); + xsltSortComp(style, inst); + } else if (IS_XSLT_NAME(inst, "comment")) { + xsltCheckInstructionElement(style, inst); + xsltCommentComp(style, inst); + } else if (IS_XSLT_NAME(inst, "number")) { + xsltCheckInstructionElement(style, inst); + xsltNumberComp(style, inst); + } else if (IS_XSLT_NAME(inst, "processing-instruction")) { + xsltCheckInstructionElement(style, inst); + xsltProcessingInstructionComp(style, inst); + } else if (IS_XSLT_NAME(inst, "call-template")) { + xsltCheckInstructionElement(style, inst); + xsltCallTemplateComp(style, inst); + } else if (IS_XSLT_NAME(inst, "param")) { + if (xsltCheckTopLevelElement(style, inst, 0) == 0) + xsltCheckInstructionElement(style, inst); + xsltParamComp(style, inst); + } else if (IS_XSLT_NAME(inst, "variable")) { + if (xsltCheckTopLevelElement(style, inst, 0) == 0) + xsltCheckInstructionElement(style, inst); + xsltVariableComp(style, inst); + } else if (IS_XSLT_NAME(inst, "otherwise")) { + xsltCheckParentElement(style, inst, BAD_CAST "choose", NULL); + xsltCheckInstructionElement(style, inst); + return; + } else if (IS_XSLT_NAME(inst, "template")) { + xsltCheckTopLevelElement(style, inst, 1); + return; + } else if (IS_XSLT_NAME(inst, "output")) { + xsltCheckTopLevelElement(style, inst, 1); + return; + } else if (IS_XSLT_NAME(inst, "preserve-space")) { + xsltCheckTopLevelElement(style, inst, 1); + return; + } else if (IS_XSLT_NAME(inst, "strip-space")) { + xsltCheckTopLevelElement(style, inst, 1); + return; + } else if ((IS_XSLT_NAME(inst, "stylesheet")) || + (IS_XSLT_NAME(inst, "transform"))) { + xmlNodePtr parent = inst->parent; + + if ((parent == NULL) || (parent->type != XML_DOCUMENT_NODE)) { + xsltTransformError(NULL, style, inst, + "element %s only allowed only as root element\n", + inst->name); + style->errors++; + } + return; + } else if (IS_XSLT_NAME(inst, "key")) { + xsltCheckTopLevelElement(style, inst, 1); + return; + } else if (IS_XSLT_NAME(inst, "message")) { + xsltCheckInstructionElement(style, inst); + return; + } else if (IS_XSLT_NAME(inst, "attribute-set")) { + xsltCheckTopLevelElement(style, inst, 1); + return; + } else if (IS_XSLT_NAME(inst, "namespace-alias")) { + xsltCheckTopLevelElement(style, inst, 1); + return; + } else if (IS_XSLT_NAME(inst, "include")) { + xsltCheckTopLevelElement(style, inst, 1); + return; + } else if (IS_XSLT_NAME(inst, "import")) { + xsltCheckTopLevelElement(style, inst, 1); + return; + } else if (IS_XSLT_NAME(inst, "decimal-format")) { + xsltCheckTopLevelElement(style, inst, 1); + return; + } else if (IS_XSLT_NAME(inst, "fallback")) { + xsltCheckInstructionElement(style, inst); + return; + } else if (IS_XSLT_NAME(inst, "document")) { + xsltCheckInstructionElement(style, inst); + inst->psvi = (void *) xsltDocumentComp(style, inst, + xsltDocumentElem); + } else if ((style == NULL) || (style->forwards_compatible == 0)) { + xsltTransformError(NULL, style, inst, + "xsltStylePreCompute: unknown xsl:%s\n", inst->name); + if (style != NULL) style->warnings++; + } + + cur = (xsltStylePreCompPtr) inst->psvi; + /* + * A ns-list is build for every XSLT item in the + * node-tree. This is needed for XPath expressions. + */ + if (cur != NULL) { + int i = 0; + + cur->nsList = xmlGetNsList(inst->doc, inst); + if (cur->nsList != NULL) { + while (cur->nsList[i] != NULL) + i++; + } + cur->nsNr = i; + } + } else { + inst->psvi = + (void *) xsltPreComputeExtModuleElement(style, inst); + + /* + * Unknown element, maybe registered at the context + * level. Mark it for later recognition. + */ + if (inst->psvi == NULL) + inst->psvi = (void *) xsltExtMarker; + } +} +#endif /* XSLT_REFACTORED */ diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/preproc.h chromium-145.0.7632.159/third_party/libxslt/src/libxslt/preproc.h --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/preproc.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/preproc.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,43 @@ +/* + * Summary: precomputing stylesheets + * Description: this is the compilation phase, where most of the + * stylesheet is "compiled" into faster to use data. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLT_PRECOMP_H__ +#define __XML_XSLT_PRECOMP_H__ + +#include +#include "xsltexports.h" +#include "xsltInternals.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Interfaces + */ +XSLTPUBVAR const xmlChar *xsltExtMarker; + +XSLTPUBFUN xsltElemPreCompPtr XSLTCALL + xsltDocumentComp (xsltStylesheetPtr style, + xmlNodePtr inst, + xsltTransformFunction function); + +XSLTPUBFUN void XSLTCALL + xsltStylePreCompute (xsltStylesheetPtr style, + xmlNodePtr inst); +XSLTPUBFUN void XSLTCALL + xsltFreeStylePreComps (xsltStylesheetPtr style); + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_PRECOMP_H__ */ + diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/security.c chromium-145.0.7632.159/third_party/libxslt/src/libxslt/security.c --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/security.c 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/security.c 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,479 @@ +/* + * security.c: Implementation of the XSLT security framework + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#define IN_LIBXSLT +#include "libxslt.h" + +#include + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif + +#if defined(_WIN32) +#include +#ifndef INVALID_FILE_ATTRIBUTES +#define INVALID_FILE_ATTRIBUTES ((DWORD)-1) +#endif +#endif + +#ifndef HAVE_STAT +# ifdef HAVE__STAT + /* MS C library seems to define stat and _stat. The definition + * is identical. Still, mapping them to each other causes a warning. */ +# ifndef _MSC_VER +# define stat(x,y) _stat(x,y) +# endif +# define HAVE_STAT +# endif +#endif + +#include +#include +#include +#include "xslt.h" +#include "xsltInternals.h" +#include "xsltutils.h" +#include "extensions.h" +#include "security.h" + + +struct _xsltSecurityPrefs { + xsltSecurityCheck readFile; + xsltSecurityCheck createFile; + xsltSecurityCheck createDir; + xsltSecurityCheck readNet; + xsltSecurityCheck writeNet; +}; + +static xsltSecurityPrefsPtr xsltDefaultSecurityPrefs = NULL; + +/************************************************************************ + * * + * Module interfaces * + * * + ************************************************************************/ + +/** + * xsltNewSecurityPrefs: + * + * Create a new security preference block + * + * Returns a pointer to the new block or NULL in case of error + */ +xsltSecurityPrefsPtr +xsltNewSecurityPrefs(void) { + xsltSecurityPrefsPtr ret; + + xsltInitGlobals(); + + ret = (xsltSecurityPrefsPtr) xmlMalloc(sizeof(xsltSecurityPrefs)); + if (ret == NULL) { + xsltTransformError(NULL, NULL, NULL, + "xsltNewSecurityPrefs : malloc failed\n"); + return(NULL); + } + memset(ret, 0, sizeof(xsltSecurityPrefs)); + return(ret); +} + +/** + * xsltFreeSecurityPrefs: + * @sec: the security block to free + * + * Free up a security preference block + */ +void +xsltFreeSecurityPrefs(xsltSecurityPrefsPtr sec) { + if (sec == NULL) + return; + xmlFree(sec); +} + +/** + * xsltSetSecurityPrefs: + * @sec: the security block to update + * @option: the option to update + * @func: the user callback to use for this option + * + * Update the security option to use the new callback checking function + * + * Returns -1 in case of error, 0 otherwise + */ +int +xsltSetSecurityPrefs(xsltSecurityPrefsPtr sec, xsltSecurityOption option, + xsltSecurityCheck func) { + xsltInitGlobals(); + if (sec == NULL) + return(-1); + switch (option) { + case XSLT_SECPREF_READ_FILE: + sec->readFile = func; return(0); + case XSLT_SECPREF_WRITE_FILE: + sec->createFile = func; return(0); + case XSLT_SECPREF_CREATE_DIRECTORY: + sec->createDir = func; return(0); + case XSLT_SECPREF_READ_NETWORK: + sec->readNet = func; return(0); + case XSLT_SECPREF_WRITE_NETWORK: + sec->writeNet = func; return(0); + } + return(-1); +} + +/** + * xsltGetSecurityPrefs: + * @sec: the security block to update + * @option: the option to lookup + * + * Lookup the security option to get the callback checking function + * + * Returns NULL if not found, the function otherwise + */ +xsltSecurityCheck +xsltGetSecurityPrefs(xsltSecurityPrefsPtr sec, xsltSecurityOption option) { + if (sec == NULL) + return(NULL); + switch (option) { + case XSLT_SECPREF_READ_FILE: + return(sec->readFile); + case XSLT_SECPREF_WRITE_FILE: + return(sec->createFile); + case XSLT_SECPREF_CREATE_DIRECTORY: + return(sec->createDir); + case XSLT_SECPREF_READ_NETWORK: + return(sec->readNet); + case XSLT_SECPREF_WRITE_NETWORK: + return(sec->writeNet); + } + return(NULL); +} + +/** + * xsltSetDefaultSecurityPrefs: + * @sec: the security block to use + * + * Set the default security preference application-wide + */ +void +xsltSetDefaultSecurityPrefs(xsltSecurityPrefsPtr sec) { + + xsltDefaultSecurityPrefs = sec; +} + +/** + * xsltGetDefaultSecurityPrefs: + * + * Get the default security preference application-wide + * + * Returns the current xsltSecurityPrefsPtr in use or NULL if none + */ +xsltSecurityPrefsPtr +xsltGetDefaultSecurityPrefs(void) { + return(xsltDefaultSecurityPrefs); +} + +/** + * xsltSetCtxtSecurityPrefs: + * @sec: the security block to use + * @ctxt: an XSLT transformation context + * + * Set the security preference for a specific transformation + * + * Returns -1 in case of error, 0 otherwise + */ +int +xsltSetCtxtSecurityPrefs(xsltSecurityPrefsPtr sec, + xsltTransformContextPtr ctxt) { + if (ctxt == NULL) + return(-1); + ctxt->sec = (void *) sec; + return(0); +} + + +/** + * xsltSecurityAllow: + * @sec: the security block to use + * @ctxt: an XSLT transformation context + * @value: unused + * + * Function used to always allow an operation + * + * Returns 1 always + */ +int +xsltSecurityAllow(xsltSecurityPrefsPtr sec ATTRIBUTE_UNUSED, + xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, + const char *value ATTRIBUTE_UNUSED) { + return(1); +} + +/** + * xsltSecurityForbid: + * @sec: the security block to use + * @ctxt: an XSLT transformation context + * @value: unused + * + * Function used to always forbid an operation + * + * Returns 0 always + */ +int +xsltSecurityForbid(xsltSecurityPrefsPtr sec ATTRIBUTE_UNUSED, + xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, + const char *value ATTRIBUTE_UNUSED) { + return(0); +} + +/************************************************************************ + * * + * Internal interfaces * + * * + ************************************************************************/ + +/** + * xsltCheckFilename + * @path: the path to check + * + * function checks to see if @path is a valid source + * (file, socket...) for XML. + * + * TODO: remove at some point !!! + * Local copy of xmlCheckFilename to avoid a hard dependency on + * a new version of libxml2 + * + * if stat is not available on the target machine, + * returns 1. if stat fails, returns 0 (if calling + * stat on the filename fails, it can't be right). + * if stat succeeds and the file is a directory, + * returns 2. otherwise returns 1. + */ + +static int +xsltCheckFilename (const char *path) +{ +#ifdef HAVE_STAT + struct stat stat_buffer; +#if defined(_WIN32) + DWORD dwAttrs; + + dwAttrs = GetFileAttributesA(path); + if (dwAttrs != INVALID_FILE_ATTRIBUTES) { + if (dwAttrs & FILE_ATTRIBUTE_DIRECTORY) { + return 2; + } + } +#endif + + if (stat(path, &stat_buffer) == -1) + return 0; + +#ifdef S_ISDIR + if (S_ISDIR(stat_buffer.st_mode)) { + return 2; + } +#endif +#endif + return 1; +} + +static int +xsltCheckWritePath(xsltSecurityPrefsPtr sec, + xsltTransformContextPtr ctxt, + const char *path) +{ + int ret; + xsltSecurityCheck check; + char *directory; + + check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_WRITE_FILE); + if (check != NULL) { + ret = check(sec, ctxt, path); + if (ret == 0) { + xsltTransformError(ctxt, NULL, NULL, + "File write for %s refused\n", path); + return(0); + } + } + + directory = xmlParserGetDirectory (path); + + if (directory != NULL) { + ret = xsltCheckFilename(directory); + if (ret == 0) { + /* + * The directory doesn't exist check for creation + */ + check = xsltGetSecurityPrefs(sec, + XSLT_SECPREF_CREATE_DIRECTORY); + if (check != NULL) { + ret = check(sec, ctxt, directory); + if (ret == 0) { + xsltTransformError(ctxt, NULL, NULL, + "Directory creation for %s refused\n", + path); + xmlFree(directory); + return(0); + } + } + ret = xsltCheckWritePath(sec, ctxt, directory); + if (ret == 1) + ret = mkdir(directory, 0755); + } + xmlFree(directory); + if (ret < 0) + return(ret); + } + + return(1); +} + +/** + * xsltCheckWrite: + * @sec: the security options + * @ctxt: an XSLT transformation context + * @URL: the resource to be written + * + * Check if the resource is allowed to be written, if necessary makes + * some preliminary work like creating directories + * + * Return 1 if write is allowed, 0 if not and -1 in case or error. + */ +int +xsltCheckWrite(xsltSecurityPrefsPtr sec, + xsltTransformContextPtr ctxt, const xmlChar *URL) { + int ret; + xmlURIPtr uri; + xsltSecurityCheck check; + + uri = xmlParseURI((const char *)URL); + if (uri == NULL) { + uri = xmlCreateURI(); + if (uri == NULL) { + xsltTransformError(ctxt, NULL, NULL, + "xsltCheckWrite: out of memory for %s\n", URL); + return(-1); + } + uri->path = (char *)xmlStrdup(URL); + } + if ((uri->scheme == NULL) || + (xmlStrEqual(BAD_CAST uri->scheme, BAD_CAST "file"))) { + +#if defined(_WIN32) + if ((uri->path)&&(uri->path[0]=='/')&& + (uri->path[1]!='\0')&&(uri->path[2]==':')) + ret = xsltCheckWritePath(sec, ctxt, uri->path+1); + else +#endif + { + /* + * Check if we are allowed to write this file + */ + ret = xsltCheckWritePath(sec, ctxt, uri->path); + } + + if (ret <= 0) { + xmlFreeURI(uri); + return(ret); + } + } else { + /* + * Check if we are allowed to write this network resource + */ + check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_WRITE_NETWORK); + if (check != NULL) { + ret = check(sec, ctxt, (const char *)URL); + if (ret == 0) { + xsltTransformError(ctxt, NULL, NULL, + "File write for %s refused\n", URL); + xmlFreeURI(uri); + return(0); + } + } + } + xmlFreeURI(uri); + return(1); +} + + +/** + * xsltCheckRead: + * @sec: the security options + * @ctxt: an XSLT transformation context + * @URL: the resource to be read + * + * Check if the resource is allowed to be read + * + * Return 1 if read is allowed, 0 if not and -1 in case or error. + */ +int +xsltCheckRead(xsltSecurityPrefsPtr sec, + xsltTransformContextPtr ctxt, const xmlChar *URL) { + int ret; + xmlURIPtr uri; + xsltSecurityCheck check; + + if (xmlStrstr(URL, BAD_CAST "://") == NULL) { + check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_READ_FILE); + if (check != NULL) { + ret = check(sec, ctxt, (const char *) URL); + if (ret == 0) { + xsltTransformError(ctxt, NULL, NULL, + "Local file read for %s refused\n", URL); + return(0); + } + } + return(1); + } + + uri = xmlParseURI((const char *)URL); + if (uri == NULL) { + xsltTransformError(ctxt, NULL, NULL, + "xsltCheckRead: URL parsing failed for %s\n", + URL); + return(-1); + } + if ((uri->scheme == NULL) || + (xmlStrEqual(BAD_CAST uri->scheme, BAD_CAST "file"))) { + + /* + * Check if we are allowed to read this file + */ + check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_READ_FILE); + if (check != NULL) { + ret = check(sec, ctxt, uri->path); + if (ret == 0) { + xsltTransformError(ctxt, NULL, NULL, + "Local file read for %s refused\n", URL); + xmlFreeURI(uri); + return(0); + } + } + } else { + /* + * Check if we are allowed to write this network resource + */ + check = xsltGetSecurityPrefs(sec, XSLT_SECPREF_READ_NETWORK); + if (check != NULL) { + ret = check(sec, ctxt, (const char *)URL); + if (ret == 0) { + xsltTransformError(ctxt, NULL, NULL, + "Network file read for %s refused\n", URL); + xmlFreeURI(uri); + return(0); + } + } + } + xmlFreeURI(uri); + return(1); +} + diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/security.h chromium-145.0.7632.159/third_party/libxslt/src/libxslt/security.h --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/security.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/security.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,104 @@ +/* + * Summary: interface for the libxslt security framework + * Description: the libxslt security framework allow to restrict + * the access to new resources (file or URL) from + * the stylesheet at runtime. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLT_SECURITY_H__ +#define __XML_XSLT_SECURITY_H__ + +#include +#include "xsltexports.h" +#include "xsltInternals.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * xsltSecurityPref: + * + * structure to indicate the preferences for security in the XSLT + * transformation. + */ +typedef struct _xsltSecurityPrefs xsltSecurityPrefs; +typedef xsltSecurityPrefs *xsltSecurityPrefsPtr; + +/** + * xsltSecurityOption: + * + * the set of option that can be configured + */ +typedef enum { + XSLT_SECPREF_READ_FILE = 1, + XSLT_SECPREF_WRITE_FILE, + XSLT_SECPREF_CREATE_DIRECTORY, + XSLT_SECPREF_READ_NETWORK, + XSLT_SECPREF_WRITE_NETWORK +} xsltSecurityOption; + +/** + * xsltSecurityCheck: + * + * User provided function to check the value of a string like a file + * path or an URL ... + */ +typedef int (*xsltSecurityCheck) (xsltSecurityPrefsPtr sec, + xsltTransformContextPtr ctxt, + const char *value); + +/* + * Module interfaces + */ +XSLTPUBFUN xsltSecurityPrefsPtr XSLTCALL + xsltNewSecurityPrefs (void); +XSLTPUBFUN void XSLTCALL + xsltFreeSecurityPrefs (xsltSecurityPrefsPtr sec); +XSLTPUBFUN int XSLTCALL + xsltSetSecurityPrefs (xsltSecurityPrefsPtr sec, + xsltSecurityOption option, + xsltSecurityCheck func); +XSLTPUBFUN xsltSecurityCheck XSLTCALL + xsltGetSecurityPrefs (xsltSecurityPrefsPtr sec, + xsltSecurityOption option); + +XSLTPUBFUN void XSLTCALL + xsltSetDefaultSecurityPrefs (xsltSecurityPrefsPtr sec); +XSLTPUBFUN xsltSecurityPrefsPtr XSLTCALL + xsltGetDefaultSecurityPrefs (void); + +XSLTPUBFUN int XSLTCALL + xsltSetCtxtSecurityPrefs (xsltSecurityPrefsPtr sec, + xsltTransformContextPtr ctxt); + +XSLTPUBFUN int XSLTCALL + xsltSecurityAllow (xsltSecurityPrefsPtr sec, + xsltTransformContextPtr ctxt, + const char *value); +XSLTPUBFUN int XSLTCALL + xsltSecurityForbid (xsltSecurityPrefsPtr sec, + xsltTransformContextPtr ctxt, + const char *value); +/* + * internal interfaces + */ +XSLTPUBFUN int XSLTCALL + xsltCheckWrite (xsltSecurityPrefsPtr sec, + xsltTransformContextPtr ctxt, + const xmlChar *URL); +XSLTPUBFUN int XSLTCALL + xsltCheckRead (xsltSecurityPrefsPtr sec, + xsltTransformContextPtr ctxt, + const xmlChar *URL); + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_SECURITY_H__ */ + diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/templates.c chromium-145.0.7632.159/third_party/libxslt/src/libxslt/templates.c --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/templates.c 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/templates.c 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,875 @@ +/* + * templates.c: Implementation of the template processing + * + * Reference: + * http://www.w3.org/TR/1999/REC-xslt-19991116 + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#define IN_LIBXSLT +#include "libxslt.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include "xslt.h" +#include "xsltInternals.h" +#include "xsltutils.h" +#include "variables.h" +#include "functions.h" +#include "templates.h" +#include "transform.h" +#include "namespaces.h" +#include "attributes.h" + +#ifdef WITH_XSLT_DEBUG +#define WITH_XSLT_DEBUG_TEMPLATES +#endif + +/************************************************************************ + * * + * Module interfaces * + * * + ************************************************************************/ + +/** + * xsltEvalXPathPredicate: + * @ctxt: the XSLT transformation context + * @comp: the XPath compiled expression + * @nsList: the namespaces in scope + * @nsNr: the number of namespaces in scope + * + * Process the expression using XPath and evaluate the result as + * an XPath predicate + * + * Returns 1 is the predicate was true, 0 otherwise + */ +int +xsltEvalXPathPredicate(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp, + xmlNsPtr *nsList, int nsNr) { + int ret; + xmlXPathObjectPtr res; + int oldNsNr; + xmlNsPtr *oldNamespaces; + xmlNodePtr oldInst; + xmlNodePtr oldNode; + int oldProximityPosition, oldContextSize; + + if ((ctxt == NULL) || (ctxt->inst == NULL)) { + xsltTransformError(ctxt, NULL, NULL, + "xsltEvalXPathPredicate: No context or instruction\n"); + return(0); + } + + oldNode = ctxt->xpathCtxt->node; + oldContextSize = ctxt->xpathCtxt->contextSize; + oldProximityPosition = ctxt->xpathCtxt->proximityPosition; + oldNsNr = ctxt->xpathCtxt->nsNr; + oldNamespaces = ctxt->xpathCtxt->namespaces; + oldInst = ctxt->inst; + + ctxt->xpathCtxt->node = ctxt->node; + ctxt->xpathCtxt->namespaces = nsList; + ctxt->xpathCtxt->nsNr = nsNr; + + res = xmlXPathCompiledEval(comp, ctxt->xpathCtxt); + + if (res != NULL) { + ret = xmlXPathEvalPredicate(ctxt->xpathCtxt, res); + xmlXPathFreeObject(res); +#ifdef WITH_XSLT_DEBUG_TEMPLATES + XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, + "xsltEvalXPathPredicate: returns %d\n", ret)); +#endif + } else { +#ifdef WITH_XSLT_DEBUG_TEMPLATES + XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, + "xsltEvalXPathPredicate: failed\n")); +#endif + ctxt->state = XSLT_STATE_STOPPED; + ret = 0; + } + + ctxt->xpathCtxt->node = oldNode; + ctxt->xpathCtxt->nsNr = oldNsNr; + ctxt->xpathCtxt->namespaces = oldNamespaces; + ctxt->inst = oldInst; + ctxt->xpathCtxt->contextSize = oldContextSize; + ctxt->xpathCtxt->proximityPosition = oldProximityPosition; + + return(ret); +} + +/** + * xsltEvalXPathStringNs: + * @ctxt: the XSLT transformation context + * @comp: the compiled XPath expression + * @nsNr: the number of namespaces in the list + * @nsList: the list of in-scope namespaces to use + * + * Process the expression using XPath, allowing to pass a namespace mapping + * context and get a string + * + * Returns the computed string value or NULL, must be deallocated by the + * caller. + */ +xmlChar * +xsltEvalXPathStringNs(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp, + int nsNr, xmlNsPtr *nsList) { + xmlChar *ret = NULL; + xmlXPathObjectPtr res; + xmlNodePtr oldInst; + xmlNodePtr oldNode; + int oldPos, oldSize; + int oldNsNr; + xmlNsPtr *oldNamespaces; + + if ((ctxt == NULL) || (ctxt->inst == NULL)) { + xsltTransformError(ctxt, NULL, NULL, + "xsltEvalXPathStringNs: No context or instruction\n"); + return(0); + } + + oldInst = ctxt->inst; + oldNode = ctxt->xpathCtxt->node; + oldPos = ctxt->xpathCtxt->proximityPosition; + oldSize = ctxt->xpathCtxt->contextSize; + oldNsNr = ctxt->xpathCtxt->nsNr; + oldNamespaces = ctxt->xpathCtxt->namespaces; + + ctxt->xpathCtxt->node = ctxt->node; + /* TODO: do we need to propagate the namespaces here ? */ + ctxt->xpathCtxt->namespaces = nsList; + ctxt->xpathCtxt->nsNr = nsNr; + res = xmlXPathCompiledEval(comp, ctxt->xpathCtxt); + if (res != NULL) { + if (res->type != XPATH_STRING) + res = xmlXPathConvertString(res); + if ((res != NULL) && (res->type == XPATH_STRING)) { + ret = res->stringval; + res->stringval = NULL; + } else { + xsltTransformError(ctxt, NULL, NULL, + "xpath : string() function didn't return a String\n"); + } + xmlXPathFreeObject(res); + } else { + ctxt->state = XSLT_STATE_STOPPED; + } +#ifdef WITH_XSLT_DEBUG_TEMPLATES + XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, + "xsltEvalXPathString: returns %s\n", ret)); +#endif + ctxt->inst = oldInst; + ctxt->xpathCtxt->node = oldNode; + ctxt->xpathCtxt->contextSize = oldSize; + ctxt->xpathCtxt->proximityPosition = oldPos; + ctxt->xpathCtxt->nsNr = oldNsNr; + ctxt->xpathCtxt->namespaces = oldNamespaces; + return(ret); +} + +/** + * xsltEvalXPathString: + * @ctxt: the XSLT transformation context + * @comp: the compiled XPath expression + * + * Process the expression using XPath and get a string + * + * Returns the computed string value or NULL, must be deallocated by the + * caller. + */ +xmlChar * +xsltEvalXPathString(xsltTransformContextPtr ctxt, xmlXPathCompExprPtr comp) { + return(xsltEvalXPathStringNs(ctxt, comp, 0, NULL)); +} + +/** + * xsltEvalTemplateString: + * @ctxt: the XSLT transformation context + * @contextNode: the current node in the source tree + * @inst: the XSLT instruction (xsl:comment, xsl:processing-instruction) + * + * Processes the sequence constructor of the given instruction on + * @contextNode and converts the resulting tree to a string. + * This is needed by e.g. xsl:comment and xsl:processing-instruction. + * + * Returns the computed string value or NULL; it's up to the caller to + * free the result. + */ +xmlChar * +xsltEvalTemplateString(xsltTransformContextPtr ctxt, + xmlNodePtr contextNode, + xmlNodePtr inst) +{ + xmlNodePtr oldInsert, insert = NULL; + xmlChar *ret; + const xmlChar *oldLastText; + int oldLastTextSize, oldLastTextUse; + + if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL) || + (inst->type != XML_ELEMENT_NODE)) + return(NULL); + + if (inst->children == NULL) + return(NULL); + + /* + * This creates a temporary element-node to add the resulting + * text content to. + * OPTIMIZE TODO: Keep such an element-node in the transformation + * context to avoid creating it every time. + */ + insert = xmlNewDocNode(ctxt->output, NULL, + (const xmlChar *)"fake", NULL); + if (insert == NULL) { + xsltTransformError(ctxt, NULL, inst, + "Failed to create temporary node\n"); + return(NULL); + } + oldInsert = ctxt->insert; + ctxt->insert = insert; + oldLastText = ctxt->lasttext; + oldLastTextSize = ctxt->lasttsize; + oldLastTextUse = ctxt->lasttuse; + /* + * OPTIMIZE TODO: if inst->children consists only of text-nodes. + */ + xsltApplyOneTemplate(ctxt, contextNode, inst->children, NULL, NULL); + + ctxt->insert = oldInsert; + ctxt->lasttext = oldLastText; + ctxt->lasttsize = oldLastTextSize; + ctxt->lasttuse = oldLastTextUse; + + ret = xmlNodeGetContent(insert); + if (insert != NULL) + xmlFreeNode(insert); + return(ret); +} + +/** + * xsltAttrTemplateValueProcessNode: + * @ctxt: the XSLT transformation context + * @str: the attribute template node value + * @inst: the instruction (or LRE) in the stylesheet holding the + * attribute with an AVT + * + * Process the given string, allowing to pass a namespace mapping + * context and return the new string value. + * + * Called by: + * - xsltAttrTemplateValueProcess() (templates.c) + * - xsltEvalAttrValueTemplate() (templates.c) + * + * QUESTION: Why is this function public? It is not used outside + * of templates.c. + * + * Returns the computed string value or NULL, must be deallocated by the + * caller. + */ +xmlChar * +xsltAttrTemplateValueProcessNode(xsltTransformContextPtr ctxt, + const xmlChar *str, xmlNodePtr inst) +{ + xmlChar *ret = NULL; + const xmlChar *cur; + xmlChar *expr, *val; + xmlNsPtr *nsList = NULL; + int nsNr = 0; + + if (str == NULL) return(NULL); + if (*str == 0) + return(xmlStrndup((xmlChar *)"", 0)); + + cur = str; + while (*cur != 0) { + if (*cur == '{') { + if (*(cur+1) == '{') { /* escaped '{' */ + cur++; + ret = xmlStrncat(ret, str, cur - str); + cur++; + str = cur; + continue; + } + ret = xmlStrncat(ret, str, cur - str); + str = cur; + cur++; + while ((*cur != 0) && (*cur != '}')) { + /* Need to check for literal (bug539741) */ + if ((*cur == '\'') || (*cur == '"')) { + char delim = *(cur++); + while ((*cur != 0) && (*cur != delim)) + cur++; + if (*cur != 0) + cur++; /* skip the ending delimiter */ + } else + cur++; + } + if (*cur == 0) { + xsltTransformError(ctxt, NULL, inst, + "xsltAttrTemplateValueProcessNode: unmatched '{'\n"); + ret = xmlStrncat(ret, str, cur - str); + goto exit; + } + str++; + expr = xmlStrndup(str, cur - str); + if (expr == NULL) + goto exit; + else if (*expr == '{') { + ret = xmlStrcat(ret, expr); + xmlFree(expr); + } else { + xmlXPathCompExprPtr comp; + /* + * TODO: keep precompiled form around + */ + if ((nsList == NULL) && (inst != NULL)) { + int i = 0; + + nsList = xmlGetNsList(inst->doc, inst); + if (nsList != NULL) { + while (nsList[i] != NULL) + i++; + nsNr = i; + } + } + comp = xmlXPathCtxtCompile(ctxt->xpathCtxt, expr); + val = xsltEvalXPathStringNs(ctxt, comp, nsNr, nsList); + xmlXPathFreeCompExpr(comp); + xmlFree(expr); + if (val != NULL) { + ret = xmlStrcat(ret, val); + xmlFree(val); + } + } + cur++; + str = cur; + } else if (*cur == '}') { + cur++; + if (*cur == '}') { /* escaped '}' */ + ret = xmlStrncat(ret, str, cur - str); + cur++; + str = cur; + continue; + } else { + xsltTransformError(ctxt, NULL, inst, + "xsltAttrTemplateValueProcessNode: unmatched '}'\n"); + } + } else + cur++; + } + if (cur != str) { + ret = xmlStrncat(ret, str, cur - str); + } + +exit: + if (nsList != NULL) + xmlFree(nsList); + + return(ret); +} + +/** + * xsltAttrTemplateValueProcess: + * @ctxt: the XSLT transformation context + * @str: the attribute template node value + * + * Process the given node and return the new string value. + * + * Returns the computed string value or NULL, must be deallocated by the + * caller. + */ +xmlChar * +xsltAttrTemplateValueProcess(xsltTransformContextPtr ctxt, const xmlChar *str) { + return(xsltAttrTemplateValueProcessNode(ctxt, str, NULL)); +} + +/** + * xsltEvalAttrValueTemplate: + * @ctxt: the XSLT transformation context + * @inst: the instruction (or LRE) in the stylesheet holding the + * attribute with an AVT + * @name: the attribute QName + * @ns: the attribute namespace URI + * + * Evaluate a attribute value template, i.e. the attribute value can + * contain expressions contained in curly braces ({}) and those are + * substituted by they computed value. + * + * Returns the computed string value or NULL, must be deallocated by the + * caller. + */ +xmlChar * +xsltEvalAttrValueTemplate(xsltTransformContextPtr ctxt, xmlNodePtr inst, + const xmlChar *name, const xmlChar *ns) +{ + xmlChar *ret; + xmlChar *expr; + + if ((ctxt == NULL) || (inst == NULL) || (name == NULL) || + (inst->type != XML_ELEMENT_NODE)) + return(NULL); + + expr = xsltGetNsProp(inst, name, ns); + if (expr == NULL) + return(NULL); + + /* + * TODO: though now {} is detected ahead, it would still be good to + * optimize both functions to keep the splitted value if the + * attribute content and the XPath precompiled expressions around + */ + + ret = xsltAttrTemplateValueProcessNode(ctxt, expr, inst); +#ifdef WITH_XSLT_DEBUG_TEMPLATES + XSLT_TRACE(ctxt,XSLT_TRACE_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, + "xsltEvalAttrValueTemplate: %s returns %s\n", expr, ret)); +#endif + if (expr != NULL) + xmlFree(expr); + return(ret); +} + +/** + * xsltEvalStaticAttrValueTemplate: + * @style: the XSLT stylesheet + * @inst: the instruction (or LRE) in the stylesheet holding the + * attribute with an AVT + * @name: the attribute Name + * @ns: the attribute namespace URI + * @found: indicator whether the attribute is present + * + * Check if an attribute value template has a static value, i.e. the + * attribute value does not contain expressions contained in curly braces ({}) + * + * Returns the static string value or NULL, must be deallocated by the + * caller. + */ +const xmlChar * +xsltEvalStaticAttrValueTemplate(xsltStylesheetPtr style, xmlNodePtr inst, + const xmlChar *name, const xmlChar *ns, int *found) { + const xmlChar *ret; + xmlChar *expr; + + if ((style == NULL) || (inst == NULL) || (name == NULL) || + (inst->type != XML_ELEMENT_NODE)) + return(NULL); + + expr = xsltGetNsProp(inst, name, ns); + if (expr == NULL) { + *found = 0; + return(NULL); + } + *found = 1; + + ret = xmlStrchr(expr, '{'); + if (ret != NULL) { + xmlFree(expr); + return(NULL); + } + ret = xmlDictLookup(style->dict, expr, -1); + xmlFree(expr); + return(ret); +} + +/** + * xsltAttrTemplateProcess: + * @ctxt: the XSLT transformation context + * @target: the element where the attribute will be grafted + * @attr: the attribute node of a literal result element + * + * Process one attribute of a Literal Result Element (in the stylesheet). + * Evaluates Attribute Value Templates and copies the attribute over to + * the result element. + * This does *not* process attribute sets (xsl:use-attribute-set). + * + * + * Returns the generated attribute node. + */ +xmlAttrPtr +xsltAttrTemplateProcess(xsltTransformContextPtr ctxt, xmlNodePtr target, + xmlAttrPtr attr) +{ + const xmlChar *value; + xmlAttrPtr ret; + + if ((ctxt == NULL) || (attr == NULL) || (target == NULL) || + (target->type != XML_ELEMENT_NODE)) + return(NULL); + + if (attr->type != XML_ATTRIBUTE_NODE) + return(NULL); + + /* + * Skip all XSLT attributes. + */ +#ifdef XSLT_REFACTORED + if (attr->psvi == xsltXSLTAttrMarker) + return(NULL); +#else + if ((attr->ns != NULL) && xmlStrEqual(attr->ns->href, XSLT_NAMESPACE)) + return(NULL); +#endif + /* + * Get the value. + */ + if (attr->children != NULL) { + if ((attr->children->type != XML_TEXT_NODE) || + (attr->children->next != NULL)) + { + xsltTransformError(ctxt, NULL, attr->parent, + "Internal error: The children of an attribute node of a " + "literal result element are not in the expected form.\n"); + return(NULL); + } + value = attr->children->content; + if (value == NULL) + value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0); + } else + value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0); + /* + * Overwrite duplicates. + */ + ret = target->properties; + while (ret != NULL) { + if (((attr->ns != NULL) == (ret->ns != NULL)) && + xmlStrEqual(ret->name, attr->name) && + ((attr->ns == NULL) || xmlStrEqual(ret->ns->href, attr->ns->href))) + { + break; + } + ret = ret->next; + } + if (ret != NULL) { + /* free the existing value */ + xmlFreeNodeList(ret->children); + ret->children = ret->last = NULL; + /* + * Adjust ns-prefix if needed. + */ + if ((ret->ns != NULL) && + (! xmlStrEqual(ret->ns->prefix, attr->ns->prefix))) + { + ret->ns = xsltGetNamespace(ctxt, attr->parent, attr->ns, target); + } + } else { + /* create a new attribute */ + if (attr->ns != NULL) + ret = xmlNewNsProp(target, + xsltGetNamespace(ctxt, attr->parent, attr->ns, target), + attr->name, NULL); + else + ret = xmlNewNsProp(target, NULL, attr->name, NULL); + } + /* + * Set the value. + */ + if (ret != NULL) { + xmlNodePtr text; + + text = xmlNewText(NULL); + if (text != NULL) { + ret->last = ret->children = text; + text->parent = (xmlNodePtr) ret; + text->doc = ret->doc; + + if (attr->psvi != NULL) { + /* + * Evaluate the Attribute Value Template. + */ + xmlChar *val; + val = xsltEvalAVT(ctxt, attr->psvi, attr->parent); + if (val == NULL) { + /* + * TODO: Damn, we need an easy mechanism to report + * qualified names! + */ + if (attr->ns) { + xsltTransformError(ctxt, NULL, attr->parent, + "Internal error: Failed to evaluate the AVT " + "of attribute '{%s}%s'.\n", + attr->ns->href, attr->name); + } else { + xsltTransformError(ctxt, NULL, attr->parent, + "Internal error: Failed to evaluate the AVT " + "of attribute '%s'.\n", + attr->name); + } + text->content = xmlStrdup(BAD_CAST ""); + } else { + text->content = val; + } + } else if ((ctxt->internalized) && (target != NULL) && + (target->doc != NULL) && + (target->doc->dict == ctxt->dict) && + xmlDictOwns(ctxt->dict, value)) { + text->content = (xmlChar *) value; + } else { + text->content = xmlStrdup(value); + } + } + } else { + if (attr->ns) { + xsltTransformError(ctxt, NULL, attr->parent, + "Internal error: Failed to create attribute '{%s}%s'.\n", + attr->ns->href, attr->name); + } else { + xsltTransformError(ctxt, NULL, attr->parent, + "Internal error: Failed to create attribute '%s'.\n", + attr->name); + } + } + return(ret); +} + + +/** + * xsltAttrListTemplateProcess: + * @ctxt: the XSLT transformation context + * @target: the element where the attributes will be grafted + * @attrs: the first attribute + * + * Processes all attributes of a Literal Result Element. + * Attribute references are applied via xsl:use-attribute-set + * attributes. + * Copies all non XSLT-attributes over to the @target element + * and evaluates Attribute Value Templates. + * + * Called by xsltApplySequenceConstructor() (transform.c). + * + * Returns a new list of attribute nodes, or NULL in case of error. + * (Don't assign the result to @target->properties; if + * the result is NULL, you'll get memory leaks, since the + * attributes will be disattached.) + */ +xmlAttrPtr +xsltAttrListTemplateProcess(xsltTransformContextPtr ctxt, + xmlNodePtr target, xmlAttrPtr attrs) +{ + xmlAttrPtr attr, copy, last = NULL; + xmlNodePtr oldInsert, text; + xmlNsPtr origNs = NULL, copyNs = NULL; + const xmlChar *value; + xmlChar *valueAVT; + int hasAttr = 0; + + if ((ctxt == NULL) || (target == NULL) || (attrs == NULL) || + (target->type != XML_ELEMENT_NODE)) + return(NULL); + + oldInsert = ctxt->insert; + ctxt->insert = target; + + /* + * Apply attribute-sets. + */ + attr = attrs; + do { +#ifdef XSLT_REFACTORED + if ((attr->psvi == xsltXSLTAttrMarker) && + xmlStrEqual(attr->name, (const xmlChar *)"use-attribute-sets")) + { + xsltApplyAttributeSet(ctxt, ctxt->node, (xmlNodePtr) attr, NULL); + } +#else + if ((attr->ns != NULL) && + xmlStrEqual(attr->name, (const xmlChar *)"use-attribute-sets") && + xmlStrEqual(attr->ns->href, XSLT_NAMESPACE)) + { + xsltApplyAttributeSet(ctxt, ctxt->node, (xmlNodePtr) attr, NULL); + } +#endif + attr = attr->next; + } while (attr != NULL); + + if (target->properties != NULL) { + hasAttr = 1; + } + + /* + * Instantiate LRE-attributes. + */ + attr = attrs; + do { + /* + * Skip XSLT attributes. + */ +#ifdef XSLT_REFACTORED + if (attr->psvi == xsltXSLTAttrMarker) { + goto next_attribute; + } +#else + if ((attr->ns != NULL) && + xmlStrEqual(attr->ns->href, XSLT_NAMESPACE)) + { + goto next_attribute; + } +#endif + /* + * Get the value. + */ + if (attr->children != NULL) { + if ((attr->children->type != XML_TEXT_NODE) || + (attr->children->next != NULL)) + { + xsltTransformError(ctxt, NULL, attr->parent, + "Internal error: The children of an attribute node of a " + "literal result element are not in the expected form.\n"); + goto error; + } + value = attr->children->content; + if (value == NULL) + value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0); + } else + value = xmlDictLookup(ctxt->dict, BAD_CAST "", 0); + + /* + * Get the namespace. Avoid lookups of same namespaces. + */ + if (attr->ns != origNs) { + origNs = attr->ns; + if (attr->ns != NULL) { +#ifdef XSLT_REFACTORED + copyNs = xsltGetSpecialNamespace(ctxt, attr->parent, + attr->ns->href, attr->ns->prefix, target); +#else + copyNs = xsltGetNamespace(ctxt, attr->parent, + attr->ns, target); +#endif + if (copyNs == NULL) + goto error; + } else + copyNs = NULL; + } + /* + * Create a new attribute. + */ + if (hasAttr) { + copy = xmlSetNsProp(target, copyNs, attr->name, NULL); + } else { + /* + * Avoid checking for duplicate attributes if there aren't + * any attribute sets. + */ + copy = xmlNewDocProp(target->doc, attr->name, NULL); + + if (copy != NULL) { + copy->ns = copyNs; + + /* + * Attach it to the target element. + */ + copy->parent = target; + if (last == NULL) { + target->properties = copy; + last = copy; + } else { + last->next = copy; + copy->prev = last; + last = copy; + } + } + } + if (copy == NULL) { + if (attr->ns) { + xsltTransformError(ctxt, NULL, attr->parent, + "Internal error: Failed to create attribute '{%s}%s'.\n", + attr->ns->href, attr->name); + } else { + xsltTransformError(ctxt, NULL, attr->parent, + "Internal error: Failed to create attribute '%s'.\n", + attr->name); + } + goto error; + } + + /* + * Set the value. + */ + text = xmlNewText(NULL); + if (text != NULL) { + copy->last = copy->children = text; + text->parent = (xmlNodePtr) copy; + text->doc = copy->doc; + + if (attr->psvi != NULL) { + /* + * Evaluate the Attribute Value Template. + */ + valueAVT = xsltEvalAVT(ctxt, attr->psvi, attr->parent); + if (valueAVT == NULL) { + /* + * TODO: Damn, we need an easy mechanism to report + * qualified names! + */ + if (attr->ns) { + xsltTransformError(ctxt, NULL, attr->parent, + "Internal error: Failed to evaluate the AVT " + "of attribute '{%s}%s'.\n", + attr->ns->href, attr->name); + } else { + xsltTransformError(ctxt, NULL, attr->parent, + "Internal error: Failed to evaluate the AVT " + "of attribute '%s'.\n", + attr->name); + } + text->content = xmlStrdup(BAD_CAST ""); + goto error; + } else { + text->content = valueAVT; + } + } else if ((ctxt->internalized) && + (target->doc != NULL) && + (target->doc->dict == ctxt->dict) && + xmlDictOwns(ctxt->dict, value)) + { + text->content = (xmlChar *) value; + } else { + text->content = xmlStrdup(value); + } + if ((copy != NULL) && (text != NULL) && + (xmlIsID(copy->doc, copy->parent, copy))) + xmlAddID(NULL, copy->doc, text->content, copy); + } + +next_attribute: + attr = attr->next; + } while (attr != NULL); + + ctxt->insert = oldInsert; + return(target->properties); + +error: + ctxt->insert = oldInsert; + return(NULL); +} + + +/** + * xsltTemplateProcess: + * @ctxt: the XSLT transformation context + * @node: the attribute template node + * + * Obsolete. Don't use it. + * + * Returns NULL. + */ +xmlNodePtr * +xsltTemplateProcess(xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, xmlNodePtr node) { + if (node == NULL) + return(NULL); + + return(0); +} + + diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/templates.h chromium-145.0.7632.159/third_party/libxslt/src/libxslt/templates.h --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/templates.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/templates.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,77 @@ +/* + * Summary: interface for the template processing + * Description: This set of routine encapsulates XPath calls + * and Attribute Value Templates evaluation. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLT_TEMPLATES_H__ +#define __XML_XSLT_TEMPLATES_H__ + +#include +#include +#include "xsltexports.h" +#include "xsltInternals.h" + +#ifdef __cplusplus +extern "C" { +#endif + +XSLTPUBFUN int XSLTCALL + xsltEvalXPathPredicate (xsltTransformContextPtr ctxt, + xmlXPathCompExprPtr comp, + xmlNsPtr *nsList, + int nsNr); +XSLTPUBFUN xmlChar * XSLTCALL + xsltEvalTemplateString (xsltTransformContextPtr ctxt, + xmlNodePtr contextNode, + xmlNodePtr inst); +XSLTPUBFUN xmlChar * XSLTCALL + xsltEvalAttrValueTemplate (xsltTransformContextPtr ctxt, + xmlNodePtr node, + const xmlChar *name, + const xmlChar *ns); +XSLTPUBFUN const xmlChar * XSLTCALL + xsltEvalStaticAttrValueTemplate (xsltStylesheetPtr style, + xmlNodePtr node, + const xmlChar *name, + const xmlChar *ns, + int *found); + +/* TODO: this is obviously broken ... the namespaces should be passed too ! */ +XSLTPUBFUN xmlChar * XSLTCALL + xsltEvalXPathString (xsltTransformContextPtr ctxt, + xmlXPathCompExprPtr comp); +XSLTPUBFUN xmlChar * XSLTCALL + xsltEvalXPathStringNs (xsltTransformContextPtr ctxt, + xmlXPathCompExprPtr comp, + int nsNr, + xmlNsPtr *nsList); + +XSLTPUBFUN xmlNodePtr * XSLTCALL + xsltTemplateProcess (xsltTransformContextPtr ctxt, + xmlNodePtr node); +XSLTPUBFUN xmlAttrPtr XSLTCALL + xsltAttrListTemplateProcess (xsltTransformContextPtr ctxt, + xmlNodePtr target, + xmlAttrPtr cur); +XSLTPUBFUN xmlAttrPtr XSLTCALL + xsltAttrTemplateProcess (xsltTransformContextPtr ctxt, + xmlNodePtr target, + xmlAttrPtr attr); +XSLTPUBFUN xmlChar * XSLTCALL + xsltAttrTemplateValueProcess (xsltTransformContextPtr ctxt, + const xmlChar* attr); +XSLTPUBFUN xmlChar * XSLTCALL + xsltAttrTemplateValueProcessNode(xsltTransformContextPtr ctxt, + const xmlChar* str, + xmlNodePtr node); +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_TEMPLATES_H__ */ + diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/transform.c chromium-145.0.7632.159/third_party/libxslt/src/libxslt/transform.c --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/transform.c 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/transform.c 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,6472 @@ +/* + * transform.c: Implementation of the XSL Transformation 1.0 engine + * transform part, i.e. applying a Stylesheet to a document + * + * References: + * http://www.w3.org/TR/1999/REC-xslt-19991116 + * + * Michael Kay "XSLT Programmer's Reference" pp 637-643 + * Writing Multiple Output Files + * + * XSLT-1.1 Working Draft + * http://www.w3.org/TR/xslt11#multiple-output + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#define IN_LIBXSLT +#include "libxslt.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xslt.h" +#include "xsltInternals.h" +#include "xsltutils.h" +#include "xsltlocale.h" +#include "pattern.h" +#include "transform.h" +#include "transformInternals.h" +#include "variables.h" +#include "numbersInternals.h" +#include "namespaces.h" +#include "attributes.h" +#include "templates.h" +#include "imports.h" +#include "keys.h" +#include "documents.h" +#include "extensions.h" +#include "extra.h" +#include "preproc.h" +#include "security.h" + +#ifdef WITH_XSLT_DEBUG +#define WITH_XSLT_DEBUG_EXTRA +#define WITH_XSLT_DEBUG_PROCESS +#define WITH_XSLT_DEBUG_VARIABLE +#endif + +#define XSLT_GENERATE_HTML_DOCTYPE +#ifdef XSLT_GENERATE_HTML_DOCTYPE +static int xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID, + const xmlChar **systemID); +#endif + +int xsltMaxDepth = 3000; +int xsltMaxVars = 15000; + +/* + * Useful macros + */ + +#ifndef FALSE +# define FALSE (0 == 1) +# define TRUE (!FALSE) +#endif + +#define IS_BLANK_NODE(n) \ + (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content))) + + +/* +* Forward declarations +*/ + +static xmlNsPtr +xsltCopyNamespaceListInternal(xmlNodePtr node, xmlNsPtr cur); + +static xmlNodePtr +xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr invocNode, + xmlNodePtr node, xmlNodePtr insert, int isLRE, + int topElemVisited); + +static void +xsltApplySequenceConstructor(xsltTransformContextPtr ctxt, + xmlNodePtr contextNode, xmlNodePtr list, + xsltTemplatePtr templ); + +static void +xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt, + xmlNodePtr contextNode, + xmlNodePtr list, + xsltTemplatePtr templ, + xsltStackElemPtr withParams); + +/** + * templPush: + * @ctxt: the transformation context + * @value: the template to push on the stack + * + * Push a template on the stack + * + * Returns the new index in the stack or 0 in case of error + */ +static int +templPush(xsltTransformContextPtr ctxt, xsltTemplatePtr value) +{ + if (ctxt->templNr >= ctxt->templMax) { + xsltTemplatePtr *tmp; + int newMax = ctxt->templMax == 0 ? 4 : ctxt->templMax * 2; + + tmp = (xsltTemplatePtr *) xmlRealloc(ctxt->templTab, + newMax * sizeof(*tmp)); + if (tmp == NULL) { + xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); + return (0); + } + ctxt->templTab = tmp; + ctxt->templMax = newMax; + } + ctxt->templTab[ctxt->templNr] = value; + ctxt->templ = value; + return (ctxt->templNr++); +} +/** + * templPop: + * @ctxt: the transformation context + * + * Pop a template value from the stack + * + * Returns the stored template value + */ +static xsltTemplatePtr +templPop(xsltTransformContextPtr ctxt) +{ + xsltTemplatePtr ret; + + if (ctxt->templNr <= 0) + return (0); + ctxt->templNr--; + if (ctxt->templNr > 0) + ctxt->templ = ctxt->templTab[ctxt->templNr - 1]; + else + ctxt->templ = (xsltTemplatePtr) 0; + ret = ctxt->templTab[ctxt->templNr]; + ctxt->templTab[ctxt->templNr] = 0; + return (ret); +} + +/** + * xsltLocalVariablePop: + * @ctxt: the transformation context + * @limitNr: number of variables which should remain + * @level: the depth in the xsl:template's tree + * + * Pops all variable values at the given @depth from the stack. + * + * Returns the stored variable value + * **NOTE:** + * This is an internal routine and should not be called by users! + */ +void +xsltLocalVariablePop(xsltTransformContextPtr ctxt, int limitNr, int level) +{ + xsltStackElemPtr variable; + + if (ctxt->varsNr <= 0) + return; + + do { + if (ctxt->varsNr <= limitNr) + break; + variable = ctxt->varsTab[ctxt->varsNr - 1]; + if (variable->level <= level) + break; + if (variable->level >= 0) + xsltFreeStackElemList(variable); + ctxt->varsNr--; + } while (ctxt->varsNr != 0); + if (ctxt->varsNr > 0) + ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1]; + else + ctxt->vars = NULL; +} + +/** + * xsltTemplateParamsCleanup: + * + * Removes xsl:param and xsl:with-param items from the + * variable-stack. Only xsl:with-param items are not freed. + */ +static void +xsltTemplateParamsCleanup(xsltTransformContextPtr ctxt) +{ + xsltStackElemPtr param; + + for (; ctxt->varsNr > ctxt->varsBase; ctxt->varsNr--) { + param = ctxt->varsTab[ctxt->varsNr -1]; + /* + * Free xsl:param items. + * xsl:with-param items will have a level of -1 or -2. + */ + if (param->level >= 0) { + xsltFreeStackElemList(param); + } + } + if (ctxt->varsNr > 0) + ctxt->vars = ctxt->varsTab[ctxt->varsNr - 1]; + else + ctxt->vars = NULL; +} + +#ifdef WITH_PROFILER + +/** + * profPush: + * @ctxt: the transformation context + * @value: the profiling value to push on the stack + * + * Push a profiling value on the stack + * + * Returns the new index in the stack or 0 in case of error + */ +static int +profPush(xsltTransformContextPtr ctxt, long value) +{ + if (ctxt->profMax == 0) { + ctxt->profMax = 4; + ctxt->profTab = + (long *) xmlMalloc(ctxt->profMax * sizeof(ctxt->profTab[0])); + if (ctxt->profTab == NULL) { + xmlGenericError(xmlGenericErrorContext, "malloc failed !\n"); + return (0); + } + } + else if (ctxt->profNr >= ctxt->profMax) { + ctxt->profMax *= 2; + ctxt->profTab = + (long *) xmlRealloc(ctxt->profTab, + ctxt->profMax * sizeof(ctxt->profTab[0])); + if (ctxt->profTab == NULL) { + xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); + return (0); + } + } + ctxt->profTab[ctxt->profNr] = value; + ctxt->prof = value; + return (ctxt->profNr++); +} +/** + * profPop: + * @ctxt: the transformation context + * + * Pop a profiling value from the stack + * + * Returns the stored profiling value + */ +static long +profPop(xsltTransformContextPtr ctxt) +{ + long ret; + + if (ctxt->profNr <= 0) + return (0); + ctxt->profNr--; + if (ctxt->profNr > 0) + ctxt->prof = ctxt->profTab[ctxt->profNr - 1]; + else + ctxt->prof = (long) 0; + ret = ctxt->profTab[ctxt->profNr]; + ctxt->profTab[ctxt->profNr] = 0; + return (ret); +} + +static void +profCallgraphAdd(xsltTemplatePtr templ, xsltTemplatePtr parent) +{ + int i; + + if (templ->templMax == 0) { + templ->templMax = 4; + templ->templCalledTab = + (xsltTemplatePtr *) xmlMalloc(templ->templMax * + sizeof(templ->templCalledTab[0])); + templ->templCountTab = + (int *) xmlMalloc(templ->templMax * + sizeof(templ->templCountTab[0])); + if (templ->templCalledTab == NULL || templ->templCountTab == NULL) { + xmlGenericError(xmlGenericErrorContext, "malloc failed !\n"); + return; + } + } + else if (templ->templNr >= templ->templMax) { + templ->templMax *= 2; + templ->templCalledTab = + (xsltTemplatePtr *) xmlRealloc(templ->templCalledTab, + templ->templMax * + sizeof(templ->templCalledTab[0])); + templ->templCountTab = + (int *) xmlRealloc(templ->templCountTab, + templ->templMax * + sizeof(templ->templCountTab[0])); + if (templ->templCalledTab == NULL || templ->templCountTab == NULL) { + xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); + return; + } + } + + for (i = 0; i < templ->templNr; i++) { + if (templ->templCalledTab[i] == parent) { + templ->templCountTab[i]++; + break; + } + } + if (i == templ->templNr) { + /* not found, add new one */ + templ->templCalledTab[templ->templNr] = parent; + templ->templCountTab[templ->templNr] = 1; + templ->templNr++; + } +} + +#endif /* WITH_PROFILER */ + +/** + * xsltPreCompEval: + * @ctxt: transform context + * @node: context node + * @comp: precompiled expression + * + * Evaluate a precompiled XPath expression. + */ +static xmlXPathObjectPtr +xsltPreCompEval(xsltTransformContextPtr ctxt, xmlNodePtr node, + xsltStylePreCompPtr comp) { + xmlXPathObjectPtr res; + xmlXPathContextPtr xpctxt; + xmlNodePtr oldXPContextNode; + xmlNsPtr *oldXPNamespaces; + int oldXPProximityPosition, oldXPContextSize, oldXPNsNr; + + xpctxt = ctxt->xpathCtxt; + oldXPContextNode = xpctxt->node; + oldXPProximityPosition = xpctxt->proximityPosition; + oldXPContextSize = xpctxt->contextSize; + oldXPNsNr = xpctxt->nsNr; + oldXPNamespaces = xpctxt->namespaces; + + xpctxt->node = node; +#ifdef XSLT_REFACTORED + if (comp->inScopeNs != NULL) { + xpctxt->namespaces = comp->inScopeNs->list; + xpctxt->nsNr = comp->inScopeNs->xpathNumber; + } else { + xpctxt->namespaces = NULL; + xpctxt->nsNr = 0; + } +#else + xpctxt->namespaces = comp->nsList; + xpctxt->nsNr = comp->nsNr; +#endif + + res = xmlXPathCompiledEval(comp->comp, xpctxt); + + xpctxt->node = oldXPContextNode; + xpctxt->proximityPosition = oldXPProximityPosition; + xpctxt->contextSize = oldXPContextSize; + xpctxt->nsNr = oldXPNsNr; + xpctxt->namespaces = oldXPNamespaces; + + return(res); +} + +/** + * xsltPreCompEvalToBoolean: + * @ctxt: transform context + * @node: context node + * @comp: precompiled expression + * + * Evaluate a precompiled XPath expression as boolean. + */ +static int +xsltPreCompEvalToBoolean(xsltTransformContextPtr ctxt, xmlNodePtr node, + xsltStylePreCompPtr comp) { + int res; + xmlXPathContextPtr xpctxt; + xmlNodePtr oldXPContextNode; + xmlNsPtr *oldXPNamespaces; + int oldXPProximityPosition, oldXPContextSize, oldXPNsNr; + + xpctxt = ctxt->xpathCtxt; + oldXPContextNode = xpctxt->node; + oldXPProximityPosition = xpctxt->proximityPosition; + oldXPContextSize = xpctxt->contextSize; + oldXPNsNr = xpctxt->nsNr; + oldXPNamespaces = xpctxt->namespaces; + + xpctxt->node = node; +#ifdef XSLT_REFACTORED + if (comp->inScopeNs != NULL) { + xpctxt->namespaces = comp->inScopeNs->list; + xpctxt->nsNr = comp->inScopeNs->xpathNumber; + } else { + xpctxt->namespaces = NULL; + xpctxt->nsNr = 0; + } +#else + xpctxt->namespaces = comp->nsList; + xpctxt->nsNr = comp->nsNr; +#endif + + res = xmlXPathCompiledEvalToBoolean(comp->comp, xpctxt); + + xpctxt->node = oldXPContextNode; + xpctxt->proximityPosition = oldXPProximityPosition; + xpctxt->contextSize = oldXPContextSize; + xpctxt->nsNr = oldXPNsNr; + xpctxt->namespaces = oldXPNamespaces; + + return(res); +} + +/************************************************************************ + * * + * XInclude default settings * + * * + ************************************************************************/ + +static int xsltDoXIncludeDefault = 0; + +/** + * xsltSetXIncludeDefault: + * @xinclude: whether to do XInclude processing + * + * Set whether XInclude should be processed on document being loaded by default + */ +void +xsltSetXIncludeDefault(int xinclude) { + xsltDoXIncludeDefault = (xinclude != 0); +} + +/** + * xsltGetXIncludeDefault: + * + * Provides the default state for XInclude processing + * + * Returns 0 if there is no processing 1 otherwise + */ +int +xsltGetXIncludeDefault(void) { + return(xsltDoXIncludeDefault); +} + +static unsigned long xsltDefaultTrace = (unsigned long) XSLT_TRACE_ALL; + +/** + * xsltDebugSetDefaultTrace: + * @val: tracing level mask + * + * Set the default debug tracing level mask + */ +void xsltDebugSetDefaultTrace(xsltDebugTraceCodes val) { + xsltDefaultTrace = val; +} + +/** + * xsltDebugGetDefaultTrace: + * + * Get the current default debug tracing level mask + * + * Returns the current default debug tracing level mask + */ +xsltDebugTraceCodes xsltDebugGetDefaultTrace(void) { + return xsltDefaultTrace; +} + +/************************************************************************ + * * + * Handling of Transformation Contexts * + * * + ************************************************************************/ + +static xsltTransformCachePtr +xsltTransformCacheCreate(void) +{ + xsltTransformCachePtr ret; + + ret = (xsltTransformCachePtr) xmlMalloc(sizeof(xsltTransformCache)); + if (ret == NULL) { + xsltTransformError(NULL, NULL, NULL, + "xsltTransformCacheCreate : malloc failed\n"); + return(NULL); + } + memset(ret, 0, sizeof(xsltTransformCache)); + return(ret); +} + +static void +xsltTransformCacheFree(xsltTransformCachePtr cache) +{ + if (cache == NULL) + return; + /* + * Free tree fragments. + */ + if (cache->rvtList) { + xsltRVTListPtr tmp, cur = cache->rvtList; + while (cur) { + tmp = cur; + cur = cur->next; + if (tmp->RVT->_private != NULL) { + /* + * Free the document info. + */ + xsltFreeDocumentKeys((xsltDocumentPtr) tmp->RVT->_private); + xmlFree(tmp->RVT->_private); + } + xmlFreeDoc(tmp->RVT); + xmlFree(tmp); + } + } + /* + * Free vars/params. + */ + if (cache->stackItems) { + xsltStackElemPtr tmp, cur = cache->stackItems; + while (cur) { + tmp = cur; + cur = cur->next; + /* + * REVISIT TODO: Should be call a destruction-function + * instead? + */ + xmlFree(tmp); + } + } + xmlFree(cache); +} + +/** + * xsltNewTransformContext: + * @style: a parsed XSLT stylesheet + * @doc: the input document + * + * Create a new XSLT TransformContext + * + * Returns the newly allocated xsltTransformContextPtr or NULL in case of error + */ +xsltTransformContextPtr +xsltNewTransformContext(xsltStylesheetPtr style, xmlDocPtr doc) { + xsltTransformContextPtr cur; + xsltDocumentPtr docu; + int i; + + xsltInitGlobals(); + + cur = (xsltTransformContextPtr) xmlMalloc(sizeof(xsltTransformContext)); + if (cur == NULL) { + xsltTransformError(NULL, NULL, (xmlNodePtr)doc, + "xsltNewTransformContext : malloc failed\n"); + return(NULL); + } + memset(cur, 0, sizeof(xsltTransformContext)); + + cur->cache = xsltTransformCacheCreate(); + if (cur->cache == NULL) + goto internal_err; + /* + * setup of the dictionary must be done early as some of the + * processing later like key handling may need it. + */ + cur->dict = xmlDictCreateSub(style->dict); + cur->internalized = ((style->internalized) && (cur->dict != NULL)); +#ifdef WITH_XSLT_DEBUG + xsltGenericDebug(xsltGenericDebugContext, + "Creating sub-dictionary from stylesheet for transformation\n"); +#endif + + /* + * initialize the template stack + */ + cur->templTab = (xsltTemplatePtr *) + xmlMalloc(10 * sizeof(xsltTemplatePtr)); + if (cur->templTab == NULL) { + xsltTransformError(NULL, NULL, (xmlNodePtr) doc, + "xsltNewTransformContext: out of memory\n"); + goto internal_err; + } + cur->templNr = 0; + cur->templMax = 5; + cur->templ = NULL; + cur->maxTemplateDepth = xsltMaxDepth; + + /* + * initialize the variables stack + */ + cur->varsTab = (xsltStackElemPtr *) + xmlMalloc(10 * sizeof(xsltStackElemPtr)); + if (cur->varsTab == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xsltNewTransformContext: out of memory\n"); + goto internal_err; + } + cur->varsNr = 0; + cur->varsMax = 10; + cur->vars = NULL; + cur->varsBase = 0; + cur->maxTemplateVars = xsltMaxVars; + + /* + * the profiling stack is not initialized by default + */ + cur->profTab = NULL; + cur->profNr = 0; + cur->profMax = 0; + cur->prof = 0; + + cur->style = style; + cur->xpathCtxt = xmlXPathNewContext(doc); + if (cur->xpathCtxt == NULL) { + xsltTransformError(NULL, NULL, (xmlNodePtr) doc, + "xsltNewTransformContext : xmlXPathNewContext failed\n"); + goto internal_err; + } + /* + * Create an XPath cache. + */ + if (xmlXPathContextSetCache(cur->xpathCtxt, 1, -1, 0) == -1) + goto internal_err; + /* + * Initialize the extras array + */ + if (style->extrasNr != 0) { + cur->extrasMax = style->extrasNr + 20; + cur->extras = (xsltRuntimeExtraPtr) + xmlMalloc(cur->extrasMax * sizeof(xsltRuntimeExtra)); + if (cur->extras == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xsltNewTransformContext: out of memory\n"); + goto internal_err; + } + cur->extrasNr = style->extrasNr; + for (i = 0;i < cur->extrasMax;i++) { + cur->extras[i].info = NULL; + cur->extras[i].deallocate = NULL; + cur->extras[i].val.ptr = NULL; + } + } else { + cur->extras = NULL; + cur->extrasNr = 0; + cur->extrasMax = 0; + } + + XSLT_REGISTER_VARIABLE_LOOKUP(cur); + XSLT_REGISTER_FUNCTION_LOOKUP(cur); + cur->xpathCtxt->nsHash = style->nsHash; + /* + * Initialize the registered external modules + */ + xsltInitCtxtExts(cur); + /* + * Setup document element ordering for later efficiencies + * (bug 133289) + */ + if (xslDebugStatus == XSLT_DEBUG_NONE) + xmlXPathOrderDocElems(doc); + /* + * Must set parserOptions before calling xsltNewDocument + * (bug 164530) + */ + cur->parserOptions = XSLT_PARSE_OPTIONS; + docu = xsltNewDocument(cur, doc); + if (docu == NULL) { + xsltTransformError(cur, NULL, (xmlNodePtr)doc, + "xsltNewTransformContext : xsltNewDocument failed\n"); + goto internal_err; + } + docu->main = 1; + cur->document = docu; + cur->inst = NULL; + cur->outputFile = NULL; + cur->sec = xsltGetDefaultSecurityPrefs(); + cur->debugStatus = xslDebugStatus; + cur->traceCode = (unsigned long*) &xsltDefaultTrace; + cur->xinclude = xsltGetXIncludeDefault(); + cur->keyInitLevel = 0; + + cur->newLocale = xsltNewLocale; + cur->freeLocale = xsltFreeLocale; + cur->genSortKey = xsltStrxfrm; + + return(cur); + +internal_err: + if (cur != NULL) + xsltFreeTransformContext(cur); + return(NULL); +} + +/** + * xsltFreeTransformContext: + * @ctxt: an XSLT transform context + * + * Free up the memory allocated by @ctxt + */ +void +xsltFreeTransformContext(xsltTransformContextPtr ctxt) { + if (ctxt == NULL) + return; + + /* + * Shutdown the extension modules associated to the stylesheet + * used if needed. + */ + xsltShutdownCtxtExts(ctxt); + + if (ctxt->xpathCtxt != NULL) { + ctxt->xpathCtxt->nsHash = NULL; + xmlXPathFreeContext(ctxt->xpathCtxt); + } + if (ctxt->templTab != NULL) + xmlFree(ctxt->templTab); + if (ctxt->varsTab != NULL) + xmlFree(ctxt->varsTab); + if (ctxt->profTab != NULL) + xmlFree(ctxt->profTab); + if ((ctxt->extrasNr > 0) && (ctxt->extras != NULL)) { + int i; + + for (i = 0;i < ctxt->extrasNr;i++) { + if ((ctxt->extras[i].deallocate != NULL) && + (ctxt->extras[i].info != NULL)) + ctxt->extras[i].deallocate(ctxt->extras[i].info); + } + xmlFree(ctxt->extras); + } + xsltFreeGlobalVariables(ctxt); + xsltFreeDocuments(ctxt); + xsltFreeCtxtExts(ctxt); + xsltFreeRVTs(ctxt); + xsltTransformCacheFree(ctxt->cache); + xmlDictFree(ctxt->dict); +#ifdef WITH_XSLT_DEBUG + xsltGenericDebug(xsltGenericDebugContext, + "freeing transformation dictionary\n"); +#endif + memset(ctxt, -1, sizeof(xsltTransformContext)); + xmlFree(ctxt); +} + +/************************************************************************ + * * + * Copy of Nodes in an XSLT fashion * + * * + ************************************************************************/ + +/** + * xsltAddChild: + * @parent: the parent node + * @cur: the child node + * + * Wrapper version of xmlAddChild with a more consistent behaviour on + * error. One expect the use to be child = xsltAddChild(parent, child); + * and the routine will take care of not leaking on errors or node merge + * + * Returns the child is successfully attached or NULL if merged or freed + */ +static xmlNodePtr +xsltAddChild(xmlNodePtr parent, xmlNodePtr cur) { + xmlNodePtr ret; + + if (cur == NULL) + return(NULL); + if (parent == NULL) { + xmlFreeNode(cur); + return(NULL); + } + ret = xmlAddChild(parent, cur); + + return(ret); +} + +/** + * xsltAddTextString: + * @ctxt: a XSLT process context + * @target: the text node where the text will be attached + * @string: the text string + * @len: the string length in byte + * + * Extend the current text node with the new string, it handles coalescing + * + * Returns: the text node + */ +static xmlNodePtr +xsltAddTextString(xsltTransformContextPtr ctxt, xmlNodePtr target, + const xmlChar *string, int len) { + /* + * optimization + */ + if ((len <= 0) || (string == NULL) || (target == NULL)) + return(target); + + if (ctxt->lasttext == target->content) { + int minSize; + + /* Check for integer overflow accounting for NUL terminator. */ + if (len >= INT_MAX - ctxt->lasttuse) { + xsltTransformError(ctxt, NULL, target, + "xsltCopyText: text allocation failed\n"); + return(NULL); + } + minSize = ctxt->lasttuse + len + 1; + + if (ctxt->lasttsize < minSize) { + xmlChar *newbuf; + int size; + int extra; + + /* Double buffer size but increase by at least 100 bytes. */ + extra = minSize < 100 ? 100 : minSize; + + /* Check for integer overflow. */ + if (extra > INT_MAX - ctxt->lasttsize) { + size = INT_MAX; + } + else { + size = ctxt->lasttsize + extra; + } + + newbuf = (xmlChar *) xmlRealloc(target->content,size); + if (newbuf == NULL) { + xsltTransformError(ctxt, NULL, target, + "xsltCopyText: text allocation failed\n"); + return(NULL); + } + ctxt->lasttsize = size; + ctxt->lasttext = newbuf; + target->content = newbuf; + } + memcpy(&(target->content[ctxt->lasttuse]), string, len); + ctxt->lasttuse += len; + target->content[ctxt->lasttuse] = 0; + } else { + xmlNodeAddContent(target, string); + ctxt->lasttext = target->content; + len = xmlStrlen(target->content); + ctxt->lasttsize = len; + ctxt->lasttuse = len; + } + return(target); +} + +/** + * xsltCopyTextString: + * @ctxt: a XSLT process context + * @target: the element where the text will be attached + * @string: the text string + * @noescape: should disable-escaping be activated for this text node. + * + * Adds @string to a newly created or an existent text node child of + * @target. + * + * Returns: the text node, where the text content of @cur is copied to. + * NULL in case of API or internal errors. + */ +xmlNodePtr +xsltCopyTextString(xsltTransformContextPtr ctxt, xmlNodePtr target, + const xmlChar *string, int noescape) +{ + xmlNodePtr copy; + int len; + + if (string == NULL) + return(NULL); + +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext, + "xsltCopyTextString: copy text %s\n", + string)); +#endif + + /* + * Play safe and reset the merging mechanism for every new + * target node. + */ + if ((target == NULL) || (target->children == NULL)) { + ctxt->lasttext = NULL; + } + + /* handle coalescing of text nodes here */ + len = xmlStrlen(string); + if ((ctxt->type == XSLT_OUTPUT_XML) && + (ctxt->style->cdataSection != NULL) && + (target != NULL) && + (target->type == XML_ELEMENT_NODE) && + (((target->ns == NULL) && + (xmlHashLookup2(ctxt->style->cdataSection, + target->name, NULL) != NULL)) || + ((target->ns != NULL) && + (xmlHashLookup2(ctxt->style->cdataSection, + target->name, target->ns->href) != NULL)))) + { + /* + * Process "cdata-section-elements". + */ + if ((target->last != NULL) && + (target->last->type == XML_CDATA_SECTION_NODE)) + { + return(xsltAddTextString(ctxt, target->last, string, len)); + } + copy = xmlNewCDataBlock(ctxt->output, string, len); + } else if (noescape) { + /* + * Process "disable-output-escaping". + */ + if ((target != NULL) && (target->last != NULL) && + (target->last->type == XML_TEXT_NODE) && + (target->last->name == xmlStringTextNoenc)) + { + return(xsltAddTextString(ctxt, target->last, string, len)); + } + copy = xmlNewTextLen(string, len); + if (copy != NULL) + copy->name = xmlStringTextNoenc; + } else { + /* + * Default processing. + */ + if ((target != NULL) && (target->last != NULL) && + (target->last->type == XML_TEXT_NODE) && + (target->last->name == xmlStringText)) { + return(xsltAddTextString(ctxt, target->last, string, len)); + } + copy = xmlNewTextLen(string, len); + } + if (copy != NULL && target != NULL) + copy = xsltAddChild(target, copy); + if (copy != NULL) { + ctxt->lasttext = copy->content; + ctxt->lasttsize = len; + ctxt->lasttuse = len; + } else { + xsltTransformError(ctxt, NULL, target, + "xsltCopyTextString: text copy failed\n"); + ctxt->lasttext = NULL; + } + return(copy); +} + +/** + * xsltCopyText: + * @ctxt: a XSLT process context + * @target: the element where the text will be attached + * @cur: the text or CDATA node + * @interned: the string is in the target doc dictionary + * + * Copy the text content of @cur and append it to @target's children. + * + * Returns: the text node, where the text content of @cur is copied to. + * NULL in case of API or internal errors. + */ +static xmlNodePtr +xsltCopyText(xsltTransformContextPtr ctxt, xmlNodePtr target, + xmlNodePtr cur, int interned) +{ + xmlNodePtr copy; + + if ((cur->type != XML_TEXT_NODE) && + (cur->type != XML_CDATA_SECTION_NODE)) + return(NULL); + if (cur->content == NULL) + return(NULL); + +#ifdef WITH_XSLT_DEBUG_PROCESS + if (cur->type == XML_CDATA_SECTION_NODE) { + XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext, + "xsltCopyText: copy CDATA text %s\n", + cur->content)); + } else if (cur->name == xmlStringTextNoenc) { + XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext, + "xsltCopyText: copy unescaped text %s\n", + cur->content)); + } else { + XSLT_TRACE(ctxt,XSLT_TRACE_COPY_TEXT,xsltGenericDebug(xsltGenericDebugContext, + "xsltCopyText: copy text %s\n", + cur->content)); + } +#endif + + /* + * Play save and reset the merging mechanism for every new + * target node. + */ + if ((target == NULL) || (target->children == NULL)) { + ctxt->lasttext = NULL; + } + + if ((ctxt->style->cdataSection != NULL) && + (ctxt->type == XSLT_OUTPUT_XML) && + (target != NULL) && + (target->type == XML_ELEMENT_NODE) && + (((target->ns == NULL) && + (xmlHashLookup2(ctxt->style->cdataSection, + target->name, NULL) != NULL)) || + ((target->ns != NULL) && + (xmlHashLookup2(ctxt->style->cdataSection, + target->name, target->ns->href) != NULL)))) + { + /* + * Process "cdata-section-elements". + */ + /* + * OPTIMIZE TODO: xsltCopyText() is also used for attribute content. + */ + /* + * TODO: Since this doesn't merge adjacent CDATA-section nodes, + * we'll get: . + * TODO: Reported in #321505. + */ + if ((target->last != NULL) && + (target->last->type == XML_CDATA_SECTION_NODE)) + { + /* + * Append to existing CDATA-section node. + */ + copy = xsltAddTextString(ctxt, target->last, cur->content, + xmlStrlen(cur->content)); + goto exit; + } else { + unsigned int len; + + len = xmlStrlen(cur->content); + copy = xmlNewCDataBlock(ctxt->output, cur->content, len); + if (copy == NULL) + goto exit; + ctxt->lasttext = copy->content; + ctxt->lasttsize = len; + ctxt->lasttuse = len; + } + } else if ((target != NULL) && + (target->last != NULL) && + /* both escaped or both non-escaped text-nodes */ + (((target->last->type == XML_TEXT_NODE) && + (target->last->name == cur->name)) || + /* non-escaped text nodes and CDATA-section nodes */ + (((target->last->type == XML_CDATA_SECTION_NODE) && + (cur->name == xmlStringTextNoenc))))) + { + /* + * we are appending to an existing text node + */ + copy = xsltAddTextString(ctxt, target->last, cur->content, + xmlStrlen(cur->content)); + goto exit; + } else if ((interned) && (target != NULL) && + (target->doc != NULL) && + (target->doc->dict == ctxt->dict)) + { + /* + * TODO: DO we want to use this also for "text" output? + */ + copy = xmlNewTextLen(NULL, 0); + if (copy == NULL) + goto exit; + if (cur->name == xmlStringTextNoenc) + copy->name = xmlStringTextNoenc; + + /* + * Must confirm that content is in dict (bug 302821) + * TODO: This check should be not needed for text coming + * from the stylesheets + */ + if (xmlDictOwns(ctxt->dict, cur->content)) + copy->content = cur->content; + else { + if ((copy->content = xmlStrdup(cur->content)) == NULL) { + xmlFreeNode(copy); + return NULL; + } + } + + ctxt->lasttext = NULL; + } else { + /* + * normal processing. keep counters to extend the text node + * in xsltAddTextString if needed. + */ + unsigned int len; + + len = xmlStrlen(cur->content); + copy = xmlNewTextLen(cur->content, len); + if (copy == NULL) + goto exit; + if (cur->name == xmlStringTextNoenc) + copy->name = xmlStringTextNoenc; + ctxt->lasttext = copy->content; + ctxt->lasttsize = len; + ctxt->lasttuse = len; + } + if (copy != NULL) { + if (target != NULL) { + copy->doc = target->doc; + /* + * MAYBE TODO: Maybe we should reset the ctxt->lasttext here + * to ensure that the optimized text-merging mechanism + * won't interfere with normal node-merging in any case. + */ + copy = xsltAddChild(target, copy); + } + } else { + xsltTransformError(ctxt, NULL, target, + "xsltCopyText: text copy failed\n"); + } + +exit: + if ((copy == NULL) || (copy->content == NULL)) { + xsltTransformError(ctxt, NULL, target, + "Internal error in xsltCopyText(): " + "Failed to copy the string.\n"); + ctxt->state = XSLT_STATE_STOPPED; + } + return(copy); +} + +/** + * xsltShallowCopyAttr: + * @ctxt: a XSLT process context + * @invocNode: responsible node in the stylesheet; used for error reports + * @target: the element where the attribute will be grafted + * @attr: the attribute to be copied + * + * Do a copy of an attribute. + * Called by: + * - xsltCopyTree() + * - xsltCopyOf() + * - xsltCopy() + * + * Returns: a new xmlAttrPtr, or NULL in case of error. + */ +static xmlAttrPtr +xsltShallowCopyAttr(xsltTransformContextPtr ctxt, xmlNodePtr invocNode, + xmlNodePtr target, xmlAttrPtr attr) +{ + xmlAttrPtr copy; + xmlChar *value; + + if (attr == NULL) + return(NULL); + + if (target->type != XML_ELEMENT_NODE) { + xsltTransformError(ctxt, NULL, invocNode, + "Cannot add an attribute node to a non-element node.\n"); + return(NULL); + } + + if (target->children != NULL) { + xsltTransformError(ctxt, NULL, invocNode, + "Attribute nodes must be added before " + "any child nodes to an element.\n"); + return(NULL); + } + + value = xmlNodeListGetString(attr->doc, attr->children, 1); + if (attr->ns != NULL) { + xmlNsPtr ns; + + ns = xsltGetSpecialNamespace(ctxt, invocNode, + attr->ns->href, attr->ns->prefix, target); + if (ns == NULL) { + xsltTransformError(ctxt, NULL, invocNode, + "Namespace fixup error: Failed to acquire an in-scope " + "namespace binding of the copied attribute '{%s}%s'.\n", + attr->ns->href, attr->name); + /* + * TODO: Should we just stop here? + */ + } + /* + * Note that xmlSetNsProp() will take care of duplicates + * and assigns the new namespace even to a duplicate. + */ + copy = xmlSetNsProp(target, ns, attr->name, value); + } else { + copy = xmlSetNsProp(target, NULL, attr->name, value); + } + if (value != NULL) + xmlFree(value); + + if (copy == NULL) + return(NULL); + +#if 0 + /* + * NOTE: This was optimized according to bug #342695. + * TODO: Can this further be optimized, if source and target + * share the same dict and attr->children is just 1 text node + * which is in the dict? How probable is such a case? + */ + /* + * TODO: Do we need to create an empty text node if the value + * is the empty string? + */ + value = xmlNodeListGetString(attr->doc, attr->children, 1); + if (value != NULL) { + txtNode = xmlNewDocText(target->doc, NULL); + if (txtNode == NULL) + return(NULL); + if ((target->doc != NULL) && + (target->doc->dict != NULL)) + { + txtNode->content = + (xmlChar *) xmlDictLookup(target->doc->dict, + BAD_CAST value, -1); + xmlFree(value); + } else + txtNode->content = value; + copy->children = txtNode; + } +#endif + + return(copy); +} + +/** + * xsltCopyAttrListNoOverwrite: + * @ctxt: a XSLT process context + * @invocNode: responsible node in the stylesheet; used for error reports + * @target: the element where the new attributes will be grafted + * @attr: the first attribute in the list to be copied + * + * Copies a list of attribute nodes, starting with @attr, over to the + * @target element node. + * + * Called by: + * - xsltCopyTree() + * + * Returns 0 on success and -1 on errors and internal errors. + */ +static int +xsltCopyAttrListNoOverwrite(xsltTransformContextPtr ctxt, + xmlNodePtr invocNode, + xmlNodePtr target, xmlAttrPtr attr) +{ + xmlAttrPtr copy; + xmlNsPtr origNs = NULL, copyNs = NULL; + xmlChar *value; + + /* + * Don't use xmlCopyProp() here, since it will try to + * reconciliate namespaces. + */ + while (attr != NULL) { + /* + * Find a namespace node in the tree of @target. + * Avoid searching for the same ns. + */ + if (attr->ns != origNs) { + origNs = attr->ns; + if (attr->ns != NULL) { + copyNs = xsltGetSpecialNamespace(ctxt, invocNode, + attr->ns->href, attr->ns->prefix, target); + if (copyNs == NULL) + return(-1); + } else + copyNs = NULL; + } + /* + * If attribute has a value, we need to copy it (watching out + * for possible entities) + */ + if ((attr->children) && (attr->children->type == XML_TEXT_NODE) && + (attr->children->next == NULL)) { + copy = xmlNewNsProp(target, copyNs, attr->name, + attr->children->content); + } else if (attr->children != NULL) { + value = xmlNodeListGetString(attr->doc, attr->children, 1); + copy = xmlNewNsProp(target, copyNs, attr->name, BAD_CAST value); + xmlFree(value); + } else { + copy = xmlNewNsProp(target, copyNs, attr->name, NULL); + } + + if (copy == NULL) + return(-1); + + attr = attr->next; + } + return(0); +} + +/** + * xsltShallowCopyElem: + * @ctxt: the XSLT process context + * @node: the element node in the source tree + * or the Literal Result Element + * @insert: the parent in the result tree + * @isLRE: if @node is a Literal Result Element + * + * Make a copy of the element node @node + * and insert it as last child of @insert. + * + * URGENT TODO: The problem with this one (for the non-refactored code) + * is that it is used for both, Literal Result Elements *and* + * copying input nodes. + * + * BIG NOTE: This is only called for XML_ELEMENT_NODEs. + * + * Called from: + * xsltApplySequenceConstructor() + * (for Literal Result Elements - which is a problem) + * xsltCopy() (for shallow-copying elements via xsl:copy) + * + * Returns a pointer to the new node, or NULL in case of error + */ +static xmlNodePtr +xsltShallowCopyElem(xsltTransformContextPtr ctxt, xmlNodePtr node, + xmlNodePtr insert, int isLRE) +{ + xmlNodePtr copy; + + if ((node->type == XML_DTD_NODE) || (insert == NULL)) + return(NULL); + if ((node->type == XML_TEXT_NODE) || + (node->type == XML_CDATA_SECTION_NODE)) + return(xsltCopyText(ctxt, insert, node, 0)); + + copy = xmlDocCopyNode(node, insert->doc, 0); + if (copy != NULL) { + copy->doc = ctxt->output; + copy = xsltAddChild(insert, copy); + if (copy == NULL) { + xsltTransformError(ctxt, NULL, node, + "xsltShallowCopyElem: copy failed\n"); + return (copy); + } + + if (node->type == XML_ELEMENT_NODE) { + /* + * Add namespaces as they are needed + */ + if (node->nsDef != NULL) { + /* + * TODO: Remove the LRE case in the refactored code + * gets enabled. + */ + if (isLRE) + xsltCopyNamespaceList(ctxt, copy, node->nsDef); + else + xsltCopyNamespaceListInternal(copy, node->nsDef); + } + + /* + * URGENT TODO: The problem with this is that it does not + * copy over all namespace nodes in scope. + * The damn thing about this is, that we would need to + * use the xmlGetNsList(), for every single node; this is + * also done in xsltCopyTree(), but only for the top node. + */ + if (node->ns != NULL) { + if (isLRE) { + /* + * REVISIT TODO: Since the non-refactored code still does + * ns-aliasing, we need to call xsltGetNamespace() here. + * Remove this when ready. + */ + copy->ns = xsltGetNamespace(ctxt, node, node->ns, copy); + } else { + copy->ns = xsltGetSpecialNamespace(ctxt, + node, node->ns->href, node->ns->prefix, copy); + + } + } else if ((insert->type == XML_ELEMENT_NODE) && + (insert->ns != NULL)) + { + /* + * "Undeclare" the default namespace. + */ + xsltGetSpecialNamespace(ctxt, node, NULL, NULL, copy); + } + } + } else { + xsltTransformError(ctxt, NULL, node, + "xsltShallowCopyElem: copy %s failed\n", node->name); + } + return(copy); +} + +/** + * xsltCopyTreeList: + * @ctxt: a XSLT process context + * @invocNode: responsible node in the stylesheet; used for error reports + * @list: the list of element nodes in the source tree. + * @insert: the parent in the result tree. + * @isLRE: is this a literal result element list + * @topElemVisited: indicates if a top-most element was already processed + * + * Make a copy of the full list of tree @list + * and insert it as last children of @insert + * + * NOTE: Not to be used for Literal Result Elements. + * + * Used by: + * - xsltCopyOf() + * + * Returns a pointer to the new list, or NULL in case of error + */ +static xmlNodePtr +xsltCopyTreeList(xsltTransformContextPtr ctxt, xmlNodePtr invocNode, + xmlNodePtr list, + xmlNodePtr insert, int isLRE, int topElemVisited) +{ + xmlNodePtr copy, ret = NULL; + + while (list != NULL) { + copy = xsltCopyTree(ctxt, invocNode, + list, insert, isLRE, topElemVisited); + if (copy != NULL) { + if (ret == NULL) { + ret = copy; + } + } + list = list->next; + } + return(ret); +} + +/** + * xsltCopyNamespaceListInternal: + * @node: the target node + * @cur: the first namespace + * + * Do a copy of a namespace list. If @node is non-NULL the + * new namespaces are added automatically. + * Called by: + * xsltCopyTree() + * + * QUESTION: What is the exact difference between this function + * and xsltCopyNamespaceList() in "namespaces.c"? + * ANSWER: xsltCopyNamespaceList() tries to apply ns-aliases. + * + * Returns: a new xmlNsPtr, or NULL in case of error. + */ +static xmlNsPtr +xsltCopyNamespaceListInternal(xmlNodePtr elem, xmlNsPtr ns) { + xmlNsPtr ret = NULL; + xmlNsPtr p = NULL, q, luNs; + + if (ns == NULL) + return(NULL); + /* + * One can add namespaces only on element nodes + */ + if ((elem != NULL) && (elem->type != XML_ELEMENT_NODE)) + elem = NULL; + + do { + if (ns->type != XML_NAMESPACE_DECL) + break; + /* + * Avoid duplicating namespace declarations on the tree. + */ + if (elem != NULL) { + if ((elem->ns != NULL) && + xmlStrEqual(elem->ns->prefix, ns->prefix) && + xmlStrEqual(elem->ns->href, ns->href)) + { + ns = ns->next; + continue; + } + luNs = xmlSearchNs(elem->doc, elem, ns->prefix); + if ((luNs != NULL) && (xmlStrEqual(luNs->href, ns->href))) + { + ns = ns->next; + continue; + } + } + q = xmlNewNs(elem, ns->href, ns->prefix); + if (p == NULL) { + ret = p = q; + } else if (q != NULL) { + p->next = q; + p = q; + } + ns = ns->next; + } while (ns != NULL); + return(ret); +} + +/** + * xsltShallowCopyNsNode: + * @ctxt: the XSLT transformation context + * @invocNode: responsible node in the stylesheet; used for error reports + * @insert: the target element node in the result tree + * @ns: the namespace node + * + * This is used for copying ns-nodes with xsl:copy-of and xsl:copy. + * + * Returns a new/existing ns-node, or NULL. + */ +static xmlNsPtr +xsltShallowCopyNsNode(xsltTransformContextPtr ctxt, + xmlNodePtr invocNode, + xmlNodePtr insert, + xmlNsPtr ns) +{ + /* + * TODO: Contrary to header comments, this is declared as int. + * be modified to return a node pointer, or NULL if any error + */ + xmlNsPtr tmpns; + + if ((insert == NULL) || (insert->type != XML_ELEMENT_NODE)) + return(NULL); + + if (insert->children != NULL) { + xsltTransformError(ctxt, NULL, invocNode, + "Namespace nodes must be added before " + "any child nodes are added to an element.\n"); + return(NULL); + } + /* + * BIG NOTE: Xalan-J simply overwrites any ns-decls with + * an equal prefix. We definitively won't do that. + * + * MSXML 4.0 and the .NET ignores ns-decls for which an + * equal prefix is already in use. + * + * Saxon raises an error like: + * "net.sf.saxon.xpath.DynamicError: Cannot create two namespace + * nodes with the same name". + * + * NOTE: We'll currently follow MSXML here. + * REVISIT TODO: Check if it's better to follow Saxon here. + */ + if (ns->prefix == NULL) { + /* + * If we are adding ns-nodes to an element using e.g. + * , then we need + * to ensure that we don't incorrectly declare a default + * namespace on an element in no namespace, which otherwise + * would move the element incorrectly into a namespace, if + * the node tree is serialized. + */ + if (insert->ns == NULL) + goto occupied; + } else if ((ns->prefix[0] == 'x') && + xmlStrEqual(ns->prefix, BAD_CAST "xml")) + { + /* + * The XML namespace is built in. + */ + return(NULL); + } + + if (insert->nsDef != NULL) { + tmpns = insert->nsDef; + do { + if ((tmpns->prefix == NULL) == (ns->prefix == NULL)) { + if ((tmpns->prefix == ns->prefix) || + xmlStrEqual(tmpns->prefix, ns->prefix)) + { + /* + * Same prefix. + */ + if (xmlStrEqual(tmpns->href, ns->href)) + return(NULL); + goto occupied; + } + } + tmpns = tmpns->next; + } while (tmpns != NULL); + } + tmpns = xmlSearchNs(insert->doc, insert, ns->prefix); + if ((tmpns != NULL) && xmlStrEqual(tmpns->href, ns->href)) + return(NULL); + /* + * Declare a new namespace. + * TODO: The problem (wrt efficiency) with this xmlNewNs() is + * that it will again search the already declared namespaces + * for a duplicate :-/ + */ + return(xmlNewNs(insert, ns->href, ns->prefix)); + +occupied: + /* + * TODO: We could as well raise an error here (like Saxon does), + * or at least generate a warning. + */ + return(NULL); +} + +/** + * xsltCopyTree: + * @ctxt: the XSLT transformation context + * @invocNode: responsible node in the stylesheet; used for error reports + * @node: the element node in the source tree + * @insert: the parent in the result tree + * @isLRE: indicates if @node is a Literal Result Element + * @topElemVisited: indicates if a top-most element was already processed + * + * Make a copy of the full tree under the element node @node + * and insert it as last child of @insert + * + * NOTE: Not to be used for Literal Result Elements. + * + * Used by: + * - xsltCopyOf() + * + * Returns a pointer to the new tree, or NULL in case of error + */ +static xmlNodePtr +xsltCopyTree(xsltTransformContextPtr ctxt, xmlNodePtr invocNode, + xmlNodePtr node, xmlNodePtr insert, int isLRE, + int topElemVisited) +{ + xmlNodePtr copy; + + if (node == NULL) + return(NULL); + switch (node->type) { + case XML_ELEMENT_NODE: + case XML_ENTITY_REF_NODE: + case XML_ENTITY_NODE: + case XML_PI_NODE: + case XML_COMMENT_NODE: + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + break; + case XML_TEXT_NODE: { + int noenc = (node->name == xmlStringTextNoenc); + return(xsltCopyTextString(ctxt, insert, node->content, noenc)); + } + case XML_CDATA_SECTION_NODE: + return(xsltCopyTextString(ctxt, insert, node->content, 0)); + case XML_ATTRIBUTE_NODE: + return((xmlNodePtr) + xsltShallowCopyAttr(ctxt, invocNode, insert, (xmlAttrPtr) node)); + case XML_NAMESPACE_DECL: + return((xmlNodePtr) xsltShallowCopyNsNode(ctxt, invocNode, + insert, (xmlNsPtr) node)); + + case XML_DOCUMENT_TYPE_NODE: + case XML_DOCUMENT_FRAG_NODE: + case XML_NOTATION_NODE: + case XML_DTD_NODE: + case XML_ELEMENT_DECL: + case XML_ATTRIBUTE_DECL: + case XML_ENTITY_DECL: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: + return(NULL); + } + if (XSLT_IS_RES_TREE_FRAG(node)) { + if (node->children != NULL) + copy = xsltCopyTreeList(ctxt, invocNode, + node->children, insert, 0, 0); + else + copy = NULL; + return(copy); + } + copy = xmlDocCopyNode(node, insert->doc, 0); + if (copy != NULL) { + copy->doc = ctxt->output; + copy = xsltAddChild(insert, copy); + if (copy == NULL) { + xsltTransformError(ctxt, NULL, invocNode, + "xsltCopyTree: Copying of '%s' failed.\n", node->name); + return (copy); + } + /* + * The node may have been coalesced into another text node. + */ + if (insert->last != copy) + return(insert->last); + copy->next = NULL; + + if (node->type == XML_ELEMENT_NODE) { + /* + * Copy in-scope namespace nodes. + * + * REVISIT: Since we try to reuse existing in-scope ns-decls by + * using xmlSearchNsByHref(), this will eventually change + * the prefix of an original ns-binding; thus it might + * break QNames in element/attribute content. + * OPTIMIZE TODO: If we had a xmlNsPtr * on the transformation + * context, plus a ns-lookup function, which writes directly + * to a given list, then we wouldn't need to create/free the + * nsList every time. + */ + if ((topElemVisited == 0) && + (node->parent != NULL) && + (node->parent->type != XML_DOCUMENT_NODE) && + (node->parent->type != XML_HTML_DOCUMENT_NODE)) + { + xmlNsPtr *nsList, *curns, ns; + + /* + * If this is a top-most element in a tree to be + * copied, then we need to ensure that all in-scope + * namespaces are copied over. For nodes deeper in the + * tree, it is sufficient to reconcile only the ns-decls + * (node->nsDef entries). + */ + + nsList = xmlGetNsList(node->doc, node); + if (nsList != NULL) { + curns = nsList; + do { + /* + * Search by prefix first in order to break as less + * QNames in element/attribute content as possible. + */ + ns = xmlSearchNs(insert->doc, insert, + (*curns)->prefix); + + if ((ns == NULL) || + (! xmlStrEqual(ns->href, (*curns)->href))) + { + ns = NULL; + /* + * Search by namespace name. + * REVISIT TODO: Currently disabled. + */ +#if 0 + ns = xmlSearchNsByHref(insert->doc, + insert, (*curns)->href); +#endif + } + if (ns == NULL) { + /* + * Declare a new namespace on the copied element. + */ + ns = xmlNewNs(copy, (*curns)->href, + (*curns)->prefix); + /* TODO: Handle errors */ + } + if (node->ns == *curns) { + /* + * If this was the original's namespace then set + * the generated counterpart on the copy. + */ + copy->ns = ns; + } + curns++; + } while (*curns != NULL); + xmlFree(nsList); + } + } else if (node->nsDef != NULL) { + /* + * Copy over all namespace declaration attributes. + */ + if (node->nsDef != NULL) { + if (isLRE) + xsltCopyNamespaceList(ctxt, copy, node->nsDef); + else + xsltCopyNamespaceListInternal(copy, node->nsDef); + } + } + /* + * Set the namespace. + */ + if (node->ns != NULL) { + if (copy->ns == NULL) { + /* + * This will map copy->ns to one of the newly created + * in-scope ns-decls, OR create a new ns-decl on @copy. + */ + copy->ns = xsltGetSpecialNamespace(ctxt, invocNode, + node->ns->href, node->ns->prefix, copy); + } + } else if ((insert->type == XML_ELEMENT_NODE) && + (insert->ns != NULL)) + { + /* + * "Undeclare" the default namespace on @copy with xmlns="". + */ + xsltGetSpecialNamespace(ctxt, invocNode, NULL, NULL, copy); + } + /* + * Copy attribute nodes. + */ + if (node->properties != NULL) { + xsltCopyAttrListNoOverwrite(ctxt, invocNode, + copy, node->properties); + } + if (topElemVisited == 0) + topElemVisited = 1; + } + /* + * Copy the subtree. + */ + if (node->children != NULL) { + xsltCopyTreeList(ctxt, invocNode, + node->children, copy, isLRE, topElemVisited); + } + } else { + xsltTransformError(ctxt, NULL, invocNode, + "xsltCopyTree: Copying of '%s' failed.\n", node->name); + } + return(copy); +} + +/************************************************************************ + * * + * Error/fallback processing * + * * + ************************************************************************/ + +/** + * xsltApplyFallbacks: + * @ctxt: a XSLT process context + * @node: the node in the source tree. + * @inst: the node generating the error + * + * Process possible xsl:fallback nodes present under @inst + * + * Returns the number of xsl:fallback element found and processed + */ +static int +xsltApplyFallbacks(xsltTransformContextPtr ctxt, xmlNodePtr node, + xmlNodePtr inst) { + + xmlNodePtr child; + int ret = 0; + + if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || + (inst->children == NULL)) + return(0); + + child = inst->children; + while (child != NULL) { + if ((IS_XSLT_ELEM(child)) && + (xmlStrEqual(child->name, BAD_CAST "fallback"))) { +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "applying xsl:fallback\n"); +#endif + ret++; + xsltApplySequenceConstructor(ctxt, node, child->children, + NULL); + } + child = child->next; + } + return(ret); +} + +/************************************************************************ + * * + * Default processing * + * * + ************************************************************************/ + +/** + * xsltDefaultProcessOneNode: + * @ctxt: a XSLT process context + * @node: the node in the source tree. + * @params: extra parameters passed to the template if any + * + * Process the source node with the default built-in template rule: + * + * + * + * + * and + * + * + * + * + * + * Note also that namespace declarations are copied directly: + * + * the built-in template rule is the only template rule that is applied + * for namespace nodes. + */ +static void +xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node, + xsltStackElemPtr params) { + xmlNodePtr copy; + xmlNodePtr cur; + int nbchild = 0, oldSize; + int childno = 0, oldPos; + xsltTemplatePtr template; + + CHECK_STOPPED; + /* + * Handling of leaves + */ + switch (node->type) { + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + case XML_ELEMENT_NODE: + break; + case XML_CDATA_SECTION_NODE: +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, + "xsltDefaultProcessOneNode: copy CDATA %s\n", + node->content)); +#endif + copy = xsltCopyText(ctxt, ctxt->insert, node, 0); + if (copy == NULL) { + xsltTransformError(ctxt, NULL, node, + "xsltDefaultProcessOneNode: cdata copy failed\n"); + } + return; + case XML_TEXT_NODE: +#ifdef WITH_XSLT_DEBUG_PROCESS + if (node->content == NULL) { + XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, + "xsltDefaultProcessOneNode: copy empty text\n")); + return; + } else { + XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, + "xsltDefaultProcessOneNode: copy text %s\n", + node->content)); + } +#endif + copy = xsltCopyText(ctxt, ctxt->insert, node, 0); + if (copy == NULL) { + xsltTransformError(ctxt, NULL, node, + "xsltDefaultProcessOneNode: text copy failed\n"); + } + return; + case XML_ATTRIBUTE_NODE: + cur = node->children; + while ((cur != NULL) && (cur->type != XML_TEXT_NODE)) + cur = cur->next; + if (cur == NULL) { + xsltTransformError(ctxt, NULL, node, + "xsltDefaultProcessOneNode: no text for attribute\n"); + } else { +#ifdef WITH_XSLT_DEBUG_PROCESS + if (cur->content == NULL) { + XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, + "xsltDefaultProcessOneNode: copy empty text\n")); + } else { + XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, + "xsltDefaultProcessOneNode: copy text %s\n", + cur->content)); + } +#endif + copy = xsltCopyText(ctxt, ctxt->insert, cur, 0); + if (copy == NULL) { + xsltTransformError(ctxt, NULL, node, + "xsltDefaultProcessOneNode: text copy failed\n"); + } + } + return; + default: + return; + } + /* + * Handling of Elements: first pass, counting + */ + cur = node->children; + while (cur != NULL) { + if (IS_XSLT_REAL_NODE(cur)) + nbchild++; + cur = cur->next; + } + + /* + * Handling of Elements: second pass, actual processing + * + * Note that params are passed to the next template. This matches + * XSLT 2.0 behavior but doesn't conform to XSLT 1.0. + */ + oldSize = ctxt->xpathCtxt->contextSize; + oldPos = ctxt->xpathCtxt->proximityPosition; + cur = node->children; + while (cur != NULL) { + childno++; + switch (cur->type) { + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + case XML_ELEMENT_NODE: + ctxt->xpathCtxt->contextSize = nbchild; + ctxt->xpathCtxt->proximityPosition = childno; + + if (ctxt->depth >= ctxt->maxTemplateDepth) { + xsltTransformError(ctxt, NULL, cur, + "xsltDefaultProcessOneNode: Maximum template depth " + "exceeded.\n" + "You can adjust xsltMaxDepth (--maxdepth) in order to " + "raise the maximum number of nested template calls and " + "variables/params (currently set to %d).\n", + ctxt->maxTemplateDepth); + ctxt->state = XSLT_STATE_STOPPED; + return; + } + ctxt->depth++; + xsltProcessOneNode(ctxt, cur, params); + ctxt->depth--; + break; + case XML_CDATA_SECTION_NODE: + template = xsltGetTemplate(ctxt, cur, NULL); + if (template) { +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, + "xsltDefaultProcessOneNode: applying template for CDATA %s\n", + cur->content)); +#endif + /* + * Instantiate the xsl:template. + */ + xsltApplyXSLTTemplate(ctxt, cur, template->content, + template, params); + } else /* if (ctxt->mode == NULL) */ { +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, + "xsltDefaultProcessOneNode: copy CDATA %s\n", + cur->content)); +#endif + copy = xsltCopyText(ctxt, ctxt->insert, cur, 0); + if (copy == NULL) { + xsltTransformError(ctxt, NULL, cur, + "xsltDefaultProcessOneNode: cdata copy failed\n"); + } + } + break; + case XML_TEXT_NODE: + template = xsltGetTemplate(ctxt, cur, NULL); + if (template) { +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, + "xsltDefaultProcessOneNode: applying template for text %s\n", + cur->content)); +#endif + ctxt->xpathCtxt->contextSize = nbchild; + ctxt->xpathCtxt->proximityPosition = childno; + /* + * Instantiate the xsl:template. + */ + xsltApplyXSLTTemplate(ctxt, cur, template->content, + template, params); + } else /* if (ctxt->mode == NULL) */ { +#ifdef WITH_XSLT_DEBUG_PROCESS + if (cur->content == NULL) { + XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, + "xsltDefaultProcessOneNode: copy empty text\n")); + } else { + XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, + "xsltDefaultProcessOneNode: copy text %s\n", + cur->content)); + } +#endif + copy = xsltCopyText(ctxt, ctxt->insert, cur, 0); + if (copy == NULL) { + xsltTransformError(ctxt, NULL, cur, + "xsltDefaultProcessOneNode: text copy failed\n"); + } + } + break; + case XML_PI_NODE: + case XML_COMMENT_NODE: + template = xsltGetTemplate(ctxt, cur, NULL); + if (template) { +#ifdef WITH_XSLT_DEBUG_PROCESS + if (cur->type == XML_PI_NODE) { + XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, + "xsltDefaultProcessOneNode: template found for PI %s\n", + cur->name)); + } else if (cur->type == XML_COMMENT_NODE) { + XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, + "xsltDefaultProcessOneNode: template found for comment\n")); + } +#endif + ctxt->xpathCtxt->contextSize = nbchild; + ctxt->xpathCtxt->proximityPosition = childno; + /* + * Instantiate the xsl:template. + */ + xsltApplyXSLTTemplate(ctxt, cur, template->content, + template, params); + } + break; + default: + break; + } + cur = cur->next; + } + ctxt->xpathCtxt->contextSize = oldSize; + ctxt->xpathCtxt->proximityPosition = oldPos; +} + +/** + * xsltProcessOneNode: + * @ctxt: a XSLT process context + * @contextNode: the "current node" in the source tree + * @withParams: extra parameters (e.g. xsl:with-param) passed to the + * template if any + * + * Process the source node. + */ +void +xsltProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, + xsltStackElemPtr withParams) +{ + xsltTemplatePtr templ; + xmlNodePtr oldNode; + + templ = xsltGetTemplate(ctxt, contextNode, NULL); + /* + * If no template is found, apply the default rule. + */ + if (templ == NULL) { +#ifdef WITH_XSLT_DEBUG_PROCESS + if (contextNode->type == XML_DOCUMENT_NODE) { + XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, + "xsltProcessOneNode: no template found for /\n")); + } else if (contextNode->type == XML_CDATA_SECTION_NODE) { + XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, + "xsltProcessOneNode: no template found for CDATA\n")); + } else if (contextNode->type == XML_ATTRIBUTE_NODE) { + XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, + "xsltProcessOneNode: no template found for attribute %s\n", + ((xmlAttrPtr) contextNode)->name)); + } else { + XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, + "xsltProcessOneNode: no template found for %s\n", contextNode->name)); + } +#endif + oldNode = ctxt->node; + ctxt->node = contextNode; + xsltDefaultProcessOneNode(ctxt, contextNode, withParams); + ctxt->node = oldNode; + return; + } + + if (contextNode->type == XML_ATTRIBUTE_NODE) { + xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule; + /* + * Set the "current template rule". + */ + ctxt->currentTemplateRule = templ; + +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, + "xsltProcessOneNode: applying template '%s' for attribute %s\n", + templ->match, contextNode->name)); +#endif + xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withParams); + + ctxt->currentTemplateRule = oldCurTempRule; + } else { + xsltTemplatePtr oldCurTempRule = ctxt->currentTemplateRule; + /* + * Set the "current template rule". + */ + ctxt->currentTemplateRule = templ; + +#ifdef WITH_XSLT_DEBUG_PROCESS + if (contextNode->type == XML_DOCUMENT_NODE) { + XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, + "xsltProcessOneNode: applying template '%s' for /\n", + templ->match)); + } else { + XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, + "xsltProcessOneNode: applying template '%s' for %s\n", + templ->match, contextNode->name)); + } +#endif + xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, templ, withParams); + + ctxt->currentTemplateRule = oldCurTempRule; + } +} + +#ifdef WITH_DEBUGGER +static xmlNodePtr +xsltDebuggerStartSequenceConstructor(xsltTransformContextPtr ctxt, + xmlNodePtr contextNode, + xmlNodePtr list, + xsltTemplatePtr templ, + int *addCallResult) +{ + xmlNodePtr debugedNode = NULL; + + if (ctxt->debugStatus != XSLT_DEBUG_NONE) { + if (templ) { + *addCallResult = xslAddCall(templ, templ->elem); + } else { + *addCallResult = xslAddCall(NULL, list); + } + switch (ctxt->debugStatus) { + case XSLT_DEBUG_RUN_RESTART: + case XSLT_DEBUG_QUIT: + if (*addCallResult) + xslDropCall(); + return(NULL); + } + if (templ) { + xslHandleDebugger(templ->elem, contextNode, templ, ctxt); + debugedNode = templ->elem; + } else if (list) { + xslHandleDebugger(list, contextNode, templ, ctxt); + debugedNode = list; + } else if (ctxt->inst) { + xslHandleDebugger(ctxt->inst, contextNode, templ, ctxt); + debugedNode = ctxt->inst; + } + } + return(debugedNode); +} +#endif /* WITH_DEBUGGER */ + +/** + * xsltLocalVariablePush: + * @ctxt: the transformation context + * @variable: variable to be pushed to the variable stack + * @level: new value for variable's level + * + * Places the variable onto the local variable stack + * + * Returns: 0 for success, -1 for any error + * **NOTE:** + * This is an internal routine and should not be called by users! + */ +int +xsltLocalVariablePush(xsltTransformContextPtr ctxt, + xsltStackElemPtr variable, + int level) +{ + if (ctxt->varsNr >= ctxt->varsMax) { + xsltStackElemPtr *tmp; + int newMax = ctxt->varsMax == 0 ? 10 : 2 * ctxt->varsMax; + + tmp = (xsltStackElemPtr *) xmlRealloc(ctxt->varsTab, + newMax * sizeof(*tmp)); + if (tmp == NULL) { + xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); + return (-1); + } + ctxt->varsTab = tmp; + ctxt->varsMax = newMax; + } + ctxt->varsTab[ctxt->varsNr++] = variable; + ctxt->vars = variable; + variable->level = level; + return(0); +} + +/** + * xsltReleaseLocalRVTs: + * + * Fragments which are results of extension instructions + * are preserved; all other fragments are freed/cached. + */ +static void +xsltReleaseLocalRVTs(xsltTransformContextPtr ctxt, xsltRVTListPtr base) +{ + xsltRVTListPtr cur = ctxt->localRVTList, tmp; + + if (cur == base) + return; + + /* Reset localRVTList early because some RVTs might be registered again. */ + ctxt->localRVTList = base; + + do { + tmp = cur; + cur = cur->next; + if (tmp->RVT->compression == XSLT_RVT_LOCAL) { + xsltReleaseRVTList(ctxt, tmp); + } else if (tmp->RVT->compression == XSLT_RVT_GLOBAL) { + xsltRegisterPersistRVT(ctxt, tmp->RVT); + xmlFree(tmp); + } else if (tmp->RVT->compression == XSLT_RVT_FUNC_RESULT) { + /* + * This will either register the RVT again or move it to the + * context variable. + */ + xsltRegisterLocalRVT(ctxt, tmp->RVT); + tmp->RVT->compression = XSLT_RVT_FUNC_RESULT; + xmlFree(tmp); + } else { + xmlGenericError(xmlGenericErrorContext, + "xsltReleaseLocalRVTs: Unexpected RVT flag %d\n", + tmp->RVT->compression); + } + } while (cur != base); +} + +/** + * xsltApplySequenceConstructor: + * @ctxt: a XSLT process context + * @contextNode: the "current node" in the source tree + * @list: the nodes of a sequence constructor; + * (plus leading xsl:param elements) + * @templ: the compiled xsl:template (optional) + * + * Processes a sequence constructor. + * + * NOTE: ctxt->currentTemplateRule was introduced to reflect the + * semantics of "current template rule". I.e. the field ctxt->templ + * is not intended to reflect this, thus always pushed onto the + * template stack. + */ +static void +xsltApplySequenceConstructor(xsltTransformContextPtr ctxt, + xmlNodePtr contextNode, xmlNodePtr list, + xsltTemplatePtr templ) +{ + xmlNodePtr oldInsert, oldInst, oldCurInst, oldContextNode; + xmlNodePtr cur, insert, copy = NULL; + int level = 0, oldVarsNr; + xsltRVTListPtr oldLocalFragmentTop; + +#ifdef XSLT_REFACTORED + xsltStylePreCompPtr info; +#endif + +#ifdef WITH_DEBUGGER + int addCallResult = 0; + xmlNodePtr debuggedNode = NULL; +#endif + + if (ctxt == NULL) + return; + +#ifdef WITH_DEBUGGER + if (ctxt->debugStatus != XSLT_DEBUG_NONE) { + debuggedNode = + xsltDebuggerStartSequenceConstructor(ctxt, contextNode, + list, templ, &addCallResult); + if (debuggedNode == NULL) + return; + } +#endif + + if (list == NULL) + return; + CHECK_STOPPED; + + /* + * Check for infinite recursion: stop if the maximum of nested templates + * is excceeded. Adjust xsltMaxDepth if you need more. + */ + if (ctxt->depth >= ctxt->maxTemplateDepth) { + xsltTransformError(ctxt, NULL, list, + "xsltApplySequenceConstructor: A potential infinite template " + "recursion was detected.\n" + "You can adjust xsltMaxDepth (--maxdepth) in order to " + "raise the maximum number of nested template calls and " + "variables/params (currently set to %d).\n", + ctxt->maxTemplateDepth); + xsltDebug(ctxt, contextNode, list, NULL); + ctxt->state = XSLT_STATE_STOPPED; + return; + } + ctxt->depth++; + + oldLocalFragmentTop = ctxt->localRVTList; + oldInsert = insert = ctxt->insert; + oldInst = oldCurInst = ctxt->inst; + oldContextNode = ctxt->node; + /* + * Save current number of variables on the stack; new vars are popped when + * exiting. + */ + oldVarsNr = ctxt->varsNr; + /* + * Process the sequence constructor. + */ + cur = list; + while (cur != NULL) { + if (ctxt->opLimit != 0) { + if (ctxt->opCount >= ctxt->opLimit) { + xsltTransformError(ctxt, NULL, cur, + "xsltApplySequenceConstructor: " + "Operation limit exceeded\n"); + ctxt->state = XSLT_STATE_STOPPED; + goto error; + } + ctxt->opCount += 1; + } + + ctxt->inst = cur; + +#ifdef WITH_DEBUGGER + switch (ctxt->debugStatus) { + case XSLT_DEBUG_RUN_RESTART: + case XSLT_DEBUG_QUIT: + break; + + } +#endif + /* + * Test; we must have a valid insertion point. + */ + if (insert == NULL) { + +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, + "xsltApplySequenceConstructor: insert == NULL !\n")); +#endif + goto error; + } + +#ifdef WITH_DEBUGGER + if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (debuggedNode != cur)) + xslHandleDebugger(cur, contextNode, templ, ctxt); +#endif + +#ifdef XSLT_REFACTORED + if (cur->type == XML_ELEMENT_NODE) { + info = (xsltStylePreCompPtr) cur->psvi; + /* + * We expect a compiled representation on: + * 1) XSLT instructions of this XSLT version (1.0) + * (with a few exceptions) + * 2) Literal result elements + * 3) Extension instructions + * 4) XSLT instructions of future XSLT versions + * (forwards-compatible mode). + */ + if (info == NULL) { + /* + * Handle the rare cases where we don't expect a compiled + * representation on an XSLT element. + */ + if (IS_XSLT_ELEM_FAST(cur) && IS_XSLT_NAME(cur, "message")) { + xsltMessage(ctxt, contextNode, cur); + goto skip_children; + } + /* + * Something really went wrong: + */ + xsltTransformError(ctxt, NULL, cur, + "Internal error in xsltApplySequenceConstructor(): " + "The element '%s' in the stylesheet has no compiled " + "representation.\n", + cur->name); + goto skip_children; + } + + if (info->type == XSLT_FUNC_LITERAL_RESULT_ELEMENT) { + xsltStyleItemLRElementInfoPtr lrInfo = + (xsltStyleItemLRElementInfoPtr) info; + /* + * Literal result elements + * -------------------------------------------------------- + */ +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE, + xsltGenericDebug(xsltGenericDebugContext, + "xsltApplySequenceConstructor: copy literal result " + "element '%s'\n", cur->name)); +#endif + /* + * Copy the raw element-node. + * OLD: if ((copy = xsltShallowCopyElem(ctxt, cur, insert)) + * == NULL) + * goto error; + */ + copy = xmlDocCopyNode(cur, insert->doc, 0); + if (copy == NULL) { + xsltTransformError(ctxt, NULL, cur, + "Internal error in xsltApplySequenceConstructor(): " + "Failed to copy literal result element '%s'.\n", + cur->name); + goto error; + } else { + /* + * Add the element-node to the result tree. + */ + copy->doc = ctxt->output; + copy = xsltAddChild(insert, copy); + /* + * Create effective namespaces declarations. + * OLD: xsltCopyNamespaceList(ctxt, copy, cur->nsDef); + */ + if (lrInfo->effectiveNs != NULL) { + xsltEffectiveNsPtr effNs = lrInfo->effectiveNs; + xmlNsPtr ns, lastns = NULL; + + while (effNs != NULL) { + /* + * Avoid generating redundant namespace + * declarations; thus lookup if there is already + * such a ns-decl in the result. + */ + ns = xmlSearchNs(copy->doc, copy, effNs->prefix); + if ((ns != NULL) && + (xmlStrEqual(ns->href, effNs->nsName))) + { + effNs = effNs->next; + continue; + } + ns = xmlNewNs(copy, effNs->nsName, effNs->prefix); + if (ns == NULL) { + xsltTransformError(ctxt, NULL, cur, + "Internal error in " + "xsltApplySequenceConstructor(): " + "Failed to copy a namespace " + "declaration.\n"); + goto error; + } + + if (lastns == NULL) + copy->nsDef = ns; + else + lastns->next =ns; + lastns = ns; + + effNs = effNs->next; + } + + } + /* + * NOTE that we don't need to apply ns-alising: this was + * already done at compile-time. + */ + if (cur->ns != NULL) { + /* + * If there's no such ns-decl in the result tree, + * then xsltGetSpecialNamespace() will + * create a ns-decl on the copied node. + */ + copy->ns = xsltGetSpecialNamespace(ctxt, cur, + cur->ns->href, cur->ns->prefix, copy); + } else { + /* + * Undeclare the default namespace if needed. + * This can be skipped, if the result element has + * no ns-decls, in which case the result element + * obviously does not declare a default namespace; + * AND there's either no parent, or the parent + * element is in no namespace; this means there's no + * default namespace is scope to care about. + * + * REVISIT: This might result in massive + * generation of ns-decls if nodes in a default + * namespaces are mixed with nodes in no namespace. + * + */ + if (copy->nsDef || + ((insert != NULL) && + (insert->type == XML_ELEMENT_NODE) && + (insert->ns != NULL))) + { + xsltGetSpecialNamespace(ctxt, cur, + NULL, NULL, copy); + } + } + } + /* + * SPEC XSLT 2.0 "Each attribute of the literal result + * element, other than an attribute in the XSLT namespace, + * is processed to produce an attribute for the element in + * the result tree." + * NOTE: See bug #341325. + */ + if (cur->properties != NULL) { + xsltAttrListTemplateProcess(ctxt, copy, cur->properties); + } + } else if (IS_XSLT_ELEM_FAST(cur)) { + /* + * XSLT instructions + * -------------------------------------------------------- + */ + if (info->type == XSLT_FUNC_UNKOWN_FORWARDS_COMPAT) { + /* + * We hit an unknown XSLT element. + * Try to apply one of the fallback cases. + */ + ctxt->insert = insert; + if (!xsltApplyFallbacks(ctxt, contextNode, cur)) { + xsltTransformError(ctxt, NULL, cur, + "The is no fallback behaviour defined for " + "the unknown XSLT element '%s'.\n", + cur->name); + } + ctxt->insert = oldInsert; + } else if (info->func != NULL) { + /* + * Execute the XSLT instruction. + */ + ctxt->insert = insert; + + info->func(ctxt, contextNode, cur, + (xsltElemPreCompPtr) info); + + /* + * Cleanup temporary tree fragments. + */ + if (oldLocalFragmentTop != ctxt->localRVTList) + xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); + + ctxt->insert = oldInsert; + } else if (info->type == XSLT_FUNC_VARIABLE) { + xsltStackElemPtr tmpvar = ctxt->vars; + + xsltParseStylesheetVariable(ctxt, cur); + + if (tmpvar != ctxt->vars) { + /* + * TODO: Using a @tmpvar is an annoying workaround, but + * the current mechanisms do not provide any other way + * of knowing if the var was really pushed onto the + * stack. + */ + ctxt->vars->level = level; + } + } else if (info->type == XSLT_FUNC_MESSAGE) { + /* + * TODO: Won't be hit, since we don't compile xsl:message. + */ + xsltMessage(ctxt, contextNode, cur); + } else { + xsltTransformError(ctxt, NULL, cur, + "Unexpected XSLT element '%s'.\n", cur->name); + } + goto skip_children; + + } else { + xsltTransformFunction func; + /* + * Extension intructions (elements) + * -------------------------------------------------------- + */ + if (cur->psvi == xsltExtMarker) { + /* + * The xsltExtMarker was set during the compilation + * of extension instructions if there was no registered + * handler for this specific extension function at + * compile-time. + * Libxslt will now lookup if a handler is + * registered in the context of this transformation. + */ + func = xsltExtElementLookup(ctxt, cur->name, + cur->ns->href); + } else + func = ((xsltElemPreCompPtr) cur->psvi)->func; + + if (func == NULL) { + /* + * No handler available. + * Try to execute fallback behaviour via xsl:fallback. + */ +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE, + xsltGenericDebug(xsltGenericDebugContext, + "xsltApplySequenceConstructor: unknown extension %s\n", + cur->name)); +#endif + ctxt->insert = insert; + if (!xsltApplyFallbacks(ctxt, contextNode, cur)) { + xsltTransformError(ctxt, NULL, cur, + "Unknown extension instruction '{%s}%s'.\n", + cur->ns->href, cur->name); + } + ctxt->insert = oldInsert; + } else { + /* + * Execute the handler-callback. + */ +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, + "xsltApplySequenceConstructor: extension construct %s\n", + cur->name)); +#endif + /* + * Disable the xsltCopyTextString optimization for + * extension elements. Extensions could append text using + * xmlAddChild which will free the buffer pointed to by + * 'lasttext'. This buffer could later be reallocated with + * a different size than recorded in 'lasttsize'. See bug + * #777432. + */ + if (cur->psvi == xsltExtMarker) { + ctxt->lasttext = NULL; + } + + ctxt->insert = insert; + + func(ctxt, contextNode, cur, cur->psvi); + + /* + * Cleanup temporary tree fragments. + */ + if (oldLocalFragmentTop != ctxt->localRVTList) + xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); + + ctxt->insert = oldInsert; + } + goto skip_children; + } + + } else if (XSLT_IS_TEXT_NODE(cur)) { + /* + * Text + * ------------------------------------------------------------ + */ +#ifdef WITH_XSLT_DEBUG_PROCESS + if (cur->name == xmlStringTextNoenc) { + XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE, + xsltGenericDebug(xsltGenericDebugContext, + "xsltApplySequenceConstructor: copy unescaped text '%s'\n", + cur->content)); + } else { + XSLT_TRACE(ctxt, XSLT_TRACE_APPLY_TEMPLATE, + xsltGenericDebug(xsltGenericDebugContext, + "xsltApplySequenceConstructor: copy text '%s'\n", + cur->content)); + } +#endif + if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL) + goto error; + } + +#else /* XSLT_REFACTORED */ + + if (IS_XSLT_ELEM(cur)) { + /* + * This is an XSLT node + */ + xsltStylePreCompPtr info = (xsltStylePreCompPtr) cur->psvi; + + if (info == NULL) { + if (IS_XSLT_NAME(cur, "message")) { + xsltMessage(ctxt, contextNode, cur); + } else { + /* + * That's an error try to apply one of the fallback cases + */ + ctxt->insert = insert; + if (!xsltApplyFallbacks(ctxt, contextNode, cur)) { + xsltGenericError(xsltGenericErrorContext, + "xsltApplySequenceConstructor: %s was not compiled\n", + cur->name); + } + ctxt->insert = oldInsert; + } + goto skip_children; + } + + if (info->func != NULL) { + oldCurInst = ctxt->inst; + ctxt->inst = cur; + ctxt->insert = insert; + + info->func(ctxt, contextNode, cur, (xsltElemPreCompPtr) info); + + /* + * Cleanup temporary tree fragments. + */ + if (oldLocalFragmentTop != ctxt->localRVTList) + xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); + + ctxt->insert = oldInsert; + ctxt->inst = oldCurInst; + goto skip_children; + } + + if (IS_XSLT_NAME(cur, "variable")) { + xsltStackElemPtr tmpvar = ctxt->vars; + + oldCurInst = ctxt->inst; + ctxt->inst = cur; + + xsltParseStylesheetVariable(ctxt, cur); + + ctxt->inst = oldCurInst; + + if (tmpvar != ctxt->vars) { + /* + * TODO: Using a @tmpvar is an annoying workaround, but + * the current mechanisms do not provide any other way + * of knowing if the var was really pushed onto the + * stack. + */ + ctxt->vars->level = level; + } + } else if (IS_XSLT_NAME(cur, "message")) { + xsltMessage(ctxt, contextNode, cur); + } else { + xsltTransformError(ctxt, NULL, cur, + "Unexpected XSLT element '%s'.\n", cur->name); + } + goto skip_children; + } else if ((cur->type == XML_TEXT_NODE) || + (cur->type == XML_CDATA_SECTION_NODE)) { + + /* + * This text comes from the stylesheet + * For stylesheets, the set of whitespace-preserving + * element names consists of just xsl:text. + */ +#ifdef WITH_XSLT_DEBUG_PROCESS + if (cur->type == XML_CDATA_SECTION_NODE) { + XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, + "xsltApplySequenceConstructor: copy CDATA text %s\n", + cur->content)); + } else if (cur->name == xmlStringTextNoenc) { + XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, + "xsltApplySequenceConstructor: copy unescaped text %s\n", + cur->content)); + } else { + XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, + "xsltApplySequenceConstructor: copy text %s\n", + cur->content)); + } +#endif + if (xsltCopyText(ctxt, insert, cur, ctxt->internalized) == NULL) + goto error; + } else if ((cur->type == XML_ELEMENT_NODE) && + (cur->ns != NULL) && (cur->psvi != NULL)) { + xsltTransformFunction function; + + oldCurInst = ctxt->inst; + ctxt->inst = cur; + /* + * Flagged as an extension element + */ + if (cur->psvi == xsltExtMarker) + function = xsltExtElementLookup(ctxt, cur->name, + cur->ns->href); + else + function = ((xsltElemPreCompPtr) cur->psvi)->func; + + if (function == NULL) { + xmlNodePtr child; + int found = 0; + +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, + "xsltApplySequenceConstructor: unknown extension %s\n", + cur->name)); +#endif + /* + * Search if there are fallbacks + */ + ctxt->insert = insert; + child = cur->children; + while (child != NULL) { + if ((IS_XSLT_ELEM(child)) && + (IS_XSLT_NAME(child, "fallback"))) + { + found = 1; + xsltApplySequenceConstructor(ctxt, contextNode, + child->children, NULL); + } + child = child->next; + } + ctxt->insert = oldInsert; + + if (!found) { + xsltTransformError(ctxt, NULL, cur, + "xsltApplySequenceConstructor: failed to find extension %s\n", + cur->name); + } + } else { +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, + "xsltApplySequenceConstructor: extension construct %s\n", + cur->name)); +#endif + + /* + * Disable the xsltCopyTextString optimization for + * extension elements. Extensions could append text using + * xmlAddChild which will free the buffer pointed to by + * 'lasttext'. This buffer could later be reallocated with + * a different size than recorded in 'lasttsize'. See bug + * #777432. + */ + if (cur->psvi == xsltExtMarker) { + ctxt->lasttext = NULL; + } + + ctxt->insert = insert; + + function(ctxt, contextNode, cur, cur->psvi); + /* + * Cleanup temporary tree fragments. + */ + if (oldLocalFragmentTop != ctxt->localRVTList) + xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); + + ctxt->insert = oldInsert; + + } + ctxt->inst = oldCurInst; + goto skip_children; + } else if (cur->type == XML_ELEMENT_NODE) { +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, + "xsltApplySequenceConstructor: copy node %s\n", + cur->name)); +#endif + oldCurInst = ctxt->inst; + ctxt->inst = cur; + + if ((copy = xsltShallowCopyElem(ctxt, cur, insert, 1)) == NULL) + goto error; + /* + * Add extra namespaces inherited from the current template + * if we are in the first level children and this is a + * "real" template. + */ + if ((templ != NULL) && (oldInsert == insert) && + (ctxt->templ != NULL) && (ctxt->templ->inheritedNs != NULL)) { + int i; + xmlNsPtr ns, ret; + + for (i = 0; i < ctxt->templ->inheritedNsNr; i++) { + const xmlChar *URI = NULL; + xsltStylesheetPtr style; + ns = ctxt->templ->inheritedNs[i]; + + /* Note that the XSLT namespace was already excluded + * in xsltGetInheritedNsList(). + */ +#if 0 + if (xmlStrEqual(ns->href, XSLT_NAMESPACE)) + continue; +#endif + style = ctxt->style; + while (style != NULL) { + if (style->nsAliases != NULL) + URI = (const xmlChar *) + xmlHashLookup(style->nsAliases, ns->href); + if (URI != NULL) + break; + + style = xsltNextImport(style); + } + if (URI == UNDEFINED_DEFAULT_NS) + continue; + if (URI == NULL) + URI = ns->href; + /* + * TODO: The following will still be buggy for the + * non-refactored code. + */ + ret = xmlSearchNs(copy->doc, copy, ns->prefix); + if ((ret == NULL) || (!xmlStrEqual(ret->href, URI))) + { + xmlNewNs(copy, URI, ns->prefix); + } + } + if (copy->ns != NULL) { + /* + * Fix the node namespace if needed + */ + copy->ns = xsltGetNamespace(ctxt, cur, copy->ns, copy); + } + } + /* + * all the attributes are directly inherited + */ + if (cur->properties != NULL) { + xsltAttrListTemplateProcess(ctxt, copy, cur->properties); + } + ctxt->inst = oldCurInst; + } +#endif /* else of XSLT_REFACTORED */ + + /* + * Descend into content in document order. + */ + if (cur->children != NULL) { + if (cur->children->type != XML_ENTITY_DECL) { + cur = cur->children; + level++; + if (copy != NULL) + insert = copy; + continue; + } + } + +skip_children: + /* + * If xslt:message was just processed, we might have hit a + * terminate='yes'; if so, then break the loop and clean up. + * TODO: Do we need to check this also before trying to descend + * into the content? + */ + if (ctxt->state == XSLT_STATE_STOPPED) + break; + if (cur->next != NULL) { + cur = cur->next; + continue; + } + + do { + cur = cur->parent; + level--; + /* + * Pop variables/params (xsl:variable and xsl:param). + */ + if ((ctxt->varsNr > oldVarsNr) && (ctxt->vars->level > level)) { + xsltLocalVariablePop(ctxt, oldVarsNr, level); + } + + insert = insert->parent; + if (cur == NULL) + break; + if (cur == list->parent) { + cur = NULL; + break; + } + if (cur->next != NULL) { + cur = cur->next; + break; + } + } while (cur != NULL); + } + +error: + /* + * In case of errors: pop remaining variables. + */ + if (ctxt->varsNr > oldVarsNr) + xsltLocalVariablePop(ctxt, oldVarsNr, -1); + + ctxt->node = oldContextNode; + ctxt->inst = oldInst; + ctxt->insert = oldInsert; + + ctxt->depth--; + +#ifdef WITH_DEBUGGER + if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) { + xslDropCall(); + } +#endif +} + +/* +* xsltApplyXSLTTemplate: +* @ctxt: a XSLT transformation context +* @contextNode: the node in the source tree. +* @list: the nodes of a sequence constructor; +* (plus leading xsl:param elements) +* @templ: the compiled xsl:template declaration; +* NULL if a sequence constructor +* @withParams: a set of caller-parameters (xsl:with-param) or NULL +* +* Called by: +* - xsltApplyImports() +* - xsltCallTemplate() +* - xsltDefaultProcessOneNode() +* - xsltProcessOneNode() +*/ +static void +xsltApplyXSLTTemplate(xsltTransformContextPtr ctxt, + xmlNodePtr contextNode, + xmlNodePtr list, + xsltTemplatePtr templ, + xsltStackElemPtr withParams) +{ + int oldVarsBase = 0; + xmlNodePtr cur; + xsltStackElemPtr tmpParam = NULL; + xsltRVTListPtr oldUserFragmentTop; +#ifdef WITH_PROFILER + long start = 0; +#endif + +#ifdef XSLT_REFACTORED + xsltStyleItemParamPtr iparam; +#else + xsltStylePreCompPtr iparam; +#endif + +#ifdef WITH_DEBUGGER + int addCallResult = 0; +#endif + + if (ctxt == NULL) + return; + if (templ == NULL) { + xsltTransformError(ctxt, NULL, list, + "xsltApplyXSLTTemplate: Bad arguments; @templ is mandatory.\n"); + return; + } + +#ifdef WITH_DEBUGGER + if (ctxt->debugStatus != XSLT_DEBUG_NONE) { + if (xsltDebuggerStartSequenceConstructor(ctxt, contextNode, + list, templ, &addCallResult) == NULL) + return; + } +#endif + + if (list == NULL) + return; + CHECK_STOPPED; + + if (ctxt->varsNr >= ctxt->maxTemplateVars) + { + xsltTransformError(ctxt, NULL, list, + "xsltApplyXSLTTemplate: A potential infinite template recursion " + "was detected.\n" + "You can adjust maxTemplateVars (--maxvars) in order to " + "raise the maximum number of variables/params (currently set to %d).\n", + ctxt->maxTemplateVars); + xsltDebug(ctxt, contextNode, list, NULL); + ctxt->state = XSLT_STATE_STOPPED; + return; + } + + oldUserFragmentTop = ctxt->tmpRVTList; + ctxt->tmpRVTList = NULL; + + /* + * Initiate a distinct scope of local params/variables. + */ + oldVarsBase = ctxt->varsBase; + ctxt->varsBase = ctxt->varsNr; + + ctxt->node = contextNode; + +#ifdef WITH_PROFILER + if (ctxt->profile) { + templ->nbCalls++; + start = xsltTimestamp(); + profPush(ctxt, 0); + profCallgraphAdd(templ, ctxt->templ); + } +#endif + + /* + * Push the xsl:template declaration onto the stack. + */ + templPush(ctxt, templ); + +#ifdef WITH_XSLT_DEBUG_PROCESS + if (templ->name != NULL) + XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, + "applying xsl:template '%s'\n", templ->name)); +#endif + /* + * Process xsl:param instructions and skip those elements for + * further processing. + */ + cur = list; + do { + if (cur->type == XML_TEXT_NODE) { + cur = cur->next; + continue; + } + if ((cur->type != XML_ELEMENT_NODE) || + (cur->name[0] != 'p') || + (cur->psvi == NULL) || + (! xmlStrEqual(cur->name, BAD_CAST "param")) || + (! IS_XSLT_ELEM(cur))) + { + break; + } + + list = cur->next; + +#ifdef XSLT_REFACTORED + iparam = (xsltStyleItemParamPtr) cur->psvi; +#else + iparam = (xsltStylePreCompPtr) cur->psvi; +#endif + + /* + * Substitute xsl:param for a given xsl:with-param. + * Since the XPath expression will reference the params/vars + * by index, we need to slot the xsl:with-params in the + * order of encountered xsl:params to keep the sequence of + * params/variables in the stack exactly as it was at + * compile time, + */ + tmpParam = NULL; + if (withParams) { + tmpParam = withParams; + do { + if ((tmpParam->name == (iparam->name)) && + (tmpParam->nameURI == (iparam->ns))) + { + /* + * Push the caller-parameter. + */ + xsltLocalVariablePush(ctxt, tmpParam, -1); + break; + } + tmpParam = tmpParam->next; + } while (tmpParam != NULL); + } + /* + * Push the xsl:param. + */ + if (tmpParam == NULL) { + /* + * Note that we must assume that the added parameter + * has a @depth of 0. + */ + xsltParseStylesheetParam(ctxt, cur); + } + cur = cur->next; + } while (cur != NULL); + /* + * Process the sequence constructor. + */ + xsltApplySequenceConstructor(ctxt, contextNode, list, templ); + + /* + * Remove remaining xsl:param and xsl:with-param items from + * the stack. Don't free xsl:with-param items. + */ + if (ctxt->varsNr > ctxt->varsBase) + xsltTemplateParamsCleanup(ctxt); + ctxt->varsBase = oldVarsBase; + + /* + * Release user-created fragments stored in the scope + * of xsl:template. Note that this mechanism is deprecated: + * user code should now use xsltRegisterLocalRVT() instead + * of the obsolete xsltRegisterTmpRVT(). + */ + if (ctxt->tmpRVTList) { + xsltRVTListPtr curRVTList = ctxt->tmpRVTList, tmp; + + while (curRVTList != NULL) { + tmp = curRVTList; + curRVTList = curRVTList->next; + xsltReleaseRVTList(ctxt, tmp); + } + } + ctxt->tmpRVTList = oldUserFragmentTop; + + /* + * Pop the xsl:template declaration from the stack. + */ + templPop(ctxt); + +#ifdef WITH_PROFILER + if (ctxt->profile) { + long spent, child, total, end; + + end = xsltTimestamp(); + child = profPop(ctxt); + total = end - start; + spent = total - child; + if (spent <= 0) { + /* + * Not possible unless the original calibration failed + * we can try to correct it on the fly. + */ + xsltCalibrateAdjust(spent); + spent = 0; + } + + templ->time += spent; + if (ctxt->profNr > 0) + ctxt->profTab[ctxt->profNr - 1] += total; + } +#endif + +#ifdef WITH_DEBUGGER + if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && (addCallResult)) { + xslDropCall(); + } +#endif +} + + +/** + * xsltApplyOneTemplate: + * @ctxt: a XSLT process context + * @contextNode: the node in the source tree. + * @list: the nodes of a sequence constructor + * @templ: not used + * @params: a set of parameters (xsl:param) or NULL + * + * Processes a sequence constructor on the current node in the source tree. + * + * @params are the already computed variable stack items; this function + * pushes them on the variable stack, and pops them before exiting; it's + * left to the caller to free or reuse @params afterwards. The initial + * states of the variable stack will always be restored before this + * function exits. + * NOTE that this does *not* initiate a new distinct variable scope; i.e. + * variables already on the stack are visible to the process. The caller's + * side needs to start a new variable scope if needed (e.g. in exsl:function). + * + * @templ is obsolete and not used anymore (e.g. does not + * provide a @templ); a non-NULL @templ might raise an error in the future. + * + * BIG NOTE: This function is not intended to process the content of an + * xsl:template; it does not expect xsl:param instructions in @list and + * will report errors if found. + * + * Called by: + * - xsltEvalVariable() (variables.c) + * - exsltFuncFunctionFunction() (libexsl/functions.c) + */ +void +xsltApplyOneTemplate(xsltTransformContextPtr ctxt, + xmlNodePtr contextNode, + xmlNodePtr list, + xsltTemplatePtr templ ATTRIBUTE_UNUSED, + xsltStackElemPtr params) +{ + if ((ctxt == NULL) || (list == NULL)) + return; + CHECK_STOPPED; + + if (params) { + /* + * This code should be obsolete - was previously used + * by libexslt/functions.c, but due to bug 381319 the + * logic there was changed. + */ + int oldVarsNr = ctxt->varsNr; + + /* + * Push the given xsl:param(s) onto the variable stack. + */ + while (params != NULL) { + xsltLocalVariablePush(ctxt, params, -1); + params = params->next; + } + xsltApplySequenceConstructor(ctxt, contextNode, list, templ); + /* + * Pop the given xsl:param(s) from the stack but don't free them. + */ + xsltLocalVariablePop(ctxt, oldVarsNr, -2); + } else + xsltApplySequenceConstructor(ctxt, contextNode, list, templ); +} + +/************************************************************************ + * * + * XSLT-1.1 extensions * + * * + ************************************************************************/ + +/** + * xsltDocumentElem: + * @ctxt: an XSLT processing context + * @node: The current node + * @inst: the instruction in the stylesheet + * @castedComp: precomputed information + * + * Process an EXSLT/XSLT-1.1 document element + */ +void +xsltDocumentElem(xsltTransformContextPtr ctxt, xmlNodePtr node, + xmlNodePtr inst, xsltElemPreCompPtr castedComp) +{ +#ifdef XSLT_REFACTORED + xsltStyleItemDocumentPtr comp = (xsltStyleItemDocumentPtr) castedComp; +#else + xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp; +#endif + xsltStylesheetPtr style = NULL; + int ret; + xmlChar *filename = NULL, *prop, *elements; + xmlChar *element, *end; + xmlDocPtr res = NULL; + xmlDocPtr oldOutput; + xmlNodePtr oldInsert, root; + const char *oldOutputFile; + xsltOutputType oldType; + xmlChar *URL = NULL; + const xmlChar *method; + const xmlChar *doctypePublic; + const xmlChar *doctypeSystem; + const xmlChar *version; + const xmlChar *encoding; + int redirect_write_append = 0; + + if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL)) + return; + + if (comp->filename == NULL) { + + if (xmlStrEqual(inst->name, (const xmlChar *) "output")) { + /* + * The element "output" is in the namespace XSLT_SAXON_NAMESPACE + * (http://icl.com/saxon) + * The @file is in no namespace. + */ +#ifdef WITH_XSLT_DEBUG_EXTRA + xsltGenericDebug(xsltGenericDebugContext, + "Found saxon:output extension\n"); +#endif + URL = xsltEvalAttrValueTemplate(ctxt, inst, + (const xmlChar *) "file", + XSLT_SAXON_NAMESPACE); + + if (URL == NULL) + URL = xsltEvalAttrValueTemplate(ctxt, inst, + (const xmlChar *) "href", + XSLT_SAXON_NAMESPACE); + } else if (xmlStrEqual(inst->name, (const xmlChar *) "write")) { +#ifdef WITH_XSLT_DEBUG_EXTRA + xsltGenericDebug(xsltGenericDebugContext, + "Found xalan:write extension\n"); +#endif + URL = xsltEvalAttrValueTemplate(ctxt, inst, + (const xmlChar *) + "select", + XSLT_XALAN_NAMESPACE); + if (URL != NULL) { + xmlXPathCompExprPtr cmp; + xmlChar *val; + + /* + * Trying to handle bug #59212 + * The value of the "select" attribute is an + * XPath expression. + * (see http://xml.apache.org/xalan-j/extensionslib.html#redirect) + */ + cmp = xmlXPathCtxtCompile(ctxt->xpathCtxt, URL); + val = xsltEvalXPathString(ctxt, cmp); + xmlXPathFreeCompExpr(cmp); + xmlFree(URL); + URL = val; + } + if (URL == NULL) + URL = xsltEvalAttrValueTemplate(ctxt, inst, + (const xmlChar *) + "file", + XSLT_XALAN_NAMESPACE); + if (URL == NULL) + URL = xsltEvalAttrValueTemplate(ctxt, inst, + (const xmlChar *) + "href", + XSLT_XALAN_NAMESPACE); + } else if (xmlStrEqual(inst->name, (const xmlChar *) "document")) { + URL = xsltEvalAttrValueTemplate(ctxt, inst, + (const xmlChar *) "href", + NULL); + } + + } else { + URL = xmlStrdup(comp->filename); + } + + if (URL == NULL) { + xsltTransformError(ctxt, NULL, inst, + "xsltDocumentElem: href/URI-Reference not found\n"); + return; + } + + /* + * If the computation failed, it's likely that the URL wasn't escaped + */ + filename = xmlBuildURI(URL, (const xmlChar *) ctxt->outputFile); + if (filename == NULL) { + xmlChar *escURL; + + escURL=xmlURIEscapeStr(URL, BAD_CAST ":/.?,"); + if (escURL != NULL) { + filename = xmlBuildURI(escURL, (const xmlChar *) ctxt->outputFile); + xmlFree(escURL); + } + } + + if (filename == NULL) { + xsltTransformError(ctxt, NULL, inst, + "xsltDocumentElem: URL computation failed for %s\n", + URL); + xmlFree(URL); + return; + } + + /* + * Security checking: can we write to this resource + */ + if (ctxt->sec != NULL) { + ret = xsltCheckWrite(ctxt->sec, ctxt, filename); + if (ret <= 0) { + if (ret == 0) + xsltTransformError(ctxt, NULL, inst, + "xsltDocumentElem: write rights for %s denied\n", + filename); + xmlFree(URL); + xmlFree(filename); + return; + } + } + + oldOutputFile = ctxt->outputFile; + oldOutput = ctxt->output; + oldInsert = ctxt->insert; + oldType = ctxt->type; + ctxt->outputFile = (const char *) filename; + + style = xsltNewStylesheet(); + if (style == NULL) { + xsltTransformError(ctxt, NULL, inst, + "xsltDocumentElem: out of memory\n"); + goto error; + } + + /* + * Version described in 1.1 draft allows full parameterization + * of the output. + */ + prop = xsltEvalAttrValueTemplate(ctxt, inst, + (const xmlChar *) "version", + NULL); + if (prop != NULL) { + if (style->version != NULL) + xmlFree(style->version); + style->version = prop; + } + prop = xsltEvalAttrValueTemplate(ctxt, inst, + (const xmlChar *) "encoding", + NULL); + if (prop != NULL) { + if (style->encoding != NULL) + xmlFree(style->encoding); + style->encoding = prop; + } + prop = xsltEvalAttrValueTemplate(ctxt, inst, + (const xmlChar *) "method", + NULL); + if (prop != NULL) { + const xmlChar *URI; + + if (style->method != NULL) + xmlFree(style->method); + style->method = NULL; + if (style->methodURI != NULL) + xmlFree(style->methodURI); + style->methodURI = NULL; + + URI = xsltGetQNameURI(inst, &prop); + if (prop == NULL) { + if (style != NULL) style->errors++; + } else if (URI == NULL) { + if ((xmlStrEqual(prop, (const xmlChar *) "xml")) || + (xmlStrEqual(prop, (const xmlChar *) "html")) || + (xmlStrEqual(prop, (const xmlChar *) "text"))) { + style->method = prop; + } else { + xsltTransformError(ctxt, NULL, inst, + "invalid value for method: %s\n", prop); + if (style != NULL) style->warnings++; + } + } else { + style->method = prop; + style->methodURI = xmlStrdup(URI); + } + } + prop = xsltEvalAttrValueTemplate(ctxt, inst, + (const xmlChar *) + "doctype-system", NULL); + if (prop != NULL) { + if (style->doctypeSystem != NULL) + xmlFree(style->doctypeSystem); + style->doctypeSystem = prop; + } + prop = xsltEvalAttrValueTemplate(ctxt, inst, + (const xmlChar *) + "doctype-public", NULL); + if (prop != NULL) { + if (style->doctypePublic != NULL) + xmlFree(style->doctypePublic); + style->doctypePublic = prop; + } + prop = xsltEvalAttrValueTemplate(ctxt, inst, + (const xmlChar *) "standalone", + NULL); + if (prop != NULL) { + if (xmlStrEqual(prop, (const xmlChar *) "yes")) { + style->standalone = 1; + } else if (xmlStrEqual(prop, (const xmlChar *) "no")) { + style->standalone = 0; + } else { + xsltTransformError(ctxt, NULL, inst, + "invalid value for standalone: %s\n", + prop); + if (style != NULL) style->warnings++; + } + xmlFree(prop); + } + + prop = xsltEvalAttrValueTemplate(ctxt, inst, + (const xmlChar *) "indent", + NULL); + if (prop != NULL) { + if (xmlStrEqual(prop, (const xmlChar *) "yes")) { + style->indent = 1; + } else if (xmlStrEqual(prop, (const xmlChar *) "no")) { + style->indent = 0; + } else { + xsltTransformError(ctxt, NULL, inst, + "invalid value for indent: %s\n", prop); + if (style != NULL) style->warnings++; + } + xmlFree(prop); + } + + prop = xsltEvalAttrValueTemplate(ctxt, inst, + (const xmlChar *) + "omit-xml-declaration", + NULL); + if (prop != NULL) { + if (xmlStrEqual(prop, (const xmlChar *) "yes")) { + style->omitXmlDeclaration = 1; + } else if (xmlStrEqual(prop, (const xmlChar *) "no")) { + style->omitXmlDeclaration = 0; + } else { + xsltTransformError(ctxt, NULL, inst, + "invalid value for omit-xml-declaration: %s\n", + prop); + if (style != NULL) style->warnings++; + } + xmlFree(prop); + } + + elements = xsltEvalAttrValueTemplate(ctxt, inst, + (const xmlChar *) + "cdata-section-elements", + NULL); + if (elements != NULL) { + if (style->stripSpaces == NULL) + style->stripSpaces = xmlHashCreate(10); + if (style->stripSpaces == NULL) { + xmlFree(elements); + return; + } + + element = elements; + while (*element != 0) { + while (xmlIsBlank_ch(*element)) + element++; + if (*element == 0) + break; + end = element; + while ((*end != 0) && (!xmlIsBlank_ch(*end))) + end++; + element = xmlStrndup(element, end - element); + if (element) { + const xmlChar *URI; + +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "add cdata section output element %s\n", + element); +#endif + URI = xsltGetQNameURI(inst, &element); + + xmlHashAddEntry2(style->stripSpaces, element, URI, + (xmlChar *) "cdata"); + xmlFree(element); + } + element = end; + } + xmlFree(elements); + } + + /* + * Create a new document tree and process the element template + */ + XSLT_GET_IMPORT_PTR(method, style, method) + XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic) + XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem) + XSLT_GET_IMPORT_PTR(version, style, version) + XSLT_GET_IMPORT_PTR(encoding, style, encoding) + + if ((method != NULL) && + (!xmlStrEqual(method, (const xmlChar *) "xml"))) { + if (xmlStrEqual(method, (const xmlChar *) "html")) { + ctxt->type = XSLT_OUTPUT_HTML; + if (((doctypePublic != NULL) || (doctypeSystem != NULL))) + res = htmlNewDoc(doctypeSystem, doctypePublic); + else { + if (version != NULL) { +#ifdef XSLT_GENERATE_HTML_DOCTYPE + xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem); +#endif + } + res = htmlNewDocNoDtD(doctypeSystem, doctypePublic); + } + if (res == NULL) + goto error; + res->dict = ctxt->dict; + xmlDictReference(res->dict); + } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) { + xsltTransformError(ctxt, NULL, inst, + "xsltDocumentElem: unsupported method xhtml\n"); + ctxt->type = XSLT_OUTPUT_HTML; + res = htmlNewDocNoDtD(doctypeSystem, doctypePublic); + if (res == NULL) + goto error; + res->dict = ctxt->dict; + xmlDictReference(res->dict); + } else if (xmlStrEqual(method, (const xmlChar *) "text")) { + ctxt->type = XSLT_OUTPUT_TEXT; + res = xmlNewDoc(style->version); + if (res == NULL) + goto error; + res->dict = ctxt->dict; + xmlDictReference(res->dict); +#ifdef WITH_XSLT_DEBUG + xsltGenericDebug(xsltGenericDebugContext, + "reusing transformation dict for output\n"); +#endif + } else { + xsltTransformError(ctxt, NULL, inst, + "xsltDocumentElem: unsupported method (%s)\n", + method); + goto error; + } + } else { + ctxt->type = XSLT_OUTPUT_XML; + res = xmlNewDoc(style->version); + if (res == NULL) + goto error; + res->dict = ctxt->dict; + xmlDictReference(res->dict); +#ifdef WITH_XSLT_DEBUG + xsltGenericDebug(xsltGenericDebugContext, + "reusing transformation dict for output\n"); +#endif + } + res->charset = XML_CHAR_ENCODING_UTF8; + if (encoding != NULL) + res->encoding = xmlStrdup(encoding); + ctxt->output = res; + ctxt->insert = (xmlNodePtr) res; + xsltApplySequenceConstructor(ctxt, node, inst->children, NULL); + + /* + * Do some post processing work depending on the generated output + */ + root = xmlDocGetRootElement(res); + if (root != NULL) { + const xmlChar *doctype = NULL; + + if ((root->ns != NULL) && (root->ns->prefix != NULL)) + doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name); + if (doctype == NULL) + doctype = root->name; + + /* + * Apply the default selection of the method + */ + if ((method == NULL) && + (root->ns == NULL) && + (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) { + xmlNodePtr tmp; + + tmp = res->children; + while ((tmp != NULL) && (tmp != root)) { + if (tmp->type == XML_ELEMENT_NODE) + break; + if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp))) + break; + tmp = tmp->next; + } + if (tmp == root) { + ctxt->type = XSLT_OUTPUT_HTML; + res->type = XML_HTML_DOCUMENT_NODE; + if (((doctypePublic != NULL) || (doctypeSystem != NULL))) { + res->intSubset = xmlCreateIntSubset(res, doctype, + doctypePublic, + doctypeSystem); +#ifdef XSLT_GENERATE_HTML_DOCTYPE + } else if (version != NULL) { + xsltGetHTMLIDs(version, &doctypePublic, + &doctypeSystem); + if (((doctypePublic != NULL) || (doctypeSystem != NULL))) + res->intSubset = + xmlCreateIntSubset(res, doctype, + doctypePublic, + doctypeSystem); +#endif + } + } + + } + if (ctxt->type == XSLT_OUTPUT_XML) { + XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic) + XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem) + if (((doctypePublic != NULL) || (doctypeSystem != NULL))) + res->intSubset = xmlCreateIntSubset(res, doctype, + doctypePublic, + doctypeSystem); + } + } + + /* + * Calls to redirect:write also take an optional attribute append. + * Attribute append="true|yes" which will attempt to simply append + * to an existing file instead of always opening a new file. The + * default behavior of always overwriting the file still happens + * if we do not specify append. + * Note that append use will forbid use of remote URI target. + */ + prop = xsltEvalAttrValueTemplate(ctxt, inst, (const xmlChar *)"append", + NULL); + if (prop != NULL) { + if (xmlStrEqual(prop, (const xmlChar *) "true") || + xmlStrEqual(prop, (const xmlChar *) "yes")) { + style->omitXmlDeclaration = 1; + redirect_write_append = 1; + } else + style->omitXmlDeclaration = 0; + xmlFree(prop); + } + + if (redirect_write_append) { + FILE *f; + + f = fopen((const char *) filename, "ab"); + if (f == NULL) { + ret = -1; + } else { + ret = xsltSaveResultToFile(f, res, style); + fclose(f); + } + } else { + ret = xsltSaveResultToFilename((const char *) filename, res, style, 0); + } + if (ret < 0) { + xsltTransformError(ctxt, NULL, inst, + "xsltDocumentElem: unable to save to %s\n", + filename); +#ifdef WITH_XSLT_DEBUG_EXTRA + } else { + xsltGenericDebug(xsltGenericDebugContext, + "Wrote %d bytes to %s\n", ret, filename); +#endif + } + + error: + ctxt->output = oldOutput; + ctxt->insert = oldInsert; + ctxt->type = oldType; + ctxt->outputFile = oldOutputFile; + if (URL != NULL) + xmlFree(URL); + if (filename != NULL) + xmlFree(filename); + if (style != NULL) + xsltFreeStylesheet(style); + if (res != NULL) + xmlFreeDoc(res); +} + +/************************************************************************ + * * + * Most of the XSLT-1.0 transformations * + * * + ************************************************************************/ + +/** + * xsltSort: + * @ctxt: a XSLT process context + * @node: the node in the source tree. + * @inst: the xslt sort node + * @comp: precomputed information + * + * function attached to xsl:sort nodes, but this should not be + * called directly + */ +void +xsltSort(xsltTransformContextPtr ctxt, + xmlNodePtr node ATTRIBUTE_UNUSED, xmlNodePtr inst, + xsltElemPreCompPtr comp) { + if (comp == NULL) { + xsltTransformError(ctxt, NULL, inst, + "xsl:sort : compilation failed\n"); + return; + } + xsltTransformError(ctxt, NULL, inst, + "xsl:sort : improper use this should not be reached\n"); +} + +/** + * xsltCopy: + * @ctxt: an XSLT process context + * @node: the node in the source tree + * @inst: the element node of the XSLT-copy instruction + * @castedComp: computed information of the XSLT-copy instruction + * + * Execute the XSLT-copy instruction on the source node. + */ +void +xsltCopy(xsltTransformContextPtr ctxt, xmlNodePtr node, + xmlNodePtr inst, xsltElemPreCompPtr castedComp) +{ +#ifdef XSLT_REFACTORED + xsltStyleItemCopyPtr comp = (xsltStyleItemCopyPtr) castedComp; +#else + xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp; +#endif + xmlNodePtr copy, oldInsert; + + oldInsert = ctxt->insert; + if (ctxt->insert != NULL) { + switch (node->type) { + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + /* + * This text comes from the stylesheet + * For stylesheets, the set of whitespace-preserving + * element names consists of just xsl:text. + */ +#ifdef WITH_XSLT_DEBUG_PROCESS + if (node->type == XML_CDATA_SECTION_NODE) { + XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, + "xsltCopy: CDATA text %s\n", node->content)); + } else { + XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, + "xsltCopy: text %s\n", node->content)); + } +#endif + xsltCopyText(ctxt, ctxt->insert, node, 0); + break; + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + break; + case XML_ELEMENT_NODE: + /* + * REVISIT NOTE: The "fake" is a doc-node, not an element node. + * REMOVED: + * if (xmlStrEqual(node->name, BAD_CAST " fake node libxslt")) + * return; + */ + +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, + "xsltCopy: node %s\n", node->name)); +#endif + copy = xsltShallowCopyElem(ctxt, node, ctxt->insert, 0); + ctxt->insert = copy; + if (comp->use != NULL) { + xsltApplyAttributeSet(ctxt, node, inst, comp->use); + } + break; + case XML_ATTRIBUTE_NODE: { +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, + "xsltCopy: attribute %s\n", node->name)); +#endif + /* + * REVISIT: We could also raise an error if the parent is not + * an element node. + * OPTIMIZE TODO: Can we set the value/children of the + * attribute without an intermediate copy of the string value? + */ + xsltShallowCopyAttr(ctxt, inst, ctxt->insert, (xmlAttrPtr) node); + break; + } + case XML_PI_NODE: +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, + "xsltCopy: PI %s\n", node->name)); +#endif + copy = xmlNewDocPI(ctxt->insert->doc, node->name, + node->content); + copy = xsltAddChild(ctxt->insert, copy); + break; + case XML_COMMENT_NODE: +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, + "xsltCopy: comment\n")); +#endif + copy = xmlNewComment(node->content); + copy = xsltAddChild(ctxt->insert, copy); + break; + case XML_NAMESPACE_DECL: +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_COPY,xsltGenericDebug(xsltGenericDebugContext, + "xsltCopy: namespace declaration\n")); +#endif + xsltShallowCopyNsNode(ctxt, inst, ctxt->insert, (xmlNsPtr)node); + break; + default: + break; + + } + } + + switch (node->type) { + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + case XML_ELEMENT_NODE: + xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children, + NULL); + break; + default: + break; + } + ctxt->insert = oldInsert; +} + +/** + * xsltText: + * @ctxt: a XSLT process context + * @node: the node in the source tree. + * @inst: the xslt text node + * @comp: precomputed information + * + * Process the xslt text node on the source node + */ +void +xsltText(xsltTransformContextPtr ctxt, xmlNodePtr node ATTRIBUTE_UNUSED, + xmlNodePtr inst, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED) { + if ((inst->children != NULL) && (comp != NULL)) { + xmlNodePtr text = inst->children; + xmlNodePtr copy; + + while (text != NULL) { + if ((text->type != XML_TEXT_NODE) && + (text->type != XML_CDATA_SECTION_NODE)) { + xsltTransformError(ctxt, NULL, inst, + "xsl:text content problem\n"); + break; + } + copy = xmlNewDocText(ctxt->output, text->content); + if (text->type != XML_CDATA_SECTION_NODE) { +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "Disable escaping: %s\n", text->content); +#endif + copy->name = xmlStringTextNoenc; + } + copy = xsltAddChild(ctxt->insert, copy); + text = text->next; + } + } +} + +/** + * xsltElement: + * @ctxt: a XSLT process context + * @node: the node in the source tree. + * @inst: the xslt element node + * @castedComp: precomputed information + * + * Process the xslt element node on the source node + */ +void +xsltElement(xsltTransformContextPtr ctxt, xmlNodePtr node, + xmlNodePtr inst, xsltElemPreCompPtr castedComp) { +#ifdef XSLT_REFACTORED + xsltStyleItemElementPtr comp = (xsltStyleItemElementPtr) castedComp; +#else + xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp; +#endif + xmlChar *prop = NULL; + const xmlChar *name, *prefix = NULL, *nsName = NULL; + xmlNodePtr copy; + xmlNodePtr oldInsert; + + if (ctxt->insert == NULL) + return; + + /* + * A comp->has_name == 0 indicates that we need to skip this instruction, + * since it was evaluated to be invalid already during compilation. + */ + if (!comp->has_name) + return; + + /* + * stack and saves + */ + oldInsert = ctxt->insert; + + if (comp->name == NULL) { + /* TODO: fix attr acquisition wrt to the XSLT namespace */ + prop = xsltEvalAttrValueTemplate(ctxt, inst, + (const xmlChar *) "name", XSLT_NAMESPACE); + if (prop == NULL) { + xsltTransformError(ctxt, NULL, inst, + "xsl:element: The attribute 'name' is missing.\n"); + goto error; + } + if (xmlValidateQName(prop, 0)) { + xsltTransformError(ctxt, NULL, inst, + "xsl:element: The effective name '%s' is not a " + "valid QName.\n", prop); + /* we fall through to catch any further errors, if possible */ + } + name = xsltSplitQName(ctxt->dict, prop, &prefix); + xmlFree(prop); + } else { + /* + * The "name" value was static. + */ +#ifdef XSLT_REFACTORED + prefix = comp->nsPrefix; + name = comp->name; +#else + name = xsltSplitQName(ctxt->dict, comp->name, &prefix); +#endif + } + + /* + * Create the new element + */ + if (ctxt->output->dict == ctxt->dict) { + copy = xmlNewDocNodeEatName(ctxt->output, NULL, (xmlChar *)name, NULL); + } else { + copy = xmlNewDocNode(ctxt->output, NULL, (xmlChar *)name, NULL); + } + if (copy == NULL) { + xsltTransformError(ctxt, NULL, inst, + "xsl:element : creation of %s failed\n", name); + return; + } + copy = xsltAddChild(ctxt->insert, copy); + if (copy == NULL) { + xsltTransformError(ctxt, NULL, inst, + "xsl:element : xsltAddChild failed\n"); + return; + } + + /* + * Namespace + * --------- + */ + if (comp->has_ns) { + if (comp->ns != NULL) { + /* + * No AVT; just plain text for the namespace name. + */ + if (comp->ns[0] != 0) + nsName = comp->ns; + } else { + xmlChar *tmpNsName; + /* + * Eval the AVT. + */ + /* TODO: check attr acquisition wrt to the XSLT namespace */ + tmpNsName = xsltEvalAttrValueTemplate(ctxt, inst, + (const xmlChar *) "namespace", XSLT_NAMESPACE); + /* + * SPEC XSLT 1.0: + * "If the string is empty, then the expanded-name of the + * attribute has a null namespace URI." + */ + if ((tmpNsName != NULL) && (tmpNsName[0] != 0)) + nsName = xmlDictLookup(ctxt->dict, BAD_CAST tmpNsName, -1); + xmlFree(tmpNsName); + } + + if (xmlStrEqual(nsName, BAD_CAST "http://www.w3.org/2000/xmlns/")) { + xsltTransformError(ctxt, NULL, inst, + "xsl:attribute: Namespace http://www.w3.org/2000/xmlns/ " + "forbidden.\n"); + goto error; + } + if (xmlStrEqual(nsName, XML_XML_NAMESPACE)) { + prefix = BAD_CAST "xml"; + } else if (xmlStrEqual(prefix, BAD_CAST "xml")) { + prefix = NULL; + } + } else { + xmlNsPtr ns; + /* + * SPEC XSLT 1.0: + * "If the namespace attribute is not present, then the QName is + * expanded into an expanded-name using the namespace declarations + * in effect for the xsl:element element, including any default + * namespace declaration. + */ + ns = xmlSearchNs(inst->doc, inst, prefix); + if (ns == NULL) { + /* + * TODO: Check this in the compilation layer in case it's a + * static value. + */ + if (prefix != NULL) { + xsltTransformError(ctxt, NULL, inst, + "xsl:element: The QName '%s:%s' has no " + "namespace binding in scope in the stylesheet; " + "this is an error, since the namespace was not " + "specified by the instruction itself.\n", prefix, name); + } + } else + nsName = ns->href; + } + /* + * Find/create a matching ns-decl in the result tree. + */ + if (nsName != NULL) { + if (xmlStrEqual(prefix, BAD_CAST "xmlns")) { + /* Don't use a prefix of "xmlns" */ + xmlChar *pref = xmlStrdup(BAD_CAST "ns_1"); + + copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, pref, copy); + + xmlFree(pref); + } else { + copy->ns = xsltGetSpecialNamespace(ctxt, inst, nsName, prefix, + copy); + } + } else if ((copy->parent != NULL) && + (copy->parent->type == XML_ELEMENT_NODE) && + (copy->parent->ns != NULL)) + { + /* + * "Undeclare" the default namespace. + */ + xsltGetSpecialNamespace(ctxt, inst, NULL, NULL, copy); + } + + ctxt->insert = copy; + + if (comp->has_use) { + if (comp->use != NULL) { + xsltApplyAttributeSet(ctxt, node, inst, comp->use); + } else { + xmlChar *attrSets = NULL; + /* + * BUG TODO: use-attribute-sets is not a value template. + * use-attribute-sets = qnames + */ + attrSets = xsltEvalAttrValueTemplate(ctxt, inst, + (const xmlChar *)"use-attribute-sets", NULL); + if (attrSets != NULL) { + xsltApplyAttributeSet(ctxt, node, inst, attrSets); + xmlFree(attrSets); + } + } + } + /* + * Instantiate the sequence constructor. + */ + if (inst->children != NULL) + xsltApplySequenceConstructor(ctxt, ctxt->node, inst->children, + NULL); + +error: + ctxt->insert = oldInsert; + return; +} + + +/** + * xsltComment: + * @ctxt: a XSLT process context + * @node: the node in the source tree. + * @inst: the xslt comment node + * @comp: precomputed information + * + * Process the xslt comment node on the source node + */ +void +xsltComment(xsltTransformContextPtr ctxt, xmlNodePtr node, + xmlNodePtr inst, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED) { + xmlChar *value = NULL; + xmlNodePtr commentNode; + int len; + + value = xsltEvalTemplateString(ctxt, node, inst); + /* TODO: use or generate the compiled form */ + len = xmlStrlen(value); + if (len > 0) { + if ((value[len-1] == '-') || + (xmlStrstr(value, BAD_CAST "--"))) { + xsltTransformError(ctxt, NULL, inst, + "xsl:comment : '--' or ending '-' not allowed in comment\n"); + /* fall through to try to catch further errors */ + } + } +#ifdef WITH_XSLT_DEBUG_PROCESS + if (value == NULL) { + XSLT_TRACE(ctxt,XSLT_TRACE_COMMENT,xsltGenericDebug(xsltGenericDebugContext, + "xsltComment: empty\n")); + } else { + XSLT_TRACE(ctxt,XSLT_TRACE_COMMENT,xsltGenericDebug(xsltGenericDebugContext, + "xsltComment: content %s\n", value)); + } +#endif + + commentNode = xmlNewComment(value); + commentNode = xsltAddChild(ctxt->insert, commentNode); + + if (value != NULL) + xmlFree(value); +} + +/** + * xsltProcessingInstruction: + * @ctxt: a XSLT process context + * @node: the node in the source tree. + * @inst: the xslt processing-instruction node + * @castedComp: precomputed information + * + * Process the xslt processing-instruction node on the source node + */ +void +xsltProcessingInstruction(xsltTransformContextPtr ctxt, xmlNodePtr node, + xmlNodePtr inst, xsltElemPreCompPtr castedComp) { +#ifdef XSLT_REFACTORED + xsltStyleItemPIPtr comp = (xsltStyleItemPIPtr) castedComp; +#else + xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp; +#endif + const xmlChar *name; + xmlChar *value = NULL; + xmlNodePtr pi; + + + if (ctxt->insert == NULL) + return; + if (comp->has_name == 0) + return; + if (comp->name == NULL) { + name = xsltEvalAttrValueTemplate(ctxt, inst, + (const xmlChar *)"name", NULL); + if (name == NULL) { + xsltTransformError(ctxt, NULL, inst, + "xsl:processing-instruction : name is missing\n"); + goto error; + } + } else { + name = comp->name; + } + /* TODO: check that it's both an an NCName and a PITarget. */ + + + value = xsltEvalTemplateString(ctxt, node, inst); + if (xmlStrstr(value, BAD_CAST "?>") != NULL) { + xsltTransformError(ctxt, NULL, inst, + "xsl:processing-instruction: '?>' not allowed within PI content\n"); + goto error; + } +#ifdef WITH_XSLT_DEBUG_PROCESS + if (value == NULL) { + XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext, + "xsltProcessingInstruction: %s empty\n", name)); + } else { + XSLT_TRACE(ctxt,XSLT_TRACE_PI,xsltGenericDebug(xsltGenericDebugContext, + "xsltProcessingInstruction: %s content %s\n", name, value)); + } +#endif + + pi = xmlNewDocPI(ctxt->insert->doc, name, value); + pi = xsltAddChild(ctxt->insert, pi); + +error: + if ((name != NULL) && (name != comp->name)) + xmlFree((xmlChar *) name); + if (value != NULL) + xmlFree(value); +} + +/** + * xsltCopyOf: + * @ctxt: an XSLT transformation context + * @node: the current node in the source tree + * @inst: the element node of the XSLT copy-of instruction + * @castedComp: precomputed information of the XSLT copy-of instruction + * + * Process the XSLT copy-of instruction. + */ +void +xsltCopyOf(xsltTransformContextPtr ctxt, xmlNodePtr node, + xmlNodePtr inst, xsltElemPreCompPtr castedComp) { +#ifdef XSLT_REFACTORED + xsltStyleItemCopyOfPtr comp = (xsltStyleItemCopyOfPtr) castedComp; +#else + xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp; +#endif + xmlXPathObjectPtr res = NULL; + xmlNodeSetPtr list = NULL; + int i; + + if ((ctxt == NULL) || (node == NULL) || (inst == NULL)) + return; + if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) { + xsltTransformError(ctxt, NULL, inst, + "xsl:copy-of : compilation failed\n"); + return; + } + + /* + * SPEC XSLT 1.0: + * "The xsl:copy-of element can be used to insert a result tree + * fragment into the result tree, without first converting it to + * a string as xsl:value-of does (see [7.6.1 Generating Text with + * xsl:value-of]). The required select attribute contains an + * expression. When the result of evaluating the expression is a + * result tree fragment, the complete fragment is copied into the + * result tree. When the result is a node-set, all the nodes in the + * set are copied in document order into the result tree; copying + * an element node copies the attribute nodes, namespace nodes and + * children of the element node as well as the element node itself; + * a root node is copied by copying its children. When the result + * is neither a node-set nor a result tree fragment, the result is + * converted to a string and then inserted into the result tree, + * as with xsl:value-of. + */ + +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext, + "xsltCopyOf: select %s\n", comp->select)); +#endif + + /* + * Evaluate the "select" expression. + */ + res = xsltPreCompEval(ctxt, node, comp); + + if (res != NULL) { + if (res->type == XPATH_NODESET) { + /* + * Node-set + * -------- + */ +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext, + "xsltCopyOf: result is a node set\n")); +#endif + list = res->nodesetval; + if (list != NULL) { + xmlNodePtr cur; + /* + * The list is already sorted in document order by XPath. + * Append everything in this order under ctxt->insert. + */ + for (i = 0;i < list->nodeNr;i++) { + cur = list->nodeTab[i]; + if (cur == NULL) + continue; + if ((cur->type == XML_DOCUMENT_NODE) || + (cur->type == XML_HTML_DOCUMENT_NODE)) + { + xsltCopyTreeList(ctxt, inst, + cur->children, ctxt->insert, 0, 0); + } else if (cur->type == XML_ATTRIBUTE_NODE) { + xsltShallowCopyAttr(ctxt, inst, + ctxt->insert, (xmlAttrPtr) cur); + } else { + xsltCopyTree(ctxt, inst, cur, ctxt->insert, 0, 0); + } + } + } + } else if (res->type == XPATH_XSLT_TREE) { + /* + * Result tree fragment + * -------------------- + * E.g. via + * Note that the root node of such trees is an xmlDocPtr in Libxslt. + */ +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext, + "xsltCopyOf: result is a result tree fragment\n")); +#endif + list = res->nodesetval; + if ((list != NULL) && (list->nodeTab != NULL) && + (list->nodeTab[0] != NULL) && + (IS_XSLT_REAL_NODE(list->nodeTab[0]))) + { + xsltCopyTreeList(ctxt, inst, + list->nodeTab[0]->children, ctxt->insert, 0, 0); + } + } else { + xmlChar *value = NULL; + /* + * Convert to a string. + */ + value = xmlXPathCastToString(res); + if (value == NULL) { + xsltTransformError(ctxt, NULL, inst, + "Internal error in xsltCopyOf(): " + "failed to cast an XPath object to string.\n"); + ctxt->state = XSLT_STATE_STOPPED; + } else { + if (value[0] != 0) { + /* + * Append content as text node. + */ + xsltCopyTextString(ctxt, ctxt->insert, value, 0); + } + xmlFree(value); + +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_COPY_OF,xsltGenericDebug(xsltGenericDebugContext, + "xsltCopyOf: result %s\n", res->stringval)); +#endif + } + } + } else { + ctxt->state = XSLT_STATE_STOPPED; + } + + if (res != NULL) + xmlXPathFreeObject(res); +} + +/** + * xsltValueOf: + * @ctxt: a XSLT process context + * @node: the node in the source tree. + * @inst: the xslt value-of node + * @castedComp: precomputed information + * + * Process the xslt value-of node on the source node + */ +void +xsltValueOf(xsltTransformContextPtr ctxt, xmlNodePtr node, + xmlNodePtr inst, xsltElemPreCompPtr castedComp) +{ +#ifdef XSLT_REFACTORED + xsltStyleItemValueOfPtr comp = (xsltStyleItemValueOfPtr) castedComp; +#else + xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp; +#endif + xmlXPathObjectPtr res = NULL; + xmlChar *value = NULL; + + if ((ctxt == NULL) || (node == NULL) || (inst == NULL)) + return; + + if ((comp == NULL) || (comp->select == NULL) || (comp->comp == NULL)) { + xsltTransformError(ctxt, NULL, inst, + "Internal error in xsltValueOf(): " + "The XSLT 'value-of' instruction was not compiled.\n"); + return; + } + +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext, + "xsltValueOf: select %s\n", comp->select)); +#endif + + res = xsltPreCompEval(ctxt, node, comp); + + /* + * Cast the XPath object to string. + */ + if (res != NULL) { + value = xmlXPathCastToString(res); + if (value == NULL) { + xsltTransformError(ctxt, NULL, inst, + "Internal error in xsltValueOf(): " + "failed to cast an XPath object to string.\n"); + ctxt->state = XSLT_STATE_STOPPED; + goto error; + } + if (value[0] != 0) { + xsltCopyTextString(ctxt, ctxt->insert, value, comp->noescape); + } + } else { + xsltTransformError(ctxt, NULL, inst, + "XPath evaluation returned no result.\n"); + ctxt->state = XSLT_STATE_STOPPED; + goto error; + } + +#ifdef WITH_XSLT_DEBUG_PROCESS + if (value) { + XSLT_TRACE(ctxt,XSLT_TRACE_VALUE_OF,xsltGenericDebug(xsltGenericDebugContext, + "xsltValueOf: result '%s'\n", value)); + } +#endif + +error: + if (value != NULL) + xmlFree(value); + if (res != NULL) + xmlXPathFreeObject(res); +} + +/** + * xsltNumber: + * @ctxt: a XSLT process context + * @node: the node in the source tree. + * @inst: the xslt number node + * @castedComp: precomputed information + * + * Process the xslt number node on the source node + */ +void +xsltNumber(xsltTransformContextPtr ctxt, xmlNodePtr node, + xmlNodePtr inst, xsltElemPreCompPtr castedComp) +{ +#ifdef XSLT_REFACTORED + xsltStyleItemNumberPtr comp = (xsltStyleItemNumberPtr) castedComp; +#else + xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp; +#endif + xmlXPathContextPtr xpctxt; + xmlNsPtr *oldXPNamespaces; + int oldXPNsNr; + + if (comp == NULL) { + xsltTransformError(ctxt, NULL, inst, + "xsl:number : compilation failed\n"); + return; + } + + if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL)) + return; + + comp->numdata.doc = inst->doc; + comp->numdata.node = inst; + + xpctxt = ctxt->xpathCtxt; + oldXPNsNr = xpctxt->nsNr; + oldXPNamespaces = xpctxt->namespaces; + +#ifdef XSLT_REFACTORED + if (comp->inScopeNs != NULL) { + xpctxt->namespaces = comp->inScopeNs->list; + xpctxt->nsNr = comp->inScopeNs->xpathNumber; + } else { + xpctxt->namespaces = NULL; + xpctxt->nsNr = 0; + } +#else + xpctxt->namespaces = comp->nsList; + xpctxt->nsNr = comp->nsNr; +#endif + + xsltNumberFormat(ctxt, &comp->numdata, node); + + xpctxt->nsNr = oldXPNsNr; + xpctxt->namespaces = oldXPNamespaces; +} + +/** + * xsltApplyImports: + * @ctxt: an XSLT transformation context + * @contextNode: the current node in the source tree. + * @inst: the element node of the XSLT 'apply-imports' instruction + * @comp: the compiled instruction + * + * Process the XSLT apply-imports element. + */ +void +xsltApplyImports(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, + xmlNodePtr inst, + xsltElemPreCompPtr comp ATTRIBUTE_UNUSED) +{ + xsltTemplatePtr templ; + + if ((ctxt == NULL) || (inst == NULL)) + return; + + if (comp == NULL) { + xsltTransformError(ctxt, NULL, inst, + "Internal error in xsltApplyImports(): " + "The XSLT 'apply-imports' instruction was not compiled.\n"); + return; + } + /* + * NOTE that ctxt->currentTemplateRule and ctxt->templ is not the + * same; the former is the "Current Template Rule" as defined by the + * XSLT spec, the latter is simply the template struct being + * currently processed. + */ + if (ctxt->currentTemplateRule == NULL) { + /* + * SPEC XSLT 2.0: + * "[ERR XTDE0560] It is a non-recoverable dynamic error if + * xsl:apply-imports or xsl:next-match is evaluated when the + * current template rule is null." + */ + xsltTransformError(ctxt, NULL, inst, + "It is an error to call 'apply-imports' " + "when there's no current template rule.\n"); + return; + } + /* + * TODO: Check if this is correct. + */ + templ = xsltGetTemplate(ctxt, contextNode, + ctxt->currentTemplateRule->style); + + if (templ != NULL) { + xsltTemplatePtr oldCurTemplRule = ctxt->currentTemplateRule; + /* + * Set the current template rule. + */ + ctxt->currentTemplateRule = templ; + /* + * URGENT TODO: Need xsl:with-param be handled somehow here? + */ + xsltApplyXSLTTemplate(ctxt, contextNode, templ->content, + templ, NULL); + + ctxt->currentTemplateRule = oldCurTemplRule; + } + else { + /* Use built-in templates. */ + xsltDefaultProcessOneNode(ctxt, contextNode, NULL); + } +} + +/** + * xsltCallTemplate: + * @ctxt: a XSLT transformation context + * @node: the "current node" in the source tree + * @inst: the XSLT 'call-template' instruction + * @castedComp: the compiled information of the instruction + * + * Processes the XSLT call-template instruction on the source node. + */ +void +xsltCallTemplate(xsltTransformContextPtr ctxt, xmlNodePtr node, + xmlNodePtr inst, xsltElemPreCompPtr castedComp) +{ +#ifdef XSLT_REFACTORED + xsltStyleItemCallTemplatePtr comp = + (xsltStyleItemCallTemplatePtr) castedComp; +#else + xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp; +#endif + xsltStackElemPtr withParams = NULL; + + if (ctxt->insert == NULL) + return; + if (comp == NULL) { + xsltTransformError(ctxt, NULL, inst, + "The XSLT 'call-template' instruction was not compiled.\n"); + return; + } + + /* + * The template must have been precomputed + */ + if (comp->templ == NULL) { + comp->templ = xsltFindTemplate(ctxt, comp->name, comp->ns); + if (comp->templ == NULL) { + if (comp->ns != NULL) { + xsltTransformError(ctxt, NULL, inst, + "The called template '{%s}%s' was not found.\n", + comp->ns, comp->name); + } else { + xsltTransformError(ctxt, NULL, inst, + "The called template '%s' was not found.\n", + comp->name); + } + return; + } + } + +#ifdef WITH_XSLT_DEBUG_PROCESS + if ((comp != NULL) && (comp->name != NULL)) + XSLT_TRACE(ctxt,XSLT_TRACE_CALL_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, + "call-template: name %s\n", comp->name)); +#endif + + if (inst->children) { + xmlNodePtr cur; + xsltStackElemPtr param; + + cur = inst->children; + while (cur != NULL) { +#ifdef WITH_DEBUGGER + if (ctxt->debugStatus != XSLT_DEBUG_NONE) + xslHandleDebugger(cur, node, comp->templ, ctxt); +#endif + if (ctxt->state == XSLT_STATE_STOPPED) break; + /* + * TODO: The "with-param"s could be part of the "call-template" + * structure. Avoid to "search" for params dynamically + * in the XML tree every time. + */ + if (IS_XSLT_ELEM(cur)) { + if (IS_XSLT_NAME(cur, "with-param")) { + param = xsltParseStylesheetCallerParam(ctxt, cur); + if (param != NULL) { + param->next = withParams; + withParams = param; + } + } else { + xsltGenericError(xsltGenericErrorContext, + "xsl:call-template: misplaced xsl:%s\n", cur->name); + } + } else { + xsltGenericError(xsltGenericErrorContext, + "xsl:call-template: misplaced %s element\n", cur->name); + } + cur = cur->next; + } + } + /* + * Create a new frame using the params first + */ + xsltApplyXSLTTemplate(ctxt, node, comp->templ->content, comp->templ, + withParams); + if (withParams != NULL) + xsltFreeStackElemList(withParams); + +#ifdef WITH_XSLT_DEBUG_PROCESS + if ((comp != NULL) && (comp->name != NULL)) + XSLT_TRACE(ctxt,XSLT_TRACE_CALL_TEMPLATE,xsltGenericDebug(xsltGenericDebugContext, + "call-template returned: name %s\n", comp->name)); +#endif +} + +/** + * xsltApplyTemplates: + * @ctxt: a XSLT transformation context + * @node: the 'current node' in the source tree + * @inst: the element node of an XSLT 'apply-templates' instruction + * @castedComp: the compiled instruction + * + * Processes the XSLT 'apply-templates' instruction on the current node. + */ +void +xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node, + xmlNodePtr inst, xsltElemPreCompPtr castedComp) +{ +#ifdef XSLT_REFACTORED + xsltStyleItemApplyTemplatesPtr comp = + (xsltStyleItemApplyTemplatesPtr) castedComp; +#else + xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp; +#endif + int i; + xmlNodePtr cur, oldContextNode; + xmlNodeSetPtr list = NULL, oldList; + xsltStackElemPtr withParams = NULL; + int oldXPProximityPosition, oldXPContextSize; + const xmlChar *oldMode, *oldModeURI; + xmlDocPtr oldXPDoc; + xsltDocumentPtr oldDocInfo; + xmlXPathContextPtr xpctxt; + + if (comp == NULL) { + xsltTransformError(ctxt, NULL, inst, + "xsl:apply-templates : compilation failed\n"); + return; + } + if ((ctxt == NULL) || (node == NULL) || (inst == NULL) || (comp == NULL)) + return; + +#ifdef WITH_XSLT_DEBUG_PROCESS + if ((node != NULL) && (node->name != NULL)) + XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, + "xsltApplyTemplates: node: '%s'\n", node->name)); +#endif + + xpctxt = ctxt->xpathCtxt; + /* + * Save context states. + */ + oldContextNode = ctxt->node; + oldMode = ctxt->mode; + oldModeURI = ctxt->modeURI; + oldDocInfo = ctxt->document; + oldList = ctxt->nodeList; + + /* + * The xpath context size and proximity position, as + * well as the xpath and context documents, may be changed + * so we save their initial state and will restore on exit + */ + oldXPContextSize = xpctxt->contextSize; + oldXPProximityPosition = xpctxt->proximityPosition; + oldXPDoc = xpctxt->doc; + + /* + * Set up contexts. + */ + ctxt->mode = comp->mode; + ctxt->modeURI = comp->modeURI; + + if (comp->select != NULL) { + xmlXPathObjectPtr res = NULL; + + if (comp->comp == NULL) { + xsltTransformError(ctxt, NULL, inst, + "xsl:apply-templates : compilation failed\n"); + goto error; + } +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, + "xsltApplyTemplates: select %s\n", comp->select)); +#endif + + res = xsltPreCompEval(ctxt, node, comp); + + if (res != NULL) { + if (res->type == XPATH_NODESET) { + list = res->nodesetval; /* consume the node set */ + res->nodesetval = NULL; + } else { + xsltTransformError(ctxt, NULL, inst, + "The 'select' expression did not evaluate to a " + "node set.\n"); + ctxt->state = XSLT_STATE_STOPPED; + xmlXPathFreeObject(res); + goto error; + } + xmlXPathFreeObject(res); + /* + * Note: An xsl:apply-templates with a 'select' attribute, + * can change the current source doc. + */ + } else { + xsltTransformError(ctxt, NULL, inst, + "Failed to evaluate the 'select' expression.\n"); + ctxt->state = XSLT_STATE_STOPPED; + goto error; + } + if (list == NULL) { +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, + "xsltApplyTemplates: select didn't evaluate to a node list\n")); +#endif + goto exit; + } + /* + * + * NOTE: Previously a document info (xsltDocument) was + * created and attached to the Result Tree Fragment. + * But such a document info is created on demand in + * xsltKeyFunction() (functions.c), so we need to create + * it here beforehand. + * In order to take care of potential keys we need to + * do some extra work for the case when a Result Tree Fragment + * is converted into a nodeset (e.g. exslt:node-set()) : + * We attach a "pseudo-doc" (xsltDocument) to _private. + * This xsltDocument, together with the keyset, will be freed + * when the Result Tree Fragment is freed. + * + */ +#if 0 + if ((ctxt->nbKeys > 0) && + (list->nodeNr != 0) && + (list->nodeTab[0]->doc != NULL) && + XSLT_IS_RES_TREE_FRAG(list->nodeTab[0]->doc)) + { + /* + * NOTE that it's also OK if @effectiveDocInfo will be + * set to NULL. + */ + isRTF = 1; + effectiveDocInfo = list->nodeTab[0]->doc->_private; + } +#endif + } else { + /* + * Build an XPath node set with the children + */ + list = xmlXPathNodeSetCreate(NULL); + if (list == NULL) + goto error; + if (node->type != XML_NAMESPACE_DECL) + cur = node->children; + else + cur = NULL; + while (cur != NULL) { + if (IS_XSLT_REAL_NODE(cur)) + xmlXPathNodeSetAddUnique(list, cur); + cur = cur->next; + } + } + +#ifdef WITH_XSLT_DEBUG_PROCESS + if (list != NULL) + XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, + "xsltApplyTemplates: list of %d nodes\n", list->nodeNr)); +#endif + + if ((list == NULL) || (list->nodeNr == 0)) + goto exit; + + /* + * Set the context's node set and size; this is also needed for + * for xsltDoSortFunction(). + */ + ctxt->nodeList = list; + /* + * Process xsl:with-param and xsl:sort instructions. + * (The code became so verbose just to avoid the + * xmlNodePtr sorts[XSLT_MAX_SORT] if there's no xsl:sort) + * BUG TODO: We are not using namespaced potentially defined on the + * xsl:sort or xsl:with-param elements; XPath expression might fail. + */ + if (inst->children) { + xsltStackElemPtr param; + + cur = inst->children; + while (cur) { + +#ifdef WITH_DEBUGGER + if (ctxt->debugStatus != XSLT_DEBUG_NONE) + xslHandleDebugger(cur, node, NULL, ctxt); +#endif + if (ctxt->state == XSLT_STATE_STOPPED) + break; + if (cur->type == XML_TEXT_NODE) { + cur = cur->next; + continue; + } + if (! IS_XSLT_ELEM(cur)) + break; + if (IS_XSLT_NAME(cur, "with-param")) { + param = xsltParseStylesheetCallerParam(ctxt, cur); + if (param != NULL) { + param->next = withParams; + withParams = param; + } + } + if (IS_XSLT_NAME(cur, "sort")) { + xsltTemplatePtr oldCurTempRule = + ctxt->currentTemplateRule; + int nbsorts = 0; + xmlNodePtr sorts[XSLT_MAX_SORT]; + + sorts[nbsorts++] = cur; + cur = cur->next; + + while (cur) { + +#ifdef WITH_DEBUGGER + if (ctxt->debugStatus != XSLT_DEBUG_NONE) + xslHandleDebugger(cur, node, NULL, ctxt); +#endif + if (ctxt->state == XSLT_STATE_STOPPED) + break; + + if (cur->type == XML_TEXT_NODE) { + cur = cur->next; + continue; + } + + if (! IS_XSLT_ELEM(cur)) + break; + if (IS_XSLT_NAME(cur, "with-param")) { + param = xsltParseStylesheetCallerParam(ctxt, cur); + if (param != NULL) { + param->next = withParams; + withParams = param; + } + } + if (IS_XSLT_NAME(cur, "sort")) { + if (nbsorts >= XSLT_MAX_SORT) { + xsltTransformError(ctxt, NULL, cur, + "The number (%d) of xsl:sort instructions exceeds the " + "maximum allowed by this processor's settings.\n", + nbsorts); + ctxt->state = XSLT_STATE_STOPPED; + break; + } else { + sorts[nbsorts++] = cur; + } + } + cur = cur->next; + } + /* + * The "current template rule" is cleared for xsl:sort. + */ + ctxt->currentTemplateRule = NULL; + /* + * Sort. + */ + xsltDoSortFunction(ctxt, sorts, nbsorts); + ctxt->currentTemplateRule = oldCurTempRule; + break; + } + cur = cur->next; + } + } + xpctxt->contextSize = list->nodeNr; + /* + * Apply templates for all selected source nodes. + */ + for (i = 0; i < list->nodeNr; i++) { + cur = list->nodeTab[i]; + /* + * The node becomes the "current node". + */ + ctxt->node = cur; + /* + * An xsl:apply-templates can change the current context doc. + * OPTIMIZE TODO: Get rid of the need to set the context doc. + */ + if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL)) + xpctxt->doc = cur->doc; + + xpctxt->proximityPosition = i + 1; + /* + * Find and apply a template for this node. + */ + xsltProcessOneNode(ctxt, cur, withParams); + } + +exit: +error: + /* + * Free the parameter list. + */ + if (withParams != NULL) + xsltFreeStackElemList(withParams); + if (list != NULL) + xmlXPathFreeNodeSet(list); + /* + * Restore context states. + */ + xpctxt->doc = oldXPDoc; + xpctxt->contextSize = oldXPContextSize; + xpctxt->proximityPosition = oldXPProximityPosition; + + ctxt->document = oldDocInfo; + ctxt->nodeList = oldList; + ctxt->node = oldContextNode; + ctxt->mode = oldMode; + ctxt->modeURI = oldModeURI; +} + + +/** + * xsltChoose: + * @ctxt: a XSLT process context + * @contextNode: the current node in the source tree + * @inst: the xsl:choose instruction + * @comp: compiled information of the instruction + * + * Processes the xsl:choose instruction on the source node. + */ +void +xsltChoose(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, + xmlNodePtr inst, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED) +{ + xmlNodePtr cur; + + if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL)) + return; + + /* + * TODO: Content model checks should be done only at compilation + * time. + */ + cur = inst->children; + if (cur == NULL) { + xsltTransformError(ctxt, NULL, inst, + "xsl:choose: The instruction has no content.\n"); + return; + } + +#ifdef XSLT_REFACTORED + /* + * We don't check the content model during transformation. + */ +#else + if ((! IS_XSLT_ELEM(cur)) || (! IS_XSLT_NAME(cur, "when"))) { + xsltTransformError(ctxt, NULL, inst, + "xsl:choose: xsl:when expected first\n"); + return; + } +#endif + + { + int testRes = 0, res = 0; + +#ifdef XSLT_REFACTORED + xsltStyleItemWhenPtr wcomp = NULL; +#else + xsltStylePreCompPtr wcomp = NULL; +#endif + + /* + * Process xsl:when --------------------------------------------------- + */ + while (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "when")) { + wcomp = cur->psvi; + + if ((wcomp == NULL) || (wcomp->test == NULL) || + (wcomp->comp == NULL)) + { + xsltTransformError(ctxt, NULL, cur, + "Internal error in xsltChoose(): " + "The XSLT 'when' instruction was not compiled.\n"); + goto error; + } + + +#ifdef WITH_DEBUGGER + if (xslDebugStatus != XSLT_DEBUG_NONE) { + /* + * TODO: Isn't comp->templ always NULL for xsl:choose? + */ + xslHandleDebugger(cur, contextNode, NULL, ctxt); + } +#endif +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext, + "xsltChoose: test %s\n", wcomp->test)); +#endif + +#ifdef XSLT_FAST_IF + res = xsltPreCompEvalToBoolean(ctxt, contextNode, wcomp); + + if (res == -1) { + ctxt->state = XSLT_STATE_STOPPED; + goto error; + } + testRes = (res == 1) ? 1 : 0; + +#else /* XSLT_FAST_IF */ + + res = xsltPreCompEval(ctxt, cotextNode, wcomp); + + if (res != NULL) { + if (res->type != XPATH_BOOLEAN) + res = xmlXPathConvertBoolean(res); + if (res->type == XPATH_BOOLEAN) + testRes = res->boolval; + else { +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext, + "xsltChoose: test didn't evaluate to a boolean\n")); +#endif + goto error; + } + xmlXPathFreeObject(res); + res = NULL; + } else { + ctxt->state = XSLT_STATE_STOPPED; + goto error; + } + +#endif /* else of XSLT_FAST_IF */ + +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext, + "xsltChoose: test evaluate to %d\n", testRes)); +#endif + if (testRes) + goto test_is_true; + + cur = cur->next; + } + + /* + * Process xsl:otherwise ---------------------------------------------- + */ + if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "otherwise")) { + +#ifdef WITH_DEBUGGER + if (xslDebugStatus != XSLT_DEBUG_NONE) + xslHandleDebugger(cur, contextNode, NULL, ctxt); +#endif + +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_CHOOSE,xsltGenericDebug(xsltGenericDebugContext, + "evaluating xsl:otherwise\n")); +#endif + goto test_is_true; + } + goto exit; + +test_is_true: + + goto process_sequence; + } + +process_sequence: + + /* + * Instantiate the sequence constructor. + */ + xsltApplySequenceConstructor(ctxt, ctxt->node, cur->children, + NULL); + +exit: +error: + return; +} + +/** + * xsltIf: + * @ctxt: a XSLT process context + * @contextNode: the current node in the source tree + * @inst: the xsl:if instruction + * @castedComp: compiled information of the instruction + * + * Processes the xsl:if instruction on the source node. + */ +void +xsltIf(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, + xmlNodePtr inst, xsltElemPreCompPtr castedComp) +{ + int res = 0; + +#ifdef XSLT_REFACTORED + xsltStyleItemIfPtr comp = (xsltStyleItemIfPtr) castedComp; +#else + xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp; +#endif + + if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL)) + return; + if ((comp == NULL) || (comp->test == NULL) || (comp->comp == NULL)) { + xsltTransformError(ctxt, NULL, inst, + "Internal error in xsltIf(): " + "The XSLT 'if' instruction was not compiled.\n"); + return; + } + +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext, + "xsltIf: test %s\n", comp->test)); +#endif + +#ifdef XSLT_FAST_IF + { + xsltRVTListPtr oldLocalFragmentTop = ctxt->localRVTList; + + res = xsltPreCompEvalToBoolean(ctxt, contextNode, comp); + + /* + * Cleanup fragments created during evaluation of the + * "select" expression. + */ + if (oldLocalFragmentTop != ctxt->localRVTList) + xsltReleaseLocalRVTs(ctxt, oldLocalFragmentTop); + } + +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext, + "xsltIf: test evaluate to %d\n", res)); +#endif + + if (res == -1) { + ctxt->state = XSLT_STATE_STOPPED; + goto error; + } + if (res == 1) { + /* + * Instantiate the sequence constructor of xsl:if. + */ + xsltApplySequenceConstructor(ctxt, + contextNode, inst->children, NULL); + } + +#else /* XSLT_FAST_IF */ + { + /* + * OLD CODE: + */ + xmlXPathObjectPtr xpobj = xsltPreCompEval(ctxt, contextNode, comp); + if (xpobj != NULL) { + if (xpobj->type != XPATH_BOOLEAN) + xpobj = xmlXPathConvertBoolean(xpobj); + if (xpobj->type == XPATH_BOOLEAN) { + res = xpobj->boolval; + +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_IF,xsltGenericDebug(xsltGenericDebugContext, + "xsltIf: test evaluate to %d\n", res)); +#endif + if (res) { + xsltApplySequenceConstructor(ctxt, + contextNode, inst->children, NULL); + } + } else { + +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt, XSLT_TRACE_IF, + xsltGenericDebug(xsltGenericDebugContext, + "xsltIf: test didn't evaluate to a boolean\n")); +#endif + ctxt->state = XSLT_STATE_STOPPED; + } + xmlXPathFreeObject(xpobj); + } else { + ctxt->state = XSLT_STATE_STOPPED; + } + } +#endif /* else of XSLT_FAST_IF */ + +error: + return; +} + +/** + * xsltForEach: + * @ctxt: an XSLT transformation context + * @contextNode: the "current node" in the source tree + * @inst: the element node of the xsl:for-each instruction + * @castedComp: the compiled information of the instruction + * + * Process the xslt for-each node on the source node + */ +void +xsltForEach(xsltTransformContextPtr ctxt, xmlNodePtr contextNode, + xmlNodePtr inst, xsltElemPreCompPtr castedComp) +{ +#ifdef XSLT_REFACTORED + xsltStyleItemForEachPtr comp = (xsltStyleItemForEachPtr) castedComp; +#else + xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp; +#endif + int i; + xmlXPathObjectPtr res = NULL; + xmlNodePtr cur, curInst; + xmlNodeSetPtr list = NULL; + xmlNodeSetPtr oldList; + int oldXPProximityPosition, oldXPContextSize; + xmlNodePtr oldContextNode; + xsltTemplatePtr oldCurTemplRule; + xmlDocPtr oldXPDoc; + xsltDocumentPtr oldDocInfo; + xmlXPathContextPtr xpctxt; + + if ((ctxt == NULL) || (contextNode == NULL) || (inst == NULL)) { + xsltGenericError(xsltGenericErrorContext, + "xsltForEach(): Bad arguments.\n"); + return; + } + + if (comp == NULL) { + xsltTransformError(ctxt, NULL, inst, + "Internal error in xsltForEach(): " + "The XSLT 'for-each' instruction was not compiled.\n"); + return; + } + if ((comp->select == NULL) || (comp->comp == NULL)) { + xsltTransformError(ctxt, NULL, inst, + "Internal error in xsltForEach(): " + "The selecting expression of the XSLT 'for-each' " + "instruction was not compiled correctly.\n"); + return; + } + xpctxt = ctxt->xpathCtxt; + +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext, + "xsltForEach: select %s\n", comp->select)); +#endif + + /* + * Save context states. + */ + oldDocInfo = ctxt->document; + oldList = ctxt->nodeList; + oldContextNode = ctxt->node; + /* + * The "current template rule" is cleared for the instantiation of + * xsl:for-each. + */ + oldCurTemplRule = ctxt->currentTemplateRule; + ctxt->currentTemplateRule = NULL; + + oldXPDoc = xpctxt->doc; + oldXPProximityPosition = xpctxt->proximityPosition; + oldXPContextSize = xpctxt->contextSize; + + /* + * Evaluate the 'select' expression. + */ + res = xsltPreCompEval(ctxt, contextNode, comp); + + if (res != NULL) { + if (res->type == XPATH_NODESET) + list = res->nodesetval; + else { + xsltTransformError(ctxt, NULL, inst, + "The 'select' expression does not evaluate to a node set.\n"); + +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext, + "xsltForEach: select didn't evaluate to a node list\n")); +#endif + goto error; + } + } else { + xsltTransformError(ctxt, NULL, inst, + "Failed to evaluate the 'select' expression.\n"); + ctxt->state = XSLT_STATE_STOPPED; + goto error; + } + + if ((list == NULL) || (list->nodeNr <= 0)) + goto exit; + +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_FOR_EACH,xsltGenericDebug(xsltGenericDebugContext, + "xsltForEach: select evaluates to %d nodes\n", list->nodeNr)); +#endif + + /* + * Set the list; this has to be done already here for xsltDoSortFunction(). + */ + ctxt->nodeList = list; + /* + * Handle xsl:sort instructions and skip them for further processing. + * BUG TODO: We are not using namespaced potentially defined on the + * xsl:sort element; XPath expression might fail. + */ + curInst = inst->children; + if (IS_XSLT_ELEM(curInst) && IS_XSLT_NAME(curInst, "sort")) { + int nbsorts = 0; + xmlNodePtr sorts[XSLT_MAX_SORT]; + + sorts[nbsorts++] = curInst; + +#ifdef WITH_DEBUGGER + if (xslDebugStatus != XSLT_DEBUG_NONE) + xslHandleDebugger(curInst, contextNode, NULL, ctxt); +#endif + + curInst = curInst->next; + while (IS_XSLT_ELEM(curInst) && IS_XSLT_NAME(curInst, "sort")) { + if (nbsorts >= XSLT_MAX_SORT) { + xsltTransformError(ctxt, NULL, curInst, + "The number of xsl:sort instructions exceeds the " + "maximum (%d) allowed by this processor.\n", + XSLT_MAX_SORT); + goto error; + } else { + sorts[nbsorts++] = curInst; + } + +#ifdef WITH_DEBUGGER + if (xslDebugStatus != XSLT_DEBUG_NONE) + xslHandleDebugger(curInst, contextNode, NULL, ctxt); +#endif + curInst = curInst->next; + } + xsltDoSortFunction(ctxt, sorts, nbsorts); + } + xpctxt->contextSize = list->nodeNr; + /* + * Instantiate the sequence constructor for each selected node. + */ + for (i = 0; i < list->nodeNr; i++) { + cur = list->nodeTab[i]; + /* + * The selected node becomes the "current node". + */ + ctxt->node = cur; + /* + * An xsl:for-each can change the current context doc. + * OPTIMIZE TODO: Get rid of the need to set the context doc. + */ + if ((cur->type != XML_NAMESPACE_DECL) && (cur->doc != NULL)) + xpctxt->doc = cur->doc; + + xpctxt->proximityPosition = i + 1; + + xsltApplySequenceConstructor(ctxt, cur, curInst, NULL); + } + +exit: +error: + if (res != NULL) + xmlXPathFreeObject(res); + /* + * Restore old states. + */ + ctxt->document = oldDocInfo; + ctxt->nodeList = oldList; + ctxt->node = oldContextNode; + ctxt->currentTemplateRule = oldCurTemplRule; + + xpctxt->doc = oldXPDoc; + xpctxt->contextSize = oldXPContextSize; + xpctxt->proximityPosition = oldXPProximityPosition; +} + +/************************************************************************ + * * + * Generic interface * + * * + ************************************************************************/ + +#ifdef XSLT_GENERATE_HTML_DOCTYPE +typedef struct xsltHTMLVersion { + const char *version; + const char *public; + const char *system; +} xsltHTMLVersion; + +static xsltHTMLVersion xsltHTMLVersions[] = { + { "5", NULL, "about:legacy-compat" }, + { "4.01frame", "-//W3C//DTD HTML 4.01 Frameset//EN", + "http://www.w3.org/TR/1999/REC-html401-19991224/frameset.dtd"}, + { "4.01strict", "-//W3C//DTD HTML 4.01//EN", + "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd"}, + { "4.01trans", "-//W3C//DTD HTML 4.01 Transitional//EN", + "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"}, + { "4.01", "-//W3C//DTD HTML 4.01 Transitional//EN", + "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"}, + { "4.0strict", "-//W3C//DTD HTML 4.01//EN", + "http://www.w3.org/TR/html4/strict.dtd"}, + { "4.0trans", "-//W3C//DTD HTML 4.01 Transitional//EN", + "http://www.w3.org/TR/html4/loose.dtd"}, + { "4.0frame", "-//W3C//DTD HTML 4.01 Frameset//EN", + "http://www.w3.org/TR/html4/frameset.dtd"}, + { "4.0", "-//W3C//DTD HTML 4.01 Transitional//EN", + "http://www.w3.org/TR/html4/loose.dtd"}, + { "3.2", "-//W3C//DTD HTML 3.2//EN", NULL } +}; + +/** + * xsltGetHTMLIDs: + * @version: the version string + * @publicID: used to return the public ID + * @systemID: used to return the system ID + * + * Returns -1 if not found, 0 otherwise and the system and public + * Identifier for this given verion of HTML + */ +static int +xsltGetHTMLIDs(const xmlChar *version, const xmlChar **publicID, + const xmlChar **systemID) { + unsigned int i; + if (version == NULL) + return(-1); + for (i = 0;i < (sizeof(xsltHTMLVersions)/sizeof(xsltHTMLVersions[1])); + i++) { + if (!xmlStrcasecmp(version, + (const xmlChar *) xsltHTMLVersions[i].version)) { + if (publicID != NULL) + *publicID = (const xmlChar *) xsltHTMLVersions[i].public; + if (systemID != NULL) + *systemID = (const xmlChar *) xsltHTMLVersions[i].system; + return(0); + } + } + return(-1); +} +#endif + +/** + * xsltApplyStripSpaces: + * @ctxt: a XSLT process context + * @node: the root of the XML tree + * + * Strip the unwanted ignorable spaces from the input tree + */ +void +xsltApplyStripSpaces(xsltTransformContextPtr ctxt, xmlNodePtr node) { + xmlNodePtr current; +#ifdef WITH_XSLT_DEBUG_PROCESS + int nb = 0; +#endif + + + current = node; + while (current != NULL) { + /* + * Cleanup children empty nodes if asked for + */ + if ((IS_XSLT_REAL_NODE(current)) && + (current->children != NULL) && + (xsltFindElemSpaceHandling(ctxt, current))) { + xmlNodePtr delete = NULL, cur = current->children; + + while (cur != NULL) { + if (IS_BLANK_NODE(cur)) + delete = cur; + + cur = cur->next; + if (delete != NULL) { + xmlUnlinkNode(delete); + xmlFreeNode(delete); + delete = NULL; +#ifdef WITH_XSLT_DEBUG_PROCESS + nb++; +#endif + } + } + } + + /* + * Skip to next node in document order. + */ + if (node->type == XML_ENTITY_REF_NODE) { + /* process deep in entities */ + xsltApplyStripSpaces(ctxt, node->children); + } + if ((current->children != NULL) && + (current->type != XML_ENTITY_REF_NODE)) { + current = current->children; + } else if (current->next != NULL) { + current = current->next; + } else { + do { + current = current->parent; + if (current == NULL) + break; + if (current == node) + goto done; + if (current->next != NULL) { + current = current->next; + break; + } + } while (current != NULL); + } + } + +done: +#ifdef WITH_XSLT_DEBUG_PROCESS + XSLT_TRACE(ctxt,XSLT_TRACE_STRIP_SPACES,xsltGenericDebug(xsltGenericDebugContext, + "xsltApplyStripSpaces: removed %d ignorable blank node\n", nb)); +#endif + return; +} + +static int +xsltCountKeys(xsltTransformContextPtr ctxt) +{ + xsltStylesheetPtr style; + xsltKeyDefPtr keyd; + + if (ctxt == NULL) + return(-1); + + /* + * Do we have those nastly templates with a key() in the match pattern? + */ + ctxt->hasTemplKeyPatterns = 0; + style = ctxt->style; + while (style != NULL) { + if (style->keyMatch != NULL) { + ctxt->hasTemplKeyPatterns = 1; + break; + } + style = xsltNextImport(style); + } + /* + * Count number of key declarations. + */ + ctxt->nbKeys = 0; + style = ctxt->style; + while (style != NULL) { + keyd = style->keys; + while (keyd) { + ctxt->nbKeys++; + keyd = keyd->next; + } + style = xsltNextImport(style); + } + return(ctxt->nbKeys); +} + +/** + * xsltCleanupSourceDoc: + * @doc: Document + * + * Resets source node flags and ids stored in 'psvi' member. + */ +void +xsltCleanupSourceDoc(xmlDocPtr doc) { + xmlNodePtr cur = (xmlNodePtr) doc; + void **psviPtr; + + while (1) { + xsltClearSourceNodeFlags(cur, XSLT_SOURCE_NODE_MASK); + psviPtr = xsltGetPSVIPtr(cur); + if (psviPtr) + *psviPtr = NULL; + + if (cur->type == XML_ELEMENT_NODE) { + xmlAttrPtr prop = cur->properties; + + while (prop) { + prop->atype &= ~(XSLT_SOURCE_NODE_MASK << 27); + prop->psvi = NULL; + prop = prop->next; + } + } + + if (cur->children != NULL && cur->type != XML_ENTITY_REF_NODE) { + cur = cur->children; + } else { + if (cur == (xmlNodePtr) doc) + return; + while (cur->next == NULL) { + cur = cur->parent; + if (cur == (xmlNodePtr) doc) + return; + } + + cur = cur->next; + } + } +} + +/** + * xsltApplyStylesheetInternal: + * @style: a parsed XSLT stylesheet + * @doc: a parsed XML document + * @params: a NULL terminated array of parameters names/values tuples + * @output: the targetted output + * @profile: profile FILE * output or NULL + * @user: user provided parameter + * + * Apply the stylesheet to the document + * NOTE: This may lead to a non-wellformed output XML wise ! + * + * Returns the result document or NULL in case of error + */ +static xmlDocPtr +xsltApplyStylesheetInternal(xsltStylesheetPtr style, xmlDocPtr doc, + const char **params, const char *output, + FILE * profile, xsltTransformContextPtr userCtxt) +{ + xmlDocPtr res = NULL; + xsltTransformContextPtr ctxt = NULL; + xmlNodePtr root, node; + const xmlChar *method; + const xmlChar *doctypePublic; + const xmlChar *doctypeSystem; + const xmlChar *version; + const xmlChar *encoding; + xsltStackElemPtr variables; + xsltStackElemPtr vptr; + + xsltInitGlobals(); + + if ((style == NULL) || (doc == NULL)) + return (NULL); + + if (style->internalized == 0) { +#ifdef WITH_XSLT_DEBUG + xsltGenericDebug(xsltGenericDebugContext, + "Stylesheet was not fully internalized !\n"); +#endif + } + if (doc->intSubset != NULL) { + /* + * Avoid hitting the DTD when scanning nodes + * but keep it linked as doc->intSubset + */ + xmlNodePtr cur = (xmlNodePtr) doc->intSubset; + if (cur->next != NULL) + cur->next->prev = cur->prev; + if (cur->prev != NULL) + cur->prev->next = cur->next; + if (doc->children == cur) + doc->children = cur->next; + if (doc->last == cur) + doc->last = cur->prev; + cur->prev = cur->next = NULL; + } + + /* + * Check for XPath document order availability + */ + root = xmlDocGetRootElement(doc); + if (root != NULL) { + if (((ptrdiff_t) root->content >= 0) && + (xslDebugStatus == XSLT_DEBUG_NONE)) + xmlXPathOrderDocElems(doc); + } + + if (userCtxt != NULL) + ctxt = userCtxt; + else + ctxt = xsltNewTransformContext(style, doc); + + if (ctxt == NULL) + return (NULL); + + ctxt->initialContextDoc = doc; + ctxt->initialContextNode = (xmlNodePtr) doc; + + if (profile != NULL) { +#ifdef WITH_PROFILER + ctxt->profile = 1; +#else + xsltTransformError(ctxt, NULL, (xmlNodePtr) doc, + "xsltApplyStylesheetInternal: " + "libxslt compiled without profiler\n"); + goto error; +#endif + } + + if (output != NULL) + ctxt->outputFile = output; + else + ctxt->outputFile = NULL; + + /* + * internalize the modes if needed + */ + if (ctxt->dict != NULL) { + if (ctxt->mode != NULL) + ctxt->mode = xmlDictLookup(ctxt->dict, ctxt->mode, -1); + if (ctxt->modeURI != NULL) + ctxt->modeURI = xmlDictLookup(ctxt->dict, ctxt->modeURI, -1); + } + + XSLT_GET_IMPORT_PTR(method, style, method) + XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic) + XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem) + XSLT_GET_IMPORT_PTR(version, style, version) + XSLT_GET_IMPORT_PTR(encoding, style, encoding) + + if ((method != NULL) && + (!xmlStrEqual(method, (const xmlChar *) "xml"))) + { + if (xmlStrEqual(method, (const xmlChar *) "html")) { + ctxt->type = XSLT_OUTPUT_HTML; + if (((doctypePublic != NULL) || (doctypeSystem != NULL))) { + res = htmlNewDoc(doctypeSystem, doctypePublic); + } else { + if (version == NULL) { + xmlDtdPtr dtd; + + res = htmlNewDoc(NULL, NULL); + /* + * Make sure no DTD node is generated in this case + */ + if (res != NULL) { + dtd = xmlGetIntSubset(res); + if (dtd != NULL) { + xmlUnlinkNode((xmlNodePtr) dtd); + xmlFreeDtd(dtd); + } + res->intSubset = NULL; + res->extSubset = NULL; + } + } else { + +#ifdef XSLT_GENERATE_HTML_DOCTYPE + xsltGetHTMLIDs(version, &doctypePublic, &doctypeSystem); +#endif + res = htmlNewDoc(doctypeSystem, doctypePublic); + } + } + if (res == NULL) + goto error; + res->dict = ctxt->dict; + xmlDictReference(res->dict); + +#ifdef WITH_XSLT_DEBUG + xsltGenericDebug(xsltGenericDebugContext, + "reusing transformation dict for output\n"); +#endif + } else if (xmlStrEqual(method, (const xmlChar *) "xhtml")) { + xsltTransformError(ctxt, NULL, (xmlNodePtr) doc, + "xsltApplyStylesheetInternal: unsupported method xhtml, using html\n"); + ctxt->type = XSLT_OUTPUT_HTML; + res = htmlNewDoc(doctypeSystem, doctypePublic); + if (res == NULL) + goto error; + res->dict = ctxt->dict; + xmlDictReference(res->dict); + +#ifdef WITH_XSLT_DEBUG + xsltGenericDebug(xsltGenericDebugContext, + "reusing transformation dict for output\n"); +#endif + } else if (xmlStrEqual(method, (const xmlChar *) "text")) { + ctxt->type = XSLT_OUTPUT_TEXT; + res = xmlNewDoc(style->version); + if (res == NULL) + goto error; + res->dict = ctxt->dict; + xmlDictReference(res->dict); + +#ifdef WITH_XSLT_DEBUG + xsltGenericDebug(xsltGenericDebugContext, + "reusing transformation dict for output\n"); +#endif + } else { + xsltTransformError(ctxt, NULL, (xmlNodePtr) doc, + "xsltApplyStylesheetInternal: unsupported method (%s)\n", + method); + goto error; + } + } else { + ctxt->type = XSLT_OUTPUT_XML; + res = xmlNewDoc(style->version); + if (res == NULL) + goto error; + res->dict = ctxt->dict; + xmlDictReference(ctxt->dict); +#ifdef WITH_XSLT_DEBUG + xsltGenericDebug(xsltGenericDebugContext, + "reusing transformation dict for output\n"); +#endif + } + res->charset = XML_CHAR_ENCODING_UTF8; + if (encoding != NULL) + res->encoding = xmlStrdup(encoding); + variables = style->variables; + + ctxt->node = (xmlNodePtr) doc; + ctxt->output = res; + + ctxt->xpathCtxt->contextSize = 1; + ctxt->xpathCtxt->proximityPosition = 1; + ctxt->xpathCtxt->node = NULL; /* TODO: Set the context node here? */ + + /* + * Start the evaluation, evaluate the params, the stylesheets globals + * and start by processing the top node. + */ + if (xsltNeedElemSpaceHandling(ctxt)) + xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc)); + /* + * Evaluate global params and user-provided params. + */ + if (ctxt->globalVars == NULL) + ctxt->globalVars = xmlHashCreate(20); + if (params != NULL) { + xsltEvalUserParams(ctxt, params); + } + + /* need to be called before evaluating global variables */ + xsltCountKeys(ctxt); + + xsltEvalGlobalVariables(ctxt); + + /* Clean up any unused RVTs. */ + xsltReleaseLocalRVTs(ctxt, NULL); + + ctxt->insert = (xmlNodePtr) res; + ctxt->varsBase = ctxt->varsNr - 1; + + /* + * Start processing the source tree ----------------------------------- + */ + xsltProcessOneNode(ctxt, ctxt->node, NULL); + /* + * Remove all remaining vars from the stack. + */ + xsltLocalVariablePop(ctxt, 0, -2); + xsltShutdownCtxtExts(ctxt); + + xsltCleanupTemplates(style); /* TODO: <- style should be read only */ + + /* + * Now cleanup our variables so stylesheet can be re-used + * + * TODO: this is not needed anymore global variables are copied + * and not evaluated directly anymore, keep this as a check + */ + if (style->variables != variables) { + vptr = style->variables; + while (vptr->next != variables) + vptr = vptr->next; + vptr->next = NULL; + xsltFreeStackElemList(style->variables); + style->variables = variables; + } + vptr = style->variables; + while (vptr != NULL) { + if (vptr->computed) { + if (vptr->value != NULL) { + xmlXPathFreeObject(vptr->value); + vptr->value = NULL; + vptr->computed = 0; + } + } + vptr = vptr->next; + } +#if 0 + /* + * code disabled by wmb; awaiting kb's review + * problem is that global variable(s) may contain xpath objects + * from doc associated with RVT, so can't be freed at this point. + * xsltFreeTransformContext includes a call to xsltFreeRVTs, so + * I assume this shouldn't be required at this point. + */ + /* + * Free all remaining tree fragments. + */ + xsltFreeRVTs(ctxt); +#endif + /* + * Do some post processing work depending on the generated output + */ + root = xmlDocGetRootElement(res); + if (root != NULL) { + const xmlChar *doctype = NULL; + + if ((root->ns != NULL) && (root->ns->prefix != NULL)) + doctype = xmlDictQLookup(ctxt->dict, root->ns->prefix, root->name); + if (doctype == NULL) + doctype = root->name; + + /* + * Apply the default selection of the method + */ + if ((method == NULL) && + (root->ns == NULL) && + (!xmlStrcasecmp(root->name, (const xmlChar *) "html"))) { + xmlNodePtr tmp; + + tmp = res->children; + while ((tmp != NULL) && (tmp != root)) { + if (tmp->type == XML_ELEMENT_NODE) + break; + if ((tmp->type == XML_TEXT_NODE) && (!xmlIsBlankNode(tmp))) + break; + tmp = tmp->next; + } + if (tmp == root) { + ctxt->type = XSLT_OUTPUT_HTML; + /* + * REVISIT TODO: XML_HTML_DOCUMENT_NODE is set after the + * transformation on the doc, but functions like + */ + res->type = XML_HTML_DOCUMENT_NODE; + if (((doctypePublic != NULL) || (doctypeSystem != NULL))) { + res->intSubset = xmlCreateIntSubset(res, doctype, + doctypePublic, + doctypeSystem); +#ifdef XSLT_GENERATE_HTML_DOCTYPE + } else if (version != NULL) { + xsltGetHTMLIDs(version, &doctypePublic, + &doctypeSystem); + if (((doctypePublic != NULL) || (doctypeSystem != NULL))) + res->intSubset = + xmlCreateIntSubset(res, doctype, + doctypePublic, + doctypeSystem); +#endif + } + } + + } + if (ctxt->type == XSLT_OUTPUT_XML) { + XSLT_GET_IMPORT_PTR(doctypePublic, style, doctypePublic) + XSLT_GET_IMPORT_PTR(doctypeSystem, style, doctypeSystem) + if (((doctypePublic != NULL) || (doctypeSystem != NULL))) { + xmlNodePtr last; + /* Need a small "hack" here to assure DTD comes before + possible comment nodes */ + node = res->children; + last = res->last; + res->children = NULL; + res->last = NULL; + res->intSubset = xmlCreateIntSubset(res, doctype, + doctypePublic, + doctypeSystem); + if (res->children != NULL) { + res->children->next = node; + node->prev = res->children; + res->last = last; + } else { + res->children = node; + res->last = last; + } + } + } + } + xmlXPathFreeNodeSet(ctxt->nodeList); + +#ifdef WITH_PROFILER + if (profile != NULL) { + xsltSaveProfiling(ctxt, profile); + } +#endif + + /* + * Be pedantic. + */ + if ((ctxt != NULL) && (ctxt->state != XSLT_STATE_OK)) { + xmlFreeDoc(res); + res = NULL; + } + if ((res != NULL) && (ctxt != NULL) && (output != NULL)) { + int ret; + + ret = xsltCheckWrite(ctxt->sec, ctxt, (const xmlChar *) output); + if (ret == 0) { + xsltTransformError(ctxt, NULL, NULL, + "xsltApplyStylesheet: forbidden to save to %s\n", + output); + } else if (ret < 0) { + xsltTransformError(ctxt, NULL, NULL, + "xsltApplyStylesheet: saving to %s may not be possible\n", + output); + } + } + +#ifdef XSLT_DEBUG_PROFILE_CACHE + printf("# Cache:\n"); + printf("# Reused tree fragments: %d\n", ctxt->cache->dbgReusedRVTs); + printf("# Reused variables : %d\n", ctxt->cache->dbgReusedVars); +#endif + + if (ctxt->sourceDocDirty) + xsltCleanupSourceDoc(doc); + + if ((ctxt != NULL) && (userCtxt == NULL)) + xsltFreeTransformContext(ctxt); + + return (res); + +error: + if (res != NULL) + xmlFreeDoc(res); + +#ifdef XSLT_DEBUG_PROFILE_CACHE + printf("# Cache:\n"); + printf("# Reused tree fragments: %d\n", ctxt->cache->dbgReusedRVTs); + printf("# Reused variables : %d\n", ctxt->cache->dbgReusedVars); +#endif + + if ((ctxt != NULL) && (userCtxt == NULL)) + xsltFreeTransformContext(ctxt); + return (NULL); +} + +/** + * xsltApplyStylesheet: + * @style: a parsed XSLT stylesheet + * @doc: a parsed XML document + * @params: a NULL terminated arry of parameters names/values tuples + * + * Apply the stylesheet to the document + * NOTE: This may lead to a non-wellformed output XML wise ! + * + * Returns the result document or NULL in case of error + */ +xmlDocPtr +xsltApplyStylesheet(xsltStylesheetPtr style, xmlDocPtr doc, + const char **params) +{ + return (xsltApplyStylesheetInternal(style, doc, params, NULL, NULL, NULL)); +} + +/** + * xsltProfileStylesheet: + * @style: a parsed XSLT stylesheet + * @doc: a parsed XML document + * @params: a NULL terminated arry of parameters names/values tuples + * @output: a FILE * for the profiling output + * + * Apply the stylesheet to the document and dump the profiling to + * the given output. + * + * Returns the result document or NULL in case of error + */ +xmlDocPtr +xsltProfileStylesheet(xsltStylesheetPtr style, xmlDocPtr doc, + const char **params, FILE * output) +{ + xmlDocPtr res; + + res = xsltApplyStylesheetInternal(style, doc, params, NULL, output, NULL); + return (res); +} + +/** + * xsltApplyStylesheetUser: + * @style: a parsed XSLT stylesheet + * @doc: a parsed XML document + * @params: a NULL terminated array of parameters names/values tuples + * @output: the targetted output + * @profile: profile FILE * output or NULL + * @userCtxt: user provided transform context + * + * Apply the stylesheet to the document and allow the user to provide + * its own transformation context. + * + * Returns the result document or NULL in case of error + */ +xmlDocPtr +xsltApplyStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc, + const char **params, const char *output, + FILE * profile, xsltTransformContextPtr userCtxt) +{ + xmlDocPtr res; + + res = xsltApplyStylesheetInternal(style, doc, params, output, + profile, userCtxt); + return (res); +} + +/** + * xsltRunStylesheetUser: + * @style: a parsed XSLT stylesheet + * @doc: a parsed XML document + * @params: a NULL terminated array of parameters names/values tuples + * @output: the URL/filename ot the generated resource if available + * @SAX: a SAX handler for progressive callback output (not implemented yet) + * @IObuf: an output buffer for progressive output (not implemented yet) + * @profile: profile FILE * output or NULL + * @userCtxt: user provided transform context + * + * Apply the stylesheet to the document and generate the output according + * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf. + * + * NOTE: This may lead to a non-wellformed output XML wise ! + * NOTE: This may also result in multiple files being generated + * NOTE: using IObuf, the result encoding used will be the one used for + * creating the output buffer, use the following macro to read it + * from the stylesheet + * XSLT_GET_IMPORT_PTR(encoding, style, encoding) + * NOTE: using SAX, any encoding specified in the stylesheet will be lost + * since the interface uses only UTF8 + * + * Returns the number of by written to the main resource or -1 in case of + * error. + */ +int +xsltRunStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc, + const char **params, const char *output, + xmlSAXHandlerPtr SAX, xmlOutputBufferPtr IObuf, + FILE * profile, xsltTransformContextPtr userCtxt) +{ + xmlDocPtr tmp; + int ret; + + if ((output == NULL) && (SAX == NULL) && (IObuf == NULL)) + return (-1); + if ((SAX != NULL) && (IObuf != NULL)) + return (-1); + + /* unsupported yet */ + if (SAX != NULL) { + XSLT_TODO /* xsltRunStylesheet xmlSAXHandlerPtr SAX */ + return (-1); + } + + tmp = xsltApplyStylesheetInternal(style, doc, params, output, profile, + userCtxt); + if (tmp == NULL) { + xsltTransformError(NULL, NULL, (xmlNodePtr) doc, + "xsltRunStylesheet : run failed\n"); + return (-1); + } + if (IObuf != NULL) { + /* TODO: incomplete, IObuf output not progressive */ + ret = xsltSaveResultTo(IObuf, tmp, style); + } else { + ret = xsltSaveResultToFilename(output, tmp, style, 0); + } + xmlFreeDoc(tmp); + return (ret); +} + +/** + * xsltRunStylesheet: + * @style: a parsed XSLT stylesheet + * @doc: a parsed XML document + * @params: a NULL terminated array of parameters names/values tuples + * @output: the URL/filename ot the generated resource if available + * @SAX: a SAX handler for progressive callback output (not implemented yet) + * @IObuf: an output buffer for progressive output (not implemented yet) + * + * Apply the stylesheet to the document and generate the output according + * to @output @SAX and @IObuf. It's an error to specify both @SAX and @IObuf. + * + * NOTE: This may lead to a non-wellformed output XML wise ! + * NOTE: This may also result in multiple files being generated + * NOTE: using IObuf, the result encoding used will be the one used for + * creating the output buffer, use the following macro to read it + * from the stylesheet + * XSLT_GET_IMPORT_PTR(encoding, style, encoding) + * NOTE: using SAX, any encoding specified in the stylesheet will be lost + * since the interface uses only UTF8 + * + * Returns the number of bytes written to the main resource or -1 in case of + * error. + */ +int +xsltRunStylesheet(xsltStylesheetPtr style, xmlDocPtr doc, + const char **params, const char *output, + xmlSAXHandlerPtr SAX, xmlOutputBufferPtr IObuf) +{ + return(xsltRunStylesheetUser(style, doc, params, output, SAX, IObuf, + NULL, NULL)); +} + +static void +xsltMessageWrapper(xsltTransformContextPtr ctxt, xmlNodePtr node, + xmlNodePtr inst, xsltElemPreCompPtr comp ATTRIBUTE_UNUSED) { + xsltMessage(ctxt, node, inst); +} + +/** + * xsltRegisterAllElement: + * @ctxt: the XPath context + * + * Registers all default XSLT elements in this context + */ +void +xsltRegisterAllElement(xsltTransformContextPtr ctxt) +{ + xsltRegisterExtElement(ctxt, (const xmlChar *) "apply-templates", + XSLT_NAMESPACE, + xsltApplyTemplates); + xsltRegisterExtElement(ctxt, (const xmlChar *) "apply-imports", + XSLT_NAMESPACE, + xsltApplyImports); + xsltRegisterExtElement(ctxt, (const xmlChar *) "call-template", + XSLT_NAMESPACE, + xsltCallTemplate); + xsltRegisterExtElement(ctxt, (const xmlChar *) "element", + XSLT_NAMESPACE, + xsltElement); + xsltRegisterExtElement(ctxt, (const xmlChar *) "attribute", + XSLT_NAMESPACE, + xsltAttribute); + xsltRegisterExtElement(ctxt, (const xmlChar *) "text", + XSLT_NAMESPACE, + xsltText); + xsltRegisterExtElement(ctxt, (const xmlChar *) "processing-instruction", + XSLT_NAMESPACE, + xsltProcessingInstruction); + xsltRegisterExtElement(ctxt, (const xmlChar *) "comment", + XSLT_NAMESPACE, + xsltComment); + xsltRegisterExtElement(ctxt, (const xmlChar *) "copy", + XSLT_NAMESPACE, + xsltCopy); + xsltRegisterExtElement(ctxt, (const xmlChar *) "value-of", + XSLT_NAMESPACE, + xsltValueOf); + xsltRegisterExtElement(ctxt, (const xmlChar *) "number", + XSLT_NAMESPACE, + xsltNumber); + xsltRegisterExtElement(ctxt, (const xmlChar *) "for-each", + XSLT_NAMESPACE, + xsltForEach); + xsltRegisterExtElement(ctxt, (const xmlChar *) "if", + XSLT_NAMESPACE, + xsltIf); + xsltRegisterExtElement(ctxt, (const xmlChar *) "choose", + XSLT_NAMESPACE, + xsltChoose); + xsltRegisterExtElement(ctxt, (const xmlChar *) "sort", + XSLT_NAMESPACE, + xsltSort); + xsltRegisterExtElement(ctxt, (const xmlChar *) "copy-of", + XSLT_NAMESPACE, + xsltCopyOf); + xsltRegisterExtElement(ctxt, (const xmlChar *) "message", + XSLT_NAMESPACE, + xsltMessageWrapper); + + /* + * Those don't have callable entry points but are registered anyway + */ + xsltRegisterExtElement(ctxt, (const xmlChar *) "variable", + XSLT_NAMESPACE, + xsltDebug); + xsltRegisterExtElement(ctxt, (const xmlChar *) "param", + XSLT_NAMESPACE, + xsltDebug); + xsltRegisterExtElement(ctxt, (const xmlChar *) "with-param", + XSLT_NAMESPACE, + xsltDebug); + xsltRegisterExtElement(ctxt, (const xmlChar *) "decimal-format", + XSLT_NAMESPACE, + xsltDebug); + xsltRegisterExtElement(ctxt, (const xmlChar *) "when", + XSLT_NAMESPACE, + xsltDebug); + xsltRegisterExtElement(ctxt, (const xmlChar *) "otherwise", + XSLT_NAMESPACE, + xsltDebug); + xsltRegisterExtElement(ctxt, (const xmlChar *) "fallback", + XSLT_NAMESPACE, + xsltDebug); + +} diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/transform.h chromium-145.0.7632.159/third_party/libxslt/src/libxslt/transform.h --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/transform.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/transform.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,207 @@ +/* + * Summary: the XSLT engine transformation part. + * Description: This module implements the bulk of the actual + * transformation processing. Most of the xsl: element + * constructs are implemented in this module. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLT_TRANSFORM_H__ +#define __XML_XSLT_TRANSFORM_H__ + +#include +#include +#include "xsltexports.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * XInclude default processing. + */ +XSLTPUBFUN void XSLTCALL + xsltSetXIncludeDefault (int xinclude); +XSLTPUBFUN int XSLTCALL + xsltGetXIncludeDefault (void); + +/** + * Export context to users. + */ +XSLTPUBFUN xsltTransformContextPtr XSLTCALL + xsltNewTransformContext (xsltStylesheetPtr style, + xmlDocPtr doc); + +XSLTPUBFUN void XSLTCALL + xsltFreeTransformContext(xsltTransformContextPtr ctxt); + +XSLTPUBFUN xmlDocPtr XSLTCALL + xsltApplyStylesheetUser (xsltStylesheetPtr style, + xmlDocPtr doc, + const char **params, + const char *output, + FILE * profile, + xsltTransformContextPtr userCtxt); +XSLTPUBFUN void XSLTCALL + xsltProcessOneNode (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xsltStackElemPtr params); +/** + * Private Interfaces. + */ +XSLTPUBFUN void XSLTCALL + xsltApplyStripSpaces (xsltTransformContextPtr ctxt, + xmlNodePtr node); +XSLTPUBFUN xmlDocPtr XSLTCALL + xsltApplyStylesheet (xsltStylesheetPtr style, + xmlDocPtr doc, + const char **params); +XSLTPUBFUN xmlDocPtr XSLTCALL + xsltProfileStylesheet (xsltStylesheetPtr style, + xmlDocPtr doc, + const char **params, + FILE * output); +XSLTPUBFUN int XSLTCALL + xsltRunStylesheet (xsltStylesheetPtr style, + xmlDocPtr doc, + const char **params, + const char *output, + xmlSAXHandlerPtr SAX, + xmlOutputBufferPtr IObuf); +XSLTPUBFUN int XSLTCALL + xsltRunStylesheetUser (xsltStylesheetPtr style, + xmlDocPtr doc, + const char **params, + const char *output, + xmlSAXHandlerPtr SAX, + xmlOutputBufferPtr IObuf, + FILE * profile, + xsltTransformContextPtr userCtxt); +XSLTPUBFUN void XSLTCALL + xsltApplyOneTemplate (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr list, + xsltTemplatePtr templ, + xsltStackElemPtr params); +XSLTPUBFUN void XSLTCALL + xsltDocumentElem (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltSort (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltCopy (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltText (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltElement (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltComment (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltAttribute (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltProcessingInstruction(xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltCopyOf (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltValueOf (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltNumber (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltApplyImports (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltCallTemplate (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltApplyTemplates (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltChoose (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltIf (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltForEach (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); +XSLTPUBFUN void XSLTCALL + xsltRegisterAllElement (xsltTransformContextPtr ctxt); + +XSLTPUBFUN xmlNodePtr XSLTCALL + xsltCopyTextString (xsltTransformContextPtr ctxt, + xmlNodePtr target, + const xmlChar *string, + int noescape); + +/* Following 2 functions needed for libexslt/functions.c */ +XSLTPUBFUN void XSLTCALL + xsltLocalVariablePop (xsltTransformContextPtr ctxt, + int limitNr, + int level); +XSLTPUBFUN int XSLTCALL + xsltLocalVariablePush (xsltTransformContextPtr ctxt, + xsltStackElemPtr variable, + int level); +/* + * Hook for the debugger if activated. + */ +XSLTPUBFUN void XSLTCALL + xslHandleDebugger (xmlNodePtr cur, + xmlNodePtr node, + xsltTemplatePtr templ, + xsltTransformContextPtr ctxt); + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_TRANSFORM_H__ */ + diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/transformInternals.h chromium-145.0.7632.159/third_party/libxslt/src/libxslt/transformInternals.h --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/transformInternals.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/transformInternals.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,9 @@ +/* + * Summary: set of internal interfaces for the XSLT engine transformation part. + * + * Copy: See Copyright for the status of this software. + * + * Author: David Kilzer + */ + +void xsltCleanupSourceDoc(xmlDocPtr doc); diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/trio.h chromium-145.0.7632.159/third_party/libxslt/src/libxslt/trio.h --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/trio.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/trio.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,216 @@ +/************************************************************************* + * + * $Id$ + * + * Copyright (C) 1998 Bjorn Reese and Daniel Stenberg. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND + * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. + * + ************************************************************************* + * + * http://ctrio.sourceforge.net/ + * + ************************************************************************/ + +#ifndef TRIO_TRIO_H +#define TRIO_TRIO_H + +#if !defined(WITHOUT_TRIO) + +/* + * Use autoconf defines if present. Packages using trio must define + * HAVE_CONFIG_H as a compiler option themselves. + */ +#if defined(HAVE_CONFIG_H) +# include +#endif + +#include "triodef.h" + +#include +#include +#if defined(TRIO_COMPILER_ANCIENT) +# include +#else +# include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Error codes. + * + * Remember to add a textual description to trio_strerror. + */ +enum { + TRIO_EOF = 1, + TRIO_EINVAL = 2, + TRIO_ETOOMANY = 3, + TRIO_EDBLREF = 4, + TRIO_EGAP = 5, + TRIO_ENOMEM = 6, + TRIO_ERANGE = 7, + TRIO_ERRNO = 8, + TRIO_ECUSTOM = 9 +}; + +/* Error macros */ +#define TRIO_ERROR_CODE(x) ((-(x)) & 0x00FF) +#define TRIO_ERROR_POSITION(x) ((-(x)) >> 8) +#define TRIO_ERROR_NAME(x) trio_strerror(x) + +typedef int (*trio_outstream_t) TRIO_PROTO((trio_pointer_t, int)); +typedef int (*trio_instream_t) TRIO_PROTO((trio_pointer_t)); + +TRIO_CONST char *trio_strerror TRIO_PROTO((int)); + +/************************************************************************* + * Print Functions + */ + +int trio_printf TRIO_PROTO((TRIO_CONST char *format, ...)); +int trio_vprintf TRIO_PROTO((TRIO_CONST char *format, va_list args)); +int trio_printfv TRIO_PROTO((TRIO_CONST char *format, void **args)); + +int trio_fprintf TRIO_PROTO((FILE *file, TRIO_CONST char *format, ...)); +int trio_vfprintf TRIO_PROTO((FILE *file, TRIO_CONST char *format, va_list args)); +int trio_fprintfv TRIO_PROTO((FILE *file, TRIO_CONST char *format, void **args)); + +int trio_dprintf TRIO_PROTO((int fd, TRIO_CONST char *format, ...)); +int trio_vdprintf TRIO_PROTO((int fd, TRIO_CONST char *format, va_list args)); +int trio_dprintfv TRIO_PROTO((int fd, TRIO_CONST char *format, void **args)); + +int trio_cprintf TRIO_PROTO((trio_outstream_t stream, trio_pointer_t closure, + TRIO_CONST char *format, ...)); +int trio_vcprintf TRIO_PROTO((trio_outstream_t stream, trio_pointer_t closure, + TRIO_CONST char *format, va_list args)); +int trio_cprintfv TRIO_PROTO((trio_outstream_t stream, trio_pointer_t closure, + TRIO_CONST char *format, void **args)); + +int trio_sprintf TRIO_PROTO((char *buffer, TRIO_CONST char *format, ...)); +int trio_vsprintf TRIO_PROTO((char *buffer, TRIO_CONST char *format, va_list args)); +int trio_sprintfv TRIO_PROTO((char *buffer, TRIO_CONST char *format, void **args)); + +int trio_snprintf TRIO_PROTO((char *buffer, size_t max, TRIO_CONST char *format, ...)); +int trio_vsnprintf TRIO_PROTO((char *buffer, size_t bufferSize, TRIO_CONST char *format, + va_list args)); +int trio_snprintfv TRIO_PROTO((char *buffer, size_t bufferSize, TRIO_CONST char *format, + void **args)); + +int trio_snprintfcat TRIO_PROTO((char *buffer, size_t max, TRIO_CONST char *format, ...)); +int trio_vsnprintfcat TRIO_PROTO((char *buffer, size_t bufferSize, TRIO_CONST char *format, + va_list args)); + +char *trio_aprintf TRIO_PROTO((TRIO_CONST char *format, ...)); +char *trio_vaprintf TRIO_PROTO((TRIO_CONST char *format, va_list args)); + +int trio_asprintf TRIO_PROTO((char **ret, TRIO_CONST char *format, ...)); +int trio_vasprintf TRIO_PROTO((char **ret, TRIO_CONST char *format, va_list args)); + +/************************************************************************* + * Scan Functions + */ +int trio_scanf TRIO_PROTO((TRIO_CONST char *format, ...)); +int trio_vscanf TRIO_PROTO((TRIO_CONST char *format, va_list args)); +int trio_scanfv TRIO_PROTO((TRIO_CONST char *format, void **args)); + +int trio_fscanf TRIO_PROTO((FILE *file, TRIO_CONST char *format, ...)); +int trio_vfscanf TRIO_PROTO((FILE *file, TRIO_CONST char *format, va_list args)); +int trio_fscanfv TRIO_PROTO((FILE *file, TRIO_CONST char *format, void **args)); + +int trio_dscanf TRIO_PROTO((int fd, TRIO_CONST char *format, ...)); +int trio_vdscanf TRIO_PROTO((int fd, TRIO_CONST char *format, va_list args)); +int trio_dscanfv TRIO_PROTO((int fd, TRIO_CONST char *format, void **args)); + +int trio_cscanf TRIO_PROTO((trio_instream_t stream, trio_pointer_t closure, + TRIO_CONST char *format, ...)); +int trio_vcscanf TRIO_PROTO((trio_instream_t stream, trio_pointer_t closure, + TRIO_CONST char *format, va_list args)); +int trio_cscanfv TRIO_PROTO((trio_instream_t stream, trio_pointer_t closure, + TRIO_CONST char *format, void **args)); + +int trio_sscanf TRIO_PROTO((TRIO_CONST char *buffer, TRIO_CONST char *format, ...)); +int trio_vsscanf TRIO_PROTO((TRIO_CONST char *buffer, TRIO_CONST char *format, va_list args)); +int trio_sscanfv TRIO_PROTO((TRIO_CONST char *buffer, TRIO_CONST char *format, void **args)); + +/************************************************************************* + * Locale Functions + */ +void trio_locale_set_decimal_point TRIO_PROTO((char *decimalPoint)); +void trio_locale_set_thousand_separator TRIO_PROTO((char *thousandSeparator)); +void trio_locale_set_grouping TRIO_PROTO((char *grouping)); + +/************************************************************************* + * Renaming + */ +#ifdef TRIO_REPLACE_STDIO +/* Replace the functions */ +#ifndef HAVE_PRINTF +# define printf trio_printf +#endif +#ifndef HAVE_VPRINTF +# define vprintf trio_vprintf +#endif +#ifndef HAVE_FPRINTF +# define fprintf trio_fprintf +#endif +#ifndef HAVE_VFPRINTF +# define vfprintf trio_vfprintf +#endif +#ifndef HAVE_SPRINTF +# define sprintf trio_sprintf +#endif +#ifndef HAVE_VSPRINTF +# define vsprintf trio_vsprintf +#endif +#ifndef HAVE_SNPRINTF +# define snprintf trio_snprintf +#endif +#ifndef HAVE_VSNPRINTF +# define vsnprintf trio_vsnprintf +#endif +#ifndef HAVE_SCANF +# define scanf trio_scanf +#endif +#ifndef HAVE_VSCANF +# define vscanf trio_vscanf +#endif +#ifndef HAVE_FSCANF +# define fscanf trio_fscanf +#endif +#ifndef HAVE_VFSCANF +# define vfscanf trio_vfscanf +#endif +#ifndef HAVE_SSCANF +# define sscanf trio_sscanf +#endif +#ifndef HAVE_VSSCANF +# define vsscanf trio_vsscanf +#endif +/* These aren't stdio functions, but we make them look similar */ +#define dprintf trio_dprintf +#define vdprintf trio_vdprintf +#define aprintf trio_aprintf +#define vaprintf trio_vaprintf +#define asprintf trio_asprintf +#define vasprintf trio_vasprintf +#define dscanf trio_dscanf +#define vdscanf trio_vdscanf +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* WITHOUT_TRIO */ + +#endif /* TRIO_TRIO_H */ diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/triodef.h chromium-145.0.7632.159/third_party/libxslt/src/libxslt/triodef.h --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/triodef.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/triodef.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,220 @@ +/************************************************************************* + * + * $Id$ + * + * Copyright (C) 2001 Bjorn Reese + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND + * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER. + * + ************************************************************************/ + +#ifndef TRIO_TRIODEF_H +#define TRIO_TRIODEF_H + +/************************************************************************* + * Platform and compiler support detection + */ +#if defined(__GNUC__) +# define TRIO_COMPILER_GCC +#elif defined(__SUNPRO_C) +# define TRIO_COMPILER_SUNPRO +#elif defined(__SUNPRO_CC) +# define TRIO_COMPILER_SUNPRO +# define __SUNPRO_C __SUNPRO_CC +#elif defined(__xlC__) || defined(__IBMC__) || defined(__IBMCPP__) +# define TRIO_COMPILER_XLC +#elif defined(_AIX) && !defined(__GNUC__) +# define TRIO_COMPILER_XLC /* Workaround for old xlc */ +#elif defined(__DECC) || defined(__DECCXX) +# define TRIO_COMPILER_DECC +#elif defined(__osf__) && defined(__LANGUAGE_C__) +# define TRIO_COMPILER_DECC /* Workaround for old DEC C compilers */ +#elif defined(_MSC_VER) +# define TRIO_COMPILER_MSVC +#elif defined(__BORLANDC__) +# define TRIO_COMPILER_BCB +#endif + +#if defined(VMS) || defined(__VMS) +/* + * VMS is placed first to avoid identifying the platform as Unix + * based on the DECC compiler later on. + */ +# define TRIO_PLATFORM_VMS +#elif defined(unix) || defined(__unix) || defined(__unix__) +# define TRIO_PLATFORM_UNIX +#elif defined(TRIO_COMPILER_XLC) || defined(_AIX) +# define TRIO_PLATFORM_UNIX +#elif defined(TRIO_COMPILER_DECC) || defined(__osf___) +# define TRIO_PLATFORM_UNIX +#elif defined(__NetBSD__) +# define TRIO_PLATFORM_UNIX +#elif defined(__QNX__) +# define TRIO_PLATFORM_UNIX +# define TRIO_PLATFORM_QNX +#elif defined(__CYGWIN__) +# define TRIO_PLATFORM_UNIX +#elif defined(AMIGA) && defined(TRIO_COMPILER_GCC) +# define TRIO_PLATFORM_UNIX +#elif defined(TRIO_COMPILER_MSVC) || defined(WIN32) || defined(_WIN32) +# define TRIO_PLATFORM_WIN32 +#elif defined(mpeix) || defined(__mpexl) +# define TRIO_PLATFORM_MPEIX +#endif + +#if defined(_AIX) +# define TRIO_PLATFORM_AIX +#elif defined(__hpux) +# define TRIO_PLATFORM_HPUX +#elif defined(sun) || defined(__sun__) +# if defined(__SVR4) || defined(__svr4__) +# define TRIO_PLATFORM_SOLARIS +# else +# define TRIO_PLATFORM_SUNOS +# endif +#endif + +#if defined(__STDC__) || defined(TRIO_COMPILER_MSVC) || defined(TRIO_COMPILER_BCB) +# define TRIO_COMPILER_SUPPORTS_C89 +# if defined(__STDC_VERSION__) +# define TRIO_COMPILER_SUPPORTS_C90 +# if (__STDC_VERSION__ >= 199409L) +# define TRIO_COMPILER_SUPPORTS_C94 +# endif +# if (__STDC_VERSION__ >= 199901L) +# define TRIO_COMPILER_SUPPORTS_C99 +# endif +# elif defined(TRIO_COMPILER_SUNPRO) +# if (__SUNPRO_C >= 0x420) +# define TRIO_COMPILER_SUPPORTS_C94 +# endif +# endif +#endif + +#if defined(_XOPEN_SOURCE) +# if defined(_XOPEN_SOURCE_EXTENDED) +# define TRIO_COMPILER_SUPPORTS_UNIX95 +# endif +# if (_XOPEN_VERSION >= 500) +# define TRIO_COMPILER_SUPPORTS_UNIX98 +# endif +# if (_XOPEN_VERSION >= 600) +# define TRIO_COMPILER_SUPPORTS_UNIX01 +# endif +#endif + +/************************************************************************* + * Generic defines + */ + +#if !defined(TRIO_PUBLIC) +# define TRIO_PUBLIC +#endif +#if !defined(TRIO_PRIVATE) +# define TRIO_PRIVATE static +#endif + +#if !(defined(TRIO_COMPILER_SUPPORTS_C89) || defined(__cplusplus)) +# define TRIO_COMPILER_ANCIENT +#endif + +#if defined(TRIO_COMPILER_ANCIENT) +# define TRIO_CONST +# define TRIO_VOLATILE +# define TRIO_SIGNED +typedef double trio_long_double_t; +typedef char * trio_pointer_t; +# define TRIO_SUFFIX_LONG(x) x +# define TRIO_PROTO(x) () +# define TRIO_NOARGS +# define TRIO_ARGS1(list,a1) list a1; +# define TRIO_ARGS2(list,a1,a2) list a1; a2; +# define TRIO_ARGS3(list,a1,a2,a3) list a1; a2; a3; +# define TRIO_ARGS4(list,a1,a2,a3,a4) list a1; a2; a3; a4; +# define TRIO_ARGS5(list,a1,a2,a3,a4,a5) list a1; a2; a3; a4; a5; +# define TRIO_ARGS6(list,a1,a2,a3,a4,a5,a6) list a1; a2; a3; a4; a5; a6; +# define TRIO_VARGS2(list,a1,a2) list a1; a2 +# define TRIO_VARGS3(list,a1,a2,a3) list a1; a2; a3 +# define TRIO_VARGS4(list,a1,a2,a3,a4) list a1; a2; a3; a4 +# define TRIO_VARGS5(list,a1,a2,a3,a4,a5) list a1; a2; a3; a4; a5 +# define TRIO_VA_DECL va_dcl +# define TRIO_VA_START(x,y) va_start(x) +# define TRIO_VA_END(x) va_end(x) +#else /* ANSI C */ +# define TRIO_CONST const +# define TRIO_VOLATILE volatile +# define TRIO_SIGNED signed +typedef long double trio_long_double_t; +typedef void * trio_pointer_t; +# define TRIO_SUFFIX_LONG(x) x ## L +# define TRIO_PROTO(x) x +# define TRIO_NOARGS void +# define TRIO_ARGS1(list,a1) (a1) +# define TRIO_ARGS2(list,a1,a2) (a1,a2) +# define TRIO_ARGS3(list,a1,a2,a3) (a1,a2,a3) +# define TRIO_ARGS4(list,a1,a2,a3,a4) (a1,a2,a3,a4) +# define TRIO_ARGS5(list,a1,a2,a3,a4,a5) (a1,a2,a3,a4,a5) +# define TRIO_ARGS6(list,a1,a2,a3,a4,a5,a6) (a1,a2,a3,a4,a5,a6) +# define TRIO_VARGS2 TRIO_ARGS2 +# define TRIO_VARGS3 TRIO_ARGS3 +# define TRIO_VARGS4 TRIO_ARGS4 +# define TRIO_VARGS5 TRIO_ARGS5 +# define TRIO_VA_DECL ... +# define TRIO_VA_START(x,y) va_start(x,y) +# define TRIO_VA_END(x) va_end(x) +#endif + +#if defined(TRIO_COMPILER_SUPPORTS_C99) || defined(__cplusplus) +# define TRIO_INLINE inline +#elif defined(TRIO_COMPILER_GCC) +# define TRIO_INLINE __inline__ +#elif defined(TRIO_COMPILER_MSVC) +# define TRIO_INLINE _inline +#elif defined(TRIO_COMPILER_BCB) +# define TRIO_INLINE __inline +#else +# define TRIO_INLINE +#endif + +/************************************************************************* + * Workarounds + */ + +#if defined(TRIO_PLATFORM_VMS) +/* + * Computations done with constants at compile time can trigger these + * even when compiling with IEEE enabled. + */ +# pragma message disable (UNDERFLOW, FLOATOVERFL) + +# if (__CRTL_VER < 80000000) +/* + * Although the compiler supports C99 language constructs, the C + * run-time library does not contain all C99 functions. + * + * This was the case for 70300022. Update the 80000000 value when + * it has been accurately determined what version of the library + * supports C99. + */ +# if defined(TRIO_COMPILER_SUPPORTS_C99) +# undef TRIO_COMPILER_SUPPORTS_C99 +# endif +# endif +#endif + +/* + * Not all preprocessors supports the LL token. + */ +#if defined(TRIO_COMPILER_BCB) +#else +# define TRIO_COMPILER_SUPPORTS_LL +#endif + +#endif /* TRIO_TRIODEF_H */ diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/variables.c chromium-145.0.7632.159/third_party/libxslt/src/libxslt/variables.c --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/variables.c 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/variables.c 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,2437 @@ +/* + * variables.c: Implementation of the variable storage and lookup + * + * Reference: + * http://www.w3.org/TR/1999/REC-xslt-19991116 + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#define IN_LIBXSLT +#include "libxslt.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xslt.h" +#include "xsltInternals.h" +#include "xsltutils.h" +#include "variables.h" +#include "transform.h" +#include "imports.h" +#include "preproc.h" +#include "keys.h" + +#ifdef WITH_XSLT_DEBUG + #define WITH_XSLT_DEBUG_VARIABLE +#endif + +#ifdef XSLT_REFACTORED +const xmlChar *xsltDocFragFake = (const xmlChar *) " fake node libxslt"; +#endif + +static const xmlChar *xsltComputingGlobalVarMarker = + (const xmlChar *) " var/param being computed"; + +#define XSLT_VAR_GLOBAL (1<<0) +#define XSLT_VAR_IN_SELECT (1<<1) +#define XSLT_TCTXT_VARIABLE(c) ((xsltStackElemPtr) (c)->contextVariable) + +static xsltRVTListPtr +xsltRVTListCreate(void) +{ + xsltRVTListPtr ret; + + ret = (xsltRVTListPtr) xmlMalloc(sizeof(xsltRVTList)); + if (ret == NULL) { + xsltTransformError(NULL, NULL, NULL, + "xsltRVTListCreate: malloc failed\n"); + return(NULL); + } + memset(ret, 0, sizeof(xsltRVTList)); + return(ret); +} + +/************************************************************************ + * * + * Result Value Tree (Result Tree Fragment) interfaces * + * * + ************************************************************************/ +/** + * xsltCreateRVT: + * @ctxt: an XSLT transformation context + * + * Creates a Result Value Tree + * (the XSLT 1.0 term for this is "Result Tree Fragment") + * + * Returns the result value tree or NULL in case of API or internal errors. + */ +xmlDocPtr +xsltCreateRVT(xsltTransformContextPtr ctxt) +{ + xsltRVTListPtr rvtList; + xmlDocPtr container; + + /* + * Question: Why is this function public? + * Answer: It is called by the EXSLT module. + */ + if (ctxt == NULL) + return(NULL); + + /* + * Reuse a RTF from the cache if available. + */ + if (ctxt->cache->rvtList) { + rvtList = ctxt->cache->rvtList; + container = ctxt->cache->rvtList->RVT; + ctxt->cache->rvtList = rvtList->next; + xmlFree(rvtList); + if (ctxt->cache->nbRVT > 0) + ctxt->cache->nbRVT--; +#ifdef XSLT_DEBUG_PROFILE_CACHE + ctxt->cache->dbgReusedRVTs++; +#endif + return(container); + } + + container = xmlNewDoc(NULL); + if (container == NULL) + return(NULL); + container->dict = ctxt->dict; + xmlDictReference(container->dict); + XSLT_MARK_RES_TREE_FRAG(container); + container->doc = container; + container->parent = NULL; + return(container); +} + +/** + * xsltRegisterTmpRVT: + * @ctxt: an XSLT transformation context + * @RVT: a result value tree (Result Tree Fragment) + * + * Registers the result value tree (XSLT 1.0 term: Result Tree Fragment) + * in the garbage collector. + * The fragment will be freed at the exit of the currently + * instantiated xsl:template. + * Obsolete; this function might produce massive memory overhead, + * since the fragment is only freed when the current xsl:template + * exits. Use xsltRegisterLocalRVT() instead. + * + * Returns 0 in case of success and -1 in case of API or internal errors. + */ +int +xsltRegisterTmpRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) +{ + xsltRVTListPtr list; + + if ((ctxt == NULL) || (RVT == NULL)) + return(-1); + + list = xsltRVTListCreate(); + if (list == NULL) return(-1); + + RVT->compression = XSLT_RVT_LOCAL; + list->RVT = RVT; + + /* + * We'll restrict the lifetime of user-created fragments + * insinde an xsl:variable and xsl:param to the lifetime of the + * var/param itself. + */ + if (ctxt->contextVariable != NULL) { + list->next = XSLT_TCTXT_VARIABLE(ctxt)->fragment; + XSLT_TCTXT_VARIABLE(ctxt)->fragment = list; + return(0); + } + + list->next = ctxt->tmpRVTList; + ctxt->tmpRVTList = list; + return(0); +} + +/** + * xsltRegisterLocalRVT: + * @ctxt: an XSLT transformation context + * @RVT: a result value tree (Result Tree Fragment; xmlDocPtr) + * + * Registers a result value tree (XSLT 1.0 term: Result Tree Fragment) + * in the RVT garbage collector. + * The fragment will be freed when the instruction which created the + * fragment exits. + * + * Returns 0 in case of success and -1 in case of API or internal errors. + */ +int +xsltRegisterLocalRVT(xsltTransformContextPtr ctxt, + xmlDocPtr RVT) +{ + xsltRVTListPtr list; + + if ((ctxt == NULL) || (RVT == NULL)) + return(-1); + + list = xsltRVTListCreate(); + if (list == NULL) return(-1); + + RVT->compression = XSLT_RVT_LOCAL; + list->RVT = RVT; + + /* + * When evaluating "select" expressions of xsl:variable + * and xsl:param, we need to bind newly created tree fragments + * to the variable itself; otherwise the fragment will be + * freed before we leave the scope of a var. + */ + if ((ctxt->contextVariable != NULL) && + (XSLT_TCTXT_VARIABLE(ctxt)->flags & XSLT_VAR_IN_SELECT)) + { + list->next = XSLT_TCTXT_VARIABLE(ctxt)->fragment; + XSLT_TCTXT_VARIABLE(ctxt)->fragment = list; + return(0); + } + /* + * Store the fragment in the scope of the current instruction. + * If not reference by a returning instruction (like EXSLT's function), + * then this fragment will be freed, when the instruction exits. + */ + list->next = ctxt->localRVTList; + ctxt->localRVTList = list; + return(0); +} + +/** + * xsltExtensionInstructionResultFinalize: + * @ctxt: an XSLT transformation context + * + * Finalizes the data (e.g. result tree fragments) created + * within a value-returning process (e.g. EXSLT's function). + * Tree fragments marked as being returned by a function are + * set to normal state, which means that the fragment garbage + * collector will free them after the function-calling process exits. + * + * Returns 0 in case of success and -1 in case of API or internal errors. + * + * This function is unsupported in newer releases of libxslt. + */ +int +xsltExtensionInstructionResultFinalize( + xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED) +{ + xmlGenericError(xmlGenericErrorContext, + "xsltExtensionInstructionResultFinalize is unsupported " + "in this release of libxslt.\n"); + return(-1); +} + +/** + * xsltExtensionInstructionResultRegister: + * @ctxt: an XSLT transformation context + * @obj: an XPath object to be inspected for result tree fragments + * + * Marks the result of a value-returning extension instruction + * in order to avoid it being garbage collected before the + * extension instruction exits. + * Note that one still has to additionally register any newly created + * tree fragments (via xsltCreateRVT()) with xsltRegisterLocalRVT(). + * + * Returns 0 in case of success and -1 in case of error. + * + * It isn't necessary to call this function in newer releases of + * libxslt. + */ +int +xsltExtensionInstructionResultRegister( + xsltTransformContextPtr ctxt ATTRIBUTE_UNUSED, + xmlXPathObjectPtr obj ATTRIBUTE_UNUSED) +{ + return(0); +} + +/** + * xsltFlagRVTs: + * @ctxt: an XSLT transformation context + * @obj: an XPath object to be inspected for result tree fragments + * @val: the flag value + * + * Updates ownership information of RVTs in @obj according to @val. + * + * @val = XSLT_RVT_FUNC_RESULT for the result of an extension function, so its + * RVTs won't be destroyed after leaving the returning scope. + * @val = XSLT_RVT_LOCAL for the result of an extension function to reset + * the state of its RVTs after it was returned to a new scope. + * @val = XSLT_RVT_GLOBAL for parts of global variables. + * + * Returns 0 in case of success and -1 in case of error. + */ +int +xsltFlagRVTs(xsltTransformContextPtr ctxt, xmlXPathObjectPtr obj, int val) { + int i; + xmlNodePtr cur; + xmlDocPtr doc; + + if ((ctxt == NULL) || (obj == NULL)) + return(-1); + + /* + * OPTIMIZE TODO: If no local variables/params and no local tree + * fragments were created, then we don't need to analyse the XPath + * objects for tree fragments. + */ + + if ((obj->type != XPATH_NODESET) && (obj->type != XPATH_XSLT_TREE)) + return(0); + if ((obj->nodesetval == NULL) || (obj->nodesetval->nodeNr == 0)) + return(0); + + for (i = 0; i < obj->nodesetval->nodeNr; i++) { + cur = obj->nodesetval->nodeTab[i]; + if (cur->type == XML_NAMESPACE_DECL) { + /* + * The XPath module sets the owner element of a ns-node on + * the ns->next field. + */ + if ((((xmlNsPtr) cur)->next != NULL) && + (((xmlNsPtr) cur)->next->type == XML_ELEMENT_NODE)) + { + cur = (xmlNodePtr) ((xmlNsPtr) cur)->next; + doc = cur->doc; + } else { + xsltTransformError(ctxt, NULL, ctxt->inst, + "Internal error in xsltFlagRVTs(): " + "Cannot retrieve the doc of a namespace node.\n"); + return(-1); + } + } else { + doc = cur->doc; + } + if (doc == NULL) { + xsltTransformError(ctxt, NULL, ctxt->inst, + "Internal error in xsltFlagRVTs(): " + "Cannot retrieve the doc of a node.\n"); + return(-1); + } + if (doc->name && (doc->name[0] == ' ') && + doc->compression != XSLT_RVT_GLOBAL) { + /* + * This is a result tree fragment. + * We store ownership information in the @compression field. + * TODO: How do we know if this is a doc acquired via the + * document() function? + */ +#ifdef WITH_XSLT_DEBUG_VARIABLE + XSLT_TRACE(ctxt, XSLT_TRACE_VARIABLES, + xsltGenericDebug(xsltGenericDebugContext, + "Flagging RVT %p: %d -> %d\n", + (void *) doc, doc->compression, val)); +#endif + + if (val == XSLT_RVT_LOCAL) { + if (doc->compression == XSLT_RVT_FUNC_RESULT) + doc->compression = XSLT_RVT_LOCAL; + } else if (val == XSLT_RVT_GLOBAL) { + if (doc->compression != XSLT_RVT_LOCAL) { + xmlGenericError(xmlGenericErrorContext, + "xsltFlagRVTs: Invalid transition %d => GLOBAL\n", + doc->compression); + doc->compression = XSLT_RVT_GLOBAL; + return(-1); + } + + /* Will be registered as persistant in xsltReleaseLocalRVTs. */ + doc->compression = XSLT_RVT_GLOBAL; + } else if (val == XSLT_RVT_FUNC_RESULT) { + doc->compression = val; + } + } + } + + return(0); +} + +/** + * xsltReleaseRVT: + * @ctxt: an XSLT transformation context + * @RVT: a result value tree (Result Tree Fragment) + * + * Either frees the RVT (which is an xmlDoc) or stores it in the context's + * cache for later reuse. Preserved for ABI/API compatibility; internal use + * has all migrated to xsltReleaseRVTList(). + */ +void +xsltReleaseRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) +{ + if (RVT == NULL) + return; + + xsltRVTListPtr list = xsltRVTListCreate(); + if (list == NULL) { + if (RVT->_private != NULL) { + xsltFreeDocumentKeys((xsltDocumentPtr) RVT->_private); + xmlFree(RVT->_private); + } + xmlFreeDoc(RVT); + return; + } + + xsltReleaseRVTList(ctxt, list); +} + +/** + * xsltReleaseRVTList: + * @ctxt: an XSLT transformation context + * @list: a list node containing a result value tree (Result Tree Fragment) + * + * Either frees the list node or stores it in the context's cache for later + * reuse. Optimization to avoid adding a fallible allocation path when the + * caller already has a RVT list node. + */ +void +xsltReleaseRVTList(xsltTransformContextPtr ctxt, xsltRVTListPtr list) +{ + if (list == NULL) + return; + + if (ctxt && (ctxt->cache->nbRVT < 40)) { + /* + * Store the Result Tree Fragment. + * Free the document info. + */ + if (list->RVT->_private != NULL) { + xsltFreeDocumentKeys((xsltDocumentPtr) list->RVT->_private); + xmlFree(list->RVT->_private); + list->RVT->_private = NULL; + } + /* + * Clear the document tree. + */ + if (list->RVT->children != NULL) { + xmlFreeNodeList(list->RVT->children); + list->RVT->children = NULL; + list->RVT->last = NULL; + } + if (list->RVT->ids != NULL) { + xmlFreeIDTable((xmlIDTablePtr) list->RVT->ids); + list->RVT->ids = NULL; + } + + /* + * Reset the ownership information. + */ + list->RVT->compression = 0; + + list->next = ctxt->cache->rvtList; + ctxt->cache->rvtList = list; + + ctxt->cache->nbRVT++; + +#ifdef XSLT_DEBUG_PROFILE_CACHE + ctxt->cache->dbgCachedRVTs++; +#endif + return; + } + /* + * Free it. + */ + if (list->RVT->_private != NULL) { + xsltFreeDocumentKeys((xsltDocumentPtr) list->RVT->_private); + xmlFree(list->RVT->_private); + } + xmlFreeDoc(list->RVT); + xmlFree(list); +} + +/** + * xsltRegisterPersistRVT: + * @ctxt: an XSLT transformation context + * @RVT: a result value tree (Result Tree Fragment) + * + * Register the result value tree (XSLT 1.0 term: Result Tree Fragment) + * in the fragment garbage collector. + * The fragment will be freed when the transformation context is + * freed. + * + * Returns 0 in case of success and -1 in case of error. + */ +int +xsltRegisterPersistRVT(xsltTransformContextPtr ctxt, xmlDocPtr RVT) +{ + xsltRVTListPtr list; + + if ((ctxt == NULL) || (RVT == NULL)) return(-1); + + list = xsltRVTListCreate(); + if (list == NULL) return(-1); + + RVT->compression = XSLT_RVT_GLOBAL; + list->RVT = RVT; + list->next = ctxt->persistRVTList; + ctxt->persistRVTList = list; + return(0); +} + +/** + * xsltFreeRVTs: + * @ctxt: an XSLT transformation context + * + * Frees all registered result value trees (Result Tree Fragments) + * of the transformation. Internal function; should not be called + * by user-code. + */ +void +xsltFreeRVTs(xsltTransformContextPtr ctxt) +{ + xsltRVTListPtr cur, next; + + if (ctxt == NULL) + return; + /* + * Local fragments. + */ + cur = ctxt->localRVTList; + while (cur != NULL) { + next = cur->next; + if (cur->RVT->_private != NULL) { + xsltFreeDocumentKeys(cur->RVT->_private); + xmlFree(cur->RVT->_private); + } + xmlFreeDoc(cur->RVT); + xmlFree(cur); + cur = next; + } + ctxt->localRVTList = NULL; + /* + * User-created per-template fragments. + */ + cur = ctxt->tmpRVTList; + while (cur != NULL) { + next = cur->next; + if (cur->RVT->_private != NULL) { + xsltFreeDocumentKeys(cur->RVT->_private); + xmlFree(cur->RVT->_private); + } + xmlFreeDoc(cur->RVT); + xmlFree(cur); + cur = next; + } + ctxt->tmpRVTList = NULL; + /* + * Global fragments. + */ + cur = ctxt->persistRVTList; + while (cur != NULL) { + next = cur->next; + if (cur->RVT->_private != NULL) { + xsltFreeDocumentKeys(cur->RVT->_private); + xmlFree(cur->RVT->_private); + } + xmlFreeDoc(cur->RVT); + xmlFree(cur); + cur = next; + } + ctxt->persistRVTList = NULL; +} + +/************************************************************************ + * * + * Module interfaces * + * * + ************************************************************************/ + +/** + * xsltNewStackElem: + * + * Create a new XSLT ParserContext + * + * Returns the newly allocated xsltParserStackElem or NULL in case of error + */ +static xsltStackElemPtr +xsltNewStackElem(xsltTransformContextPtr ctxt) +{ + xsltStackElemPtr ret; + /* + * Reuse a stack item from the cache if available. + */ + if (ctxt && ctxt->cache->stackItems) { + ret = ctxt->cache->stackItems; + ctxt->cache->stackItems = ret->next; + ret->next = NULL; + ctxt->cache->nbStackItems--; +#ifdef XSLT_DEBUG_PROFILE_CACHE + ctxt->cache->dbgReusedVars++; +#endif + return(ret); + } + ret = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem)); + if (ret == NULL) { + xsltTransformError(NULL, NULL, NULL, + "xsltNewStackElem : malloc failed\n"); + return(NULL); + } + memset(ret, 0, sizeof(xsltStackElem)); + ret->context = ctxt; + return(ret); +} + +/** + * xsltCopyStackElem: + * @elem: an XSLT stack element + * + * Makes a copy of the stack element + * + * Returns the copy of NULL + */ +static xsltStackElemPtr +xsltCopyStackElem(xsltStackElemPtr elem) { + xsltStackElemPtr cur; + + cur = (xsltStackElemPtr) xmlMalloc(sizeof(xsltStackElem)); + if (cur == NULL) { + xsltTransformError(NULL, NULL, NULL, + "xsltCopyStackElem : malloc failed\n"); + return(NULL); + } + memset(cur, 0, sizeof(xsltStackElem)); + cur->context = elem->context; + cur->name = elem->name; + cur->nameURI = elem->nameURI; + cur->select = elem->select; + cur->tree = elem->tree; + cur->comp = elem->comp; + return(cur); +} + +/** + * xsltFreeStackElem: + * @elem: an XSLT stack element + * + * Free up the memory allocated by @elem + */ +static void +xsltFreeStackElem(xsltStackElemPtr elem) { + if (elem == NULL) + return; + if (elem->value != NULL) + xmlXPathFreeObject(elem->value); + /* + * Release the list of temporary Result Tree Fragments. + */ + if (elem->context) { + xsltRVTListPtr cur; + + while (elem->fragment != NULL) { + cur = elem->fragment; + elem->fragment = cur->next; + + if (cur->RVT->compression == XSLT_RVT_LOCAL) { + xsltReleaseRVTList(elem->context, cur); + } else if (cur->RVT->compression == XSLT_RVT_FUNC_RESULT) { + xsltRegisterLocalRVT(elem->context, cur->RVT); + cur->RVT->compression = XSLT_RVT_FUNC_RESULT; + xmlFree(cur); + } else { + xmlGenericError(xmlGenericErrorContext, + "xsltFreeStackElem: Unexpected RVT flag %d\n", + cur->RVT->compression); + } + } + } + /* + * Cache or free the variable structure. + */ + if (elem->context && (elem->context->cache->nbStackItems < 50)) { + /* + * Store the item in the cache. + */ + xsltTransformContextPtr ctxt = elem->context; + memset(elem, 0, sizeof(xsltStackElem)); + elem->context = ctxt; + elem->next = ctxt->cache->stackItems; + ctxt->cache->stackItems = elem; + ctxt->cache->nbStackItems++; +#ifdef XSLT_DEBUG_PROFILE_CACHE + ctxt->cache->dbgCachedVars++; +#endif + return; + } + xmlFree(elem); +} + +static void +xsltFreeStackElemEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) { + xsltFreeStackElem((xsltStackElemPtr) payload); +} + + +/** + * xsltFreeStackElemList: + * @elem: an XSLT stack element + * + * Free up the memory allocated by @elem + */ +void +xsltFreeStackElemList(xsltStackElemPtr elem) { + xsltStackElemPtr next; + + while (elem != NULL) { + next = elem->next; + xsltFreeStackElem(elem); + elem = next; + } +} + +/** + * xsltStackLookup: + * @ctxt: an XSLT transformation context + * @name: the local part of the name + * @nameURI: the URI part of the name + * + * Locate an element in the stack based on its name. + */ +static xsltStackElemPtr +xsltStackLookup(xsltTransformContextPtr ctxt, const xmlChar *name, + const xmlChar *nameURI) { + int i; + xsltStackElemPtr cur; + + if ((ctxt == NULL) || (name == NULL) || (ctxt->varsNr == 0)) + return(NULL); + + /* + * Do the lookup from the top of the stack, but + * don't use params being computed in a call-param + * First lookup expects the variable name and URI to + * come from the disctionnary and hence pointer comparison. + */ + for (i = ctxt->varsNr; i > ctxt->varsBase; i--) { + cur = ctxt->varsTab[i-1]; + while (cur != NULL) { + if ((cur->name == name) && (cur->nameURI == nameURI)) { + return(cur); + } + cur = cur->next; + } + } + + /* + * Redo the lookup with interned string compares + * to avoid string compares. + */ + name = xmlDictLookup(ctxt->dict, name, -1); + if (nameURI != NULL) + nameURI = xmlDictLookup(ctxt->dict, nameURI, -1); + + for (i = ctxt->varsNr; i > ctxt->varsBase; i--) { + cur = ctxt->varsTab[i-1]; + while (cur != NULL) { + if ((cur->name == name) && (cur->nameURI == nameURI)) { + return(cur); + } + cur = cur->next; + } + } + + return(NULL); +} + +#ifdef XSLT_REFACTORED +#else + +/** + * xsltCheckStackElem: + * @ctxt: xn XSLT transformation context + * @name: the variable name + * @nameURI: the variable namespace URI + * + * Checks whether a variable or param is already defined. + * + * URGENT TODO: Checks for redefinition of vars/params should be + * done only at compilation time. + * + * Returns 1 if variable is present, 2 if param is present, 3 if this + * is an inherited param, 0 if not found, -1 in case of failure. + */ +static int +xsltCheckStackElem(xsltTransformContextPtr ctxt, const xmlChar *name, + const xmlChar *nameURI) { + xsltStackElemPtr cur; + + if ((ctxt == NULL) || (name == NULL)) + return(-1); + + cur = xsltStackLookup(ctxt, name, nameURI); + if (cur == NULL) + return(0); + if (cur->comp != NULL) { + if (cur->comp->type == XSLT_FUNC_WITHPARAM) + return(3); + else if (cur->comp->type == XSLT_FUNC_PARAM) + return(2); + } + + return(1); +} + +#endif /* XSLT_REFACTORED */ + +/** + * xsltAddStackElem: + * @ctxt: xn XSLT transformation context + * @elem: a stack element + * + * Push an element (or list) onto the stack. + * In case of a list, each member will be pushed into + * a seperate slot; i.e. there's always 1 stack entry for + * 1 stack element. + * + * Returns 0 in case of success, -1 in case of failure. + */ +static int +xsltAddStackElem(xsltTransformContextPtr ctxt, xsltStackElemPtr elem) +{ + if ((ctxt == NULL) || (elem == NULL)) + return(-1); + + do { + if (ctxt->varsNr >= ctxt->varsMax) { + xsltStackElemPtr *tmp; + int newMax = ctxt->varsMax == 0 ? 10 : 2 * ctxt->varsMax; + + tmp = (xsltStackElemPtr *) xmlRealloc(ctxt->varsTab, + newMax * sizeof(*tmp)); + if (tmp == NULL) { + xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); + return (-1); + } + ctxt->varsTab = tmp; + ctxt->varsMax = newMax; + } + ctxt->varsTab[ctxt->varsNr++] = elem; + ctxt->vars = elem; + + elem = elem->next; + } while (elem != NULL); + + return(0); +} + +/** + * xsltAddStackElemList: + * @ctxt: xn XSLT transformation context + * @elems: a stack element list + * + * Push an element list onto the stack. + * + * Returns 0 in case of success, -1 in case of failure. + */ +int +xsltAddStackElemList(xsltTransformContextPtr ctxt, xsltStackElemPtr elems) +{ + return(xsltAddStackElem(ctxt, elems)); +} + +/************************************************************************ + * * + * Module interfaces * + * * + ************************************************************************/ + +/** + * xsltEvalVariable: + * @ctxt: the XSLT transformation context + * @variable: the variable or parameter item + * @comp: the compiled XSLT instruction + * + * Evaluate a variable value. + * + * Returns the XPath Object value or NULL in case of error + */ +static xmlXPathObjectPtr +xsltEvalVariable(xsltTransformContextPtr ctxt, xsltStackElemPtr variable, + xsltStylePreCompPtr castedComp) +{ +#ifdef XSLT_REFACTORED + xsltStyleItemVariablePtr comp = + (xsltStyleItemVariablePtr) castedComp; +#else + xsltStylePreCompPtr comp = castedComp; +#endif + xmlXPathObjectPtr result = NULL; + xmlNodePtr oldInst; + + if ((ctxt == NULL) || (variable == NULL)) + return(NULL); + + /* + * A variable or parameter are evaluated on demand; thus the + * context (of XSLT and XPath) need to be temporarily adjusted and + * restored on exit. + */ + oldInst = ctxt->inst; + +#ifdef WITH_XSLT_DEBUG_VARIABLE + XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, + "Evaluating variable '%s'\n", variable->name)); +#endif + if (variable->select != NULL) { + xmlXPathCompExprPtr xpExpr = NULL; + xmlDocPtr oldXPDoc; + xmlNodePtr oldXPContextNode; + int oldXPProximityPosition, oldXPContextSize, oldXPNsNr; + xmlNsPtr *oldXPNamespaces; + xmlXPathContextPtr xpctxt = ctxt->xpathCtxt; + xsltStackElemPtr oldVar = ctxt->contextVariable; + + if ((comp != NULL) && (comp->comp != NULL)) { + xpExpr = comp->comp; + } else { + xpExpr = xmlXPathCtxtCompile(ctxt->xpathCtxt, variable->select); + } + if (xpExpr == NULL) + return(NULL); + /* + * Save context states. + */ + oldXPDoc = xpctxt->doc; + oldXPContextNode = xpctxt->node; + oldXPProximityPosition = xpctxt->proximityPosition; + oldXPContextSize = xpctxt->contextSize; + oldXPNamespaces = xpctxt->namespaces; + oldXPNsNr = xpctxt->nsNr; + + xpctxt->node = ctxt->node; + /* + * OPTIMIZE TODO: Lame try to set the context doc. + * Get rid of this somehow in xpath.c. + */ + if ((ctxt->node->type != XML_NAMESPACE_DECL) && + ctxt->node->doc) + xpctxt->doc = ctxt->node->doc; + /* + * BUG TODO: The proximity position and the context size will + * potentially be wrong. + * Example: + * + * + * + * + * + * + * Here the proximity position and context size are changed + * to the context of , but + * the variable needs to be evaluated in the context of + * . + */ + if (comp != NULL) { + +#ifdef XSLT_REFACTORED + if (comp->inScopeNs != NULL) { + xpctxt->namespaces = comp->inScopeNs->list; + xpctxt->nsNr = comp->inScopeNs->xpathNumber; + } else { + xpctxt->namespaces = NULL; + xpctxt->nsNr = 0; + } +#else + xpctxt->namespaces = comp->nsList; + xpctxt->nsNr = comp->nsNr; +#endif + } else { + xpctxt->namespaces = NULL; + xpctxt->nsNr = 0; + } + + /* + * We need to mark that we are "selecting" a var's value; + * if any tree fragments are created inside the expression, + * then those need to be stored inside the variable; otherwise + * we'll eventually free still referenced fragments, before + * we leave the scope of the variable. + */ + ctxt->contextVariable = variable; + variable->flags |= XSLT_VAR_IN_SELECT; + + result = xmlXPathCompiledEval(xpExpr, xpctxt); + + variable->flags ^= XSLT_VAR_IN_SELECT; + /* + * Restore Context states. + */ + ctxt->contextVariable = oldVar; + + xpctxt->doc = oldXPDoc; + xpctxt->node = oldXPContextNode; + xpctxt->contextSize = oldXPContextSize; + xpctxt->proximityPosition = oldXPProximityPosition; + xpctxt->namespaces = oldXPNamespaces; + xpctxt->nsNr = oldXPNsNr; + + if ((comp == NULL) || (comp->comp == NULL)) + xmlXPathFreeCompExpr(xpExpr); + if (result == NULL) { + xsltTransformError(ctxt, NULL, + (comp != NULL) ? comp->inst : NULL, + "Failed to evaluate the expression of variable '%s'.\n", + variable->name); + ctxt->state = XSLT_STATE_STOPPED; + +#ifdef WITH_XSLT_DEBUG_VARIABLE +#ifdef LIBXML_DEBUG_ENABLED + } else { + if ((xsltGenericDebugContext == stdout) || + (xsltGenericDebugContext == stderr)) + xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext, + result, 0); +#endif +#endif + } + } else { + if (variable->tree == NULL) { + result = xmlXPathNewCString(""); + } else { + if (variable->tree) { + xmlDocPtr container; + xsltRVTListPtr rvtList; + xmlNodePtr oldInsert; + xmlDocPtr oldOutput; + const xmlChar *oldLastText; + int oldLastTextSize, oldLastTextUse; + xsltStackElemPtr oldVar = ctxt->contextVariable; + + /* + * Generate a result tree fragment. + */ + container = xsltCreateRVT(ctxt); + if (container == NULL) + goto error; + /* + * NOTE: Local Result Tree Fragments of params/variables + * are not registered globally anymore; the life-time + * is not directly dependant of the param/variable itself. + * + * OLD: xsltRegisterTmpRVT(ctxt, container); + */ + /* + * Attach the Result Tree Fragment to the variable; + * when the variable is freed, it will also free + * the Result Tree Fragment. + */ + rvtList = xsltRVTListCreate(); + if (rvtList == NULL) + goto error; + rvtList->RVT = container; + variable->fragment = rvtList; + container->compression = XSLT_RVT_LOCAL; + + oldOutput = ctxt->output; + oldInsert = ctxt->insert; + oldLastText = ctxt->lasttext; + oldLastTextSize = ctxt->lasttsize; + oldLastTextUse = ctxt->lasttuse; + + ctxt->output = container; + ctxt->insert = (xmlNodePtr) container; + ctxt->contextVariable = variable; + /* + * Process the sequence constructor (variable->tree). + * The resulting tree will be held by @container. + */ + xsltApplyOneTemplate(ctxt, ctxt->node, variable->tree, + NULL, NULL); + + ctxt->contextVariable = oldVar; + ctxt->insert = oldInsert; + ctxt->output = oldOutput; + ctxt->lasttext = oldLastText; + ctxt->lasttsize = oldLastTextSize; + ctxt->lasttuse = oldLastTextUse; + + result = xmlXPathNewValueTree((xmlNodePtr) container); + } + if (result == NULL) { + result = xmlXPathNewCString(""); + } else { + /* + * This stops older libxml2 versions from freeing the nodes + * in the tree. + */ + result->boolval = 0; + } +#ifdef WITH_XSLT_DEBUG_VARIABLE +#ifdef LIBXML_DEBUG_ENABLED + + if ((xsltGenericDebugContext == stdout) || + (xsltGenericDebugContext == stderr)) + xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext, + result, 0); +#endif +#endif + } + } + +error: + ctxt->inst = oldInst; + return(result); +} + +/** + * xsltEvalGlobalVariable: + * @elem: the variable or parameter + * @ctxt: the XSLT transformation context + * + * Evaluates a the value of a global xsl:variable or + * xsl:param declaration. + * + * Returns the XPath Object value or NULL in case of error + */ +static xmlXPathObjectPtr +xsltEvalGlobalVariable(xsltStackElemPtr elem, xsltTransformContextPtr ctxt) +{ + xmlXPathObjectPtr result = NULL; + xmlNodePtr oldInst; + const xmlChar* oldVarName; + xsltStackElemPtr oldCtxtVar = ctxt->contextVariable; + +#ifdef XSLT_REFACTORED + xsltStyleBasicItemVariablePtr comp; +#else + xsltStylePreCompPtr comp; +#endif + + if ((ctxt == NULL) || (elem == NULL)) + return(NULL); + if (elem->computed) + return(elem->value); + + +#ifdef WITH_XSLT_DEBUG_VARIABLE + XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, + "Evaluating global variable %s\n", elem->name)); +#endif + +#ifdef WITH_DEBUGGER + if ((ctxt->debugStatus != XSLT_DEBUG_NONE) && + elem->comp && elem->comp->inst) + xslHandleDebugger(elem->comp->inst, NULL, NULL, ctxt); +#endif + + oldInst = ctxt->inst; +#ifdef XSLT_REFACTORED + comp = (xsltStyleBasicItemVariablePtr) elem->comp; +#else + comp = elem->comp; +#endif + oldVarName = elem->name; + elem->name = xsltComputingGlobalVarMarker; + + /* + * The "context variable" isn't used for globals, so we must + * make sure to set it to NULL. + */ + oldCtxtVar = ctxt->contextVariable; + ctxt->contextVariable = NULL; + + /* + * OPTIMIZE TODO: We should consider instantiating global vars/params + * on-demand. The vars/params don't need to be evaluated if never + * called; and in the case of global params, if values for such params + * are provided by the user. + */ + if (elem->select != NULL) { + xmlXPathCompExprPtr xpExpr = NULL; + xmlDocPtr oldXPDoc; + xmlNodePtr oldXPContextNode; + int oldXPProximityPosition, oldXPContextSize, oldXPNsNr; + xmlNsPtr *oldXPNamespaces; + xmlXPathContextPtr xpctxt = ctxt->xpathCtxt; + + if ((comp != NULL) && (comp->comp != NULL)) { + xpExpr = comp->comp; + } else { + xpExpr = xmlXPathCtxtCompile(ctxt->xpathCtxt, elem->select); + } + if (xpExpr == NULL) + goto error; + + + if (comp != NULL) + ctxt->inst = comp->inst; + else + ctxt->inst = NULL; + /* + * SPEC XSLT 1.0: + * "At top-level, the expression or template specifying the + * variable value is evaluated with the same context as that used + * to process the root node of the source document: the current + * node is the root node of the source document and the current + * node list is a list containing just the root node of the source + * document." + */ + /* + * Save context states. + */ + oldXPDoc = xpctxt->doc; + oldXPContextNode = xpctxt->node; + oldXPProximityPosition = xpctxt->proximityPosition; + oldXPContextSize = xpctxt->contextSize; + oldXPNamespaces = xpctxt->namespaces; + oldXPNsNr = xpctxt->nsNr; + + xpctxt->node = ctxt->initialContextNode; + xpctxt->doc = ctxt->initialContextDoc; + xpctxt->contextSize = 1; + xpctxt->proximityPosition = 1; + + if (comp != NULL) { + +#ifdef XSLT_REFACTORED + if (comp->inScopeNs != NULL) { + xpctxt->namespaces = comp->inScopeNs->list; + xpctxt->nsNr = comp->inScopeNs->xpathNumber; + } else { + xpctxt->namespaces = NULL; + xpctxt->nsNr = 0; + } +#else + xpctxt->namespaces = comp->nsList; + xpctxt->nsNr = comp->nsNr; +#endif + } else { + xpctxt->namespaces = NULL; + xpctxt->nsNr = 0; + } + + result = xmlXPathCompiledEval(xpExpr, xpctxt); + + /* + * Restore Context states. + */ + xpctxt->doc = oldXPDoc; + xpctxt->node = oldXPContextNode; + xpctxt->contextSize = oldXPContextSize; + xpctxt->proximityPosition = oldXPProximityPosition; + xpctxt->namespaces = oldXPNamespaces; + xpctxt->nsNr = oldXPNsNr; + + if ((comp == NULL) || (comp->comp == NULL)) + xmlXPathFreeCompExpr(xpExpr); + if (result == NULL) { + if (comp == NULL) + xsltTransformError(ctxt, NULL, NULL, + "Evaluating global variable %s failed\n", elem->name); + else + xsltTransformError(ctxt, NULL, comp->inst, + "Evaluating global variable %s failed\n", elem->name); + ctxt->state = XSLT_STATE_STOPPED; + goto error; + } + + /* + * Mark all RVTs that are referenced from result as part + * of this variable so they won't be freed too early. + */ + xsltFlagRVTs(ctxt, result, XSLT_RVT_GLOBAL); + +#ifdef WITH_XSLT_DEBUG_VARIABLE +#ifdef LIBXML_DEBUG_ENABLED + if ((xsltGenericDebugContext == stdout) || + (xsltGenericDebugContext == stderr)) + xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext, + result, 0); +#endif +#endif + } else { + if (elem->tree == NULL) { + result = xmlXPathNewCString(""); + } else { + xmlDocPtr container; + xmlNodePtr oldInsert; + xmlDocPtr oldOutput, oldXPDoc; + /* + * Generate a result tree fragment. + */ + container = xsltCreateRVT(ctxt); + if (container == NULL) + goto error; + /* + * Let the lifetime of the tree fragment be handled by + * the Libxslt's garbage collector. + */ + xsltRegisterPersistRVT(ctxt, container); + + oldOutput = ctxt->output; + oldInsert = ctxt->insert; + + oldXPDoc = ctxt->xpathCtxt->doc; + + ctxt->output = container; + ctxt->insert = (xmlNodePtr) container; + + ctxt->xpathCtxt->doc = ctxt->initialContextDoc; + /* + * Process the sequence constructor. + */ + xsltApplyOneTemplate(ctxt, ctxt->node, elem->tree, NULL, NULL); + + ctxt->xpathCtxt->doc = oldXPDoc; + + ctxt->insert = oldInsert; + ctxt->output = oldOutput; + + result = xmlXPathNewValueTree((xmlNodePtr) container); + if (result == NULL) { + result = xmlXPathNewCString(""); + } else { + /* + * This stops older libxml2 versions from freeing the nodes + * in the tree. + */ + result->boolval = 0; + } +#ifdef WITH_XSLT_DEBUG_VARIABLE +#ifdef LIBXML_DEBUG_ENABLED + if ((xsltGenericDebugContext == stdout) || + (xsltGenericDebugContext == stderr)) + xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext, + result, 0); +#endif +#endif + } + } + +error: + ctxt->contextVariable = oldCtxtVar; + + elem->name = oldVarName; + ctxt->inst = oldInst; + if (result != NULL) { + elem->value = result; + elem->computed = 1; + } + return(result); +} + +/** + * xsltEvalGlobalVariables: + * @ctxt: the XSLT transformation context + * + * Evaluates all global variables and parameters of a stylesheet. + * For internal use only. This is called at start of a transformation. + * + * Returns 0 in case of success, -1 in case of error + */ +int +xsltEvalGlobalVariables(xsltTransformContextPtr ctxt) { + xsltStackElemPtr elem; + xsltStackElemPtr head = NULL; + xsltStylesheetPtr style; + + if ((ctxt == NULL) || (ctxt->document == NULL)) + return(-1); + +#ifdef WITH_XSLT_DEBUG_VARIABLE + XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, + "Registering global variables\n")); +#endif + /* + * Walk the list from the stylesheets and populate the hash table + */ + style = ctxt->style; + while (style != NULL) { + elem = style->variables; + +#ifdef WITH_XSLT_DEBUG_VARIABLE + if ((style->doc != NULL) && (style->doc->URL != NULL)) { + XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, + "Registering global variables from %s\n", + style->doc->URL)); + } +#endif + + while (elem != NULL) { + xsltStackElemPtr def; + + /* + * Global variables are stored in the variables pool. + */ + def = (xsltStackElemPtr) + xmlHashLookup2(ctxt->globalVars, + elem->name, elem->nameURI); + if (def == NULL) { + + def = xsltCopyStackElem(elem); + if (xmlHashAddEntry2(ctxt->globalVars, + elem->name, elem->nameURI, def) < 0) { + xmlGenericError(xmlGenericErrorContext, + "hash update failed\n"); + xsltFreeStackElem(def); + return(-1); + } + def->next = head; + head = def; + } else if ((elem->comp != NULL) && + (elem->comp->type == XSLT_FUNC_VARIABLE)) { + /* + * Redefinition of variables from a different stylesheet + * should not generate a message. + */ + if ((elem->comp->inst != NULL) && + (def->comp != NULL) && (def->comp->inst != NULL) && + (elem->comp->inst->doc == def->comp->inst->doc)) + { + xsltTransformError(ctxt, style, elem->comp->inst, + "Global variable %s already defined\n", elem->name); + if (style != NULL) style->errors++; + } + } + elem = elem->next; + } + + style = xsltNextImport(style); + } + + /* + * This part does the actual evaluation. Note that scanning the hash + * table would result in a non-deterministic order, leading to + * non-deterministic generated IDs. + */ + elem = head; + while (elem != NULL) { + xsltStackElemPtr next; + + xsltEvalGlobalVariable(elem, ctxt); + next = elem->next; + elem->next = NULL; + elem = next; + } + + return(0); +} + +/** + * xsltRegisterGlobalVariable: + * @style: the XSLT transformation context + * @name: the variable name + * @ns_uri: the variable namespace URI + * @sel: the expression which need to be evaluated to generate a value + * @tree: the subtree if sel is NULL + * @comp: the precompiled value + * @value: the string value if available + * + * Register a new variable value. If @value is NULL it unregisters + * the variable + * + * Returns 0 in case of success, -1 in case of error + */ +static int +xsltRegisterGlobalVariable(xsltStylesheetPtr style, const xmlChar *name, + const xmlChar *ns_uri, const xmlChar *sel, + xmlNodePtr tree, xsltStylePreCompPtr comp, + const xmlChar *value) { + xsltStackElemPtr elem, tmp; + if (style == NULL) + return(-1); + if (name == NULL) + return(-1); + if (comp == NULL) + return(-1); + +#ifdef WITH_XSLT_DEBUG_VARIABLE + if (comp->type == XSLT_FUNC_PARAM) + xsltGenericDebug(xsltGenericDebugContext, + "Defining global param %s\n", name); + else + xsltGenericDebug(xsltGenericDebugContext, + "Defining global variable %s\n", name); +#endif + + elem = xsltNewStackElem(NULL); + if (elem == NULL) + return(-1); + elem->comp = comp; + elem->name = xmlDictLookup(style->dict, name, -1); + elem->select = xmlDictLookup(style->dict, sel, -1); + if (ns_uri) + elem->nameURI = xmlDictLookup(style->dict, ns_uri, -1); + elem->tree = tree; + tmp = style->variables; + while (tmp != NULL) { + if ((elem->comp->type == XSLT_FUNC_VARIABLE) && + (tmp->comp->type == XSLT_FUNC_VARIABLE) && + (xmlStrEqual(elem->name, tmp->name)) && + ((elem->nameURI == tmp->nameURI) || + (xmlStrEqual(elem->nameURI, tmp->nameURI)))) + { + xsltTransformError(NULL, style, comp->inst, + "redefinition of global variable %s\n", elem->name); + style->errors++; + } + tmp = tmp->next; + } + elem->next = style->variables;; + style->variables = elem; + if (value != NULL) { + elem->computed = 1; + elem->value = xmlXPathNewString(value); + } + return(0); +} + +/** + * xsltProcessUserParamInternal + * + * @ctxt: the XSLT transformation context + * @name: a null terminated parameter name + * @value: a null terminated value (may be an XPath expression) + * @eval: 0 to treat the value literally, else evaluate as XPath expression + * + * If @eval is 0 then @value is treated literally and is stored in the global + * parameter/variable table without any change. + * + * Uf @eval is 1 then @value is treated as an XPath expression and is + * evaluated. In this case, if you want to pass a string which will be + * interpreted literally then it must be enclosed in single or double quotes. + * If the string contains single quotes (double quotes) then it cannot be + * enclosed single quotes (double quotes). If the string which you want to + * be treated literally contains both single and double quotes (e.g. Meet + * at Joe's for "Twelfth Night" at 7 o'clock) then there is no suitable + * quoting character. You cannot use ' or " inside the string + * because the replacement of character entities with their equivalents is + * done at a different stage of processing. The solution is to call + * xsltQuoteUserParams or xsltQuoteOneUserParam. + * + * This needs to be done on parsed stylesheets before starting to apply + * transformations. Normally this will be called (directly or indirectly) + * only from xsltEvalUserParams, xsltEvalOneUserParam, xsltQuoteUserParams, + * or xsltQuoteOneUserParam. + * + * Returns 0 in case of success, -1 in case of error + */ + +static +int +xsltProcessUserParamInternal(xsltTransformContextPtr ctxt, + const xmlChar * name, + const xmlChar * value, + int eval) { + + xsltStylesheetPtr style; + const xmlChar *prefix; + const xmlChar *href; + xmlXPathCompExprPtr xpExpr; + xmlXPathObjectPtr result; + + xsltStackElemPtr elem; + int res; + void *res_ptr; + + if (ctxt == NULL) + return(-1); + if (name == NULL) + return(0); + if (value == NULL) + return(0); + + style = ctxt->style; + +#ifdef WITH_XSLT_DEBUG_VARIABLE + XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, + "Evaluating user parameter %s=%s\n", name, value)); +#endif + + /* + * Name lookup + */ + href = NULL; + + if (name[0] == '{') { + int len = 0; + + while ((name[len] != 0) && (name[len] != '}')) len++; + if (name[len] == 0) { + xsltTransformError(ctxt, style, NULL, + "user param : malformed parameter name : %s\n", name); + } else { + href = xmlDictLookup(ctxt->dict, &name[1], len-1); + name = xmlDictLookup(ctxt->dict, &name[len + 1], -1); + } + } + else { + name = xsltSplitQName(ctxt->dict, name, &prefix); + if (prefix != NULL) { + xmlNsPtr ns; + + ns = xmlSearchNs(style->doc, xmlDocGetRootElement(style->doc), + prefix); + if (ns == NULL) { + xsltTransformError(ctxt, style, NULL, + "user param : no namespace bound to prefix %s\n", prefix); + href = NULL; + } else { + href = ns->href; + } + } + } + + if (name == NULL) + return (-1); + + res_ptr = xmlHashLookup2(ctxt->globalVars, name, href); + if (res_ptr != 0) { + xsltTransformError(ctxt, style, NULL, + "Global parameter %s already defined\n", name); + } + if (ctxt->globalVars == NULL) + ctxt->globalVars = xmlHashCreate(20); + + /* + * do not overwrite variables with parameters from the command line + */ + while (style != NULL) { + elem = ctxt->style->variables; + while (elem != NULL) { + if ((elem->comp != NULL) && + (elem->comp->type == XSLT_FUNC_VARIABLE) && + (xmlStrEqual(elem->name, name)) && + (xmlStrEqual(elem->nameURI, href))) { + return(0); + } + elem = elem->next; + } + style = xsltNextImport(style); + } + style = ctxt->style; + elem = NULL; + + /* + * Do the evaluation if @eval is non-zero. + */ + + result = NULL; + if (eval != 0) { + xpExpr = xmlXPathCtxtCompile(ctxt->xpathCtxt, value); + if (xpExpr != NULL) { + xmlDocPtr oldXPDoc; + xmlNodePtr oldXPContextNode; + int oldXPProximityPosition, oldXPContextSize, oldXPNsNr; + xmlNsPtr *oldXPNamespaces; + xmlXPathContextPtr xpctxt = ctxt->xpathCtxt; + + /* + * Save context states. + */ + oldXPDoc = xpctxt->doc; + oldXPContextNode = xpctxt->node; + oldXPProximityPosition = xpctxt->proximityPosition; + oldXPContextSize = xpctxt->contextSize; + oldXPNamespaces = xpctxt->namespaces; + oldXPNsNr = xpctxt->nsNr; + + /* + * SPEC XSLT 1.0: + * "At top-level, the expression or template specifying the + * variable value is evaluated with the same context as that used + * to process the root node of the source document: the current + * node is the root node of the source document and the current + * node list is a list containing just the root node of the source + * document." + */ + xpctxt->doc = ctxt->initialContextDoc; + xpctxt->node = ctxt->initialContextNode; + xpctxt->contextSize = 1; + xpctxt->proximityPosition = 1; + /* + * There is really no in scope namespace for parameters on the + * command line. + */ + xpctxt->namespaces = NULL; + xpctxt->nsNr = 0; + + result = xmlXPathCompiledEval(xpExpr, xpctxt); + + /* + * Restore Context states. + */ + xpctxt->doc = oldXPDoc; + xpctxt->node = oldXPContextNode; + xpctxt->contextSize = oldXPContextSize; + xpctxt->proximityPosition = oldXPProximityPosition; + xpctxt->namespaces = oldXPNamespaces; + xpctxt->nsNr = oldXPNsNr; + + xmlXPathFreeCompExpr(xpExpr); + } + if (result == NULL) { + xsltTransformError(ctxt, style, NULL, + "Evaluating user parameter %s failed\n", name); + ctxt->state = XSLT_STATE_STOPPED; + return(-1); + } + } + + /* + * If @eval is 0 then @value is to be taken literally and result is NULL + * + * If @eval is not 0, then @value is an XPath expression and has been + * successfully evaluated and result contains the resulting value and + * is not NULL. + * + * Now create an xsltStackElemPtr for insertion into the context's + * global variable/parameter hash table. + */ + +#ifdef WITH_XSLT_DEBUG_VARIABLE +#ifdef LIBXML_DEBUG_ENABLED + if ((xsltGenericDebugContext == stdout) || + (xsltGenericDebugContext == stderr)) + xmlXPathDebugDumpObject((FILE *)xsltGenericDebugContext, + result, 0); +#endif +#endif + + elem = xsltNewStackElem(NULL); + if (elem != NULL) { + elem->name = name; + elem->select = xmlDictLookup(ctxt->dict, value, -1); + if (href != NULL) + elem->nameURI = xmlDictLookup(ctxt->dict, href, -1); + elem->tree = NULL; + elem->computed = 1; + if (eval == 0) { + elem->value = xmlXPathNewString(value); + } + else { + elem->value = result; + } + } + + /* + * Global parameters are stored in the XPath context variables pool. + */ + + res = xmlHashAddEntry2(ctxt->globalVars, name, href, elem); + if (res != 0) { + xsltFreeStackElem(elem); + xsltTransformError(ctxt, style, NULL, + "Global parameter %s already defined\n", name); + } + return(0); +} + +/** + * xsltEvalUserParams: + * + * @ctxt: the XSLT transformation context + * @params: a NULL terminated array of parameters name/value tuples + * + * Evaluate the global variables of a stylesheet. This needs to be + * done on parsed stylesheets before starting to apply transformations. + * Each of the parameters is evaluated as an XPath expression and stored + * in the global variables/parameter hash table. If you want your + * parameter used literally, use xsltQuoteUserParams. + * + * Returns 0 in case of success, -1 in case of error + */ + +int +xsltEvalUserParams(xsltTransformContextPtr ctxt, const char **params) { + size_t indx = 0; + const xmlChar *name; + const xmlChar *value; + + if (params == NULL) + return(0); + while (params[indx] != NULL) { + name = (const xmlChar *) params[indx++]; + value = (const xmlChar *) params[indx++]; + if (xsltEvalOneUserParam(ctxt, name, value) != 0) + return(-1); + } + return 0; +} + +/** + * xsltQuoteUserParams: + * + * @ctxt: the XSLT transformation context + * @params: a NULL terminated arry of parameters names/values tuples + * + * Similar to xsltEvalUserParams, but the values are treated literally and + * are * *not* evaluated as XPath expressions. This should be done on parsed + * stylesheets before starting to apply transformations. + * + * Returns 0 in case of success, -1 in case of error. + */ + +int +xsltQuoteUserParams(xsltTransformContextPtr ctxt, const char **params) { + size_t indx = 0; + const xmlChar *name; + const xmlChar *value; + + if (params == NULL) + return(0); + while (params[indx] != NULL) { + name = (const xmlChar *) params[indx++]; + value = (const xmlChar *) params[indx++]; + if (xsltQuoteOneUserParam(ctxt, name, value) != 0) + return(-1); + } + return 0; +} + +/** + * xsltEvalOneUserParam: + * @ctxt: the XSLT transformation context + * @name: a null terminated string giving the name of the parameter + * @value: a null terminated string giving the XPath expression to be evaluated + * + * This is normally called from xsltEvalUserParams to process a single + * parameter from a list of parameters. The @value is evaluated as an + * XPath expression and the result is stored in the context's global + * variable/parameter hash table. + * + * To have a parameter treated literally (not as an XPath expression) + * use xsltQuoteUserParams (or xsltQuoteOneUserParam). For more + * details see description of xsltProcessOneUserParamInternal. + * + * Returns 0 in case of success, -1 in case of error. + */ + +int +xsltEvalOneUserParam(xsltTransformContextPtr ctxt, + const xmlChar * name, + const xmlChar * value) { + return xsltProcessUserParamInternal(ctxt, name, value, + 1 /* xpath eval ? */); +} + +/** + * xsltQuoteOneUserParam: + * @ctxt: the XSLT transformation context + * @name: a null terminated string giving the name of the parameter + * @value: a null terminated string giving the parameter value + * + * This is normally called from xsltQuoteUserParams to process a single + * parameter from a list of parameters. The @value is stored in the + * context's global variable/parameter hash table. + * + * Returns 0 in case of success, -1 in case of error. + */ + +int +xsltQuoteOneUserParam(xsltTransformContextPtr ctxt, + const xmlChar * name, + const xmlChar * value) { + return xsltProcessUserParamInternal(ctxt, name, value, + 0 /* xpath eval ? */); +} + +/** + * xsltBuildVariable: + * @ctxt: the XSLT transformation context + * @comp: the precompiled form + * @tree: the tree if select is NULL + * + * Computes a new variable value. + * + * Returns the xsltStackElemPtr or NULL in case of error + */ +static xsltStackElemPtr +xsltBuildVariable(xsltTransformContextPtr ctxt, + xsltStylePreCompPtr castedComp, + xmlNodePtr tree) +{ +#ifdef XSLT_REFACTORED + xsltStyleBasicItemVariablePtr comp = + (xsltStyleBasicItemVariablePtr) castedComp; +#else + xsltStylePreCompPtr comp = castedComp; +#endif + xsltStackElemPtr elem; + +#ifdef WITH_XSLT_DEBUG_VARIABLE + XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, + "Building variable %s", comp->name)); + if (comp->select != NULL) + XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, + " select %s", comp->select)); + XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, "\n")); +#endif + + elem = xsltNewStackElem(ctxt); + if (elem == NULL) + return(NULL); + elem->comp = (xsltStylePreCompPtr) comp; + elem->name = comp->name; + elem->select = comp->select; + elem->nameURI = comp->ns; + elem->tree = tree; + elem->value = xsltEvalVariable(ctxt, elem, + (xsltStylePreCompPtr) comp); + elem->computed = 1; + return(elem); +} + +/** + * xsltRegisterVariable: + * @ctxt: the XSLT transformation context + * @comp: the compiled XSLT-variable (or param) instruction + * @tree: the tree if select is NULL + * @isParam: indicates if this is a parameter + * + * Computes and registers a new variable. + * + * Returns 0 in case of success, -1 in case of error + */ +static int +xsltRegisterVariable(xsltTransformContextPtr ctxt, + xsltStylePreCompPtr castedComp, + xmlNodePtr tree, int isParam) +{ +#ifdef XSLT_REFACTORED + xsltStyleBasicItemVariablePtr comp = + (xsltStyleBasicItemVariablePtr) castedComp; +#else + xsltStylePreCompPtr comp = castedComp; + int present; +#endif + xsltStackElemPtr variable; + +#ifdef XSLT_REFACTORED + /* + * REFACTORED NOTE: Redefinitions of vars/params are checked + * at compilation time in the refactored code. + * xsl:with-param parameters are checked in xsltApplyXSLTTemplate(). + */ +#else + present = xsltCheckStackElem(ctxt, comp->name, comp->ns); + if (isParam == 0) { + if ((present != 0) && (present != 3)) { + /* TODO: report QName. */ + xsltTransformError(ctxt, NULL, comp->inst, + "XSLT-variable: Redefinition of variable '%s'.\n", comp->name); + return(0); + } + } else if (present != 0) { + if ((present == 1) || (present == 2)) { + /* TODO: report QName. */ + xsltTransformError(ctxt, NULL, comp->inst, + "XSLT-param: Redefinition of parameter '%s'.\n", comp->name); + return(0); + } +#ifdef WITH_XSLT_DEBUG_VARIABLE + XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, + "param %s defined by caller\n", comp->name)); +#endif + return(0); + } +#endif /* else of XSLT_REFACTORED */ + + variable = xsltBuildVariable(ctxt, (xsltStylePreCompPtr) comp, tree); + if (xsltAddStackElem(ctxt, variable) < 0) { + xsltFreeStackElem(variable); + return(-1); + } + return(0); +} + +/** + * xsltGlobalVariableLookup: + * @ctxt: the XSLT transformation context + * @name: the variable name + * @ns_uri: the variable namespace URI + * + * Search in the Variable array of the context for the given + * variable value. + * + * Returns the value or NULL if not found + */ +static xmlXPathObjectPtr +xsltGlobalVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name, + const xmlChar *ns_uri) { + xsltStackElemPtr elem; + xmlXPathObjectPtr ret = NULL; + + /* + * Lookup the global variables in XPath global variable hash table + */ + if ((ctxt->xpathCtxt == NULL) || (ctxt->globalVars == NULL)) + return(NULL); + elem = (xsltStackElemPtr) + xmlHashLookup2(ctxt->globalVars, name, ns_uri); + if (elem == NULL) { +#ifdef WITH_XSLT_DEBUG_VARIABLE + XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, + "global variable not found %s\n", name)); +#endif + return(NULL); + } + /* + * URGENT TODO: Move the detection of recursive definitions + * to compile-time. + */ + if (elem->computed == 0) { + if (elem->name == xsltComputingGlobalVarMarker) { + xsltTransformError(ctxt, NULL, elem->comp->inst, + "Recursive definition of %s\n", name); + return(NULL); + } + ret = xsltEvalGlobalVariable(elem, ctxt); + } else + ret = elem->value; + return(xmlXPathObjectCopy(ret)); +} + +/** + * xsltVariableLookup: + * @ctxt: the XSLT transformation context + * @name: the variable name + * @ns_uri: the variable namespace URI + * + * Search in the Variable array of the context for the given + * variable value. + * + * Returns the value or NULL if not found + */ +xmlXPathObjectPtr +xsltVariableLookup(xsltTransformContextPtr ctxt, const xmlChar *name, + const xmlChar *ns_uri) { + xsltStackElemPtr elem; + + if (ctxt == NULL) + return(NULL); + + elem = xsltStackLookup(ctxt, name, ns_uri); + if (elem == NULL) { + return(xsltGlobalVariableLookup(ctxt, name, ns_uri)); + } + if (elem->computed == 0) { +#ifdef WITH_XSLT_DEBUG_VARIABLE + XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, + "uncomputed variable %s\n", name)); +#endif + elem->value = xsltEvalVariable(ctxt, elem, NULL); + elem->computed = 1; + } + if (elem->value != NULL) + return(xmlXPathObjectCopy(elem->value)); +#ifdef WITH_XSLT_DEBUG_VARIABLE + XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, + "variable not found %s\n", name)); +#endif + return(NULL); +} + +/** + * xsltParseStylesheetCallerParam: + * @ctxt: the XSLT transformation context + * @inst: the xsl:with-param instruction element + * + * Processes an xsl:with-param instruction at transformation time. + * The value is computed, but not recorded. + * NOTE that this is also called with an *xsl:param* element + * from exsltFuncFunctionFunction(). + * + * Returns the new xsltStackElemPtr or NULL + */ + +xsltStackElemPtr +xsltParseStylesheetCallerParam(xsltTransformContextPtr ctxt, xmlNodePtr inst) +{ +#ifdef XSLT_REFACTORED + xsltStyleBasicItemVariablePtr comp; +#else + xsltStylePreCompPtr comp; +#endif + xmlNodePtr tree = NULL; /* The first child node of the instruction or + the instruction itself. */ + xsltStackElemPtr param = NULL; + + if ((ctxt == NULL) || (inst == NULL) || (inst->type != XML_ELEMENT_NODE)) + return(NULL); + +#ifdef XSLT_REFACTORED + comp = (xsltStyleBasicItemVariablePtr) inst->psvi; +#else + comp = (xsltStylePreCompPtr) inst->psvi; +#endif + + if (comp == NULL) { + xsltTransformError(ctxt, NULL, inst, + "Internal error in xsltParseStylesheetCallerParam(): " + "The XSLT 'with-param' instruction was not compiled.\n"); + return(NULL); + } + if (comp->name == NULL) { + xsltTransformError(ctxt, NULL, inst, + "Internal error in xsltParseStylesheetCallerParam(): " + "XSLT 'with-param': The attribute 'name' was not compiled.\n"); + return(NULL); + } + +#ifdef WITH_XSLT_DEBUG_VARIABLE + XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, + "Handling xsl:with-param %s\n", comp->name)); +#endif + + if (comp->select == NULL) { + tree = inst->children; + } else { +#ifdef WITH_XSLT_DEBUG_VARIABLE + XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, + " select %s\n", comp->select)); +#endif + tree = inst; + } + + param = xsltBuildVariable(ctxt, (xsltStylePreCompPtr) comp, tree); + + return(param); +} + +/** + * xsltParseGlobalVariable: + * @style: the XSLT stylesheet + * @cur: the "variable" element + * + * Parses a global XSLT 'variable' declaration at compilation time + * and registers it + */ +void +xsltParseGlobalVariable(xsltStylesheetPtr style, xmlNodePtr cur) +{ +#ifdef XSLT_REFACTORED + xsltStyleItemVariablePtr comp; +#else + xsltStylePreCompPtr comp; +#endif + + if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE)) + return; + +#ifdef XSLT_REFACTORED + /* + * Note that xsltStylePreCompute() will be called from + * xslt.c only. + */ + comp = (xsltStyleItemVariablePtr) cur->psvi; +#else + xsltStylePreCompute(style, cur); + comp = (xsltStylePreCompPtr) cur->psvi; +#endif + if (comp == NULL) { + xsltTransformError(NULL, style, cur, + "xsl:variable : compilation failed\n"); + return; + } + + if (comp->name == NULL) { + xsltTransformError(NULL, style, cur, + "xsl:variable : missing name attribute\n"); + return; + } + + /* + * Parse the content (a sequence constructor) of xsl:variable. + */ + if (cur->children != NULL) { +#ifdef XSLT_REFACTORED + xsltParseSequenceConstructor(XSLT_CCTXT(style), cur->children); +#else + xsltParseTemplateContent(style, cur); +#endif + } +#ifdef WITH_XSLT_DEBUG_VARIABLE + xsltGenericDebug(xsltGenericDebugContext, + "Registering global variable %s\n", comp->name); +#endif + + xsltRegisterGlobalVariable(style, comp->name, comp->ns, + comp->select, cur->children, (xsltStylePreCompPtr) comp, + NULL); +} + +/** + * xsltParseGlobalParam: + * @style: the XSLT stylesheet + * @cur: the "param" element + * + * parse an XSLT transformation param declaration and record + * its value. + */ + +void +xsltParseGlobalParam(xsltStylesheetPtr style, xmlNodePtr cur) { +#ifdef XSLT_REFACTORED + xsltStyleItemParamPtr comp; +#else + xsltStylePreCompPtr comp; +#endif + + if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE)) + return; + +#ifdef XSLT_REFACTORED + /* + * Note that xsltStylePreCompute() will be called from + * xslt.c only. + */ + comp = (xsltStyleItemParamPtr) cur->psvi; +#else + xsltStylePreCompute(style, cur); + comp = (xsltStylePreCompPtr) cur->psvi; +#endif + if (comp == NULL) { + xsltTransformError(NULL, style, cur, + "xsl:param : compilation failed\n"); + return; + } + + if (comp->name == NULL) { + xsltTransformError(NULL, style, cur, + "xsl:param : missing name attribute\n"); + return; + } + + /* + * Parse the content (a sequence constructor) of xsl:param. + */ + if (cur->children != NULL) { +#ifdef XSLT_REFACTORED + xsltParseSequenceConstructor(XSLT_CCTXT(style), cur->children); +#else + xsltParseTemplateContent(style, cur); +#endif + } + +#ifdef WITH_XSLT_DEBUG_VARIABLE + xsltGenericDebug(xsltGenericDebugContext, + "Registering global param %s\n", comp->name); +#endif + + xsltRegisterGlobalVariable(style, comp->name, comp->ns, + comp->select, cur->children, (xsltStylePreCompPtr) comp, + NULL); +} + +/** + * xsltParseStylesheetVariable: + * @ctxt: the XSLT transformation context + * @inst: the xsl:variable instruction element + * + * Registers a local XSLT 'variable' instruction at transformation time + * and evaluates its value. + */ +void +xsltParseStylesheetVariable(xsltTransformContextPtr ctxt, xmlNodePtr inst) +{ +#ifdef XSLT_REFACTORED + xsltStyleItemVariablePtr comp; +#else + xsltStylePreCompPtr comp; +#endif + + if ((inst == NULL) || (ctxt == NULL) || (inst->type != XML_ELEMENT_NODE)) + return; + + comp = inst->psvi; + if (comp == NULL) { + xsltTransformError(ctxt, NULL, inst, + "Internal error in xsltParseStylesheetVariable(): " + "The XSLT 'variable' instruction was not compiled.\n"); + return; + } + if (comp->name == NULL) { + xsltTransformError(ctxt, NULL, inst, + "Internal error in xsltParseStylesheetVariable(): " + "The attribute 'name' was not compiled.\n"); + return; + } + +#ifdef WITH_XSLT_DEBUG_VARIABLE + XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, + "Registering variable '%s'\n", comp->name)); +#endif + + xsltRegisterVariable(ctxt, (xsltStylePreCompPtr) comp, inst->children, 0); +} + +/** + * xsltParseStylesheetParam: + * @ctxt: the XSLT transformation context + * @cur: the XSLT 'param' element + * + * Registers a local XSLT 'param' declaration at transformation time and + * evaluates its value. + */ +void +xsltParseStylesheetParam(xsltTransformContextPtr ctxt, xmlNodePtr cur) +{ +#ifdef XSLT_REFACTORED + xsltStyleItemParamPtr comp; +#else + xsltStylePreCompPtr comp; +#endif + + if ((cur == NULL) || (ctxt == NULL) || (cur->type != XML_ELEMENT_NODE)) + return; + + comp = cur->psvi; + if ((comp == NULL) || (comp->name == NULL)) { + xsltTransformError(ctxt, NULL, cur, + "Internal error in xsltParseStylesheetParam(): " + "The XSLT 'param' declaration was not compiled correctly.\n"); + return; + } + +#ifdef WITH_XSLT_DEBUG_VARIABLE + XSLT_TRACE(ctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, + "Registering param %s\n", comp->name)); +#endif + + xsltRegisterVariable(ctxt, (xsltStylePreCompPtr) comp, cur->children, 1); +} + +/** + * xsltFreeGlobalVariables: + * @ctxt: the XSLT transformation context + * + * Free up the data associated to the global variables + * its value. + */ + +void +xsltFreeGlobalVariables(xsltTransformContextPtr ctxt) { + xmlHashFree(ctxt->globalVars, xsltFreeStackElemEntry); +} + +/** + * xsltXPathVariableLookup: + * @ctxt: a void * but the the XSLT transformation context actually + * @name: the variable name + * @ns_uri: the variable namespace URI + * + * This is the entry point when a varibale is needed by the XPath + * interpretor. + * + * Returns the value or NULL if not found + */ +xmlXPathObjectPtr +xsltXPathVariableLookup(void *ctxt, const xmlChar *name, + const xmlChar *ns_uri) { + xsltTransformContextPtr tctxt; + xmlXPathObjectPtr valueObj = NULL; + + if ((ctxt == NULL) || (name == NULL)) + return(NULL); + +#ifdef WITH_XSLT_DEBUG_VARIABLE + XSLT_TRACE(((xsltTransformContextPtr)ctxt),XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, + "Lookup variable '%s'\n", name)); +#endif + + tctxt = (xsltTransformContextPtr) ctxt; + /* + * Local variables/params --------------------------------------------- + * + * Do the lookup from the top of the stack, but + * don't use params being computed in a call-param + * First lookup expects the variable name and URI to + * come from the disctionnary and hence pointer comparison. + */ + if (tctxt->varsNr != 0) { + int i; + xsltStackElemPtr variable = NULL, cur; + + for (i = tctxt->varsNr; i > tctxt->varsBase; i--) { + cur = tctxt->varsTab[i-1]; + if ((cur->name == name) && (cur->nameURI == ns_uri)) { + variable = cur; + goto local_variable_found; + } + cur = cur->next; + } + /* + * Redo the lookup with interned strings to avoid string comparison. + * + * OPTIMIZE TODO: The problem here is, that if we request a + * global variable, then this will be also executed. + */ + { + const xmlChar *tmpName = name, *tmpNsName = ns_uri; + + name = xmlDictLookup(tctxt->dict, name, -1); + if (ns_uri) + ns_uri = xmlDictLookup(tctxt->dict, ns_uri, -1); + if ((tmpName != name) || (tmpNsName != ns_uri)) { + for (i = tctxt->varsNr; i > tctxt->varsBase; i--) { + cur = tctxt->varsTab[i-1]; + if ((cur->name == name) && (cur->nameURI == ns_uri)) { + variable = cur; + goto local_variable_found; + } + } + } + } + +local_variable_found: + + if (variable) { + if (variable->computed == 0) { + +#ifdef WITH_XSLT_DEBUG_VARIABLE + XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, + "uncomputed variable '%s'\n", name)); +#endif + variable->value = xsltEvalVariable(tctxt, variable, NULL); + variable->computed = 1; + } + if (variable->value != NULL) { + valueObj = xmlXPathObjectCopy(variable->value); + } + return(valueObj); + } + } + /* + * Global variables/params -------------------------------------------- + */ + if (tctxt->globalVars) { + valueObj = xsltGlobalVariableLookup(tctxt, name, ns_uri); + } + + if (valueObj == NULL) { + +#ifdef WITH_XSLT_DEBUG_VARIABLE + XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, + "variable not found '%s'\n", name)); +#endif + + if (ns_uri) { + xsltTransformError(tctxt, NULL, tctxt->inst, + "Variable '{%s}%s' has not been declared.\n", ns_uri, name); + } else { + xsltTransformError(tctxt, NULL, tctxt->inst, + "Variable '%s' has not been declared.\n", name); + } + } else { + +#ifdef WITH_XSLT_DEBUG_VARIABLE + XSLT_TRACE(tctxt,XSLT_TRACE_VARIABLES,xsltGenericDebug(xsltGenericDebugContext, + "found variable '%s'\n", name)); +#endif + } + + return(valueObj); +} diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/variables.h chromium-145.0.7632.159/third_party/libxslt/src/libxslt/variables.h --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/variables.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/variables.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,118 @@ +/* + * Summary: interface for the variable matching and lookup. + * Description: interface for the variable matching and lookup. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLT_VARIABLES_H__ +#define __XML_XSLT_VARIABLES_H__ + +#include +#include +#include "xsltexports.h" +#include "xsltInternals.h" +#include "functions.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * XSLT_REGISTER_VARIABLE_LOOKUP: + * + * Registering macro, not general purpose at all but used in different modules. + */ + +#define XSLT_REGISTER_VARIABLE_LOOKUP(ctxt) \ + xmlXPathRegisterVariableLookup((ctxt)->xpathCtxt, \ + xsltXPathVariableLookup, (void *)(ctxt)); \ + xsltRegisterAllFunctions((ctxt)->xpathCtxt); \ + xsltRegisterAllElement(ctxt); \ + (ctxt)->xpathCtxt->extra = ctxt + +/* + * Flags for memory management of RVTs + */ + +/** + * XSLT_RVT_LOCAL: + * + * RVT is destroyed after the current instructions ends. + */ +#define XSLT_RVT_LOCAL 1 + +/** + * XSLT_RVT_FUNC_RESULT: + * + * RVT is part of results returned with func:result. The RVT won't be + * destroyed after exiting a template and will be reset to XSLT_RVT_LOCAL or + * XSLT_RVT_VARIABLE in the template that receives the return value. + */ +#define XSLT_RVT_FUNC_RESULT 2 + +/** + * XSLT_RVT_GLOBAL: + * + * RVT is part of a global variable. + */ +#define XSLT_RVT_GLOBAL 3 + +/* + * Interfaces for the variable module. + */ + +XSLTPUBFUN int XSLTCALL + xsltEvalGlobalVariables (xsltTransformContextPtr ctxt); +XSLTPUBFUN int XSLTCALL + xsltEvalUserParams (xsltTransformContextPtr ctxt, + const char **params); +XSLTPUBFUN int XSLTCALL + xsltQuoteUserParams (xsltTransformContextPtr ctxt, + const char **params); +XSLTPUBFUN int XSLTCALL + xsltEvalOneUserParam (xsltTransformContextPtr ctxt, + const xmlChar * name, + const xmlChar * value); +XSLTPUBFUN int XSLTCALL + xsltQuoteOneUserParam (xsltTransformContextPtr ctxt, + const xmlChar * name, + const xmlChar * value); + +XSLTPUBFUN void XSLTCALL + xsltParseGlobalVariable (xsltStylesheetPtr style, + xmlNodePtr cur); +XSLTPUBFUN void XSLTCALL + xsltParseGlobalParam (xsltStylesheetPtr style, + xmlNodePtr cur); +XSLTPUBFUN void XSLTCALL + xsltParseStylesheetVariable (xsltTransformContextPtr ctxt, + xmlNodePtr cur); +XSLTPUBFUN void XSLTCALL + xsltParseStylesheetParam (xsltTransformContextPtr ctxt, + xmlNodePtr cur); +XSLTPUBFUN xsltStackElemPtr XSLTCALL + xsltParseStylesheetCallerParam (xsltTransformContextPtr ctxt, + xmlNodePtr cur); +XSLTPUBFUN int XSLTCALL + xsltAddStackElemList (xsltTransformContextPtr ctxt, + xsltStackElemPtr elems); +XSLTPUBFUN void XSLTCALL + xsltFreeGlobalVariables (xsltTransformContextPtr ctxt); +XSLTPUBFUN xmlXPathObjectPtr XSLTCALL + xsltVariableLookup (xsltTransformContextPtr ctxt, + const xmlChar *name, + const xmlChar *ns_uri); +XSLTPUBFUN xmlXPathObjectPtr XSLTCALL + xsltXPathVariableLookup (void *ctxt, + const xmlChar *name, + const xmlChar *ns_uri); +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_VARIABLES_H__ */ + diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/win32config.h chromium-145.0.7632.159/third_party/libxslt/src/libxslt/win32config.h --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/win32config.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/win32config.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,53 @@ +/* + * Summary: Windows configuration header + * Description: Windows configuration header + * + * Copy: See Copyright for the status of this software. + * + * Author: Igor Zlatkovic + */ +#ifndef __LIBXSLT_WIN32_CONFIG__ +#define __LIBXSLT_WIN32_CONFIG__ + +#define MODULE_EXTENSION ".dll" + +/* snprintf emulation taken from http://stackoverflow.com/a/8712996/1956010 */ +#if defined(_MSC_VER) && _MSC_VER < 1900 + +#include +#include + +#define snprintf c99_snprintf +#define vsnprintf c99_vsnprintf + +__inline int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) +{ + int count = -1; + + if (size != 0) + count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap); + if (count == -1) + count = _vscprintf(format, ap); + + return count; +} + +__inline int c99_snprintf(char *outBuf, size_t size, const char *format, ...) +{ + int count; + va_list ap; + + va_start(ap, format); + count = c99_vsnprintf(outBuf, size, format, ap); + va_end(ap); + + return count; +} + +#endif /* defined(_MSC_VER) && _MSC_VER < 1900 */ + +#define HAVE_SYS_STAT_H +#define HAVE__STAT + +#endif /* __LIBXSLT_WIN32_CONFIG__ */ + diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/xslt.c chromium-145.0.7632.159/third_party/libxslt/src/libxslt/xslt.c --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/xslt.c 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/xslt.c 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,7066 @@ +/* + * xslt.c: Implemetation of an XSL Transformation 1.0 engine + * + * Reference: + * XSLT specification + * http://www.w3.org/TR/1999/REC-xslt-19991116 + * + * Associating Style Sheets with XML documents + * http://www.w3.org/1999/06/REC-xml-stylesheet-19990629 + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#define IN_LIBXSLT +#include "libxslt.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xslt.h" +#include "xsltInternals.h" +#include "pattern.h" +#include "variables.h" +#include "namespaces.h" +#include "attributes.h" +#include "xsltutils.h" +#include "imports.h" +#include "keys.h" +#include "documents.h" +#include "extensions.h" +#include "preproc.h" +#include "extra.h" +#include "security.h" +#include "xsltlocale.h" + +#ifdef WITH_XSLT_DEBUG +#define WITH_XSLT_DEBUG_PARSING +/* #define WITH_XSLT_DEBUG_BLANKS */ +#endif + +const char *xsltEngineVersion = LIBXSLT_VERSION_STRING LIBXSLT_VERSION_EXTRA; +const int xsltLibxsltVersion = LIBXSLT_VERSION; +const int xsltLibxmlVersion = LIBXML_VERSION; + +#ifdef XSLT_REFACTORED + +const xmlChar *xsltConstNamespaceNameXSLT = (const xmlChar *) XSLT_NAMESPACE; + +#define XSLT_ELEMENT_CATEGORY_XSLT 0 +#define XSLT_ELEMENT_CATEGORY_EXTENSION 1 +#define XSLT_ELEMENT_CATEGORY_LRE 2 + +/* +* xsltLiteralResultMarker: +* Marker for Literal result elements, in order to avoid multiple attempts +* to recognize such elements in the stylesheet's tree. +* This marker is set on node->psvi during the initial traversal +* of a stylesheet's node tree. +* +const xmlChar *xsltLiteralResultMarker = + (const xmlChar *) "Literal Result Element"; +*/ + +/* +* xsltXSLTTextMarker: +* Marker for xsl:text elements. Used to recognize xsl:text elements +* for post-processing of the stylesheet's tree, where those +* elements are removed from the tree. +*/ +const xmlChar *xsltXSLTTextMarker = (const xmlChar *) "XSLT Text Element"; + +/* +* xsltXSLTAttrMarker: +* Marker for XSLT attribute on Literal Result Elements. +*/ +const xmlChar *xsltXSLTAttrMarker = (const xmlChar *) "LRE XSLT Attr"; + +#endif + +#ifdef XSLT_LOCALE_WINAPI +extern xmlRMutexPtr xsltLocaleMutex; +#endif + +/* + * Useful macros + */ + +#ifdef IS_BLANK +#undef IS_BLANK +#endif +#define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || \ + ((c) == 0x0D)) + +#ifdef IS_BLANK_NODE +#undef IS_BLANK_NODE +#endif +#define IS_BLANK_NODE(n) \ + (((n)->type == XML_TEXT_NODE) && (xsltIsBlank((n)->content))) + +/** + * xsltParseContentError: + * + * @style: the stylesheet + * @node: the node where the error occured + * + * Compile-time error function. + */ +static void +xsltParseContentError(xsltStylesheetPtr style, + xmlNodePtr node) +{ + if ((style == NULL) || (node == NULL)) + return; + + if (IS_XSLT_ELEM(node)) + xsltTransformError(NULL, style, node, + "The XSLT-element '%s' is not allowed at this position.\n", + node->name); + else + xsltTransformError(NULL, style, node, + "The element '%s' is not allowed at this position.\n", + node->name); + style->errors++; +} + +#ifdef XSLT_REFACTORED +#else +/** + * exclPrefixPush: + * @style: the transformation stylesheet + * @value: the excluded namespace name to push on the stack + * + * Push an excluded namespace name on the stack + * + * Returns the new index in the stack or -1 if already present or + * in case of error + */ +static int +exclPrefixPush(xsltStylesheetPtr style, xmlChar * orig) +{ + xmlChar *value; + int i; + + /* + * orig can come from a namespace definition on a node which + * could be deleted later, for example in xsltParseTemplateContent. + * Store the string in stylesheet's dict to avoid use after free. + */ + value = (xmlChar *) xmlDictLookup(style->dict, orig, -1); + if (value == NULL) + return(-1); + + /* do not push duplicates */ + for (i = 0;i < style->exclPrefixNr;i++) { + if (xmlStrEqual(style->exclPrefixTab[i], value)) + return(-1); + } + if (style->exclPrefixNr >= style->exclPrefixMax) { + xmlChar **tmp; + size_t max = style->exclPrefixMax ? style->exclPrefixMax * 2 : 4; + + tmp = xmlRealloc(style->exclPrefixTab, + max * sizeof(style->exclPrefixTab[0])); + if (tmp == NULL) { + xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); + return (-1); + } + style->exclPrefixTab = tmp; + style->exclPrefixMax = max; + } + style->exclPrefixTab[style->exclPrefixNr] = value; + style->exclPrefix = value; + return (style->exclPrefixNr++); +} +/** + * exclPrefixPop: + * @style: the transformation stylesheet + * + * Pop an excluded prefix value from the stack + * + * Returns the stored excluded prefix value + */ +static xmlChar * +exclPrefixPop(xsltStylesheetPtr style) +{ + xmlChar *ret; + + if (style->exclPrefixNr <= 0) + return (0); + style->exclPrefixNr--; + if (style->exclPrefixNr > 0) + style->exclPrefix = style->exclPrefixTab[style->exclPrefixNr - 1]; + else + style->exclPrefix = NULL; + ret = style->exclPrefixTab[style->exclPrefixNr]; + style->exclPrefixTab[style->exclPrefixNr] = 0; + return (ret); +} +#endif + +/************************************************************************ + * * + * Helper functions * + * * + ************************************************************************/ + +static int initialized = 0; +/** + * xsltInit: + * + * Initializes the processor (e.g. registers built-in extensions, + * etc.) + */ +void +xsltInit (void) { + if (initialized == 0) { + initialized = 1; +#ifdef XSLT_LOCALE_WINAPI + xsltLocaleMutex = xmlNewRMutex(); +#endif + xsltRegisterAllExtras(); + } +} + +/** + * xsltUninit: + * + * Uninitializes the processor. + */ +void +xsltUninit (void) { +#ifdef XSLT_LOCALE_WINAPI + xmlFreeRMutex(xsltLocaleMutex); + xsltLocaleMutex = NULL; +#endif + initialized = 0; +} + +/** + * xsltIsBlank: + * @str: a string + * + * Check if a string is ignorable + * + * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise + */ +int +xsltIsBlank(xmlChar *str) { + if (str == NULL) + return(1); + while (*str != 0) { + if (!(IS_BLANK(*str))) return(0); + str++; + } + return(1); +} + +/************************************************************************ + * * + * Routines to handle XSLT data structures * + * * + ************************************************************************/ +static xsltDecimalFormatPtr +xsltNewDecimalFormat(const xmlChar *nsUri, xmlChar *name) +{ + xsltDecimalFormatPtr self; + /* UTF-8 for 0x2030 */ + static const xmlChar permille[4] = {0xe2, 0x80, 0xb0, 0}; + + self = xmlMalloc(sizeof(xsltDecimalFormat)); + if (self != NULL) { + self->next = NULL; + self->nsUri = nsUri; + self->name = name; + + /* Default values */ + self->digit = xmlStrdup(BAD_CAST("#")); + self->patternSeparator = xmlStrdup(BAD_CAST(";")); + self->decimalPoint = xmlStrdup(BAD_CAST(".")); + self->grouping = xmlStrdup(BAD_CAST(",")); + self->percent = xmlStrdup(BAD_CAST("%")); + self->permille = xmlStrdup(BAD_CAST(permille)); + self->zeroDigit = xmlStrdup(BAD_CAST("0")); + self->minusSign = xmlStrdup(BAD_CAST("-")); + self->infinity = xmlStrdup(BAD_CAST("Infinity")); + self->noNumber = xmlStrdup(BAD_CAST("NaN")); + } + return self; +} + +static void +xsltFreeDecimalFormat(xsltDecimalFormatPtr self) +{ + if (self != NULL) { + if (self->digit) + xmlFree(self->digit); + if (self->patternSeparator) + xmlFree(self->patternSeparator); + if (self->decimalPoint) + xmlFree(self->decimalPoint); + if (self->grouping) + xmlFree(self->grouping); + if (self->percent) + xmlFree(self->percent); + if (self->permille) + xmlFree(self->permille); + if (self->zeroDigit) + xmlFree(self->zeroDigit); + if (self->minusSign) + xmlFree(self->minusSign); + if (self->infinity) + xmlFree(self->infinity); + if (self->noNumber) + xmlFree(self->noNumber); + if (self->name) + xmlFree(self->name); + xmlFree(self); + } +} + +static void +xsltFreeDecimalFormatList(xsltStylesheetPtr self) +{ + xsltDecimalFormatPtr iter; + xsltDecimalFormatPtr tmp; + + if (self == NULL) + return; + + iter = self->decimalFormat; + while (iter != NULL) { + tmp = iter->next; + xsltFreeDecimalFormat(iter); + iter = tmp; + } +} + +/** + * xsltDecimalFormatGetByName: + * @style: the XSLT stylesheet + * @name: the decimal-format name to find + * + * Find decimal-format by name + * + * Returns the xsltDecimalFormatPtr + */ +xsltDecimalFormatPtr +xsltDecimalFormatGetByName(xsltStylesheetPtr style, xmlChar *name) +{ + xsltDecimalFormatPtr result = NULL; + + if (name == NULL) + return style->decimalFormat; + + while (style != NULL) { + for (result = style->decimalFormat->next; + result != NULL; + result = result->next) { + if ((result->nsUri == NULL) && xmlStrEqual(name, result->name)) + return result; + } + style = xsltNextImport(style); + } + return result; +} + +/** + * xsltDecimalFormatGetByQName: + * @style: the XSLT stylesheet + * @nsUri: the namespace URI of the QName + * @name: the local part of the QName + * + * Find decimal-format by QName + * + * Returns the xsltDecimalFormatPtr + */ +xsltDecimalFormatPtr +xsltDecimalFormatGetByQName(xsltStylesheetPtr style, const xmlChar *nsUri, + const xmlChar *name) +{ + xsltDecimalFormatPtr result = NULL; + + if (name == NULL) + return style->decimalFormat; + + while (style != NULL) { + for (result = style->decimalFormat->next; + result != NULL; + result = result->next) { + if (xmlStrEqual(nsUri, result->nsUri) && + xmlStrEqual(name, result->name)) + return result; + } + style = xsltNextImport(style); + } + return result; +} + + +/** + * xsltNewTemplate: + * + * Create a new XSLT Template + * + * Returns the newly allocated xsltTemplatePtr or NULL in case of error + */ +static xsltTemplatePtr +xsltNewTemplate(void) { + xsltTemplatePtr cur; + + cur = (xsltTemplatePtr) xmlMalloc(sizeof(xsltTemplate)); + if (cur == NULL) { + xsltTransformError(NULL, NULL, NULL, + "xsltNewTemplate : malloc failed\n"); + return(NULL); + } + memset(cur, 0, sizeof(xsltTemplate)); + cur->priority = XSLT_PAT_NO_PRIORITY; + return(cur); +} + +/** + * xsltFreeTemplate: + * @template: an XSLT template + * + * Free up the memory allocated by @template + */ +static void +xsltFreeTemplate(xsltTemplatePtr template) { + if (template == NULL) + return; + if (template->match) xmlFree(template->match); +/* +* NOTE: @name and @nameURI are put into the string dict now. +* if (template->name) xmlFree(template->name); +* if (template->nameURI) xmlFree(template->nameURI); +*/ +/* + if (template->mode) xmlFree(template->mode); + if (template->modeURI) xmlFree(template->modeURI); + */ + if (template->inheritedNs) xmlFree(template->inheritedNs); + + /* free profiling data */ + if (template->templCalledTab) xmlFree(template->templCalledTab); + if (template->templCountTab) xmlFree(template->templCountTab); + + memset(template, -1, sizeof(xsltTemplate)); + xmlFree(template); +} + +/** + * xsltFreeTemplateList: + * @template: an XSLT template list + * + * Free up the memory allocated by all the elements of @template + */ +static void +xsltFreeTemplateList(xsltTemplatePtr template) { + xsltTemplatePtr cur; + + while (template != NULL) { + cur = template; + template = template->next; + xsltFreeTemplate(cur); + } +} + +#ifdef XSLT_REFACTORED + +static void +xsltFreeNsAliasList(xsltNsAliasPtr item) +{ + xsltNsAliasPtr tmp; + + while (item) { + tmp = item; + item = item->next; + xmlFree(tmp); + } + return; +} + +#ifdef XSLT_REFACTORED_XSLT_NSCOMP +static void +xsltFreeNamespaceMap(xsltNsMapPtr item) +{ + xsltNsMapPtr tmp; + + while (item) { + tmp = item; + item = item->next; + xmlFree(tmp); + } + return; +} + +static xsltNsMapPtr +xsltNewNamespaceMapItem(xsltCompilerCtxtPtr cctxt, + xmlDocPtr doc, + xmlNsPtr ns, + xmlNodePtr elem) +{ + xsltNsMapPtr ret; + + if ((cctxt == NULL) || (doc == NULL) || (ns == NULL)) + return(NULL); + + ret = (xsltNsMapPtr) xmlMalloc(sizeof(xsltNsMap)); + if (ret == NULL) { + xsltTransformError(NULL, cctxt->style, elem, + "Internal error: (xsltNewNamespaceMapItem) " + "memory allocation failed.\n"); + return(NULL); + } + memset(ret, 0, sizeof(xsltNsMap)); + ret->doc = doc; + ret->ns = ns; + ret->origNsName = ns->href; + /* + * Store the item at current stylesheet-level. + */ + if (cctxt->psData->nsMap != NULL) + ret->next = cctxt->psData->nsMap; + cctxt->psData->nsMap = ret; + + return(ret); +} +#endif /* XSLT_REFACTORED_XSLT_NSCOMP */ + +/** + * xsltCompilerVarInfoFree: + * @cctxt: the compilation context + * + * Frees the list of information for vars/params. + */ +static void +xsltCompilerVarInfoFree(xsltCompilerCtxtPtr cctxt) +{ + xsltVarInfoPtr ivar = cctxt->ivars, ivartmp; + + while (ivar) { + ivartmp = ivar; + ivar = ivar->next; + xmlFree(ivartmp); + } +} + +/** + * xsltCompilerCtxtFree: + * + * Free an XSLT compiler context. + */ +static void +xsltCompilationCtxtFree(xsltCompilerCtxtPtr cctxt) +{ + if (cctxt == NULL) + return; +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "Freeing compilation context\n"); + xsltGenericDebug(xsltGenericDebugContext, + "### Max inodes: %d\n", cctxt->maxNodeInfos); + xsltGenericDebug(xsltGenericDebugContext, + "### Max LREs : %d\n", cctxt->maxLREs); +#endif + /* + * Free node-infos. + */ + if (cctxt->inodeList != NULL) { + xsltCompilerNodeInfoPtr tmp, cur = cctxt->inodeList; + while (cur != NULL) { + tmp = cur; + cur = cur->next; + xmlFree(tmp); + } + } + if (cctxt->tmpList != NULL) + xsltPointerListFree(cctxt->tmpList); + if (cctxt->nsAliases != NULL) + xsltFreeNsAliasList(cctxt->nsAliases); + + if (cctxt->ivars) + xsltCompilerVarInfoFree(cctxt); + + xmlFree(cctxt); +} + +/** + * xsltCompilerCreate: + * + * Creates an XSLT compiler context. + * + * Returns the pointer to the created xsltCompilerCtxt or + * NULL in case of an internal error. + */ +static xsltCompilerCtxtPtr +xsltCompilationCtxtCreate(xsltStylesheetPtr style) { + xsltCompilerCtxtPtr ret; + + ret = (xsltCompilerCtxtPtr) xmlMalloc(sizeof(xsltCompilerCtxt)); + if (ret == NULL) { + xsltTransformError(NULL, style, NULL, + "xsltCompilerCreate: allocation of compiler " + "context failed.\n"); + return(NULL); + } + memset(ret, 0, sizeof(xsltCompilerCtxt)); + + ret->errSeverity = XSLT_ERROR_SEVERITY_ERROR; + ret->tmpList = xsltPointerListCreate(20); + if (ret->tmpList == NULL) { + goto internal_err; + } + + return(ret); + +internal_err: + xsltCompilationCtxtFree(ret); + return(NULL); +} + +static void +xsltLREEffectiveNsNodesFree(xsltEffectiveNsPtr first) +{ + xsltEffectiveNsPtr tmp; + + while (first != NULL) { + tmp = first; + first = first->nextInStore; + xmlFree(tmp); + } +} + +static void +xsltFreePrincipalStylesheetData(xsltPrincipalStylesheetDataPtr data) +{ + if (data == NULL) + return; + + if (data->inScopeNamespaces != NULL) { + int i; + xsltNsListContainerPtr nsi; + xsltPointerListPtr list = + (xsltPointerListPtr) data->inScopeNamespaces; + + for (i = 0; i < list->number; i++) { + /* + * REVISIT TODO: Free info of in-scope namespaces. + */ + nsi = (xsltNsListContainerPtr) list->items[i]; + if (nsi->list != NULL) + xmlFree(nsi->list); + xmlFree(nsi); + } + xsltPointerListFree(list); + data->inScopeNamespaces = NULL; + } + + if (data->exclResultNamespaces != NULL) { + int i; + xsltPointerListPtr list = (xsltPointerListPtr) + data->exclResultNamespaces; + + for (i = 0; i < list->number; i++) + xsltPointerListFree((xsltPointerListPtr) list->items[i]); + + xsltPointerListFree(list); + data->exclResultNamespaces = NULL; + } + + if (data->extElemNamespaces != NULL) { + xsltPointerListPtr list = (xsltPointerListPtr) + data->extElemNamespaces; + int i; + + for (i = 0; i < list->number; i++) + xsltPointerListFree((xsltPointerListPtr) list->items[i]); + + xsltPointerListFree(list); + data->extElemNamespaces = NULL; + } + if (data->effectiveNs) { + xsltLREEffectiveNsNodesFree(data->effectiveNs); + data->effectiveNs = NULL; + } +#ifdef XSLT_REFACTORED_XSLT_NSCOMP + xsltFreeNamespaceMap(data->nsMap); +#endif + xmlFree(data); +} + +static xsltPrincipalStylesheetDataPtr +xsltNewPrincipalStylesheetData(void) +{ + xsltPrincipalStylesheetDataPtr ret; + + ret = (xsltPrincipalStylesheetDataPtr) + xmlMalloc(sizeof(xsltPrincipalStylesheetData)); + if (ret == NULL) { + xsltTransformError(NULL, NULL, NULL, + "xsltNewPrincipalStylesheetData: memory allocation failed.\n"); + return(NULL); + } + memset(ret, 0, sizeof(xsltPrincipalStylesheetData)); + + /* + * Global list of in-scope namespaces. + */ + ret->inScopeNamespaces = xsltPointerListCreate(-1); + if (ret->inScopeNamespaces == NULL) + goto internal_err; + /* + * Global list of excluded result ns-decls. + */ + ret->exclResultNamespaces = xsltPointerListCreate(-1); + if (ret->exclResultNamespaces == NULL) + goto internal_err; + /* + * Global list of extension instruction namespace names. + */ + ret->extElemNamespaces = xsltPointerListCreate(-1); + if (ret->extElemNamespaces == NULL) + goto internal_err; + + return(ret); + +internal_err: + + return(NULL); +} + +#endif + +/** + * xsltNewStylesheetInternal: + * @parent: the parent stylesheet or NULL + * + * Create a new XSLT Stylesheet + * + * Returns the newly allocated xsltStylesheetPtr or NULL in case of error + */ +static xsltStylesheetPtr +xsltNewStylesheetInternal(xsltStylesheetPtr parent) { + xsltStylesheetPtr ret = NULL; + + ret = (xsltStylesheetPtr) xmlMalloc(sizeof(xsltStylesheet)); + if (ret == NULL) { + xsltTransformError(NULL, NULL, NULL, + "xsltNewStylesheet : malloc failed\n"); + goto internal_err; + } + memset(ret, 0, sizeof(xsltStylesheet)); + + ret->parent = parent; + ret->omitXmlDeclaration = -1; + ret->standalone = -1; + ret->decimalFormat = xsltNewDecimalFormat(NULL, NULL); + ret->indent = -1; + ret->errors = 0; + ret->warnings = 0; + ret->exclPrefixNr = 0; + ret->exclPrefixMax = 0; + ret->exclPrefixTab = NULL; + ret->extInfos = NULL; + ret->extrasNr = 0; + ret->internalized = 1; + ret->literal_result = 0; + ret->forwards_compatible = 0; + ret->dict = xmlDictCreate(); +#ifdef WITH_XSLT_DEBUG + xsltGenericDebug(xsltGenericDebugContext, + "creating dictionary for stylesheet\n"); +#endif + + if (parent == NULL) { + ret->principal = ret; + + ret->xpathCtxt = xmlXPathNewContext(NULL); + if (ret->xpathCtxt == NULL) { + xsltTransformError(NULL, NULL, NULL, + "xsltNewStylesheet: xmlXPathNewContext failed\n"); + goto internal_err; + } + if (xmlXPathContextSetCache(ret->xpathCtxt, 1, -1, 0) == -1) + goto internal_err; + } else { + ret->principal = parent->principal; + } + + xsltInit(); + + return(ret); + +internal_err: + if (ret != NULL) + xsltFreeStylesheet(ret); + return(NULL); +} + +/** + * xsltNewStylesheet: + * + * Create a new XSLT Stylesheet + * + * Returns the newly allocated xsltStylesheetPtr or NULL in case of error + */ +xsltStylesheetPtr +xsltNewStylesheet(void) { + return xsltNewStylesheetInternal(NULL); +} + +/** + * xsltAllocateExtra: + * @style: an XSLT stylesheet + * + * Allocate an extra runtime information slot statically while compiling + * the stylesheet and return its number + * + * Returns the number of the slot + */ +int +xsltAllocateExtra(xsltStylesheetPtr style) +{ + return(style->extrasNr++); +} + +/** + * xsltAllocateExtraCtxt: + * @ctxt: an XSLT transformation context + * + * Allocate an extra runtime information slot at run-time + * and return its number + * This make sure there is a slot ready in the transformation context + * + * Returns the number of the slot + */ +int +xsltAllocateExtraCtxt(xsltTransformContextPtr ctxt) +{ + if (ctxt->extrasNr >= ctxt->extrasMax) { + int i; + if (ctxt->extrasNr == 0) { + ctxt->extrasMax = 20; + ctxt->extras = (xsltRuntimeExtraPtr) + xmlMalloc(ctxt->extrasMax * sizeof(xsltRuntimeExtra)); + if (ctxt->extras == NULL) { + xsltTransformError(ctxt, NULL, NULL, + "xsltAllocateExtraCtxt: out of memory\n"); + return(0); + } + for (i = 0;i < ctxt->extrasMax;i++) { + ctxt->extras[i].info = NULL; + ctxt->extras[i].deallocate = NULL; + ctxt->extras[i].val.ptr = NULL; + } + + } else { + xsltRuntimeExtraPtr tmp; + + ctxt->extrasMax += 100; + tmp = (xsltRuntimeExtraPtr) xmlRealloc(ctxt->extras, + ctxt->extrasMax * sizeof(xsltRuntimeExtra)); + if (tmp == NULL) { + xsltTransformError(ctxt, NULL, NULL, + "xsltAllocateExtraCtxt: out of memory\n"); + return(0); + } + ctxt->extras = tmp; + for (i = ctxt->extrasNr;i < ctxt->extrasMax;i++) { + ctxt->extras[i].info = NULL; + ctxt->extras[i].deallocate = NULL; + ctxt->extras[i].val.ptr = NULL; + } + } + } + return(ctxt->extrasNr++); +} + +/** + * xsltFreeStylesheetList: + * @style: an XSLT stylesheet list + * + * Free up the memory allocated by the list @style + */ +static void +xsltFreeStylesheetList(xsltStylesheetPtr style) { + xsltStylesheetPtr next; + + while (style != NULL) { + next = style->next; + xsltFreeStylesheet(style); + style = next; + } +} + +/** + * xsltCleanupStylesheetTree: + * + * @doc: the document-node + * @node: the element where the stylesheet is rooted at + * + * Actually @node need not be the document-element, but + * currently Libxslt does not support embedded stylesheets. + * + * Returns 0 if OK, -1 on API or internal errors. + */ +static int +xsltCleanupStylesheetTree(xmlDocPtr doc ATTRIBUTE_UNUSED, + xmlNodePtr rootElem ATTRIBUTE_UNUSED) +{ +#if 0 /* TODO: Currently disabled, since probably not needed. */ + xmlNodePtr cur; + + if ((doc == NULL) || (rootElem == NULL) || + (rootElem->type != XML_ELEMENT_NODE) || + (doc != rootElem->doc)) + return(-1); + + /* + * Cleanup was suggested by Aleksey Sanin: + * Clear the PSVI field to avoid problems if the + * node-tree of the stylesheet is intended to be used for + * further processing by the user (e.g. for compiling it + * once again - although not recommended). + */ + + cur = rootElem; + while (cur != NULL) { + if (cur->type == XML_ELEMENT_NODE) { + /* + * Clear the PSVI field. + */ + cur->psvi = NULL; + if (cur->children) { + cur = cur->children; + continue; + } + } + +leave_node: + if (cur == rootElem) + break; + if (cur->next != NULL) + cur = cur->next; + else { + cur = cur->parent; + if (cur == NULL) + break; + goto leave_node; + } + } +#endif /* #if 0 */ + return(0); +} + +/** + * xsltFreeStylesheet: + * @style: an XSLT stylesheet + * + * Free up the memory allocated by @style + */ +void +xsltFreeStylesheet(xsltStylesheetPtr style) +{ + if (style == NULL) + return; + +#ifdef XSLT_REFACTORED + /* + * Start with a cleanup of the main stylesheet's doc. + */ + if ((style->principal == style) && (style->doc)) + xsltCleanupStylesheetTree(style->doc, + xmlDocGetRootElement(style->doc)); +#ifdef XSLT_REFACTORED_XSLT_NSCOMP + /* + * Restore changed ns-decls before freeing the document. + */ + if ((style->doc != NULL) && + XSLT_HAS_INTERNAL_NSMAP(style)) + { + xsltRestoreDocumentNamespaces(XSLT_GET_INTERNAL_NSMAP(style), + style->doc); + } +#endif /* XSLT_REFACTORED_XSLT_NSCOMP */ +#else + /* + * Start with a cleanup of the main stylesheet's doc. + */ + if ((style->parent == NULL) && (style->doc)) + xsltCleanupStylesheetTree(style->doc, + xmlDocGetRootElement(style->doc)); +#endif /* XSLT_REFACTORED */ + + xsltFreeKeys(style); + xsltFreeExts(style); + xsltFreeTemplateHashes(style); + xsltFreeDecimalFormatList(style); + xsltFreeTemplateList(style->templates); + xsltFreeAttributeSetsHashes(style); + xsltFreeNamespaceAliasHashes(style); + xsltFreeStylePreComps(style); + /* + * Free documents of all included stylsheet modules of this + * stylesheet level. + */ + xsltFreeStyleDocuments(style); + /* + * TODO: Best time to shutdown extension stuff? + */ + xsltShutdownExts(style); + + if (style->variables != NULL) + xsltFreeStackElemList(style->variables); + if (style->cdataSection != NULL) + xmlHashFree(style->cdataSection, NULL); + if (style->stripSpaces != NULL) + xmlHashFree(style->stripSpaces, NULL); + if (style->nsHash != NULL) + xmlHashFree(style->nsHash, NULL); + if (style->exclPrefixTab != NULL) + xmlFree(style->exclPrefixTab); + if (style->method != NULL) + xmlFree(style->method); + if (style->methodURI != NULL) + xmlFree(style->methodURI); + if (style->version != NULL) + xmlFree(style->version); + if (style->encoding != NULL) + xmlFree(style->encoding); + if (style->doctypePublic != NULL) + xmlFree(style->doctypePublic); + if (style->doctypeSystem != NULL) + xmlFree(style->doctypeSystem); + if (style->mediaType != NULL) + xmlFree(style->mediaType); + if (style->attVTs) + xsltFreeAVTList(style->attVTs); + if (style->imports != NULL) + xsltFreeStylesheetList(style->imports); + +#ifdef XSLT_REFACTORED + /* + * If this is the principal stylesheet, then + * free its internal data. + */ + if (style->principal == style) { + if (style->principalData) { + xsltFreePrincipalStylesheetData(style->principalData); + style->principalData = NULL; + } + } +#endif + /* + * Better to free the main document of this stylesheet level + * at the end - so here. + */ + if (style->doc != NULL) { + xmlFreeDoc(style->doc); + } + +#ifdef WITH_XSLT_DEBUG + xsltGenericDebug(xsltGenericDebugContext, + "freeing dictionary from stylesheet\n"); +#endif + xmlDictFree(style->dict); + + if (style->xpathCtxt != NULL) + xmlXPathFreeContext(style->xpathCtxt); + + memset(style, -1, sizeof(xsltStylesheet)); + xmlFree(style); +} + +/************************************************************************ + * * + * Parsing of an XSLT Stylesheet * + * * + ************************************************************************/ + +#ifdef XSLT_REFACTORED + /* + * This is now performed in an optimized way in xsltParseXSLTTemplate. + */ +#else +/** + * xsltGetInheritedNsList: + * @style: the stylesheet + * @template: the template + * @node: the current node + * + * Search all the namespace applying to a given element except the ones + * from excluded output prefixes currently in scope. Initialize the + * template inheritedNs list with it. + * + * Returns the number of entries found + */ +static int +xsltGetInheritedNsList(xsltStylesheetPtr style, + xsltTemplatePtr template, + xmlNodePtr node) +{ + xmlNsPtr cur; + xmlNsPtr *ret = NULL, *tmp; + int nbns = 0; + int maxns = 0; + int i; + + if ((style == NULL) || (template == NULL) || (node == NULL) || + (template->inheritedNsNr != 0) || (template->inheritedNs != NULL)) + return(0); + while (node != NULL) { + if (node->type == XML_ELEMENT_NODE) { + cur = node->nsDef; + while (cur != NULL) { + if (xmlStrEqual(cur->href, XSLT_NAMESPACE)) + goto skip_ns; + + if ((cur->prefix != NULL) && + (xsltCheckExtPrefix(style, cur->prefix))) + goto skip_ns; + /* + * Check if this namespace was excluded. + * Note that at this point only the exclusions defined + * on the topmost stylesheet element are in the exclusion-list. + */ + for (i = 0;i < style->exclPrefixNr;i++) { + if (xmlStrEqual(cur->href, style->exclPrefixTab[i])) + goto skip_ns; + } + /* + * Skip shadowed namespace bindings. + */ + for (i = 0; i < nbns; i++) { + if ((cur->prefix == ret[i]->prefix) || + (xmlStrEqual(cur->prefix, ret[i]->prefix))) + break; + } + if (i >= nbns) { + if (nbns >= maxns) { + maxns = (maxns == 0) ? 10 : 2 * maxns; + tmp = (xmlNsPtr *) xmlRealloc(ret, + (maxns + 1) * sizeof(xmlNsPtr)); + if (tmp == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xsltGetInheritedNsList : realloc failed!\n"); + xmlFree(ret); + return(0); + } + ret = tmp; + } + ret[nbns++] = cur; + ret[nbns] = NULL; + } +skip_ns: + cur = cur->next; + } + } + node = node->parent; + } + if (nbns != 0) { +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "template has %d inherited namespaces\n", nbns); +#endif + template->inheritedNsNr = nbns; + template->inheritedNs = ret; + } + return (nbns); +} +#endif /* else of XSLT_REFACTORED */ + +/** + * xsltParseStylesheetOutput: + * @style: the XSLT stylesheet + * @cur: the "output" element + * + * parse an XSLT stylesheet output element and record + * information related to the stylesheet output + */ + +void +xsltParseStylesheetOutput(xsltStylesheetPtr style, xmlNodePtr cur) +{ + xmlChar *elements, + *prop; + xmlChar *element, + *end; + + if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE)) + return; + + prop = xmlGetNsProp(cur, (const xmlChar *) "version", NULL); + if (prop != NULL) { + if (style->version != NULL) + xmlFree(style->version); + style->version = prop; + } + + prop = xmlGetNsProp(cur, (const xmlChar *) "encoding", NULL); + if (prop != NULL) { + if (style->encoding != NULL) + xmlFree(style->encoding); + style->encoding = prop; + } + + /* relaxed to support xt:document + * TODO KB: What does "relaxed to support xt:document" mean? + */ + prop = xmlGetNsProp(cur, (const xmlChar *) "method", NULL); + if (prop != NULL) { + const xmlChar *URI; + + if (style->method != NULL) + xmlFree(style->method); + style->method = NULL; + if (style->methodURI != NULL) + xmlFree(style->methodURI); + style->methodURI = NULL; + + /* + * TODO: Don't use xsltGetQNameURI(). + */ + URI = xsltGetQNameURI(cur, &prop); + if (prop == NULL) { + if (style != NULL) style->errors++; + } else if (URI == NULL) { + if ((xmlStrEqual(prop, (const xmlChar *) "xml")) || + (xmlStrEqual(prop, (const xmlChar *) "html")) || + (xmlStrEqual(prop, (const xmlChar *) "text"))) { + style->method = prop; + } else { + xsltTransformError(NULL, style, cur, + "invalid value for method: %s\n", prop); + if (style != NULL) style->warnings++; + xmlFree(prop); + } + } else { + style->method = prop; + style->methodURI = xmlStrdup(URI); + } + } + + prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-system", NULL); + if (prop != NULL) { + if (style->doctypeSystem != NULL) + xmlFree(style->doctypeSystem); + style->doctypeSystem = prop; + } + + prop = xmlGetNsProp(cur, (const xmlChar *) "doctype-public", NULL); + if (prop != NULL) { + if (style->doctypePublic != NULL) + xmlFree(style->doctypePublic); + style->doctypePublic = prop; + } + + prop = xmlGetNsProp(cur, (const xmlChar *) "standalone", NULL); + if (prop != NULL) { + if (xmlStrEqual(prop, (const xmlChar *) "yes")) { + style->standalone = 1; + } else if (xmlStrEqual(prop, (const xmlChar *) "no")) { + style->standalone = 0; + } else { + xsltTransformError(NULL, style, cur, + "invalid value for standalone: %s\n", prop); + style->errors++; + } + xmlFree(prop); + } + + prop = xmlGetNsProp(cur, (const xmlChar *) "indent", NULL); + if (prop != NULL) { + if (xmlStrEqual(prop, (const xmlChar *) "yes")) { + style->indent = 1; + } else if (xmlStrEqual(prop, (const xmlChar *) "no")) { + style->indent = 0; + } else { + xsltTransformError(NULL, style, cur, + "invalid value for indent: %s\n", prop); + style->errors++; + } + xmlFree(prop); + } + + prop = xmlGetNsProp(cur, (const xmlChar *) "omit-xml-declaration", NULL); + if (prop != NULL) { + if (xmlStrEqual(prop, (const xmlChar *) "yes")) { + style->omitXmlDeclaration = 1; + } else if (xmlStrEqual(prop, (const xmlChar *) "no")) { + style->omitXmlDeclaration = 0; + } else { + xsltTransformError(NULL, style, cur, + "invalid value for omit-xml-declaration: %s\n", + prop); + style->errors++; + } + xmlFree(prop); + } + + elements = xmlGetNsProp(cur, (const xmlChar *) "cdata-section-elements", + NULL); + if (elements != NULL) { + if (style->cdataSection == NULL) + style->cdataSection = xmlHashCreate(10); + if (style->cdataSection == NULL) { + xmlFree(elements); + return; + } + + element = elements; + while (*element != 0) { + while (IS_BLANK(*element)) + element++; + if (*element == 0) + break; + end = element; + while ((*end != 0) && (!IS_BLANK(*end))) + end++; + element = xmlStrndup(element, end - element); + if (element) { +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "add cdata section output element %s\n", + element); +#endif + if (xmlValidateQName(BAD_CAST element, 0) != 0) { + xsltTransformError(NULL, style, cur, + "Attribute 'cdata-section-elements': The value " + "'%s' is not a valid QName.\n", element); + xmlFree(element); + style->errors++; + } else { + const xmlChar *URI; + + /* + * TODO: Don't use xsltGetQNameURI(). + */ + URI = xsltGetQNameURI(cur, &element); + if (element == NULL) { + /* + * TODO: We'll report additionally an error + * via the stylesheet's error handling. + */ + xsltTransformError(NULL, style, cur, + "Attribute 'cdata-section-elements': " + "Not a valid QName.\n"); + style->errors++; + } else { + xmlNsPtr ns; + + /* + * XSLT-1.0 "Each QName is expanded into an + * expanded-name using the namespace declarations in + * effect on the xsl:output element in which the QName + * occurs; if there is a default namespace, it is used + * for QNames that do not have a prefix" + * NOTE: Fix of bug #339570. + */ + if (URI == NULL) { + ns = xmlSearchNs(style->doc, cur, NULL); + if (ns != NULL) + URI = ns->href; + } + xmlHashAddEntry2(style->cdataSection, element, URI, + (void *) "cdata"); + xmlFree(element); + } + } + } + element = end; + } + xmlFree(elements); + } + + prop = xmlGetNsProp(cur, (const xmlChar *) "media-type", NULL); + if (prop != NULL) { + if (style->mediaType) + xmlFree(style->mediaType); + style->mediaType = prop; + } + if (cur->children != NULL) { + xsltParseContentError(style, cur->children); + } +} + +/** + * xsltParseStylesheetDecimalFormat: + * @style: the XSLT stylesheet + * @cur: the "decimal-format" element + * + * + * + * + * parse an XSLT stylesheet decimal-format element and + * and record the formatting characteristics + */ +static void +xsltParseStylesheetDecimalFormat(xsltStylesheetPtr style, xmlNodePtr cur) +{ + xmlChar *prop; + xsltDecimalFormatPtr format; + xsltDecimalFormatPtr iter; + + if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE)) + return; + + format = style->decimalFormat; + + prop = xmlGetNsProp(cur, BAD_CAST("name"), NULL); + if (prop != NULL) { + const xmlChar *nsUri; + + if (xmlValidateQName(prop, 0) != 0) { + xsltTransformError(NULL, style, cur, + "xsl:decimal-format: Invalid QName '%s'.\n", prop); + style->warnings++; + xmlFree(prop); + return; + } + /* + * TODO: Don't use xsltGetQNameURI(). + */ + nsUri = xsltGetQNameURI(cur, &prop); + if (prop == NULL) { + style->warnings++; + return; + } + format = xsltDecimalFormatGetByQName(style, nsUri, prop); + if (format != NULL) { + xsltTransformError(NULL, style, cur, + "xsltParseStylestyleDecimalFormat: %s already exists\n", prop); + style->warnings++; + xmlFree(prop); + return; + } + format = xsltNewDecimalFormat(nsUri, prop); + if (format == NULL) { + xsltTransformError(NULL, style, cur, + "xsltParseStylestyleDecimalFormat: failed creating new decimal-format\n"); + style->errors++; + xmlFree(prop); + return; + } + /* Append new decimal-format structure */ + for (iter = style->decimalFormat; iter->next; iter = iter->next) + ; + if (iter) + iter->next = format; + } + + prop = xmlGetNsProp(cur, (const xmlChar *)"decimal-separator", NULL); + if (prop != NULL) { + if (format->decimalPoint != NULL) xmlFree(format->decimalPoint); + format->decimalPoint = prop; + } + + prop = xmlGetNsProp(cur, (const xmlChar *)"grouping-separator", NULL); + if (prop != NULL) { + if (format->grouping != NULL) xmlFree(format->grouping); + format->grouping = prop; + } + + prop = xmlGetNsProp(cur, (const xmlChar *)"infinity", NULL); + if (prop != NULL) { + if (format->infinity != NULL) xmlFree(format->infinity); + format->infinity = prop; + } + + prop = xmlGetNsProp(cur, (const xmlChar *)"minus-sign", NULL); + if (prop != NULL) { + if (format->minusSign != NULL) xmlFree(format->minusSign); + format->minusSign = prop; + } + + prop = xmlGetNsProp(cur, (const xmlChar *)"NaN", NULL); + if (prop != NULL) { + if (format->noNumber != NULL) xmlFree(format->noNumber); + format->noNumber = prop; + } + + prop = xmlGetNsProp(cur, (const xmlChar *)"percent", NULL); + if (prop != NULL) { + if (format->percent != NULL) xmlFree(format->percent); + format->percent = prop; + } + + prop = xmlGetNsProp(cur, (const xmlChar *)"per-mille", NULL); + if (prop != NULL) { + if (format->permille != NULL) xmlFree(format->permille); + format->permille = prop; + } + + prop = xmlGetNsProp(cur, (const xmlChar *)"zero-digit", NULL); + if (prop != NULL) { + if (format->zeroDigit != NULL) xmlFree(format->zeroDigit); + format->zeroDigit = prop; + } + + prop = xmlGetNsProp(cur, (const xmlChar *)"digit", NULL); + if (prop != NULL) { + if (format->digit != NULL) xmlFree(format->digit); + format->digit = prop; + } + + prop = xmlGetNsProp(cur, (const xmlChar *)"pattern-separator", NULL); + if (prop != NULL) { + if (format->patternSeparator != NULL) xmlFree(format->patternSeparator); + format->patternSeparator = prop; + } + if (cur->children != NULL) { + xsltParseContentError(style, cur->children); + } +} + +/** + * xsltParseStylesheetPreserveSpace: + * @style: the XSLT stylesheet + * @cur: the "preserve-space" element + * + * parse an XSLT stylesheet preserve-space element and record + * elements needing preserving + */ + +static void +xsltParseStylesheetPreserveSpace(xsltStylesheetPtr style, xmlNodePtr cur) { + xmlChar *elements; + xmlChar *element, *end; + + if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE)) + return; + + elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL); + if (elements == NULL) { + xsltTransformError(NULL, style, cur, + "xsltParseStylesheetPreserveSpace: missing elements attribute\n"); + if (style != NULL) style->warnings++; + return; + } + + if (style->stripSpaces == NULL) + style->stripSpaces = xmlHashCreate(10); + if (style->stripSpaces == NULL) { + xmlFree(elements); + return; + } + + element = elements; + while (*element != 0) { + while (IS_BLANK(*element)) element++; + if (*element == 0) + break; + end = element; + while ((*end != 0) && (!IS_BLANK(*end))) end++; + element = xmlStrndup(element, end - element); + if (element) { +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "add preserved space element %s\n", element); +#endif + if (xmlStrEqual(element, (const xmlChar *)"*")) { + style->stripAll = -1; + } else { + const xmlChar *URI; + + /* + * TODO: Don't use xsltGetQNameURI(). + */ + URI = xsltGetQNameURI(cur, &element); + + xmlHashAddEntry2(style->stripSpaces, element, URI, + (xmlChar *) "preserve"); + } + xmlFree(element); + } + element = end; + } + xmlFree(elements); + if (cur->children != NULL) { + xsltParseContentError(style, cur->children); + } +} + +#ifdef XSLT_REFACTORED +#else +/** + * xsltParseStylesheetExtPrefix: + * @style: the XSLT stylesheet + * @template: the "extension-element-prefixes" prefix + * + * parse an XSLT stylesheet's "extension-element-prefix" attribute value + * and register the namespaces of extension instruction. + * SPEC "A namespace is designated as an extension namespace by using + * an extension-element-prefixes attribute on: + * 1) an xsl:stylesheet element + * 2) an xsl:extension-element-prefixes attribute on a + * literal result element + * 3) an extension instruction." + */ +static void +xsltParseStylesheetExtPrefix(xsltStylesheetPtr style, xmlNodePtr cur, + int isXsltElem) { + xmlChar *prefixes; + xmlChar *prefix, *end; + + if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE)) + return; + + if (isXsltElem) { + /* For xsl:stylesheet/xsl:transform. */ + prefixes = xmlGetNsProp(cur, + (const xmlChar *)"extension-element-prefixes", NULL); + } else { + /* For literal result elements and extension instructions. */ + prefixes = xmlGetNsProp(cur, + (const xmlChar *)"extension-element-prefixes", XSLT_NAMESPACE); + } + if (prefixes == NULL) { + return; + } + + prefix = prefixes; + while (*prefix != 0) { + while (IS_BLANK(*prefix)) prefix++; + if (*prefix == 0) + break; + end = prefix; + while ((*end != 0) && (!IS_BLANK(*end))) end++; + prefix = xmlStrndup(prefix, end - prefix); + if (prefix) { + xmlNsPtr ns; + + if (xmlStrEqual(prefix, (const xmlChar *)"#default")) + ns = xmlSearchNs(style->doc, cur, NULL); + else + ns = xmlSearchNs(style->doc, cur, prefix); + if (ns == NULL) { + xsltTransformError(NULL, style, cur, + "xsl:extension-element-prefix : undefined namespace %s\n", + prefix); + if (style != NULL) style->warnings++; + } else { +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "add extension prefix %s\n", prefix); +#endif + xsltRegisterExtPrefix(style, prefix, ns->href); + } + xmlFree(prefix); + } + prefix = end; + } + xmlFree(prefixes); +} +#endif /* else of XSLT_REFACTORED */ + +/** + * xsltParseStylesheetStripSpace: + * @style: the XSLT stylesheet + * @cur: the "strip-space" element + * + * parse an XSLT stylesheet's strip-space element and record + * the elements needing stripping + */ + +static void +xsltParseStylesheetStripSpace(xsltStylesheetPtr style, xmlNodePtr cur) { + xmlChar *elements; + xmlChar *element, *end; + + if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE)) + return; + + if (style->stripSpaces == NULL) + style->stripSpaces = xmlHashCreate(10); + if (style->stripSpaces == NULL) + return; + + elements = xmlGetNsProp(cur, (const xmlChar *)"elements", NULL); + if (elements == NULL) { + xsltTransformError(NULL, style, cur, + "xsltParseStylesheetStripSpace: missing elements attribute\n"); + if (style != NULL) style->warnings++; + return; + } + + element = elements; + while (*element != 0) { + while (IS_BLANK(*element)) element++; + if (*element == 0) + break; + end = element; + while ((*end != 0) && (!IS_BLANK(*end))) end++; + element = xmlStrndup(element, end - element); + if (element) { +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "add stripped space element %s\n", element); +#endif + if (xmlStrEqual(element, (const xmlChar *)"*")) { + style->stripAll = 1; + } else { + const xmlChar *URI; + + /* + * TODO: Don't use xsltGetQNameURI(). + */ + URI = xsltGetQNameURI(cur, &element); + + xmlHashAddEntry2(style->stripSpaces, element, URI, + (xmlChar *) "strip"); + } + xmlFree(element); + } + element = end; + } + xmlFree(elements); + if (cur->children != NULL) { + xsltParseContentError(style, cur->children); + } +} + +#ifdef XSLT_REFACTORED +#else +/** + * xsltParseStylesheetExcludePrefix: + * @style: the XSLT stylesheet + * @cur: the current point in the stylesheet + * + * parse an XSLT stylesheet exclude prefix and record + * namespaces needing stripping + * + * Returns the number of Excluded prefixes added at that level + */ + +static int +xsltParseStylesheetExcludePrefix(xsltStylesheetPtr style, xmlNodePtr cur, + int isXsltElem) +{ + int nb = 0; + xmlChar *prefixes; + xmlChar *prefix, *end; + + if ((cur == NULL) || (style == NULL) || (cur->type != XML_ELEMENT_NODE)) + return(0); + + if (isXsltElem) + prefixes = xmlGetNsProp(cur, + (const xmlChar *)"exclude-result-prefixes", NULL); + else + prefixes = xmlGetNsProp(cur, + (const xmlChar *)"exclude-result-prefixes", XSLT_NAMESPACE); + + if (prefixes == NULL) { + return(0); + } + + prefix = prefixes; + while (*prefix != 0) { + while (IS_BLANK(*prefix)) prefix++; + if (*prefix == 0) + break; + end = prefix; + while ((*end != 0) && (!IS_BLANK(*end))) end++; + prefix = xmlStrndup(prefix, end - prefix); + if (prefix) { + xmlNsPtr ns; + + if (xmlStrEqual(prefix, (const xmlChar *)"#default")) + ns = xmlSearchNs(style->doc, cur, NULL); + else + ns = xmlSearchNs(style->doc, cur, prefix); + if (ns == NULL) { + xsltTransformError(NULL, style, cur, + "xsl:exclude-result-prefixes : undefined namespace %s\n", + prefix); + if (style != NULL) style->warnings++; + } else { + if (exclPrefixPush(style, (xmlChar *) ns->href) >= 0) { +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "exclude result prefix %s\n", prefix); +#endif + nb++; + } + } + xmlFree(prefix); + } + prefix = end; + } + xmlFree(prefixes); + return(nb); +} +#endif /* else of XSLT_REFACTORED */ + +#ifdef XSLT_REFACTORED + +/* +* xsltTreeEnsureXMLDecl: +* @doc: the doc +* +* BIG NOTE: +* This was copy&pasted from Libxml2's xmlTreeEnsureXMLDecl() in "tree.c". +* Ensures that there is an XML namespace declaration on the doc. +* +* Returns the XML ns-struct or NULL on API and internal errors. +*/ +static xmlNsPtr +xsltTreeEnsureXMLDecl(xmlDocPtr doc) +{ + if (doc == NULL) + return (NULL); + if (doc->oldNs != NULL) + return (doc->oldNs); + { + xmlNsPtr ns; + ns = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); + if (ns == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xsltTreeEnsureXMLDecl: Failed to allocate " + "the XML namespace.\n"); + return (NULL); + } + memset(ns, 0, sizeof(xmlNs)); + ns->type = XML_LOCAL_NAMESPACE; + /* + * URGENT TODO: revisit this. + */ +#ifdef LIBXML_NAMESPACE_DICT + if (doc->dict) + ns->href = xmlDictLookup(doc->dict, XML_XML_NAMESPACE, -1); + else + ns->href = xmlStrdup(XML_XML_NAMESPACE); +#else + ns->href = xmlStrdup(XML_XML_NAMESPACE); +#endif + ns->prefix = xmlStrdup((const xmlChar *)"xml"); + doc->oldNs = ns; + return (ns); + } +} + +/* +* xsltTreeAcquireStoredNs: +* @doc: the doc +* @nsName: the namespace name +* @prefix: the prefix +* +* BIG NOTE: +* This was copy&pasted from Libxml2's xmlDOMWrapStoreNs() in "tree.c". +* Creates or reuses an xmlNs struct on doc->oldNs with +* the given prefix and namespace name. +* +* Returns the aquired ns struct or NULL in case of an API +* or internal error. +*/ +static xmlNsPtr +xsltTreeAcquireStoredNs(xmlDocPtr doc, + const xmlChar *nsName, + const xmlChar *prefix) +{ + xmlNsPtr ns; + + if (doc == NULL) + return (NULL); + if (doc->oldNs != NULL) + ns = doc->oldNs; + else + ns = xsltTreeEnsureXMLDecl(doc); + if (ns == NULL) + return (NULL); + if (ns->next != NULL) { + /* Reuse. */ + ns = ns->next; + while (ns != NULL) { + if ((ns->prefix == NULL) != (prefix == NULL)) { + /* NOP */ + } else if (prefix == NULL) { + if (xmlStrEqual(ns->href, nsName)) + return (ns); + } else { + if ((ns->prefix[0] == prefix[0]) && + xmlStrEqual(ns->prefix, prefix) && + xmlStrEqual(ns->href, nsName)) + return (ns); + + } + if (ns->next == NULL) + break; + ns = ns->next; + } + } + /* Create. */ + ns->next = xmlNewNs(NULL, nsName, prefix); + return (ns->next); +} + +/** + * xsltLREBuildEffectiveNs: + * + * Apply ns-aliasing on the namespace of the given @elem and + * its attributes. + */ +static int +xsltLREBuildEffectiveNs(xsltCompilerCtxtPtr cctxt, + xmlNodePtr elem) +{ + xmlNsPtr ns; + xsltNsAliasPtr alias; + + if ((cctxt == NULL) || (elem == NULL)) + return(-1); + if ((cctxt->nsAliases == NULL) || (! cctxt->hasNsAliases)) + return(0); + + alias = cctxt->nsAliases; + while (alias != NULL) { + if ( /* If both namespaces are NULL... */ + ( (elem->ns == NULL) && + ((alias->literalNs == NULL) || + (alias->literalNs->href == NULL)) ) || + /* ... or both namespace are equal */ + ( (elem->ns != NULL) && + (alias->literalNs != NULL) && + xmlStrEqual(elem->ns->href, alias->literalNs->href) ) ) + { + if ((alias->targetNs != NULL) && + (alias->targetNs->href != NULL)) + { + /* + * Convert namespace. + */ + if (elem->doc == alias->docOfTargetNs) { + /* + * This is the nice case: same docs. + * This will eventually assign a ns-decl which + * is shadowed, but this has no negative effect on + * the generation of the result tree. + */ + elem->ns = alias->targetNs; + } else { + /* + * This target xmlNs originates from a different + * stylesheet tree. Try to locate it in the + * in-scope namespaces. + * OPTIMIZE TODO: Use the compiler-node-info inScopeNs. + */ + ns = xmlSearchNs(elem->doc, elem, + alias->targetNs->prefix); + /* + * If no matching ns-decl found, then assign a + * ns-decl stored in xmlDoc. + */ + if ((ns == NULL) || + (! xmlStrEqual(ns->href, alias->targetNs->href))) + { + /* + * BIG NOTE: The use of xsltTreeAcquireStoredNs() + * is not very efficient, but currently I don't + * see an other way of *safely* changing a node's + * namespace, since the xmlNs struct in + * alias->targetNs might come from an other + * stylesheet tree. So we need to anchor it in the + * current document, without adding it to the tree, + * which would otherwise change the in-scope-ns + * semantic of the tree. + */ + ns = xsltTreeAcquireStoredNs(elem->doc, + alias->targetNs->href, + alias->targetNs->prefix); + + if (ns == NULL) { + xsltTransformError(NULL, cctxt->style, elem, + "Internal error in " + "xsltLREBuildEffectiveNs(): " + "failed to acquire a stored " + "ns-declaration.\n"); + cctxt->style->errors++; + return(-1); + + } + } + elem->ns = ns; + } + } else { + /* + * Move into or leave in the NULL namespace. + */ + elem->ns = NULL; + } + break; + } + alias = alias->next; + } + /* + * Same with attributes of literal result elements. + */ + if (elem->properties != NULL) { + xmlAttrPtr attr = elem->properties; + + while (attr != NULL) { + if (attr->ns == NULL) { + attr = attr->next; + continue; + } + alias = cctxt->nsAliases; + while (alias != NULL) { + if ( /* If both namespaces are NULL... */ + ( (elem->ns == NULL) && + ((alias->literalNs == NULL) || + (alias->literalNs->href == NULL)) ) || + /* ... or both namespace are equal */ + ( (elem->ns != NULL) && + (alias->literalNs != NULL) && + xmlStrEqual(elem->ns->href, alias->literalNs->href) ) ) + { + if ((alias->targetNs != NULL) && + (alias->targetNs->href != NULL)) + { + if (elem->doc == alias->docOfTargetNs) { + elem->ns = alias->targetNs; + } else { + ns = xmlSearchNs(elem->doc, elem, + alias->targetNs->prefix); + if ((ns == NULL) || + (! xmlStrEqual(ns->href, alias->targetNs->href))) + { + ns = xsltTreeAcquireStoredNs(elem->doc, + alias->targetNs->href, + alias->targetNs->prefix); + + if (ns == NULL) { + xsltTransformError(NULL, cctxt->style, elem, + "Internal error in " + "xsltLREBuildEffectiveNs(): " + "failed to acquire a stored " + "ns-declaration.\n"); + cctxt->style->errors++; + return(-1); + + } + } + elem->ns = ns; + } + } else { + /* + * Move into or leave in the NULL namespace. + */ + elem->ns = NULL; + } + break; + } + alias = alias->next; + } + + attr = attr->next; + } + } + return(0); +} + +/** + * xsltLREBuildEffectiveNsNodes: + * + * Computes the effective namespaces nodes for a literal result + * element. + * @effectiveNs is the set of effective ns-nodes + * on the literal result element, which will be added to the result + * element if not already existing in the result tree. + * This means that excluded namespaces (via exclude-result-prefixes, + * extension-element-prefixes and the XSLT namespace) not added + * to the set. + * Namespace-aliasing was applied on the @effectiveNs. + */ +static int +xsltLREBuildEffectiveNsNodes(xsltCompilerCtxtPtr cctxt, + xsltStyleItemLRElementInfoPtr item, + xmlNodePtr elem, + int isLRE) +{ + xmlNsPtr ns, tmpns; + xsltEffectiveNsPtr effNs, lastEffNs = NULL; + int i, j, holdByElem; + xsltPointerListPtr extElemNs = cctxt->inode->extElemNs; + xsltPointerListPtr exclResultNs = cctxt->inode->exclResultNs; + + if ((cctxt == NULL) || (cctxt->inode == NULL) || (elem == NULL) || + (item == NULL) || (item->effectiveNs != NULL)) + return(-1); + + if (item->inScopeNs == NULL) + return(0); + + extElemNs = cctxt->inode->extElemNs; + exclResultNs = cctxt->inode->exclResultNs; + + for (i = 0; i < item->inScopeNs->totalNumber; i++) { + ns = item->inScopeNs->list[i]; + /* + * Skip namespaces designated as excluded namespaces + * ------------------------------------------------- + * + * XSLT-20 TODO: In XSLT 2.0 we need to keep namespaces + * which are target namespaces of namespace-aliases + * regardless if designated as excluded. + * + * Exclude the XSLT namespace. + */ + if (xmlStrEqual(ns->href, XSLT_NAMESPACE)) + goto skip_ns; + + /* + * Apply namespace aliasing + * ------------------------ + * + * SPEC XSLT 2.0 + * "- A namespace node whose string value is a literal namespace + * URI is not copied to the result tree. + * - A namespace node whose string value is a target namespace URI + * is copied to the result tree, whether or not the URI + * identifies an excluded namespace." + * + * NOTE: The ns-aliasing machanism is non-cascading. + * (checked with Saxon, Xalan and MSXML .NET). + * URGENT TODO: is style->nsAliases the effective list of + * ns-aliases, or do we need to lookup the whole + * import-tree? + * TODO: Get rid of import-tree lookup. + */ + if (cctxt->hasNsAliases) { + xsltNsAliasPtr alias; + /* + * First check for being a target namespace. + */ + alias = cctxt->nsAliases; + do { + /* + * TODO: Is xmlns="" handled already? + */ + if ((alias->targetNs != NULL) && + (xmlStrEqual(alias->targetNs->href, ns->href))) + { + /* + * Recognized as a target namespace; use it regardless + * if excluded otherwise. + */ + goto add_effective_ns; + } + alias = alias->next; + } while (alias != NULL); + + alias = cctxt->nsAliases; + do { + /* + * TODO: Is xmlns="" handled already? + */ + if ((alias->literalNs != NULL) && + (xmlStrEqual(alias->literalNs->href, ns->href))) + { + /* + * Recognized as an namespace alias; do not use it. + */ + goto skip_ns; + } + alias = alias->next; + } while (alias != NULL); + } + + /* + * Exclude excluded result namespaces. + */ + if (exclResultNs) { + for (j = 0; j < exclResultNs->number; j++) + if (xmlStrEqual(ns->href, BAD_CAST exclResultNs->items[j])) + goto skip_ns; + } + /* + * Exclude extension-element namespaces. + */ + if (extElemNs) { + for (j = 0; j < extElemNs->number; j++) + if (xmlStrEqual(ns->href, BAD_CAST extElemNs->items[j])) + goto skip_ns; + } + +add_effective_ns: + /* + * OPTIMIZE TODO: This information may not be needed. + */ + if (isLRE && (elem->nsDef != NULL)) { + holdByElem = 0; + tmpns = elem->nsDef; + do { + if (tmpns == ns) { + holdByElem = 1; + break; + } + tmpns = tmpns->next; + } while (tmpns != NULL); + } else + holdByElem = 0; + + + /* + * Add the effective namespace declaration. + */ + effNs = (xsltEffectiveNsPtr) xmlMalloc(sizeof(xsltEffectiveNs)); + if (effNs == NULL) { + xsltTransformError(NULL, cctxt->style, elem, + "Internal error in xsltLREBuildEffectiveNs(): " + "failed to allocate memory.\n"); + cctxt->style->errors++; + return(-1); + } + if (cctxt->psData->effectiveNs == NULL) { + cctxt->psData->effectiveNs = effNs; + effNs->nextInStore = NULL; + } else { + effNs->nextInStore = cctxt->psData->effectiveNs; + cctxt->psData->effectiveNs = effNs; + } + + effNs->next = NULL; + effNs->prefix = ns->prefix; + effNs->nsName = ns->href; + effNs->holdByElem = holdByElem; + + if (lastEffNs == NULL) + item->effectiveNs = effNs; + else + lastEffNs->next = effNs; + lastEffNs = effNs; + +skip_ns: + {} + } + return(0); +} + + +/** + * xsltLREInfoCreate: + * + * @isLRE: indicates if the given @elem is a literal result element + * + * Creates a new info for a literal result element. + */ +static int +xsltLREInfoCreate(xsltCompilerCtxtPtr cctxt, + xmlNodePtr elem, + int isLRE) +{ + xsltStyleItemLRElementInfoPtr item; + + if ((cctxt == NULL) || (cctxt->inode == NULL)) + return(-1); + + item = (xsltStyleItemLRElementInfoPtr) + xmlMalloc(sizeof(xsltStyleItemLRElementInfo)); + if (item == NULL) { + xsltTransformError(NULL, cctxt->style, NULL, + "Internal error in xsltLREInfoCreate(): " + "memory allocation failed.\n"); + cctxt->style->errors++; + return(-1); + } + memset(item, 0, sizeof(xsltStyleItemLRElementInfo)); + item->type = XSLT_FUNC_LITERAL_RESULT_ELEMENT; + /* + * Store it in the stylesheet. + */ + item->next = cctxt->style->preComps; + cctxt->style->preComps = (xsltElemPreCompPtr) item; + /* + * @inScopeNs are used for execution of XPath expressions + * in AVTs. + */ + item->inScopeNs = cctxt->inode->inScopeNs; + + if (elem) + xsltLREBuildEffectiveNsNodes(cctxt, item, elem, isLRE); + + cctxt->inode->litResElemInfo = item; + cctxt->inode->nsChanged = 0; + cctxt->maxLREs++; + return(0); +} + +/** + * xsltCompilerVarInfoPush: + * @cctxt: the compilation context + * + * Pushes a new var/param info onto the stack. + * + * Returns the acquired variable info. + */ +static xsltVarInfoPtr +xsltCompilerVarInfoPush(xsltCompilerCtxtPtr cctxt, + xmlNodePtr inst, + const xmlChar *name, + const xmlChar *nsName) +{ + xsltVarInfoPtr ivar; + + if ((cctxt->ivar != NULL) && (cctxt->ivar->next != NULL)) { + ivar = cctxt->ivar->next; + } else if ((cctxt->ivar == NULL) && (cctxt->ivars != NULL)) { + ivar = cctxt->ivars; + } else { + ivar = (xsltVarInfoPtr) xmlMalloc(sizeof(xsltVarInfo)); + if (ivar == NULL) { + xsltTransformError(NULL, cctxt->style, inst, + "xsltParseInScopeVarPush: xmlMalloc() failed!\n"); + cctxt->style->errors++; + return(NULL); + } + /* memset(retVar, 0, sizeof(xsltInScopeVar)); */ + if (cctxt->ivars == NULL) { + cctxt->ivars = ivar; + ivar->prev = NULL; + } else { + cctxt->ivar->next = ivar; + ivar->prev = cctxt->ivar; + } + cctxt->ivar = ivar; + ivar->next = NULL; + } + ivar->depth = cctxt->depth; + ivar->name = name; + ivar->nsName = nsName; + return(ivar); +} + +/** + * xsltCompilerVarInfoPop: + * @cctxt: the compilation context + * + * Pops all var/param infos from the stack, which + * have the current depth. + */ +static void +xsltCompilerVarInfoPop(xsltCompilerCtxtPtr cctxt) +{ + + while ((cctxt->ivar != NULL) && + (cctxt->ivar->depth > cctxt->depth)) + { + cctxt->ivar = cctxt->ivar->prev; + } +} + +/* +* xsltCompilerNodePush: +* +* @cctxt: the compilation context +* @node: the node to be pushed (this can also be the doc-node) +* +* +* +* Returns the current node info structure or +* NULL in case of an internal error. +*/ +static xsltCompilerNodeInfoPtr +xsltCompilerNodePush(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) +{ + xsltCompilerNodeInfoPtr inode, iprev; + + if ((cctxt->inode != NULL) && (cctxt->inode->next != NULL)) { + inode = cctxt->inode->next; + } else if ((cctxt->inode == NULL) && (cctxt->inodeList != NULL)) { + inode = cctxt->inodeList; + } else { + /* + * Create a new node-info. + */ + inode = (xsltCompilerNodeInfoPtr) + xmlMalloc(sizeof(xsltCompilerNodeInfo)); + if (inode == NULL) { + xsltTransformError(NULL, cctxt->style, NULL, + "xsltCompilerNodePush: malloc failed.\n"); + return(NULL); + } + memset(inode, 0, sizeof(xsltCompilerNodeInfo)); + if (cctxt->inodeList == NULL) + cctxt->inodeList = inode; + else { + cctxt->inodeLast->next = inode; + inode->prev = cctxt->inodeLast; + } + cctxt->inodeLast = inode; + cctxt->maxNodeInfos++; + if (cctxt->inode == NULL) { + cctxt->inode = inode; + /* + * Create an initial literal result element info for + * the root of the stylesheet. + */ + xsltLREInfoCreate(cctxt, NULL, 0); + } + } + cctxt->depth++; + cctxt->inode = inode; + /* + * REVISIT TODO: Keep the reset always complete. + * NOTE: Be carefull with the @node, since it might be + * a doc-node. + */ + inode->node = node; + inode->depth = cctxt->depth; + inode->templ = NULL; + inode->category = XSLT_ELEMENT_CATEGORY_XSLT; + inode->type = 0; + inode->item = NULL; + inode->curChildType = 0; + inode->extContentHandled = 0; + inode->isRoot = 0; + + if (inode->prev != NULL) { + iprev = inode->prev; + /* + * Inherit the following information: + * --------------------------------- + * + * In-scope namespaces + */ + inode->inScopeNs = iprev->inScopeNs; + /* + * Info for literal result elements + */ + inode->litResElemInfo = iprev->litResElemInfo; + inode->nsChanged = iprev->nsChanged; + /* + * Excluded result namespaces + */ + inode->exclResultNs = iprev->exclResultNs; + /* + * Extension instruction namespaces + */ + inode->extElemNs = iprev->extElemNs; + /* + * Whitespace preservation + */ + inode->preserveWhitespace = iprev->preserveWhitespace; + /* + * Forwards-compatible mode + */ + inode->forwardsCompat = iprev->forwardsCompat; + } else { + inode->inScopeNs = NULL; + inode->exclResultNs = NULL; + inode->extElemNs = NULL; + inode->preserveWhitespace = 0; + inode->forwardsCompat = 0; + } + + return(inode); +} + +/* +* xsltCompilerNodePop: +* +* @cctxt: the compilation context +* @node: the node to be pushed (this can also be the doc-node) +* +* Pops the current node info. +*/ +static void +xsltCompilerNodePop(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) +{ + if (cctxt->inode == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xsltCompilerNodePop: Top-node mismatch.\n"); + return; + } + /* + * NOTE: Be carefull with the @node, since it might be + * a doc-node. + */ + if (cctxt->inode->node != node) { + xmlGenericError(xmlGenericErrorContext, + "xsltCompilerNodePop: Node mismatch.\n"); + goto mismatch; + } + if (cctxt->inode->depth != cctxt->depth) { + xmlGenericError(xmlGenericErrorContext, + "xsltCompilerNodePop: Depth mismatch.\n"); + goto mismatch; + } + cctxt->depth--; + /* + * Pop information of variables. + */ + if ((cctxt->ivar) && (cctxt->ivar->depth > cctxt->depth)) + xsltCompilerVarInfoPop(cctxt); + + cctxt->inode = cctxt->inode->prev; + if (cctxt->inode != NULL) + cctxt->inode->curChildType = 0; + return; + +mismatch: + { + const xmlChar *nsName = NULL, *name = NULL; + const xmlChar *infnsName = NULL, *infname = NULL; + + if (node) { + if (node->type == XML_ELEMENT_NODE) { + name = node->name; + if (node->ns != NULL) + nsName = node->ns->href; + else + nsName = BAD_CAST ""; + } else { + name = BAD_CAST "#document"; + nsName = BAD_CAST ""; + } + } else + name = BAD_CAST "Not given"; + + if (cctxt->inode->node) { + if (node->type == XML_ELEMENT_NODE) { + infname = cctxt->inode->node->name; + if (cctxt->inode->node->ns != NULL) + infnsName = cctxt->inode->node->ns->href; + else + infnsName = BAD_CAST ""; + } else { + infname = BAD_CAST "#document"; + infnsName = BAD_CAST ""; + } + } else + infname = BAD_CAST "Not given"; + + + xmlGenericError(xmlGenericErrorContext, + "xsltCompilerNodePop: Given : '%s' URI '%s'\n", + name, nsName); + xmlGenericError(xmlGenericErrorContext, + "xsltCompilerNodePop: Expected: '%s' URI '%s'\n", + infname, infnsName); + } +} + +/* +* xsltCompilerBuildInScopeNsList: +* +* Create and store the list of in-scope namespaces for the given +* node in the stylesheet. If there are no changes in the in-scope +* namespaces then the last ns-info of the ancestor axis will be returned. +* Compilation-time only. +* +* Returns the ns-info or NULL if there are no namespaces in scope. +*/ +static xsltNsListContainerPtr +xsltCompilerBuildInScopeNsList(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) +{ + xsltNsListContainerPtr nsi = NULL; + xmlNsPtr *list = NULL, ns; + int i, maxns = 5; + /* + * Create a new ns-list for this position in the node-tree. + * xmlGetNsList() will return NULL, if there are no ns-decls in the + * tree. Note that the ns-decl for the XML namespace is not added + * to the resulting list; the XPath module handles the XML namespace + * internally. + */ + while (node != NULL) { + if (node->type == XML_ELEMENT_NODE) { + ns = node->nsDef; + while (ns != NULL) { + if (nsi == NULL) { + nsi = (xsltNsListContainerPtr) + xmlMalloc(sizeof(xsltNsListContainer)); + if (nsi == NULL) { + xsltTransformError(NULL, cctxt->style, NULL, + "xsltCompilerBuildInScopeNsList: " + "malloc failed!\n"); + goto internal_err; + } + memset(nsi, 0, sizeof(xsltNsListContainer)); + nsi->list = + (xmlNsPtr *) xmlMalloc(maxns * sizeof(xmlNsPtr)); + if (nsi->list == NULL) { + xsltTransformError(NULL, cctxt->style, NULL, + "xsltCompilerBuildInScopeNsList: " + "malloc failed!\n"); + goto internal_err; + } + nsi->list[0] = NULL; + } + /* + * Skip shadowed namespace bindings. + */ + for (i = 0; i < nsi->totalNumber; i++) { + if ((ns->prefix == nsi->list[i]->prefix) || + (xmlStrEqual(ns->prefix, nsi->list[i]->prefix))) + break; + } + if (i >= nsi->totalNumber) { + if (nsi->totalNumber +1 >= maxns) { + maxns *= 2; + nsi->list = + (xmlNsPtr *) xmlRealloc(nsi->list, + maxns * sizeof(xmlNsPtr)); + if (nsi->list == NULL) { + xsltTransformError(NULL, cctxt->style, NULL, + "xsltCompilerBuildInScopeNsList: " + "realloc failed!\n"); + goto internal_err; + } + } + nsi->list[nsi->totalNumber++] = ns; + nsi->list[nsi->totalNumber] = NULL; + } + + ns = ns->next; + } + } + node = node->parent; + } + if (nsi == NULL) + return(NULL); + /* + * Move the default namespace to last position. + */ + nsi->xpathNumber = nsi->totalNumber; + for (i = 0; i < nsi->totalNumber; i++) { + if (nsi->list[i]->prefix == NULL) { + ns = nsi->list[i]; + nsi->list[i] = nsi->list[nsi->totalNumber-1]; + nsi->list[nsi->totalNumber-1] = ns; + nsi->xpathNumber--; + break; + } + } + /* + * Store the ns-list in the stylesheet. + */ + if (xsltPointerListAddSize( + (xsltPointerListPtr)cctxt->psData->inScopeNamespaces, + (void *) nsi, 5) == -1) + { + xmlFree(nsi); + nsi = NULL; + xsltTransformError(NULL, cctxt->style, NULL, + "xsltCompilerBuildInScopeNsList: failed to add ns-info.\n"); + goto internal_err; + } + /* + * Notify of change in status wrt namespaces. + */ + if (cctxt->inode != NULL) + cctxt->inode->nsChanged = 1; + + return(nsi); + +internal_err: + if (list != NULL) + xmlFree(list); + cctxt->style->errors++; + return(NULL); +} + +static int +xsltParseNsPrefixList(xsltCompilerCtxtPtr cctxt, + xsltPointerListPtr list, + xmlNodePtr node, + const xmlChar *value) +{ + xmlChar *cur, *end; + xmlNsPtr ns; + + if ((cctxt == NULL) || (value == NULL) || (list == NULL)) + return(-1); + + list->number = 0; + + cur = (xmlChar *) value; + while (*cur != 0) { + while (IS_BLANK(*cur)) cur++; + if (*cur == 0) + break; + end = cur; + while ((*end != 0) && (!IS_BLANK(*end))) end++; + cur = xmlStrndup(cur, end - cur); + if (cur == NULL) { + cur = end; + continue; + } + /* + * TODO: Export and use xmlSearchNsByPrefixStrict() + * in Libxml2, tree.c, since xmlSearchNs() is in most + * cases not efficient and in some cases not correct. + * + * XSLT-2 TODO: XSLT 2.0 allows an additional "#all" value. + */ + if ((cur[0] == '#') && + xmlStrEqual(cur, (const xmlChar *)"#default")) + ns = xmlSearchNs(cctxt->style->doc, node, NULL); + else + ns = xmlSearchNs(cctxt->style->doc, node, cur); + + if (ns == NULL) { + /* + * TODO: Better to report the attr-node, otherwise + * the user won't know which attribute was invalid. + */ + xsltTransformError(NULL, cctxt->style, node, + "No namespace binding in scope for prefix '%s'.\n", cur); + /* + * XSLT-1.0: "It is an error if there is no namespace + * bound to the prefix on the element bearing the + * exclude-result-prefixes or xsl:exclude-result-prefixes + * attribute." + */ + cctxt->style->errors++; + } else { +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "resolved prefix '%s'\n", cur); +#endif + /* + * Note that we put the namespace name into the dict. + */ + if (xsltPointerListAddSize(list, + (void *) xmlDictLookup(cctxt->style->dict, + ns->href, -1), 5) == -1) + { + xmlFree(cur); + goto internal_err; + } + } + xmlFree(cur); + + cur = end; + } + return(0); + +internal_err: + cctxt->style->errors++; + return(-1); +} + +/** + * xsltCompilerUtilsCreateMergedList: + * @dest: the destination list (optional) + * @first: the first list + * @second: the second list (optional) + * + * Appends the content of @second to @first into @destination. + * If @destination is NULL a new list will be created. + * + * Returns the merged list of items or NULL if there's nothing to merge. + */ +static xsltPointerListPtr +xsltCompilerUtilsCreateMergedList(xsltPointerListPtr first, + xsltPointerListPtr second) +{ + xsltPointerListPtr ret; + size_t num; + + if (first) + num = first->number; + else + num = 0; + if (second) + num += second->number; + if (num == 0) + return(NULL); + ret = xsltPointerListCreate(num); + if (ret == NULL) + return(NULL); + /* + * Copy contents. + */ + if ((first != NULL) && (first->number != 0)) { + memcpy(ret->items, first->items, + first->number * sizeof(void *)); + if ((second != NULL) && (second->number != 0)) + memcpy(ret->items + first->number, second->items, + second->number * sizeof(void *)); + } else if ((second != NULL) && (second->number != 0)) + memcpy(ret->items, (void *) second->items, + second->number * sizeof(void *)); + ret->number = num; + return(ret); +} + +/* +* xsltParseExclResultPrefixes: +* +* Create and store the list of in-scope namespaces for the given +* node in the stylesheet. If there are no changes in the in-scope +* namespaces then the last ns-info of the ancestor axis will be returned. +* Compilation-time only. +* +* Returns the ns-info or NULL if there are no namespaces in scope. +*/ +static xsltPointerListPtr +xsltParseExclResultPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node, + xsltPointerListPtr def, + int instrCategory) +{ + xsltPointerListPtr list = NULL; + xmlChar *value; + xmlAttrPtr attr; + + if ((cctxt == NULL) || (node == NULL)) + return(NULL); + + if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT) + attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes", NULL); + else + attr = xmlHasNsProp(node, BAD_CAST "exclude-result-prefixes", + XSLT_NAMESPACE); + if (attr == NULL) + return(def); + + if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) { + /* + * Mark the XSLT attr. + */ + attr->psvi = (void *) xsltXSLTAttrMarker; + } + + if ((attr->children != NULL) && + (attr->children->content != NULL)) + value = attr->children->content; + else { + xsltTransformError(NULL, cctxt->style, node, + "Attribute 'exclude-result-prefixes': Invalid value.\n"); + cctxt->style->errors++; + return(def); + } + + if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node, + BAD_CAST value) != 0) + goto exit; + if (cctxt->tmpList->number == 0) + goto exit; + /* + * Merge the list with the inherited list. + */ + list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList); + if (list == NULL) + goto exit; + /* + * Store the list in the stylesheet/compiler context. + */ + if (xsltPointerListAddSize( + cctxt->psData->exclResultNamespaces, list, 5) == -1) + { + xsltPointerListFree(list); + list = NULL; + goto exit; + } + /* + * Notify of change in status wrt namespaces. + */ + if (cctxt->inode != NULL) + cctxt->inode->nsChanged = 1; + +exit: + if (list != NULL) + return(list); + else + return(def); +} + +/* +* xsltParseExtElemPrefixes: +* +* Create and store the list of in-scope namespaces for the given +* node in the stylesheet. If there are no changes in the in-scope +* namespaces then the last ns-info of the ancestor axis will be returned. +* Compilation-time only. +* +* Returns the ns-info or NULL if there are no namespaces in scope. +*/ +static xsltPointerListPtr +xsltParseExtElemPrefixes(xsltCompilerCtxtPtr cctxt, xmlNodePtr node, + xsltPointerListPtr def, + int instrCategory) +{ + xsltPointerListPtr list = NULL; + xmlAttrPtr attr; + xmlChar *value; + int i; + + if ((cctxt == NULL) || (node == NULL)) + return(NULL); + + if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT) + attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes", NULL); + else + attr = xmlHasNsProp(node, BAD_CAST "extension-element-prefixes", + XSLT_NAMESPACE); + if (attr == NULL) + return(def); + + if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) { + /* + * Mark the XSLT attr. + */ + attr->psvi = (void *) xsltXSLTAttrMarker; + } + + if ((attr->children != NULL) && + (attr->children->content != NULL)) + value = attr->children->content; + else { + xsltTransformError(NULL, cctxt->style, node, + "Attribute 'extension-element-prefixes': Invalid value.\n"); + cctxt->style->errors++; + return(def); + } + + + if (xsltParseNsPrefixList(cctxt, cctxt->tmpList, node, + BAD_CAST value) != 0) + goto exit; + + if (cctxt->tmpList->number == 0) + goto exit; + /* + * REVISIT: Register the extension namespaces. + */ + for (i = 0; i < cctxt->tmpList->number; i++) + xsltRegisterExtPrefix(cctxt->style, NULL, + BAD_CAST cctxt->tmpList->items[i]); + /* + * Merge the list with the inherited list. + */ + list = xsltCompilerUtilsCreateMergedList(def, cctxt->tmpList); + if (list == NULL) + goto exit; + /* + * Store the list in the stylesheet. + */ + if (xsltPointerListAddSize( + cctxt->psData->extElemNamespaces, list, 5) == -1) + { + xsltPointerListFree(list); + list = NULL; + goto exit; + } + /* + * Notify of change in status wrt namespaces. + */ + if (cctxt->inode != NULL) + cctxt->inode->nsChanged = 1; + +exit: + if (list != NULL) + return(list); + else + return(def); +} + +/* +* xsltParseAttrXSLTVersion: +* +* @cctxt: the compilation context +* @node: the element-node +* @isXsltElem: whether this is an XSLT element +* +* Parses the attribute xsl:version. +* +* Returns 1 if there was such an attribute, 0 if not and +* -1 if an internal or API error occured. +*/ +static int +xsltParseAttrXSLTVersion(xsltCompilerCtxtPtr cctxt, xmlNodePtr node, + int instrCategory) +{ + xmlChar *value; + xmlAttrPtr attr; + + if ((cctxt == NULL) || (node == NULL)) + return(-1); + + if (instrCategory == XSLT_ELEMENT_CATEGORY_XSLT) + attr = xmlHasNsProp(node, BAD_CAST "version", NULL); + else + attr = xmlHasNsProp(node, BAD_CAST "version", XSLT_NAMESPACE); + + if (attr == NULL) + return(0); + + attr->psvi = (void *) xsltXSLTAttrMarker; + + if ((attr->children != NULL) && + (attr->children->content != NULL)) + value = attr->children->content; + else { + xsltTransformError(NULL, cctxt->style, node, + "Attribute 'version': Invalid value.\n"); + cctxt->style->errors++; + return(1); + } + + if (! xmlStrEqual(value, (const xmlChar *)"1.0")) { + cctxt->inode->forwardsCompat = 1; + /* + * TODO: To what extent do we support the + * forwards-compatible mode? + */ + /* + * Report this only once per compilation episode. + */ + if (! cctxt->hasForwardsCompat) { + cctxt->hasForwardsCompat = 1; + cctxt->errSeverity = XSLT_ERROR_SEVERITY_WARNING; + xsltTransformError(NULL, cctxt->style, node, + "Warning: the attribute xsl:version specifies a value " + "different from '1.0'. Switching to forwards-compatible " + "mode. Only features of XSLT 1.0 are supported by this " + "processor.\n"); + cctxt->style->warnings++; + cctxt->errSeverity = XSLT_ERROR_SEVERITY_ERROR; + } + } else { + cctxt->inode->forwardsCompat = 0; + } + + if (attr && (instrCategory == XSLT_ELEMENT_CATEGORY_LRE)) { + /* + * Set a marker on XSLT attributes. + */ + attr->psvi = (void *) xsltXSLTAttrMarker; + } + return(1); +} + +static int +xsltParsePreprocessStylesheetTree(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) +{ + xmlNodePtr deleteNode, cur, txt, textNode = NULL; + xmlDocPtr doc; + xsltStylesheetPtr style; + int internalize = 0, findSpaceAttr; + int xsltStylesheetElemDepth; + xmlAttrPtr attr; + xmlChar *value; + const xmlChar *name, *nsNameXSLT = NULL; + int strictWhitespace, inXSLText = 0; +#ifdef XSLT_REFACTORED_XSLT_NSCOMP + xsltNsMapPtr nsMapItem; +#endif + + if ((cctxt == NULL) || (cctxt->style == NULL) || + (node == NULL) || (node->type != XML_ELEMENT_NODE)) + return(-1); + + doc = node->doc; + if (doc == NULL) + goto internal_err; + + style = cctxt->style; + if ((style->dict != NULL) && (doc->dict == style->dict)) + internalize = 1; + else + style->internalized = 0; + + /* + * Init value of xml:space. Since this might be an embedded + * stylesheet, this is needed to be performed on the element + * where the stylesheet is rooted at, taking xml:space of + * ancestors into account. + */ + if (! cctxt->simplified) + xsltStylesheetElemDepth = cctxt->depth +1; + else + xsltStylesheetElemDepth = 0; + + if (xmlNodeGetSpacePreserve(node) != 1) + cctxt->inode->preserveWhitespace = 0; + else + cctxt->inode->preserveWhitespace = 1; + + /* + * Eval if we should keep the old incorrect behaviour. + */ + strictWhitespace = (cctxt->strict != 0) ? 1 : 0; + + nsNameXSLT = xsltConstNamespaceNameXSLT; + + deleteNode = NULL; + cur = node; + while (cur != NULL) { + if (deleteNode != NULL) { + +#ifdef WITH_XSLT_DEBUG_BLANKS + xsltGenericDebug(xsltGenericDebugContext, + "xsltParsePreprocessStylesheetTree: removing node\n"); +#endif + xmlUnlinkNode(deleteNode); + xmlFreeNode(deleteNode); + deleteNode = NULL; + } + if (cur->type == XML_ELEMENT_NODE) { + + /* + * Clear the PSVI field. + */ + cur->psvi = NULL; + + xsltCompilerNodePush(cctxt, cur); + + inXSLText = 0; + textNode = NULL; + findSpaceAttr = 1; + cctxt->inode->stripWhitespace = 0; + /* + * TODO: I'd love to use a string pointer comparison here :-/ + */ + if (IS_XSLT_ELEM(cur)) { +#ifdef XSLT_REFACTORED_XSLT_NSCOMP + if (cur->ns->href != nsNameXSLT) { + nsMapItem = xsltNewNamespaceMapItem(cctxt, + doc, cur->ns, cur); + if (nsMapItem == NULL) + goto internal_err; + cur->ns->href = nsNameXSLT; + } +#endif + + if (cur->name == NULL) + goto process_attributes; + /* + * Mark the XSLT element for later recognition. + * TODO: Using the marker is still too dangerous, since if + * the parsing mechanism leaves out an XSLT element, then + * this might hit the transformation-mechanism, which + * will break if it doesn't expect such a marker. + */ + /* cur->psvi = (void *) xsltXSLTElemMarker; */ + + /* + * XSLT 2.0: "Any whitespace text node whose parent is + * one of the following elements is removed from the " + * tree, regardless of any xml:space attributes:..." + * xsl:apply-imports, + * xsl:apply-templates, + * xsl:attribute-set, + * xsl:call-template, + * xsl:choose, + * xsl:stylesheet, xsl:transform. + * XSLT 2.0: xsl:analyze-string, + * xsl:character-map, + * xsl:next-match + * + * TODO: I'd love to use a string pointer comparison here :-/ + */ + name = cur->name; + switch (*name) { + case 't': + if ((name[0] == 't') && (name[1] == 'e') && + (name[2] == 'x') && (name[3] == 't') && + (name[4] == 0)) + { + /* + * Process the xsl:text element. + * ---------------------------- + * Mark it for later recognition. + */ + cur->psvi = (void *) xsltXSLTTextMarker; + /* + * For stylesheets, the set of + * whitespace-preserving element names + * consists of just xsl:text. + */ + findSpaceAttr = 0; + cctxt->inode->preserveWhitespace = 1; + inXSLText = 1; + } + break; + case 'c': + if (xmlStrEqual(name, BAD_CAST "choose") || + xmlStrEqual(name, BAD_CAST "call-template")) + cctxt->inode->stripWhitespace = 1; + break; + case 'a': + if (xmlStrEqual(name, BAD_CAST "apply-templates") || + xmlStrEqual(name, BAD_CAST "apply-imports") || + xmlStrEqual(name, BAD_CAST "attribute-set")) + + cctxt->inode->stripWhitespace = 1; + break; + default: + if (xsltStylesheetElemDepth == cctxt->depth) { + /* + * This is a xsl:stylesheet/xsl:transform. + */ + cctxt->inode->stripWhitespace = 1; + break; + } + + if ((cur->prev != NULL) && + (cur->prev->type == XML_TEXT_NODE)) + { + /* + * XSLT 2.0 : "Any whitespace text node whose + * following-sibling node is an xsl:param or + * xsl:sort element is removed from the tree, + * regardless of any xml:space attributes." + */ + if (((*name == 'p') || (*name == 's')) && + (xmlStrEqual(name, BAD_CAST "param") || + xmlStrEqual(name, BAD_CAST "sort"))) + { + do { + if (IS_BLANK_NODE(cur->prev)) { + txt = cur->prev; + xmlUnlinkNode(txt); + xmlFreeNode(txt); + } else { + /* + * This will result in a content + * error, when hitting the parsing + * functions. + */ + break; + } + } while (cur->prev); + } + } + break; + } + } + +process_attributes: + /* + * Process attributes. + * ------------------ + */ + if (cur->properties != NULL) { + if (cur->children == NULL) + findSpaceAttr = 0; + attr = cur->properties; + do { +#ifdef XSLT_REFACTORED_XSLT_NSCOMP + if ((attr->ns) && (attr->ns->href != nsNameXSLT) && + xmlStrEqual(attr->ns->href, nsNameXSLT)) + { + nsMapItem = xsltNewNamespaceMapItem(cctxt, + doc, attr->ns, cur); + if (nsMapItem == NULL) + goto internal_err; + attr->ns->href = nsNameXSLT; + } +#endif + if (internalize) { + /* + * Internalize the attribute's value; the goal is to + * speed up operations and minimize used space by + * compiled stylesheets. + */ + txt = attr->children; + /* + * NOTE that this assumes only one + * text-node in the attribute's content. + */ + if ((txt != NULL) && (txt->content != NULL) && + (!xmlDictOwns(style->dict, txt->content))) + { + value = (xmlChar *) xmlDictLookup(style->dict, + txt->content, -1); + xmlNodeSetContent(txt, NULL); + txt->content = value; + } + } + /* + * Process xml:space attributes. + * ---------------------------- + */ + if ((findSpaceAttr != 0) && + (attr->ns != NULL) && + (attr->name != NULL) && + (attr->name[0] == 's') && + (attr->ns->prefix != NULL) && + (attr->ns->prefix[0] == 'x') && + (attr->ns->prefix[1] == 'm') && + (attr->ns->prefix[2] == 'l') && + (attr->ns->prefix[3] == 0)) + { + value = xmlGetNsProp(cur, BAD_CAST "space", + XML_XML_NAMESPACE); + if (value != NULL) { + if (xmlStrEqual(value, BAD_CAST "preserve")) { + cctxt->inode->preserveWhitespace = 1; + } else if (xmlStrEqual(value, BAD_CAST "default")) { + cctxt->inode->preserveWhitespace = 0; + } else { + /* Invalid value for xml:space. */ + xsltTransformError(NULL, style, cur, + "Attribute xml:space: Invalid value.\n"); + cctxt->style->warnings++; + } + findSpaceAttr = 0; + xmlFree(value); + } + + } + attr = attr->next; + } while (attr != NULL); + } + /* + * We'll descend into the children of element nodes only. + */ + if (cur->children != NULL) { + cur = cur->children; + continue; + } + } else if ((cur->type == XML_TEXT_NODE) || + (cur->type == XML_CDATA_SECTION_NODE)) + { + /* + * Merge adjacent text/CDATA-section-nodes + * --------------------------------------- + * In order to avoid breaking of existing stylesheets, + * if the old behaviour is wanted (strictWhitespace == 0), + * then we *won't* merge adjacent text-nodes + * (except in xsl:text); this will ensure that whitespace-only + * text nodes are (incorrectly) not stripped in some cases. + * + * Example: : zoo + * Corrent (strict) result: zoo + * Incorrect (old) result : zoo + * + * NOTE that we *will* merge adjacent text-nodes if + * they are in xsl:text. + * Example, the following: + * zoo + * will result in both cases in: + * zoo + */ + cur->type = XML_TEXT_NODE; + if ((strictWhitespace != 0) || (inXSLText != 0)) { + /* + * New behaviour; merge nodes. + */ + if (textNode == NULL) + textNode = cur; + else { + if (cur->content != NULL) + xmlNodeAddContent(textNode, cur->content); + deleteNode = cur; + } + if ((cur->next == NULL) || + (cur->next->type == XML_ELEMENT_NODE)) + goto end_of_text; + else + goto next_sibling; + } else { + /* + * Old behaviour. + */ + if (textNode == NULL) + textNode = cur; + goto end_of_text; + } + } else if ((cur->type == XML_COMMENT_NODE) || + (cur->type == XML_PI_NODE)) + { + /* + * Remove processing instructions and comments. + */ + deleteNode = cur; + if ((cur->next == NULL) || + (cur->next->type == XML_ELEMENT_NODE)) + goto end_of_text; + else + goto next_sibling; + } else { + textNode = NULL; + /* + * Invalid node-type for this data-model. + */ + xsltTransformError(NULL, style, cur, + "Invalid type of node for the XSLT data model.\n"); + cctxt->style->errors++; + goto next_sibling; + } + +end_of_text: + if (textNode) { + value = textNode->content; + /* + * At this point all adjacent text/CDATA-section nodes + * have been merged. + * + * Strip whitespace-only text-nodes. + * (cctxt->inode->stripWhitespace) + */ + if ((value == NULL) || (*value == 0) || + (((cctxt->inode->stripWhitespace) || + (! cctxt->inode->preserveWhitespace)) && + IS_BLANK(*value) && + xsltIsBlank(value))) + { + if (textNode != cur) { + xmlUnlinkNode(textNode); + xmlFreeNode(textNode); + } else + deleteNode = textNode; + textNode = NULL; + goto next_sibling; + } + /* + * Convert CDATA-section nodes to text-nodes. + * TODO: Can this produce problems? + */ + if (textNode->type != XML_TEXT_NODE) { + textNode->type = XML_TEXT_NODE; + textNode->name = xmlStringText; + } + if (internalize && + (textNode->content != NULL) && + (!xmlDictOwns(style->dict, textNode->content))) + { + /* + * Internalize the string. + */ + value = (xmlChar *) xmlDictLookup(style->dict, + textNode->content, -1); + xmlNodeSetContent(textNode, NULL); + textNode->content = value; + } + textNode = NULL; + /* + * Note that "disable-output-escaping" of the xsl:text + * element will be applied at a later level, when + * XSLT elements are processed. + */ + } + +next_sibling: + if (cur->type == XML_ELEMENT_NODE) { + xsltCompilerNodePop(cctxt, cur); + } + if (cur == node) + break; + if (cur->next != NULL) { + cur = cur->next; + } else { + cur = cur->parent; + inXSLText = 0; + goto next_sibling; + }; + } + if (deleteNode != NULL) { +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "xsltParsePreprocessStylesheetTree: removing node\n"); +#endif + xmlUnlinkNode(deleteNode); + xmlFreeNode(deleteNode); + } + return(0); + +internal_err: + return(-1); +} + +#endif /* XSLT_REFACTORED */ + +#ifdef XSLT_REFACTORED +#else +static void +xsltPreprocessStylesheet(xsltStylesheetPtr style, xmlNodePtr cur) +{ + xmlNodePtr deleteNode, styleelem; + int internalize = 0; + + if ((style == NULL) || (cur == NULL)) + return; + + if ((cur->doc != NULL) && (style->dict != NULL) && + (cur->doc->dict == style->dict)) + internalize = 1; + else + style->internalized = 0; + + if ((cur != NULL) && (IS_XSLT_ELEM(cur)) && + (IS_XSLT_NAME(cur, "stylesheet"))) { + styleelem = cur; + } else { + styleelem = NULL; + } + + /* + * This content comes from the stylesheet + * For stylesheets, the set of whitespace-preserving + * element names consists of just xsl:text. + */ + deleteNode = NULL; + while (cur != NULL) { + if (deleteNode != NULL) { +#ifdef WITH_XSLT_DEBUG_BLANKS + xsltGenericDebug(xsltGenericDebugContext, + "xsltPreprocessStylesheet: removing ignorable blank node\n"); +#endif + xmlUnlinkNode(deleteNode); + xmlFreeNode(deleteNode); + deleteNode = NULL; + } + if (cur->type == XML_ELEMENT_NODE) { + int exclPrefixes; + /* + * Internalize attributes values. + */ + if ((internalize) && (cur->properties != NULL)) { + xmlAttrPtr attr = cur->properties; + xmlNodePtr txt; + + while (attr != NULL) { + txt = attr->children; + if ((txt != NULL) && (txt->type == XML_TEXT_NODE) && + (txt->content != NULL) && + (!xmlDictOwns(style->dict, txt->content))) + { + xmlChar *tmp; + + /* + * internalize the text string, goal is to speed + * up operations and minimize used space by compiled + * stylesheets. + */ + tmp = (xmlChar *) xmlDictLookup(style->dict, + txt->content, -1); + if (tmp != txt->content) { + xmlNodeSetContent(txt, NULL); + txt->content = tmp; + } + } + attr = attr->next; + } + } + if (IS_XSLT_ELEM(cur)) { + exclPrefixes = 0; + if (IS_XSLT_NAME(cur, "text")) { + for (;exclPrefixes > 0;exclPrefixes--) + exclPrefixPop(style); + goto skip_children; + } + } else { + exclPrefixes = xsltParseStylesheetExcludePrefix(style, cur, 0); + } + + if ((cur->nsDef != NULL) && (style->exclPrefixNr > 0)) { + xmlNsPtr ns = cur->nsDef, prev = NULL, next; + xmlNodePtr root = NULL; + int i, moved; + + root = xmlDocGetRootElement(cur->doc); + if ((root != NULL) && (root != cur)) { + while (ns != NULL) { + moved = 0; + next = ns->next; + for (i = 0;i < style->exclPrefixNr;i++) { + if ((ns->prefix != NULL) && + (xmlStrEqual(ns->href, + style->exclPrefixTab[i]))) { + /* + * Move the namespace definition on the root + * element to avoid duplicating it without + * loosing it. + */ + if (prev == NULL) { + cur->nsDef = ns->next; + } else { + prev->next = ns->next; + } + ns->next = root->nsDef; + root->nsDef = ns; + moved = 1; + break; + } + } + if (moved == 0) + prev = ns; + ns = next; + } + } + } + /* + * If we have prefixes locally, recurse and pop them up when + * going back + */ + if (exclPrefixes > 0) { + xsltPreprocessStylesheet(style, cur->children); + for (;exclPrefixes > 0;exclPrefixes--) + exclPrefixPop(style); + goto skip_children; + } + } else if (cur->type == XML_TEXT_NODE) { + if (IS_BLANK_NODE(cur)) { + if (xmlNodeGetSpacePreserve(cur->parent) != 1) { + deleteNode = cur; + } + } else if ((cur->content != NULL) && (internalize) && + (!xmlDictOwns(style->dict, cur->content))) { + xmlChar *tmp; + + /* + * internalize the text string, goal is to speed + * up operations and minimize used space by compiled + * stylesheets. + */ + tmp = (xmlChar *) xmlDictLookup(style->dict, cur->content, -1); + xmlNodeSetContent(cur, NULL); + cur->content = tmp; + } + } else if ((cur->type != XML_ELEMENT_NODE) && + (cur->type != XML_CDATA_SECTION_NODE)) { + deleteNode = cur; + goto skip_children; + } + + /* + * Skip to next node. In case of a namespaced element children of + * the stylesheet and not in the XSLT namespace and not an extension + * element, ignore its content. + */ + if ((cur->type == XML_ELEMENT_NODE) && (cur->ns != NULL) && + (styleelem != NULL) && (cur->parent == styleelem) && + (!xmlStrEqual(cur->ns->href, XSLT_NAMESPACE)) && + (!xsltCheckExtURI(style, cur->ns->href))) { + goto skip_children; + } else if (cur->children != NULL) { + cur = cur->children; + continue; + } + +skip_children: + if (cur->next != NULL) { + cur = cur->next; + continue; + } + do { + + cur = cur->parent; + if (cur == NULL) + break; + if (cur == (xmlNodePtr) style->doc) { + cur = NULL; + break; + } + if (cur->next != NULL) { + cur = cur->next; + break; + } + } while (cur != NULL); + } + if (deleteNode != NULL) { +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "xsltPreprocessStylesheet: removing ignorable blank node\n"); +#endif + xmlUnlinkNode(deleteNode); + xmlFreeNode(deleteNode); + } +} +#endif /* end of else XSLT_REFACTORED */ + +/** + * xsltGatherNamespaces: + * @style: the XSLT stylesheet + * + * Browse the stylesheet and build the namspace hash table which + * will be used for XPath interpretation. If needed do a bit of normalization + */ + +static void +xsltGatherNamespaces(xsltStylesheetPtr style) { + xmlNodePtr cur; + const xmlChar *URI; + + if (style == NULL) + return; + /* + * TODO: basically if the stylesheet uses the same prefix for different + * patterns, well they may be in problem, hopefully they will get + * a warning first. + */ + /* + * TODO: Eliminate the use of the hash for XPath expressions. + * An expression should be evaluated in the context of the in-scope + * namespaces; eliminate the restriction of an XML document to contain + * no duplicate prefixes for different namespace names. + * + */ + cur = xmlDocGetRootElement(style->doc); + while (cur != NULL) { + if (cur->type == XML_ELEMENT_NODE) { + xmlNsPtr ns = cur->nsDef; + while (ns != NULL) { + if (ns->prefix != NULL) { + if (style->nsHash == NULL) { + style->nsHash = xmlHashCreate(10); + if (style->nsHash == NULL) { + xsltTransformError(NULL, style, cur, + "xsltGatherNamespaces: failed to create hash table\n"); + style->errors++; + return; + } + } + URI = xmlHashLookup(style->nsHash, ns->prefix); + if ((URI != NULL) && (!xmlStrEqual(URI, ns->href))) { + xsltTransformError(NULL, style, cur, + "Namespaces prefix %s used for multiple namespaces\n",ns->prefix); + style->warnings++; + } else if (URI == NULL) { + xmlHashUpdateEntry(style->nsHash, ns->prefix, + (void *) ns->href, NULL); + +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "Added namespace: %s mapped to %s\n", ns->prefix, ns->href); +#endif + } + } + ns = ns->next; + } + } + + /* + * Skip to next node + */ + if (cur->children != NULL) { + if (cur->children->type != XML_ENTITY_DECL) { + cur = cur->children; + continue; + } + } + if (cur->next != NULL) { + cur = cur->next; + continue; + } + + do { + cur = cur->parent; + if (cur == NULL) + break; + if (cur == (xmlNodePtr) style->doc) { + cur = NULL; + break; + } + if (cur->next != NULL) { + cur = cur->next; + break; + } + } while (cur != NULL); + } +} + +#ifdef XSLT_REFACTORED + +static xsltStyleType +xsltGetXSLTElementTypeByNode(xsltCompilerCtxtPtr cctxt, + xmlNodePtr node) +{ + if ((node == NULL) || (node->type != XML_ELEMENT_NODE) || + (node->name == NULL)) + return(0); + + if (node->name[0] == 'a') { + if (IS_XSLT_NAME(node, "apply-templates")) + return(XSLT_FUNC_APPLYTEMPLATES); + else if (IS_XSLT_NAME(node, "attribute")) + return(XSLT_FUNC_ATTRIBUTE); + else if (IS_XSLT_NAME(node, "apply-imports")) + return(XSLT_FUNC_APPLYIMPORTS); + else if (IS_XSLT_NAME(node, "attribute-set")) + return(0); + + } else if (node->name[0] == 'c') { + if (IS_XSLT_NAME(node, "choose")) + return(XSLT_FUNC_CHOOSE); + else if (IS_XSLT_NAME(node, "copy")) + return(XSLT_FUNC_COPY); + else if (IS_XSLT_NAME(node, "copy-of")) + return(XSLT_FUNC_COPYOF); + else if (IS_XSLT_NAME(node, "call-template")) + return(XSLT_FUNC_CALLTEMPLATE); + else if (IS_XSLT_NAME(node, "comment")) + return(XSLT_FUNC_COMMENT); + + } else if (node->name[0] == 'd') { + if (IS_XSLT_NAME(node, "document")) + return(XSLT_FUNC_DOCUMENT); + else if (IS_XSLT_NAME(node, "decimal-format")) + return(0); + + } else if (node->name[0] == 'e') { + if (IS_XSLT_NAME(node, "element")) + return(XSLT_FUNC_ELEMENT); + + } else if (node->name[0] == 'f') { + if (IS_XSLT_NAME(node, "for-each")) + return(XSLT_FUNC_FOREACH); + else if (IS_XSLT_NAME(node, "fallback")) + return(XSLT_FUNC_FALLBACK); + + } else if (*(node->name) == 'i') { + if (IS_XSLT_NAME(node, "if")) + return(XSLT_FUNC_IF); + else if (IS_XSLT_NAME(node, "include")) + return(0); + else if (IS_XSLT_NAME(node, "import")) + return(0); + + } else if (*(node->name) == 'k') { + if (IS_XSLT_NAME(node, "key")) + return(0); + + } else if (*(node->name) == 'm') { + if (IS_XSLT_NAME(node, "message")) + return(XSLT_FUNC_MESSAGE); + + } else if (*(node->name) == 'n') { + if (IS_XSLT_NAME(node, "number")) + return(XSLT_FUNC_NUMBER); + else if (IS_XSLT_NAME(node, "namespace-alias")) + return(0); + + } else if (*(node->name) == 'o') { + if (IS_XSLT_NAME(node, "otherwise")) + return(XSLT_FUNC_OTHERWISE); + else if (IS_XSLT_NAME(node, "output")) + return(0); + + } else if (*(node->name) == 'p') { + if (IS_XSLT_NAME(node, "param")) + return(XSLT_FUNC_PARAM); + else if (IS_XSLT_NAME(node, "processing-instruction")) + return(XSLT_FUNC_PI); + else if (IS_XSLT_NAME(node, "preserve-space")) + return(0); + + } else if (*(node->name) == 's') { + if (IS_XSLT_NAME(node, "sort")) + return(XSLT_FUNC_SORT); + else if (IS_XSLT_NAME(node, "strip-space")) + return(0); + else if (IS_XSLT_NAME(node, "stylesheet")) + return(0); + + } else if (node->name[0] == 't') { + if (IS_XSLT_NAME(node, "text")) + return(XSLT_FUNC_TEXT); + else if (IS_XSLT_NAME(node, "template")) + return(0); + else if (IS_XSLT_NAME(node, "transform")) + return(0); + + } else if (*(node->name) == 'v') { + if (IS_XSLT_NAME(node, "value-of")) + return(XSLT_FUNC_VALUEOF); + else if (IS_XSLT_NAME(node, "variable")) + return(XSLT_FUNC_VARIABLE); + + } else if (*(node->name) == 'w') { + if (IS_XSLT_NAME(node, "when")) + return(XSLT_FUNC_WHEN); + if (IS_XSLT_NAME(node, "with-param")) + return(XSLT_FUNC_WITHPARAM); + } + return(0); +} + +/** + * xsltParseAnyXSLTElem: + * + * @cctxt: the compilation context + * @elem: the element node of the XSLT instruction + * + * Parses, validates the content models and compiles XSLT instructions. + * + * Returns 0 if everything's fine; + * -1 on API or internal errors. + */ +int +xsltParseAnyXSLTElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr elem) +{ + if ((cctxt == NULL) || (elem == NULL) || + (elem->type != XML_ELEMENT_NODE)) + return(-1); + + elem->psvi = NULL; + + if (! (IS_XSLT_ELEM_FAST(elem))) + return(-1); + /* + * Detection of handled content of extension instructions. + */ + if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) { + cctxt->inode->extContentHandled = 1; + } + + xsltCompilerNodePush(cctxt, elem); + /* + * URGENT TODO: Find a way to speed up this annoying redundant + * textual node-name and namespace comparison. + */ + if (cctxt->inode->prev->curChildType != 0) + cctxt->inode->type = cctxt->inode->prev->curChildType; + else + cctxt->inode->type = xsltGetXSLTElementTypeByNode(cctxt, elem); + /* + * Update the in-scope namespaces if needed. + */ + if (elem->nsDef != NULL) + cctxt->inode->inScopeNs = + xsltCompilerBuildInScopeNsList(cctxt, elem); + /* + * xsltStylePreCompute(): + * This will compile the information found on the current + * element's attributes. NOTE that this won't process the + * children of the instruction. + */ + xsltStylePreCompute(cctxt->style, elem); + /* + * TODO: How to react on errors in xsltStylePreCompute() ? + */ + + /* + * Validate the content model of the XSLT-element. + */ + switch (cctxt->inode->type) { + case XSLT_FUNC_APPLYIMPORTS: + /* EMPTY */ + goto empty_content; + case XSLT_FUNC_APPLYTEMPLATES: + /* */ + goto apply_templates; + case XSLT_FUNC_ATTRIBUTE: + /* */ + goto sequence_constructor; + case XSLT_FUNC_CALLTEMPLATE: + /* */ + goto call_template; + case XSLT_FUNC_CHOOSE: + /* */ + goto choose; + case XSLT_FUNC_COMMENT: + /* */ + goto sequence_constructor; + case XSLT_FUNC_COPY: + /* */ + goto sequence_constructor; + case XSLT_FUNC_COPYOF: + /* EMPTY */ + goto empty_content; + case XSLT_FUNC_DOCUMENT: /* Extra one */ + /* ?? template ?? */ + goto sequence_constructor; + case XSLT_FUNC_ELEMENT: + /* */ + goto sequence_constructor; + case XSLT_FUNC_FALLBACK: + /* */ + goto sequence_constructor; + case XSLT_FUNC_FOREACH: + /* */ + goto for_each; + case XSLT_FUNC_IF: + /* */ + goto sequence_constructor; + case XSLT_FUNC_OTHERWISE: + /* */ + goto sequence_constructor; + case XSLT_FUNC_MESSAGE: + /* */ + goto sequence_constructor; + case XSLT_FUNC_NUMBER: + /* EMPTY */ + goto empty_content; + case XSLT_FUNC_PARAM: + /* + * Check for redefinition. + */ + if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) { + xsltVarInfoPtr ivar = cctxt->ivar; + + do { + if ((ivar->name == + ((xsltStyleItemParamPtr) elem->psvi)->name) && + (ivar->nsName == + ((xsltStyleItemParamPtr) elem->psvi)->ns)) + { + elem->psvi = NULL; + xsltTransformError(NULL, cctxt->style, elem, + "Redefinition of variable or parameter '%s'.\n", + ivar->name); + cctxt->style->errors++; + goto error; + } + ivar = ivar->prev; + } while (ivar != NULL); + } + /* */ + goto sequence_constructor; + case XSLT_FUNC_PI: + /* */ + goto sequence_constructor; + case XSLT_FUNC_SORT: + /* EMPTY */ + goto empty_content; + case XSLT_FUNC_TEXT: + /* */ + goto text; + case XSLT_FUNC_VALUEOF: + /* EMPTY */ + goto empty_content; + case XSLT_FUNC_VARIABLE: + /* + * Check for redefinition. + */ + if ((elem->psvi != NULL) && (cctxt->ivar != NULL)) { + xsltVarInfoPtr ivar = cctxt->ivar; + + do { + if ((ivar->name == + ((xsltStyleItemVariablePtr) elem->psvi)->name) && + (ivar->nsName == + ((xsltStyleItemVariablePtr) elem->psvi)->ns)) + { + elem->psvi = NULL; + xsltTransformError(NULL, cctxt->style, elem, + "Redefinition of variable or parameter '%s'.\n", + ivar->name); + cctxt->style->errors++; + goto error; + } + ivar = ivar->prev; + } while (ivar != NULL); + } + /* */ + goto sequence_constructor; + case XSLT_FUNC_WHEN: + /* */ + goto sequence_constructor; + case XSLT_FUNC_WITHPARAM: + /* */ + goto sequence_constructor; + default: +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "xsltParseXSLTNode: Unhandled XSLT element '%s'.\n", + elem->name); +#endif + xsltTransformError(NULL, cctxt->style, elem, + "xsltParseXSLTNode: Internal error; " + "unhandled XSLT element '%s'.\n", elem->name); + cctxt->style->errors++; + goto internal_err; + } + +apply_templates: + /* */ + if (elem->children != NULL) { + xmlNodePtr child = elem->children; + do { + if (child->type == XML_ELEMENT_NODE) { + if (IS_XSLT_ELEM_FAST(child)) { + if (xmlStrEqual(child->name, BAD_CAST "with-param")) { + cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM; + xsltParseAnyXSLTElem(cctxt, child); + } else if (xmlStrEqual(child->name, BAD_CAST "sort")) { + cctxt->inode->curChildType = XSLT_FUNC_SORT; + xsltParseAnyXSLTElem(cctxt, child); + } else + xsltParseContentError(cctxt->style, child); + } else + xsltParseContentError(cctxt->style, child); + } + child = child->next; + } while (child != NULL); + } + goto exit; + +call_template: + /* */ + if (elem->children != NULL) { + xmlNodePtr child = elem->children; + do { + if (child->type == XML_ELEMENT_NODE) { + if (IS_XSLT_ELEM_FAST(child)) { + xsltStyleType type; + + type = xsltGetXSLTElementTypeByNode(cctxt, child); + if (type == XSLT_FUNC_WITHPARAM) { + cctxt->inode->curChildType = XSLT_FUNC_WITHPARAM; + xsltParseAnyXSLTElem(cctxt, child); + } else { + xsltParseContentError(cctxt->style, child); + } + } else + xsltParseContentError(cctxt->style, child); + } + child = child->next; + } while (child != NULL); + } + goto exit; + +text: + if (elem->children != NULL) { + xmlNodePtr child = elem->children; + do { + if ((child->type != XML_TEXT_NODE) && + (child->type != XML_CDATA_SECTION_NODE)) + { + xsltTransformError(NULL, cctxt->style, elem, + "The XSLT 'text' element must have only character " + "data as content.\n"); + } + child = child->next; + } while (child != NULL); + } + goto exit; + +empty_content: + if (elem->children != NULL) { + xmlNodePtr child = elem->children; + /* + * Relaxed behaviour: we will allow whitespace-only text-nodes. + */ + do { + if (((child->type != XML_TEXT_NODE) && + (child->type != XML_CDATA_SECTION_NODE)) || + (! IS_BLANK_NODE(child))) + { + xsltTransformError(NULL, cctxt->style, elem, + "This XSLT element must have no content.\n"); + cctxt->style->errors++; + break; + } + child = child->next; + } while (child != NULL); + } + goto exit; + +choose: + /* */ + /* + * TODO: text-nodes in between are *not* allowed in XSLT 1.0. + * The old behaviour did not check this. + * NOTE: In XSLT 2.0 they are stripped beforehand + * if whitespace-only (regardless of xml:space). + */ + if (elem->children != NULL) { + xmlNodePtr child = elem->children; + int nbWhen = 0, nbOtherwise = 0, err = 0; + do { + if (child->type == XML_ELEMENT_NODE) { + if (IS_XSLT_ELEM_FAST(child)) { + xsltStyleType type; + + type = xsltGetXSLTElementTypeByNode(cctxt, child); + if (type == XSLT_FUNC_WHEN) { + nbWhen++; + if (nbOtherwise) { + xsltParseContentError(cctxt->style, child); + err = 1; + break; + } + cctxt->inode->curChildType = XSLT_FUNC_WHEN; + xsltParseAnyXSLTElem(cctxt, child); + } else if (type == XSLT_FUNC_OTHERWISE) { + if (! nbWhen) { + xsltParseContentError(cctxt->style, child); + err = 1; + break; + } + if (nbOtherwise) { + xsltTransformError(NULL, cctxt->style, elem, + "The XSLT 'choose' element must not contain " + "more than one XSLT 'otherwise' element.\n"); + cctxt->style->errors++; + err = 1; + break; + } + nbOtherwise++; + cctxt->inode->curChildType = XSLT_FUNC_OTHERWISE; + xsltParseAnyXSLTElem(cctxt, child); + } else + xsltParseContentError(cctxt->style, child); + } else + xsltParseContentError(cctxt->style, child); + } + /* + else + xsltParseContentError(cctxt, child); + */ + child = child->next; + } while (child != NULL); + if ((! err) && (! nbWhen)) { + xsltTransformError(NULL, cctxt->style, elem, + "The XSLT element 'choose' must contain at least one " + "XSLT element 'when'.\n"); + cctxt->style->errors++; + } + } + goto exit; + +for_each: + /* */ + /* + * NOTE: Text-nodes before xsl:sort are *not* allowed in XSLT 1.0. + * The old behaviour did not allow this, but it catched this + * only at transformation-time. + * In XSLT 2.0 they are stripped beforehand if whitespace-only + * (regardless of xml:space). + */ + if (elem->children != NULL) { + xmlNodePtr child = elem->children; + /* + * Parse xsl:sort first. + */ + do { + if ((child->type == XML_ELEMENT_NODE) && + IS_XSLT_ELEM_FAST(child)) + { + if (xsltGetXSLTElementTypeByNode(cctxt, child) == + XSLT_FUNC_SORT) + { + cctxt->inode->curChildType = XSLT_FUNC_SORT; + xsltParseAnyXSLTElem(cctxt, child); + } else + break; + } else + break; + child = child->next; + } while (child != NULL); + /* + * Parse the sequece constructor. + */ + if (child != NULL) + xsltParseSequenceConstructor(cctxt, child); + } + goto exit; + +sequence_constructor: + /* + * Parse the sequence constructor. + */ + if (elem->children != NULL) + xsltParseSequenceConstructor(cctxt, elem->children); + + /* + * Register information for vars/params. Only needed if there + * are any following siblings. + */ + if ((elem->next != NULL) && + ((cctxt->inode->type == XSLT_FUNC_VARIABLE) || + (cctxt->inode->type == XSLT_FUNC_PARAM))) + { + if ((elem->psvi != NULL) && + (((xsltStyleBasicItemVariablePtr) elem->psvi)->name)) + { + xsltCompilerVarInfoPush(cctxt, elem, + ((xsltStyleBasicItemVariablePtr) elem->psvi)->name, + ((xsltStyleBasicItemVariablePtr) elem->psvi)->ns); + } + } + +error: +exit: + xsltCompilerNodePop(cctxt, elem); + return(0); + +internal_err: + xsltCompilerNodePop(cctxt, elem); + return(-1); +} + +/** + * xsltForwardsCompatUnkownItemCreate: + * + * @cctxt: the compilation context + * + * Creates a compiled representation of the unknown + * XSLT instruction. + * + * Returns the compiled representation. + */ +static xsltStyleItemUknownPtr +xsltForwardsCompatUnkownItemCreate(xsltCompilerCtxtPtr cctxt) +{ + xsltStyleItemUknownPtr item; + + item = (xsltStyleItemUknownPtr) xmlMalloc(sizeof(xsltStyleItemUknown)); + if (item == NULL) { + xsltTransformError(NULL, cctxt->style, NULL, + "Internal error in xsltForwardsCompatUnkownItemCreate(): " + "Failed to allocate memory.\n"); + cctxt->style->errors++; + return(NULL); + } + memset(item, 0, sizeof(xsltStyleItemUknown)); + item->type = XSLT_FUNC_UNKOWN_FORWARDS_COMPAT; + /* + * Store it in the stylesheet. + */ + item->next = cctxt->style->preComps; + cctxt->style->preComps = (xsltElemPreCompPtr) item; + return(item); +} + +/** + * xsltParseUnknownXSLTElem: + * + * @cctxt: the compilation context + * @node: the element of the unknown XSLT instruction + * + * Parses an unknown XSLT element. + * If forwards compatible mode is enabled this will allow + * such an unknown XSLT and; otherwise it is rejected. + * + * Returns 1 in the unknown XSLT instruction is rejected, + * 0 if everything's fine and + * -1 on API or internal errors. + */ +static int +xsltParseUnknownXSLTElem(xsltCompilerCtxtPtr cctxt, + xmlNodePtr node) +{ + if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE)) + return(-1); + + /* + * Detection of handled content of extension instructions. + */ + if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) { + cctxt->inode->extContentHandled = 1; + } + if (cctxt->inode->forwardsCompat == 0) { + /* + * We are not in forwards-compatible mode, so raise an error. + */ + xsltTransformError(NULL, cctxt->style, node, + "Unknown XSLT element '%s'.\n", node->name); + cctxt->style->errors++; + return(1); + } + /* + * Forwards-compatible mode. + * ------------------------ + * + * Parse/compile xsl:fallback elements. + * + * QUESTION: Do we have to raise an error if there's no xsl:fallback? + * ANSWER: No, since in the stylesheet the fallback behaviour might + * also be provided by using the XSLT function "element-available". + */ + if (cctxt->unknownItem == NULL) { + /* + * Create a singleton for all unknown XSLT instructions. + */ + cctxt->unknownItem = xsltForwardsCompatUnkownItemCreate(cctxt); + if (cctxt->unknownItem == NULL) { + node->psvi = NULL; + return(-1); + } + } + node->psvi = cctxt->unknownItem; + if (node->children == NULL) + return(0); + else { + xmlNodePtr child = node->children; + + xsltCompilerNodePush(cctxt, node); + /* + * Update the in-scope namespaces if needed. + */ + if (node->nsDef != NULL) + cctxt->inode->inScopeNs = + xsltCompilerBuildInScopeNsList(cctxt, node); + /* + * Parse all xsl:fallback children. + */ + do { + if ((child->type == XML_ELEMENT_NODE) && + IS_XSLT_ELEM_FAST(child) && + IS_XSLT_NAME(child, "fallback")) + { + cctxt->inode->curChildType = XSLT_FUNC_FALLBACK; + xsltParseAnyXSLTElem(cctxt, child); + } + child = child->next; + } while (child != NULL); + + xsltCompilerNodePop(cctxt, node); + } + return(0); +} + +/** + * xsltParseSequenceConstructor: + * + * @cctxt: the compilation context + * @cur: the start-node of the content to be parsed + * + * Parses a "template" content (or "sequence constructor" in XSLT 2.0 terms). + * This will additionally remove xsl:text elements from the tree. + */ +void +xsltParseSequenceConstructor(xsltCompilerCtxtPtr cctxt, xmlNodePtr cur) +{ + xsltStyleType type; + xmlNodePtr deleteNode = NULL; + + if (cctxt == NULL) { + xmlGenericError(xmlGenericErrorContext, + "xsltParseSequenceConstructor: Bad arguments\n"); + cctxt->style->errors++; + return; + } + /* + * Detection of handled content of extension instructions. + */ + if (cctxt->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) { + cctxt->inode->extContentHandled = 1; + } + if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) + return; + /* + * This is the content reffered to as a "template". + * E.g. an xsl:element has such content model: + * + * + * + * NOTE that in XSLT-2 the term "template" was abandoned due to + * confusion with xsl:template and the term "sequence constructor" + * was introduced instead. + * + * The following XSLT-instructions are allowed to appear: + * xsl:apply-templates, xsl:call-template, xsl:apply-imports, + * xsl:for-each, xsl:value-of, xsl:copy-of, xsl:number, + * xsl:choose, xsl:if, xsl:text, xsl:copy, xsl:variable, + * xsl:message, xsl:fallback, + * xsl:processing-instruction, xsl:comment, xsl:element + * xsl:attribute. + * Additional allowed content: + * 1) extension instructions + * 2) literal result elements + * 3) PCDATA + * + * NOTE that this content model does *not* allow xsl:param. + */ + while (cur != NULL) { + cctxt->style->principal->opCount += 1; + + if (deleteNode != NULL) { +#ifdef WITH_XSLT_DEBUG_BLANKS + xsltGenericDebug(xsltGenericDebugContext, + "xsltParseSequenceConstructor: removing xsl:text element\n"); +#endif + xmlUnlinkNode(deleteNode); + xmlFreeNode(deleteNode); + deleteNode = NULL; + } + if (cur->type == XML_ELEMENT_NODE) { + + if (cur->psvi == xsltXSLTTextMarker) { + /* + * xsl:text elements + * -------------------------------------------------------- + */ + xmlNodePtr tmp; + + cur->psvi = NULL; + /* + * Mark the xsl:text element for later deletion. + */ + deleteNode = cur; + /* + * Validate content. + */ + tmp = cur->children; + if (tmp) { + /* + * We don't expect more than one text-node in the + * content, since we already merged adjacent + * text/CDATA-nodes and eliminated PI/comment-nodes. + */ + if ((tmp->type == XML_TEXT_NODE) || + (tmp->next == NULL)) + { + /* + * Leave the contained text-node in the tree. + */ + xmlUnlinkNode(tmp); + if (xmlAddPrevSibling(cur, tmp) == NULL) { + xsltTransformError(ctxt, NULL, NULL, + "out of memory\n"); + xmlFreeNode(tmp); + } + } else { + tmp = NULL; + xsltTransformError(NULL, cctxt->style, cur, + "Element 'xsl:text': Invalid type " + "of node found in content.\n"); + cctxt->style->errors++; + } + } + if (cur->properties) { + xmlAttrPtr attr; + /* + * TODO: We need to report errors for + * invalid attrs. + */ + attr = cur->properties; + do { + if ((attr->ns == NULL) && + (attr->name != NULL) && + (attr->name[0] == 'd') && + xmlStrEqual(attr->name, + BAD_CAST "disable-output-escaping")) + { + /* + * Attr "disable-output-escaping". + * XSLT-2: This attribute is deprecated. + */ + if ((attr->children != NULL) && + xmlStrEqual(attr->children->content, + BAD_CAST "yes")) + { + /* + * Disable output escaping for this + * text node. + */ + if (tmp) + tmp->name = xmlStringTextNoenc; + } else if ((attr->children == NULL) || + (attr->children->content == NULL) || + (!xmlStrEqual(attr->children->content, + BAD_CAST "no"))) + { + xsltTransformError(NULL, cctxt->style, + cur, + "Attribute 'disable-output-escaping': " + "Invalid value. Expected is " + "'yes' or 'no'.\n"); + cctxt->style->errors++; + } + break; + } + attr = attr->next; + } while (attr != NULL); + } + } else if (IS_XSLT_ELEM_FAST(cur)) { + /* + * TODO: Using the XSLT-marker is still not stable yet. + */ + /* if (cur->psvi == xsltXSLTElemMarker) { */ + /* + * XSLT instructions + * -------------------------------------------------------- + */ + cur->psvi = NULL; + type = xsltGetXSLTElementTypeByNode(cctxt, cur); + switch (type) { + case XSLT_FUNC_APPLYIMPORTS: + case XSLT_FUNC_APPLYTEMPLATES: + case XSLT_FUNC_ATTRIBUTE: + case XSLT_FUNC_CALLTEMPLATE: + case XSLT_FUNC_CHOOSE: + case XSLT_FUNC_COMMENT: + case XSLT_FUNC_COPY: + case XSLT_FUNC_COPYOF: + case XSLT_FUNC_DOCUMENT: /* Extra one */ + case XSLT_FUNC_ELEMENT: + case XSLT_FUNC_FALLBACK: + case XSLT_FUNC_FOREACH: + case XSLT_FUNC_IF: + case XSLT_FUNC_MESSAGE: + case XSLT_FUNC_NUMBER: + case XSLT_FUNC_PI: + case XSLT_FUNC_TEXT: + case XSLT_FUNC_VALUEOF: + case XSLT_FUNC_VARIABLE: + /* + * Parse the XSLT element. + */ + cctxt->inode->curChildType = type; + xsltParseAnyXSLTElem(cctxt, cur); + break; + default: + xsltParseUnknownXSLTElem(cctxt, cur); + cur = cur->next; + continue; + } + } else { + /* + * Non-XSLT elements + * ----------------- + */ + xsltCompilerNodePush(cctxt, cur); + /* + * Update the in-scope namespaces if needed. + */ + if (cur->nsDef != NULL) + cctxt->inode->inScopeNs = + xsltCompilerBuildInScopeNsList(cctxt, cur); + /* + * The current element is either a literal result element + * or an extension instruction. + * + * Process attr "xsl:extension-element-prefixes". + * FUTURE TODO: IIRC in XSLT 2.0 this attribute must be + * processed by the implementor of the extension function; + * i.e., it won't be handled by the XSLT processor. + */ + /* SPEC 1.0: + * "exclude-result-prefixes" is only allowed on literal + * result elements and "xsl:exclude-result-prefixes" + * on xsl:stylesheet/xsl:transform. + * SPEC 2.0: + * "There are a number of standard attributes + * that may appear on any XSLT element: specifically + * version, exclude-result-prefixes, + * extension-element-prefixes, xpath-default-namespace, + * default-collation, and use-when." + * + * SPEC 2.0: + * For literal result elements: + * "xsl:version, xsl:exclude-result-prefixes, + * xsl:extension-element-prefixes, + * xsl:xpath-default-namespace, + * xsl:default-collation, or xsl:use-when." + */ + if (cur->properties) + cctxt->inode->extElemNs = + xsltParseExtElemPrefixes(cctxt, + cur, cctxt->inode->extElemNs, + XSLT_ELEMENT_CATEGORY_LRE); + /* + * Eval if we have an extension instruction here. + */ + if ((cur->ns != NULL) && + (cctxt->inode->extElemNs != NULL) && + (xsltCheckExtPrefix(cctxt->style, cur->ns->href) == 1)) + { + /* + * Extension instructions + * ---------------------------------------------------- + * Mark the node information. + */ + cctxt->inode->category = XSLT_ELEMENT_CATEGORY_EXTENSION; + cctxt->inode->extContentHandled = 0; + if (cur->psvi != NULL) { + cur->psvi = NULL; + /* + * TODO: Temporary sanity check. + */ + xsltTransformError(NULL, cctxt->style, cur, + "Internal error in xsltParseSequenceConstructor(): " + "Occupied PSVI field.\n"); + cctxt->style->errors++; + cur = cur->next; + continue; + } + cur->psvi = (void *) + xsltPreComputeExtModuleElement(cctxt->style, cur); + + if (cur->psvi == NULL) { + /* + * OLD COMMENT: "Unknown element, maybe registered + * at the context level. Mark it for later + * recognition." + * QUESTION: What does the xsltExtMarker mean? + * ANSWER: It is used in + * xsltApplySequenceConstructor() at + * transformation-time to look out for extension + * registered in the transformation context. + */ + cur->psvi = (void *) xsltExtMarker; + } + /* + * BIG NOTE: Now the ugly part. In previous versions + * of Libxslt (until 1.1.16), all the content of an + * extension instruction was processed and compiled without + * the need of the extension-author to explicitely call + * such a processing;.We now need to mimic this old + * behaviour in order to avoid breaking old code + * on the extension-author's side. + * The mechanism: + * 1) If the author does *not* set the + * compile-time-flag @extContentHandled, then we'll + * parse the content assuming that it's a "template" + * (or "sequence constructor in XSLT 2.0 terms). + * NOTE: If the extension is registered at + * transformation-time only, then there's no way of + * knowing that content shall be valid, and we'll + * process the content the same way. + * 2) If the author *does* set the flag, then we'll assume + * that the author has handled the parsing him/herself + * (e.g. called xsltParseSequenceConstructor(), etc. + * explicitely in his/her code). + */ + if ((cur->children != NULL) && + (cctxt->inode->extContentHandled == 0)) + { + /* + * Default parsing of the content using the + * sequence-constructor model. + */ + xsltParseSequenceConstructor(cctxt, cur->children); + } + } else { + /* + * Literal result element + * ---------------------------------------------------- + * Allowed XSLT attributes: + * xsl:extension-element-prefixes CDATA #IMPLIED + * xsl:exclude-result-prefixes CDATA #IMPLIED + * TODO: xsl:use-attribute-sets %qnames; #IMPLIED + * xsl:version NMTOKEN #IMPLIED + */ + cur->psvi = NULL; + cctxt->inode->category = XSLT_ELEMENT_CATEGORY_LRE; + if (cur->properties != NULL) { + xmlAttrPtr attr = cur->properties; + /* + * Attribute "xsl:exclude-result-prefixes". + */ + cctxt->inode->exclResultNs = + xsltParseExclResultPrefixes(cctxt, cur, + cctxt->inode->exclResultNs, + XSLT_ELEMENT_CATEGORY_LRE); + /* + * Attribute "xsl:version". + */ + xsltParseAttrXSLTVersion(cctxt, cur, + XSLT_ELEMENT_CATEGORY_LRE); + /* + * Report invalid XSLT attributes. + * For XSLT 1.0 only xsl:use-attribute-sets is allowed + * next to xsl:version, xsl:exclude-result-prefixes and + * xsl:extension-element-prefixes. + * + * Mark all XSLT attributes, in order to skip such + * attributes when instantiating the LRE. + */ + do { + if ((attr->psvi != xsltXSLTAttrMarker) && + IS_XSLT_ATTR_FAST(attr)) + { + if (! xmlStrEqual(attr->name, + BAD_CAST "use-attribute-sets")) + { + xsltTransformError(NULL, cctxt->style, + cur, + "Unknown XSLT attribute '%s'.\n", + attr->name); + cctxt->style->errors++; + } else { + /* + * XSLT attr marker. + */ + attr->psvi = (void *) xsltXSLTAttrMarker; + } + } + attr = attr->next; + } while (attr != NULL); + } + /* + * Create/reuse info for the literal result element. + */ + if (cctxt->inode->nsChanged) + xsltLREInfoCreate(cctxt, cur, 1); + cur->psvi = cctxt->inode->litResElemInfo; + /* + * Apply ns-aliasing on the element and on its attributes. + */ + if (cctxt->hasNsAliases) + xsltLREBuildEffectiveNs(cctxt, cur); + /* + * Compile attribute value templates (AVT). + */ + if (cur->properties) { + xmlAttrPtr attr = cur->properties; + + while (attr != NULL) { + xsltCompileAttr(cctxt->style, attr); + attr = attr->next; + } + } + /* + * Parse the content, which is defined to be a "template" + * (or "sequence constructor" in XSLT 2.0 terms). + */ + if (cur->children != NULL) { + xsltParseSequenceConstructor(cctxt, cur->children); + } + } + /* + * Leave the non-XSLT element. + */ + xsltCompilerNodePop(cctxt, cur); + } + } + cur = cur->next; + } + if (deleteNode != NULL) { +#ifdef WITH_XSLT_DEBUG_BLANKS + xsltGenericDebug(xsltGenericDebugContext, + "xsltParseSequenceConstructor: removing xsl:text element\n"); +#endif + xmlUnlinkNode(deleteNode); + xmlFreeNode(deleteNode); + deleteNode = NULL; + } +} + +/** + * xsltParseTemplateContent: + * @style: the XSLT stylesheet + * @templ: the node containing the content to be parsed + * + * Parses and compiles the content-model of an xsl:template element. + * Note that this is *not* the "template" content model (or "sequence + * constructor" in XSLT 2.0); it it allows addional xsl:param + * elements as immediate children of @templ. + * + * Called by: + * exsltFuncFunctionComp() (EXSLT, functions.c) + * So this is intended to be called from extension functions. + */ +void +xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) { + if ((style == NULL) || (templ == NULL) || + (templ->type == XML_NAMESPACE_DECL)) + return; + + /* + * Detection of handled content of extension instructions. + */ + if (XSLT_CCTXT(style)->inode->category == XSLT_ELEMENT_CATEGORY_EXTENSION) { + XSLT_CCTXT(style)->inode->extContentHandled = 1; + } + + if (templ->children != NULL) { + xmlNodePtr child = templ->children; + /* + * Process xsl:param elements, which can only occur as the + * immediate children of xsl:template (well, and of any + * user-defined extension instruction if needed). + */ + do { + style->principal->opCount += 1; + + if ((child->type == XML_ELEMENT_NODE) && + IS_XSLT_ELEM_FAST(child) && + IS_XSLT_NAME(child, "param")) + { + XSLT_CCTXT(style)->inode->curChildType = XSLT_FUNC_PARAM; + xsltParseAnyXSLTElem(XSLT_CCTXT(style), child); + } else + break; + child = child->next; + } while (child != NULL); + /* + * Parse the content and register the pattern. + */ + xsltParseSequenceConstructor(XSLT_CCTXT(style), child); + } +} + +#else /* XSLT_REFACTORED */ + +/** + * xsltParseTemplateContent: + * @style: the XSLT stylesheet + * @templ: the container node (can be a document for literal results) + * + * parse a template content-model + * Clean-up the template content from unwanted ignorable blank nodes + * and process xslt:text + */ +void +xsltParseTemplateContent(xsltStylesheetPtr style, xmlNodePtr templ) { + xmlNodePtr cur, delete; + + if ((style == NULL) || (templ == NULL) || + (templ->type == XML_NAMESPACE_DECL)) return; + + /* + * This content comes from the stylesheet + * For stylesheets, the set of whitespace-preserving + * element names consists of just xsl:text. + */ + cur = templ->children; + delete = NULL; + while (cur != NULL) { + style->principal->opCount += 1; + + if (delete != NULL) { +#ifdef WITH_XSLT_DEBUG_BLANKS + xsltGenericDebug(xsltGenericDebugContext, + "xsltParseTemplateContent: removing text\n"); +#endif + xmlUnlinkNode(delete); + xmlFreeNode(delete); + delete = NULL; + } + if (IS_XSLT_ELEM(cur)) { + xsltStylePreCompute(style, cur); + + if (IS_XSLT_NAME(cur, "text")) { + /* + * TODO: Processing of xsl:text should be moved to + * xsltPreprocessStylesheet(), since otherwise this + * will be performed for every multiply included + * stylesheet; i.e. this here is not skipped with + * the use of the style->nopreproc flag. + */ + if (cur->children != NULL) { + xmlChar *prop; + xmlNodePtr text = cur->children, next; + int noesc = 0; + + prop = xmlGetNsProp(cur, + (const xmlChar *)"disable-output-escaping", + NULL); + if (prop != NULL) { +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "Disable escaping: %s\n", text->content); +#endif + if (xmlStrEqual(prop, (const xmlChar *)"yes")) { + noesc = 1; + } else if (!xmlStrEqual(prop, + (const xmlChar *)"no")){ + xsltTransformError(NULL, style, cur, + "xsl:text: disable-output-escaping allows only yes or no\n"); + style->warnings++; + + } + xmlFree(prop); + } + + while (text != NULL) { + if (text->type == XML_COMMENT_NODE) { + text = text->next; + continue; + } + if ((text->type != XML_TEXT_NODE) && + (text->type != XML_CDATA_SECTION_NODE)) { + xsltTransformError(NULL, style, cur, + "xsltParseTemplateContent: xslt:text content problem\n"); + style->errors++; + break; + } + if ((noesc) && (text->type != XML_CDATA_SECTION_NODE)) + text->name = xmlStringTextNoenc; + text = text->next; + } + + /* + * replace xsl:text by the list of childs + */ + if (text == NULL) { + text = cur->children; + while (text != NULL) { + if ((style->internalized) && + (text->content != NULL) && + (!xmlDictOwns(style->dict, text->content))) { + + /* + * internalize the text string + */ + if (text->doc->dict != NULL) { + const xmlChar *tmp; + + tmp = xmlDictLookup(text->doc->dict, + text->content, -1); + if (tmp != text->content) { + xmlNodeSetContent(text, NULL); + text->content = (xmlChar *) tmp; + } + } + } + + next = text->next; + xmlUnlinkNode(text); + if (xmlAddPrevSibling(cur, text) == NULL) { + xsltTransformError(NULL, style, NULL, + "out of memory\n"); + xmlFreeNode(text); + } + text = next; + } + } + } + delete = cur; + goto skip_children; + } + } + else if ((cur->ns != NULL) && (style->nsDefs != NULL) && + (xsltCheckExtPrefix(style, cur->ns->prefix))) + { + /* + * okay this is an extension element compile it too + */ + xsltStylePreCompute(style, cur); + } + else if (cur->type == XML_ELEMENT_NODE) + { + /* + * This is an element which will be output as part of the + * template exectution, precompile AVT if found. + */ + if ((cur->ns == NULL) && (style->defaultAlias != NULL)) { + cur->ns = xmlSearchNsByHref(cur->doc, cur, + style->defaultAlias); + } + if (cur->properties != NULL) { + xmlAttrPtr attr = cur->properties; + + while (attr != NULL) { + xsltCompileAttr(style, attr); + attr = attr->next; + } + } + } + /* + * Skip to next node + */ + if (cur->children != NULL) { + if (cur->children->type != XML_ENTITY_DECL) { + cur = cur->children; + continue; + } + } +skip_children: + if (cur->next != NULL) { + cur = cur->next; + continue; + } + + do { + cur = cur->parent; + if (cur == NULL) + break; + if (cur == templ) { + cur = NULL; + break; + } + if (cur->next != NULL) { + cur = cur->next; + break; + } + } while (cur != NULL); + } + if (delete != NULL) { +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "xsltParseTemplateContent: removing text\n"); +#endif + xmlUnlinkNode(delete); + xmlFreeNode(delete); + delete = NULL; + } + + /* + * Skip the first params + */ + cur = templ->children; + while (cur != NULL) { + if ((IS_XSLT_ELEM(cur)) && (!(IS_XSLT_NAME(cur, "param")))) + break; + cur = cur->next; + } + + /* + * Browse the remainder of the template + */ + while (cur != NULL) { + if ((IS_XSLT_ELEM(cur)) && (IS_XSLT_NAME(cur, "param"))) { + xmlNodePtr param = cur; + + xsltTransformError(NULL, style, cur, + "xsltParseTemplateContent: ignoring misplaced param element\n"); + if (style != NULL) style->warnings++; + cur = cur->next; + xmlUnlinkNode(param); + xmlFreeNode(param); + } else + break; + } +} + +#endif /* else XSLT_REFACTORED */ + +/** + * xsltParseStylesheetKey: + * @style: the XSLT stylesheet + * @key: the "key" element + * + * + * + * + * parse an XSLT stylesheet key definition and register it + */ + +static void +xsltParseStylesheetKey(xsltStylesheetPtr style, xmlNodePtr key) { + xmlChar *prop = NULL; + xmlChar *use = NULL; + xmlChar *match = NULL; + xmlChar *name = NULL; + xmlChar *nameURI = NULL; + + if ((style == NULL) || (key == NULL) || (key->type != XML_ELEMENT_NODE)) + return; + + /* + * Get arguments + */ + prop = xmlGetNsProp(key, (const xmlChar *)"name", NULL); + if (prop != NULL) { + const xmlChar *URI; + + /* + * TODO: Don't use xsltGetQNameURI(). + */ + URI = xsltGetQNameURI(key, &prop); + if (prop == NULL) { + if (style != NULL) style->errors++; + goto error; + } else { + name = prop; + if (URI != NULL) + nameURI = xmlStrdup(URI); + } +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "xsltParseStylesheetKey: name %s\n", name); +#endif + } else { + xsltTransformError(NULL, style, key, + "xsl:key : error missing name\n"); + if (style != NULL) style->errors++; + goto error; + } + + match = xmlGetNsProp(key, (const xmlChar *)"match", NULL); + if (match == NULL) { + xsltTransformError(NULL, style, key, + "xsl:key : error missing match\n"); + if (style != NULL) style->errors++; + goto error; + } + + use = xmlGetNsProp(key, (const xmlChar *)"use", NULL); + if (use == NULL) { + xsltTransformError(NULL, style, key, + "xsl:key : error missing use\n"); + if (style != NULL) style->errors++; + goto error; + } + + /* + * register the keys + */ + xsltAddKey(style, name, nameURI, match, use, key); + + +error: + if (use != NULL) + xmlFree(use); + if (match != NULL) + xmlFree(match); + if (name != NULL) + xmlFree(name); + if (nameURI != NULL) + xmlFree(nameURI); + + if (key->children != NULL) { + xsltParseContentError(style, key->children); + } +} + +#ifdef XSLT_REFACTORED +/** + * xsltParseXSLTTemplate: + * @style: the XSLT stylesheet + * @template: the "template" element + * + * parse an XSLT stylesheet template building the associated structures + * TODO: Is @style ever expected to be NULL? + * + * Called from: + * xsltParseXSLTStylesheet() + * xsltParseStylesheetTop() + */ + +static void +xsltParseXSLTTemplate(xsltCompilerCtxtPtr cctxt, xmlNodePtr templNode) { + xsltTemplatePtr templ; + xmlChar *prop; + double priority; + + if ((cctxt == NULL) || (templNode == NULL) || + (templNode->type != XML_ELEMENT_NODE)) + return; + + /* + * Create and link the structure + */ + templ = xsltNewTemplate(); + if (templ == NULL) + return; + + xsltCompilerNodePush(cctxt, templNode); + if (templNode->nsDef != NULL) + cctxt->inode->inScopeNs = + xsltCompilerBuildInScopeNsList(cctxt, templNode); + + templ->next = cctxt->style->templates; + cctxt->style->templates = templ; + templ->style = cctxt->style; + + /* + * Attribute "mode". + */ + prop = xmlGetNsProp(templNode, (const xmlChar *)"mode", NULL); + if (prop != NULL) { + const xmlChar *modeURI; + + /* + * TODO: We need a standardized function for extraction + * of namespace names and local names from QNames. + * Don't use xsltGetQNameURI() as it cannot channe� + * reports through the context. + */ + modeURI = xsltGetQNameURI(templNode, &prop); + if (prop == NULL) { + cctxt->style->errors++; + goto error; + } + templ->mode = xmlDictLookup(cctxt->style->dict, prop, -1); + xmlFree(prop); + prop = NULL; + if (xmlValidateNCName(templ->mode, 0)) { + xsltTransformError(NULL, cctxt->style, templNode, + "xsl:template: Attribute 'mode': The local part '%s' " + "of the value is not a valid NCName.\n", templ->name); + cctxt->style->errors++; + goto error; + } + if (modeURI != NULL) + templ->modeURI = xmlDictLookup(cctxt->style->dict, modeURI, -1); +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "xsltParseXSLTTemplate: mode %s\n", templ->mode); +#endif + } + /* + * Attribute "match". + */ + prop = xmlGetNsProp(templNode, (const xmlChar *)"match", NULL); + if (prop != NULL) { + templ->match = prop; + prop = NULL; + } + /* + * Attribute "priority". + */ + prop = xmlGetNsProp(templNode, (const xmlChar *)"priority", NULL); + if (prop != NULL) { + priority = xmlXPathStringEvalNumber(prop); + templ->priority = (float) priority; + xmlFree(prop); + prop = NULL; + } + /* + * Attribute "name". + */ + prop = xmlGetNsProp(templNode, (const xmlChar *)"name", NULL); + if (prop != NULL) { + const xmlChar *nameURI; + xsltTemplatePtr curTempl; + + /* + * TODO: Don't use xsltGetQNameURI(). + */ + nameURI = xsltGetQNameURI(templNode, &prop); + if (prop == NULL) { + cctxt->style->errors++; + goto error; + } + templ->name = xmlDictLookup(cctxt->style->dict, prop, -1); + xmlFree(prop); + prop = NULL; + if (xmlValidateNCName(templ->name, 0)) { + xsltTransformError(NULL, cctxt->style, templNode, + "xsl:template: Attribute 'name': The local part '%s' of " + "the value is not a valid NCName.\n", templ->name); + cctxt->style->errors++; + goto error; + } + if (nameURI != NULL) + templ->nameURI = xmlDictLookup(cctxt->style->dict, nameURI, -1); + curTempl = templ->next; + while (curTempl != NULL) { + if ((nameURI != NULL && xmlStrEqual(curTempl->name, templ->name) && + xmlStrEqual(curTempl->nameURI, nameURI) ) || + (nameURI == NULL && curTempl->nameURI == NULL && + xmlStrEqual(curTempl->name, templ->name))) + { + xsltTransformError(NULL, cctxt->style, templNode, + "xsl:template: error duplicate name '%s'\n", templ->name); + cctxt->style->errors++; + goto error; + } + curTempl = curTempl->next; + } + } + if (templNode->children != NULL) { + xsltParseTemplateContent(cctxt->style, templNode); + /* + * MAYBE TODO: Custom behaviour: In order to stay compatible with + * Xalan and MSXML(.NET), we could allow whitespace + * to appear before an xml:param element; this whitespace + * will additionally become part of the "template". + * NOTE that this is totally deviates from the spec, but + * is the de facto behaviour of Xalan and MSXML(.NET). + * Personally I wouldn't allow this, since if we have: + * + * + * + * + * ... the whitespace between every xsl:param would be + * added to the result tree. + */ + } + + templ->elem = templNode; + templ->content = templNode->children; + xsltAddTemplate(cctxt->style, templ, templ->mode, templ->modeURI); + +error: + xsltCompilerNodePop(cctxt, templNode); + return; +} + +#else /* XSLT_REFACTORED */ + +/** + * xsltParseStylesheetTemplate: + * @style: the XSLT stylesheet + * @template: the "template" element + * + * parse an XSLT stylesheet template building the associated structures + */ + +static void +xsltParseStylesheetTemplate(xsltStylesheetPtr style, xmlNodePtr template) { + xsltTemplatePtr ret; + xmlChar *prop; + xmlChar *mode = NULL; + xmlChar *modeURI = NULL; + double priority; + + if ((style == NULL) || (template == NULL) || + (template->type != XML_ELEMENT_NODE)) + return; + + if (style->principal->opLimit > 0) { + if (style->principal->opCount > style->principal->opLimit) { + xsltTransformError(NULL, style, NULL, + "XSLT parser operation limit exceeded\n"); + style->errors++; + return; + } + } + + /* + * Create and link the structure + */ + ret = xsltNewTemplate(); + if (ret == NULL) + return; + ret->next = style->templates; + style->templates = ret; + ret->style = style; + + /* + * Get inherited namespaces + */ + /* + * TODO: Apply the optimized in-scope-namespace mechanism + * as for the other XSLT instructions. + */ + xsltGetInheritedNsList(style, ret, template); + + /* + * Get arguments + */ + prop = xmlGetNsProp(template, (const xmlChar *)"mode", NULL); + if (prop != NULL) { + const xmlChar *URI; + + /* + * TODO: Don't use xsltGetQNameURI(). + */ + URI = xsltGetQNameURI(template, &prop); + if (prop == NULL) { + if (style != NULL) style->errors++; + goto error; + } else { + mode = prop; + if (URI != NULL) + modeURI = xmlStrdup(URI); + } + ret->mode = xmlDictLookup(style->dict, mode, -1); + ret->modeURI = xmlDictLookup(style->dict, modeURI, -1); +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "xsltParseStylesheetTemplate: mode %s\n", mode); +#endif + if (mode != NULL) xmlFree(mode); + if (modeURI != NULL) xmlFree(modeURI); + } + prop = xmlGetNsProp(template, (const xmlChar *)"match", NULL); + if (prop != NULL) { + if (ret->match != NULL) xmlFree(ret->match); + ret->match = prop; + } + + prop = xmlGetNsProp(template, (const xmlChar *)"priority", NULL); + if (prop != NULL) { + priority = xmlXPathStringEvalNumber(prop); + ret->priority = (float) priority; + xmlFree(prop); + } + + prop = xmlGetNsProp(template, (const xmlChar *)"name", NULL); + if (prop != NULL) { + const xmlChar *URI; + + /* + * TODO: Don't use xsltGetQNameURI(). + */ + URI = xsltGetQNameURI(template, &prop); + if (prop == NULL) { + if (style != NULL) style->errors++; + goto error; + } else { + if (xmlValidateNCName(prop,0)) { + xsltTransformError(NULL, style, template, + "xsl:template : error invalid name '%s'\n", prop); + if (style != NULL) style->errors++; + xmlFree(prop); + goto error; + } + ret->name = xmlDictLookup(style->dict, BAD_CAST prop, -1); + xmlFree(prop); + prop = NULL; + if (URI != NULL) + ret->nameURI = xmlDictLookup(style->dict, BAD_CAST URI, -1); + else + ret->nameURI = NULL; + } + } + + /* + * parse the content and register the pattern + */ + xsltParseTemplateContent(style, template); + ret->elem = template; + ret->content = template->children; + xsltAddTemplate(style, ret, ret->mode, ret->modeURI); + +error: + return; +} + +#endif /* else XSLT_REFACTORED */ + +#ifdef XSLT_REFACTORED + +/** + * xsltIncludeComp: + * @cctxt: the compilation context + * @node: the xsl:include node + * + * Process the xslt include node on the source node + */ +static xsltStyleItemIncludePtr +xsltCompileXSLTIncludeElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) { + xsltStyleItemIncludePtr item; + + if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE)) + return(NULL); + + node->psvi = NULL; + item = (xsltStyleItemIncludePtr) xmlMalloc(sizeof(xsltStyleItemInclude)); + if (item == NULL) { + xsltTransformError(NULL, cctxt->style, node, + "xsltIncludeComp : malloc failed\n"); + cctxt->style->errors++; + return(NULL); + } + memset(item, 0, sizeof(xsltStyleItemInclude)); + + node->psvi = item; + item->inst = node; + item->type = XSLT_FUNC_INCLUDE; + + item->next = cctxt->style->preComps; + cctxt->style->preComps = (xsltElemPreCompPtr) item; + + return(item); +} + +static int +xsltParseFindTopLevelElem(xsltCompilerCtxtPtr cctxt, + xmlNodePtr cur, + const xmlChar *name, + const xmlChar *namespaceURI, + int breakOnOtherElem, + xmlNodePtr *resultNode) +{ + if (name == NULL) + return(-1); + + *resultNode = NULL; + while (cur != NULL) { + if (cur->type == XML_ELEMENT_NODE) { + if ((cur->ns != NULL) && (cur->name != NULL)) { + if ((*(cur->name) == *name) && + xmlStrEqual(cur->name, name) && + xmlStrEqual(cur->ns->href, namespaceURI)) + { + *resultNode = cur; + return(1); + } + } + if (breakOnOtherElem) + break; + } + cur = cur->next; + } + *resultNode = cur; + return(0); +} + +static int +xsltParseTopLevelXSLTElem(xsltCompilerCtxtPtr cctxt, + xmlNodePtr node, + xsltStyleType type) +{ + int ret = 0; + + /* + * TODO: The reason why this function exists: + * due to historical reasons some of the + * top-level declarations are processed by functions + * in other files. Since we need still to set + * up the node-info and generate information like + * in-scope namespaces, this is a wrapper around + * those old parsing functions. + */ + xsltCompilerNodePush(cctxt, node); + if (node->nsDef != NULL) + cctxt->inode->inScopeNs = + xsltCompilerBuildInScopeNsList(cctxt, node); + cctxt->inode->type = type; + + switch (type) { + case XSLT_FUNC_INCLUDE: + { + int oldIsInclude; + + if (xsltCompileXSLTIncludeElem(cctxt, node) == NULL) + goto exit; + /* + * Mark this stylesheet tree as being currently included. + */ + oldIsInclude = cctxt->isInclude; + cctxt->isInclude = 1; + + if (xsltParseStylesheetInclude(cctxt->style, node) != 0) { + cctxt->style->errors++; + } + cctxt->isInclude = oldIsInclude; + } + break; + case XSLT_FUNC_PARAM: + xsltStylePreCompute(cctxt->style, node); + xsltParseGlobalParam(cctxt->style, node); + break; + case XSLT_FUNC_VARIABLE: + xsltStylePreCompute(cctxt->style, node); + xsltParseGlobalVariable(cctxt->style, node); + break; + case XSLT_FUNC_ATTRSET: + xsltParseStylesheetAttributeSet(cctxt->style, node); + break; + default: + xsltTransformError(NULL, cctxt->style, node, + "Internal error: (xsltParseTopLevelXSLTElem) " + "Cannot handle this top-level declaration.\n"); + cctxt->style->errors++; + ret = -1; + } + +exit: + xsltCompilerNodePop(cctxt, node); + + return(ret); +} + +#if 0 +static int +xsltParseRemoveWhitespace(xmlNodePtr node) +{ + if ((node == NULL) || (node->children == NULL)) + return(0); + else { + xmlNodePtr delNode = NULL, child = node->children; + + do { + if (delNode) { + xmlUnlinkNode(delNode); + xmlFreeNode(delNode); + delNode = NULL; + } + if (((child->type == XML_TEXT_NODE) || + (child->type == XML_CDATA_SECTION_NODE)) && + (IS_BLANK_NODE(child))) + delNode = child; + child = child->next; + } while (child != NULL); + if (delNode) { + xmlUnlinkNode(delNode); + xmlFreeNode(delNode); + delNode = NULL; + } + } + return(0); +} +#endif + +static int +xsltParseXSLTStylesheetElemCore(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) +{ +#ifdef WITH_XSLT_DEBUG_PARSING + int templates = 0; +#endif + xmlNodePtr cur, start = NULL; + xsltStylesheetPtr style; + + if ((cctxt == NULL) || (node == NULL) || + (node->type != XML_ELEMENT_NODE)) + return(-1); + + style = cctxt->style; + /* + * At this stage all import declarations of all stylesheet modules + * with the same stylesheet level have been processed. + * Now we can safely parse the rest of the declarations. + */ + if (IS_XSLT_ELEM_FAST(node) && IS_XSLT_NAME(node, "include")) + { + xsltDocumentPtr include; + /* + * URGENT TODO: Make this work with simplified stylesheets! + * I.e., when we won't find an xsl:stylesheet element. + */ + /* + * This is as include declaration. + */ + include = ((xsltStyleItemIncludePtr) node->psvi)->include; + if (include == NULL) { + /* TODO: raise error? */ + return(-1); + } + /* + * TODO: Actually an xsl:include should locate an embedded + * stylesheet as well; so the document-element won't always + * be the element where the actual stylesheet is rooted at. + * But such embedded stylesheets are not supported by Libxslt yet. + */ + node = xmlDocGetRootElement(include->doc); + if (node == NULL) { + return(-1); + } + } + + if (node->children == NULL) + return(0); + /* + * Push the xsl:stylesheet/xsl:transform element. + */ + xsltCompilerNodePush(cctxt, node); + cctxt->inode->isRoot = 1; + cctxt->inode->nsChanged = 0; + /* + * Start with the naked dummy info for literal result elements. + */ + cctxt->inode->litResElemInfo = cctxt->inodeList->litResElemInfo; + + /* + * In every case, we need to have + * the in-scope namespaces of the element, where the + * stylesheet is rooted at, regardless if it's an XSLT + * instruction or a literal result instruction (or if + * this is an embedded stylesheet). + */ + cctxt->inode->inScopeNs = + xsltCompilerBuildInScopeNsList(cctxt, node); + + /* + * Process attributes of xsl:stylesheet/xsl:transform. + * -------------------------------------------------- + * Allowed are: + * id = id + * extension-element-prefixes = tokens + * exclude-result-prefixes = tokens + * version = number (mandatory) + */ + if (xsltParseAttrXSLTVersion(cctxt, node, + XSLT_ELEMENT_CATEGORY_XSLT) == 0) + { + /* + * Attribute "version". + * XSLT 1.0: "An xsl:stylesheet element *must* have a version + * attribute, indicating the version of XSLT that the + * stylesheet requires". + * The root element of a simplified stylesheet must also have + * this attribute. + */ +#ifdef XSLT_REFACTORED_MANDATORY_VERSION + if (isXsltElem) + xsltTransformError(NULL, cctxt->style, node, + "The attribute 'version' is missing.\n"); + cctxt->style->errors++; +#else + /* OLD behaviour. */ + xsltTransformError(NULL, cctxt->style, node, + "xsl:version is missing: document may not be a stylesheet\n"); + cctxt->style->warnings++; +#endif + } + /* + * The namespaces declared by the attributes + * "extension-element-prefixes" and + * "exclude-result-prefixes" are local to *this* + * stylesheet tree; i.e., they are *not* visible to + * other stylesheet-modules, whether imported or included. + * + * Attribute "extension-element-prefixes". + */ + cctxt->inode->extElemNs = + xsltParseExtElemPrefixes(cctxt, node, NULL, + XSLT_ELEMENT_CATEGORY_XSLT); + /* + * Attribute "exclude-result-prefixes". + */ + cctxt->inode->exclResultNs = + xsltParseExclResultPrefixes(cctxt, node, NULL, + XSLT_ELEMENT_CATEGORY_XSLT); + /* + * Create/reuse info for the literal result element. + */ + if (cctxt->inode->nsChanged) + xsltLREInfoCreate(cctxt, node, 0); + /* + * Processed top-level elements: + * ---------------------------- + * xsl:variable, xsl:param (QName, in-scope ns, + * expression (vars allowed)) + * xsl:attribute-set (QName, in-scope ns) + * xsl:strip-space, xsl:preserve-space (XPath NameTests, + * in-scope ns) + * I *think* global scope, merge with includes + * xsl:output (QName, in-scope ns) + * xsl:key (QName, in-scope ns, pattern, + * expression (vars *not* allowed)) + * xsl:decimal-format (QName, needs in-scope ns) + * xsl:namespace-alias (in-scope ns) + * global scope, merge with includes + * xsl:template (last, QName, pattern) + * + * (whitespace-only text-nodes have *not* been removed + * yet; this will be done in xsltParseSequenceConstructor) + * + * Report misplaced child-nodes first. + */ + cur = node->children; + while (cur != NULL) { + if (cur->type == XML_TEXT_NODE) { + xsltTransformError(NULL, style, cur, + "Misplaced text node (content: '%s').\n", + (cur->content != NULL) ? cur->content : BAD_CAST ""); + style->errors++; + } else if (cur->type != XML_ELEMENT_NODE) { + xsltTransformError(NULL, style, cur, "Misplaced node.\n"); + style->errors++; + } + cur = cur->next; + } + /* + * Skip xsl:import elements; they have been processed + * already. + */ + cur = node->children; + while ((cur != NULL) && xsltParseFindTopLevelElem(cctxt, cur, + BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1) + cur = cur->next; + if (cur == NULL) + goto exit; + + start = cur; + /* + * Process all top-level xsl:param elements. + */ + while ((cur != NULL) && + xsltParseFindTopLevelElem(cctxt, cur, + BAD_CAST "param", XSLT_NAMESPACE, 0, &cur) == 1) + { + xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_PARAM); + cur = cur->next; + } + /* + * Process all top-level xsl:variable elements. + */ + cur = start; + while ((cur != NULL) && + xsltParseFindTopLevelElem(cctxt, cur, + BAD_CAST "variable", XSLT_NAMESPACE, 0, &cur) == 1) + { + xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_VARIABLE); + cur = cur->next; + } + /* + * Process all the rest of top-level elements. + */ + cur = start; + while (cur != NULL) { + /* + * Process element nodes. + */ + if (cur->type == XML_ELEMENT_NODE) { + if (cur->ns == NULL) { + xsltTransformError(NULL, style, cur, + "Unexpected top-level element in no namespace.\n"); + style->errors++; + cur = cur->next; + continue; + } + /* + * Process all XSLT elements. + */ + if (IS_XSLT_ELEM_FAST(cur)) { + /* + * xsl:import is only allowed at the beginning. + */ + if (IS_XSLT_NAME(cur, "import")) { + xsltTransformError(NULL, style, cur, + "Misplaced xsl:import element.\n"); + style->errors++; + cur = cur->next; + continue; + } + /* + * TODO: Change the return type of the parsing functions + * to int. + */ + if (IS_XSLT_NAME(cur, "template")) { +#ifdef WITH_XSLT_DEBUG_PARSING + templates++; +#endif + /* + * TODO: Is the position of xsl:template in the + * tree significant? If not it would be easier to + * parse them at a later stage. + */ + xsltParseXSLTTemplate(cctxt, cur); + } else if (IS_XSLT_NAME(cur, "variable")) { + /* NOP; done already */ + } else if (IS_XSLT_NAME(cur, "param")) { + /* NOP; done already */ + } else if (IS_XSLT_NAME(cur, "include")) { + if (cur->psvi != NULL) + xsltParseXSLTStylesheetElemCore(cctxt, cur); + else { + xsltTransformError(NULL, style, cur, + "Internal error: " + "(xsltParseXSLTStylesheetElemCore) " + "The xsl:include element was not compiled.\n"); + style->errors++; + } + } else if (IS_XSLT_NAME(cur, "strip-space")) { + /* No node info needed. */ + xsltParseStylesheetStripSpace(style, cur); + } else if (IS_XSLT_NAME(cur, "preserve-space")) { + /* No node info needed. */ + xsltParseStylesheetPreserveSpace(style, cur); + } else if (IS_XSLT_NAME(cur, "output")) { + /* No node-info needed. */ + xsltParseStylesheetOutput(style, cur); + } else if (IS_XSLT_NAME(cur, "key")) { + /* TODO: node-info needed for expressions ? */ + xsltParseStylesheetKey(style, cur); + } else if (IS_XSLT_NAME(cur, "decimal-format")) { + /* No node-info needed. */ + xsltParseStylesheetDecimalFormat(style, cur); + } else if (IS_XSLT_NAME(cur, "attribute-set")) { + xsltParseTopLevelXSLTElem(cctxt, cur, + XSLT_FUNC_ATTRSET); + } else if (IS_XSLT_NAME(cur, "namespace-alias")) { + /* NOP; done already */ + } else { + if (cctxt->inode->forwardsCompat) { + /* + * Forwards-compatible mode: + * + * XSLT-1: "if it is a top-level element and + * XSLT 1.0 does not allow such elements as top-level + * elements, then the element must be ignored along + * with its content;" + */ + /* + * TODO: I don't think we should generate a warning. + */ + xsltTransformError(NULL, style, cur, + "Forwards-compatible mode: Ignoring unknown XSLT " + "element '%s'.\n", cur->name); + style->warnings++; + } else { + xsltTransformError(NULL, style, cur, + "Unknown XSLT element '%s'.\n", cur->name); + style->errors++; + } + } + } else { + xsltTopLevelFunction function; + + /* + * Process non-XSLT elements, which are in a + * non-NULL namespace. + */ + /* + * QUESTION: What does xsltExtModuleTopLevelLookup() + * do exactly? + */ + function = xsltExtModuleTopLevelLookup(cur->name, + cur->ns->href); + if (function != NULL) + function(style, cur); +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "xsltParseXSLTStylesheetElemCore : User-defined " + "data element '%s'.\n", cur->name); +#endif + } + } + cur = cur->next; + } + +exit: + +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "### END of parsing top-level elements of doc '%s'.\n", + node->doc->URL); + xsltGenericDebug(xsltGenericDebugContext, + "### Templates: %d\n", templates); +#ifdef XSLT_REFACTORED + xsltGenericDebug(xsltGenericDebugContext, + "### Max inodes: %d\n", cctxt->maxNodeInfos); + xsltGenericDebug(xsltGenericDebugContext, + "### Max LREs : %d\n", cctxt->maxLREs); +#endif /* XSLT_REFACTORED */ +#endif /* WITH_XSLT_DEBUG_PARSING */ + + xsltCompilerNodePop(cctxt, node); + return(0); +} + +/** + * xsltParseXSLTStylesheet: + * @cctxt: the compiler context + * @node: the xsl:stylesheet/xsl:transform element-node + * + * Parses the xsl:stylesheet and xsl:transform element. + * + * + * + * + * + * BIG TODO: The xsl:include stuff. + * + * Called by xsltParseStylesheetTree() + * + * Returns 0 on success, a positive result on errors and + * -1 on API or internal errors. + */ +static int +xsltParseXSLTStylesheetElem(xsltCompilerCtxtPtr cctxt, xmlNodePtr node) +{ + xmlNodePtr cur, start; + + if ((cctxt == NULL) || (node == NULL) || (node->type != XML_ELEMENT_NODE)) + return(-1); + + if (node->children == NULL) + goto exit; + + /* + * Process top-level elements: + * xsl:import (must be first) + * xsl:include (this is just a pre-processing) + */ + cur = node->children; + /* + * Process xsl:import elements. + * XSLT 1.0: "The xsl:import element children must precede all + * other element children of an xsl:stylesheet element, + * including any xsl:include element children." + */ + while ((cur != NULL) && + xsltParseFindTopLevelElem(cctxt, cur, + BAD_CAST "import", XSLT_NAMESPACE, 1, &cur) == 1) + { + if (xsltParseStylesheetImport(cctxt->style, cur) != 0) { + cctxt->style->errors++; + } + cur = cur->next; + } + if (cur == NULL) + goto exit; + start = cur; + /* + * Pre-process all xsl:include elements. + */ + cur = start; + while ((cur != NULL) && + xsltParseFindTopLevelElem(cctxt, cur, + BAD_CAST "include", XSLT_NAMESPACE, 0, &cur) == 1) + { + xsltParseTopLevelXSLTElem(cctxt, cur, XSLT_FUNC_INCLUDE); + cur = cur->next; + } + /* + * Pre-process all xsl:namespace-alias elements. + * URGENT TODO: This won't work correctly: the order of included + * aliases and aliases defined here is significant. + */ + cur = start; + while ((cur != NULL) && + xsltParseFindTopLevelElem(cctxt, cur, + BAD_CAST "namespace-alias", XSLT_NAMESPACE, 0, &cur) == 1) + { + xsltNamespaceAlias(cctxt->style, cur); + cur = cur->next; + } + + if (cctxt->isInclude) { + /* + * If this stylesheet is intended for inclusion, then + * we will process only imports and includes. + */ + goto exit; + } + /* + * Now parse the rest of the top-level elements. + */ + xsltParseXSLTStylesheetElemCore(cctxt, node); +exit: + + return(0); +} + +#else /* XSLT_REFACTORED */ + +/** + * xsltParseStylesheetTop: + * @style: the XSLT stylesheet + * @top: the top level "stylesheet" or "transform" element + * + * scan the top level elements of an XSL stylesheet + */ +static void +xsltParseStylesheetTop(xsltStylesheetPtr style, xmlNodePtr top) { + xmlNodePtr cur; + xmlChar *prop; +#ifdef WITH_XSLT_DEBUG_PARSING + int templates = 0; +#endif + + if ((top == NULL) || (top->type != XML_ELEMENT_NODE)) + return; + + if (style->principal->opLimit > 0) { + if (style->principal->opCount > style->principal->opLimit) { + xsltTransformError(NULL, style, NULL, + "XSLT parser operation limit exceeded\n"); + style->errors++; + return; + } + } + + prop = xmlGetNsProp(top, (const xmlChar *)"version", NULL); + if (prop == NULL) { + xsltTransformError(NULL, style, top, + "xsl:version is missing: document may not be a stylesheet\n"); + if (style != NULL) style->warnings++; + } else { + if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) && + (!xmlStrEqual(prop, (const xmlChar *)"1.1"))) { + xsltTransformError(NULL, style, top, + "xsl:version: only 1.1 features are supported\n"); + if (style != NULL) { + style->forwards_compatible = 1; + style->warnings++; + } + } + xmlFree(prop); + } + + /* + * process xsl:import elements + */ + cur = top->children; + while (cur != NULL) { + style->principal->opCount += 1; + + if (IS_BLANK_NODE(cur)) { + cur = cur->next; + continue; + } + if (IS_XSLT_ELEM(cur) && IS_XSLT_NAME(cur, "import")) { + if (xsltParseStylesheetImport(style, cur) != 0) + if (style != NULL) style->errors++; + } else + break; + cur = cur->next; + } + + /* + * process other top-level elements + */ + while (cur != NULL) { + style->principal->opCount += 1; + + if (IS_BLANK_NODE(cur)) { + cur = cur->next; + continue; + } + if (cur->type == XML_TEXT_NODE) { + if (cur->content != NULL) { + xsltTransformError(NULL, style, cur, + "misplaced text node: '%s'\n", cur->content); + } + if (style != NULL) style->errors++; + cur = cur->next; + continue; + } + if ((cur->type == XML_ELEMENT_NODE) && (cur->ns == NULL)) { + xsltGenericError(xsltGenericErrorContext, + "Found a top-level element %s with null namespace URI\n", + cur->name); + if (style != NULL) style->errors++; + cur = cur->next; + continue; + } + if ((cur->type == XML_ELEMENT_NODE) && (!(IS_XSLT_ELEM(cur)))) { + xsltTopLevelFunction function; + + function = xsltExtModuleTopLevelLookup(cur->name, + cur->ns->href); + if (function != NULL) + function(style, cur); + +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "xsltParseStylesheetTop : found foreign element %s\n", + cur->name); +#endif + cur = cur->next; + continue; + } + if (IS_XSLT_NAME(cur, "import")) { + xsltTransformError(NULL, style, cur, + "xsltParseStylesheetTop: ignoring misplaced import element\n"); + if (style != NULL) style->errors++; + } else if (IS_XSLT_NAME(cur, "include")) { + if (xsltParseStylesheetInclude(style, cur) != 0) + if (style != NULL) style->errors++; + } else if (IS_XSLT_NAME(cur, "strip-space")) { + xsltParseStylesheetStripSpace(style, cur); + } else if (IS_XSLT_NAME(cur, "preserve-space")) { + xsltParseStylesheetPreserveSpace(style, cur); + } else if (IS_XSLT_NAME(cur, "output")) { + xsltParseStylesheetOutput(style, cur); + } else if (IS_XSLT_NAME(cur, "key")) { + xsltParseStylesheetKey(style, cur); + } else if (IS_XSLT_NAME(cur, "decimal-format")) { + xsltParseStylesheetDecimalFormat(style, cur); + } else if (IS_XSLT_NAME(cur, "attribute-set")) { + xsltParseStylesheetAttributeSet(style, cur); + } else if (IS_XSLT_NAME(cur, "variable")) { + xsltParseGlobalVariable(style, cur); + } else if (IS_XSLT_NAME(cur, "param")) { + xsltParseGlobalParam(style, cur); + } else if (IS_XSLT_NAME(cur, "template")) { +#ifdef WITH_XSLT_DEBUG_PARSING + templates++; +#endif + xsltParseStylesheetTemplate(style, cur); + } else if (IS_XSLT_NAME(cur, "namespace-alias")) { + xsltNamespaceAlias(style, cur); + } else { + if ((style != NULL) && (style->forwards_compatible == 0)) { + xsltTransformError(NULL, style, cur, + "xsltParseStylesheetTop: unknown %s element\n", + cur->name); + if (style != NULL) style->errors++; + } + } + cur = cur->next; + } +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "parsed %d templates\n", templates); +#endif +} + +#endif /* else of XSLT_REFACTORED */ + +#ifdef XSLT_REFACTORED +/** + * xsltParseSimplifiedStylesheetTree: + * + * @style: the stylesheet (TODO: Change this to the compiler context) + * @doc: the document containing the stylesheet. + * @node: the node where the stylesheet is rooted at + * + * Returns 0 in case of success, a positive result if an error occurred + * and -1 on API and internal errors. + */ +static int +xsltParseSimplifiedStylesheetTree(xsltCompilerCtxtPtr cctxt, + xmlDocPtr doc, + xmlNodePtr node) +{ + xsltTemplatePtr templ; + + if ((cctxt == NULL) || (node == NULL)) + return(-1); + + if (xsltParseAttrXSLTVersion(cctxt, node, 0) == XSLT_ELEMENT_CATEGORY_LRE) + { + /* + * TODO: Adjust report, since this might be an + * embedded stylesheet. + */ + xsltTransformError(NULL, cctxt->style, node, + "The attribute 'xsl:version' is missing; cannot identify " + "this document as an XSLT stylesheet document.\n"); + cctxt->style->errors++; + return(1); + } + +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "xsltParseSimplifiedStylesheetTree: document is stylesheet\n"); +#endif + + /* + * Create and link the template + */ + templ = xsltNewTemplate(); + if (templ == NULL) { + return(-1); + } + templ->next = cctxt->style->templates; + cctxt->style->templates = templ; + templ->match = xmlStrdup(BAD_CAST "/"); + + /* + * Note that we push the document-node in this special case. + */ + xsltCompilerNodePush(cctxt, (xmlNodePtr) doc); + /* + * In every case, we need to have + * the in-scope namespaces of the element, where the + * stylesheet is rooted at, regardless if it's an XSLT + * instruction or a literal result instruction (or if + * this is an embedded stylesheet). + */ + cctxt->inode->inScopeNs = + xsltCompilerBuildInScopeNsList(cctxt, node); + /* + * Parse the content and register the match-pattern. + */ + xsltParseSequenceConstructor(cctxt, node); + xsltCompilerNodePop(cctxt, (xmlNodePtr) doc); + + templ->elem = (xmlNodePtr) doc; + templ->content = node; + xsltAddTemplate(cctxt->style, templ, NULL, NULL); + cctxt->style->literal_result = 1; + return(0); +} + +#ifdef XSLT_REFACTORED_XSLT_NSCOMP +/** + * xsltRestoreDocumentNamespaces: + * @ns: map of namespaces + * @doc: the document + * + * Restore the namespaces for the document + * + * Returns 0 in case of success, -1 in case of failure + */ +int +xsltRestoreDocumentNamespaces(xsltNsMapPtr ns, xmlDocPtr doc) +{ + if (doc == NULL) + return(-1); + /* + * Revert the changes we have applied to the namespace-URIs of + * ns-decls. + */ + while (ns != NULL) { + if ((ns->doc == doc) && (ns->ns != NULL)) { + ns->ns->href = ns->origNsName; + ns->origNsName = NULL; + ns->ns = NULL; + } + ns = ns->next; + } + return(0); +} +#endif /* XSLT_REFACTORED_XSLT_NSCOMP */ + +/** + * xsltParseStylesheetProcess: + * @style: the XSLT stylesheet (the current stylesheet-level) + * @doc: and xmlDoc parsed XML + * + * Parses an XSLT stylesheet, adding the associated structures. + * Called by: + * xsltParseStylesheetImportedDoc() (xslt.c) + * xsltParseStylesheetInclude() (imports.c) + * + * Returns the value of the @style parameter if everything + * went right, NULL if something went amiss. + */ +xsltStylesheetPtr +xsltParseStylesheetProcess(xsltStylesheetPtr style, xmlDocPtr doc) +{ + xsltCompilerCtxtPtr cctxt; + xmlNodePtr cur; + int oldIsSimplifiedStylesheet; + + xsltInitGlobals(); + + if ((style == NULL) || (doc == NULL)) + return(NULL); + + cctxt = XSLT_CCTXT(style); + + cur = xmlDocGetRootElement(doc); + if (cur == NULL) { + xsltTransformError(NULL, style, (xmlNodePtr) doc, + "xsltParseStylesheetProcess : empty stylesheet\n"); + return(NULL); + } + oldIsSimplifiedStylesheet = cctxt->simplified; + + if ((IS_XSLT_ELEM(cur)) && + ((IS_XSLT_NAME(cur, "stylesheet")) || + (IS_XSLT_NAME(cur, "transform")))) { +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "xsltParseStylesheetProcess : found stylesheet\n"); +#endif + cctxt->simplified = 0; + style->literal_result = 0; + } else { + cctxt->simplified = 1; + style->literal_result = 1; + } + /* + * Pre-process the stylesheet if not already done before. + * This will remove PIs and comments, merge adjacent + * text nodes, internalize strings, etc. + */ + if (! style->nopreproc) + xsltParsePreprocessStylesheetTree(cctxt, cur); + /* + * Parse and compile the stylesheet. + */ + if (style->literal_result == 0) { + if (xsltParseXSLTStylesheetElem(cctxt, cur) != 0) + return(NULL); + } else { + if (xsltParseSimplifiedStylesheetTree(cctxt, doc, cur) != 0) + return(NULL); + } + + cctxt->simplified = oldIsSimplifiedStylesheet; + + return(style); +} + +#else /* XSLT_REFACTORED */ + +/** + * xsltParseStylesheetProcess: + * @ret: the XSLT stylesheet (the current stylesheet-level) + * @doc: and xmlDoc parsed XML + * + * Parses an XSLT stylesheet, adding the associated structures. + * Called by: + * xsltParseStylesheetImportedDoc() (xslt.c) + * xsltParseStylesheetInclude() (imports.c) + * + * Returns the value of the @style parameter if everything + * went right, NULL if something went amiss. + */ +xsltStylesheetPtr +xsltParseStylesheetProcess(xsltStylesheetPtr ret, xmlDocPtr doc) { + xmlNodePtr cur; + + xsltInitGlobals(); + + if (doc == NULL) + return(NULL); + if (ret == NULL) + return(ret); + + /* + * First steps, remove blank nodes, + * locate the xsl:stylesheet element and the + * namespace declaration. + */ + cur = xmlDocGetRootElement(doc); + if (cur == NULL) { + xsltTransformError(NULL, ret, (xmlNodePtr) doc, + "xsltParseStylesheetProcess : empty stylesheet\n"); + return(NULL); + } + + if ((IS_XSLT_ELEM(cur)) && + ((IS_XSLT_NAME(cur, "stylesheet")) || + (IS_XSLT_NAME(cur, "transform")))) { +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "xsltParseStylesheetProcess : found stylesheet\n"); +#endif + ret->literal_result = 0; + xsltParseStylesheetExcludePrefix(ret, cur, 1); + xsltParseStylesheetExtPrefix(ret, cur, 1); + } else { + xsltParseStylesheetExcludePrefix(ret, cur, 0); + xsltParseStylesheetExtPrefix(ret, cur, 0); + ret->literal_result = 1; + } + if (!ret->nopreproc) { + xsltPreprocessStylesheet(ret, cur); + } + if (ret->literal_result == 0) { + xsltParseStylesheetTop(ret, cur); + } else { + xmlChar *prop; + xsltTemplatePtr template; + + /* + * the document itself might be the template, check xsl:version + */ + prop = xmlGetNsProp(cur, (const xmlChar *)"version", XSLT_NAMESPACE); + if (prop == NULL) { + xsltTransformError(NULL, ret, cur, + "xsltParseStylesheetProcess : document is not a stylesheet\n"); + return(NULL); + } + +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "xsltParseStylesheetProcess : document is stylesheet\n"); +#endif + + if ((!xmlStrEqual(prop, (const xmlChar *)"1.0")) && + (!xmlStrEqual(prop, (const xmlChar *)"1.1"))) { + xsltTransformError(NULL, ret, cur, + "xsl:version: only 1.1 features are supported\n"); + ret->forwards_compatible = 1; + ret->warnings++; + } + xmlFree(prop); + + /* + * Create and link the template + */ + template = xsltNewTemplate(); + if (template == NULL) { + return(NULL); + } + template->next = ret->templates; + ret->templates = template; + template->match = xmlStrdup((const xmlChar *)"/"); + + /* + * parse the content and register the pattern + */ + xsltParseTemplateContent(ret, (xmlNodePtr) doc); + template->elem = (xmlNodePtr) doc; + template->content = doc->children; + xsltAddTemplate(ret, template, NULL, NULL); + ret->literal_result = 1; + } + + return(ret); +} + +#endif /* else of XSLT_REFACTORED */ + +/** + * xsltParseStylesheetImportedDoc: + * @doc: an xmlDoc parsed XML + * @parentStyle: pointer to the parent stylesheet (if it exists) + * + * parse an XSLT stylesheet building the associated structures + * except the processing not needed for imported documents. + * + * Returns a new XSLT stylesheet structure. + */ + +xsltStylesheetPtr +xsltParseStylesheetImportedDoc(xmlDocPtr doc, + xsltStylesheetPtr parentStyle) { + xsltStylesheetPtr retStyle; + + if (doc == NULL) + return(NULL); + + retStyle = xsltNewStylesheetInternal(parentStyle); + if (retStyle == NULL) + return(NULL); + + if (xsltParseStylesheetUser(retStyle, doc) != 0) { + xsltFreeStylesheet(retStyle); + return(NULL); + } + + return(retStyle); +} + +/** + * xsltParseStylesheetUser: + * @style: pointer to the stylesheet + * @doc: an xmlDoc parsed XML + * + * Parse an XSLT stylesheet with a user-provided stylesheet struct. + * + * Returns 0 if successful, -1 in case of error. + */ +int +xsltParseStylesheetUser(xsltStylesheetPtr style, xmlDocPtr doc) { + if ((style == NULL) || (doc == NULL)) + return(-1); + + /* + * Adjust the string dict. + */ + if (doc->dict != NULL) { + xmlDictFree(style->dict); + style->dict = doc->dict; +#ifdef WITH_XSLT_DEBUG + xsltGenericDebug(xsltGenericDebugContext, + "reusing dictionary from %s for stylesheet\n", + doc->URL); +#endif + xmlDictReference(style->dict); + } + + /* + * TODO: Eliminate xsltGatherNamespaces(); we must not restrict + * the stylesheet to containt distinct namespace prefixes. + */ + xsltGatherNamespaces(style); + +#ifdef XSLT_REFACTORED + { + xsltCompilerCtxtPtr cctxt; + xsltStylesheetPtr oldCurSheet; + + if (style->parent == NULL) { + xsltPrincipalStylesheetDataPtr principalData; + /* + * Create extra data for the principal stylesheet. + */ + principalData = xsltNewPrincipalStylesheetData(); + if (principalData == NULL) { + return(-1); + } + style->principalData = principalData; + /* + * Create the compilation context + * ------------------------------ + * (only once; for the principal stylesheet). + * This is currently the only function where the + * compilation context is created. + */ + cctxt = xsltCompilationCtxtCreate(style); + if (cctxt == NULL) { + return(-1); + } + style->compCtxt = (void *) cctxt; + cctxt->style = style; + cctxt->dict = style->dict; + cctxt->psData = principalData; + /* + * Push initial dummy node info. + */ + cctxt->depth = -1; + xsltCompilerNodePush(cctxt, (xmlNodePtr) doc); + } else { + /* + * Imported stylesheet. + */ + cctxt = style->parent->compCtxt; + style->compCtxt = cctxt; + } + /* + * Save the old and set the current stylesheet structure in the + * compilation context. + */ + oldCurSheet = cctxt->style; + cctxt->style = style; + + style->doc = doc; + xsltParseStylesheetProcess(style, doc); + + cctxt->style = oldCurSheet; + if (style->parent == NULL) { + /* + * Pop the initial dummy node info. + */ + xsltCompilerNodePop(cctxt, (xmlNodePtr) doc); + } else { + /* + * Clear the compilation context of imported + * stylesheets. + * TODO: really? + */ + /* style->compCtxt = NULL; */ + } + +#ifdef XSLT_REFACTORED_XSLT_NSCOMP + if (style->errors != 0) { + /* + * Restore all changes made to namespace URIs of ns-decls. + */ + if (cctxt->psData->nsMap) + xsltRestoreDocumentNamespaces(cctxt->psData->nsMap, doc); + } +#endif + + if (style->parent == NULL) { + xsltCompilationCtxtFree(style->compCtxt); + style->compCtxt = NULL; + } + } + +#else /* XSLT_REFACTORED */ + /* + * Old behaviour. + */ + style->doc = doc; + if (xsltParseStylesheetProcess(style, doc) == NULL) { + style->doc = NULL; + return(-1); + } +#endif /* else of XSLT_REFACTORED */ + + if (style->parent == NULL) + xsltResolveStylesheetAttributeSet(style); + + if (style->errors != 0) { + /* + * Detach the doc from the stylesheet; otherwise the doc + * will be freed in xsltFreeStylesheet(). + */ + style->doc = NULL; + /* + * Cleanup the doc if its the main stylesheet. + */ + if (style->parent == NULL) + xsltCleanupStylesheetTree(doc, xmlDocGetRootElement(doc)); + return(-1); + } + + return(0); +} + +/** + * xsltParseStylesheetDoc: + * @doc: an xmlDoc parsed XML + * + * parse an XSLT stylesheet, building the associated structures. doc + * is kept as a reference within the returned stylesheet, so changes + * to doc after the parsing will be reflected when the stylesheet + * is applied, and the doc is automatically freed when the + * stylesheet is closed. + * + * Returns a new XSLT stylesheet structure. + */ + +xsltStylesheetPtr +xsltParseStylesheetDoc(xmlDocPtr doc) { + xsltInitGlobals(); + + return(xsltParseStylesheetImportedDoc(doc, NULL)); +} + +/** + * xsltParseStylesheetFile: + * @filename: the filename/URL to the stylesheet + * + * Load and parse an XSLT stylesheet + * + * Returns a new XSLT stylesheet structure. + */ + +xsltStylesheetPtr +xsltParseStylesheetFile(const xmlChar* filename) { + xsltSecurityPrefsPtr sec; + xsltStylesheetPtr ret; + xmlDocPtr doc; + + xsltInitGlobals(); + + if (filename == NULL) + return(NULL); + +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "xsltParseStylesheetFile : parse %s\n", filename); +#endif + + /* + * Security framework check + */ + sec = xsltGetDefaultSecurityPrefs(); + if (sec != NULL) { + int res; + + res = xsltCheckRead(sec, NULL, filename); + if (res <= 0) { + if (res == 0) + xsltTransformError(NULL, NULL, NULL, + "xsltParseStylesheetFile: read rights for %s denied\n", + filename); + return(NULL); + } + } + + doc = xsltDocDefaultLoader(filename, NULL, XSLT_PARSE_OPTIONS, + NULL, XSLT_LOAD_START); + if (doc == NULL) { + xsltTransformError(NULL, NULL, NULL, + "xsltParseStylesheetFile : cannot parse %s\n", filename); + return(NULL); + } + ret = xsltParseStylesheetDoc(doc); + if (ret == NULL) { + xmlFreeDoc(doc); + return(NULL); + } + + return(ret); +} + +/************************************************************************ + * * + * Handling of Stylesheet PI * + * * + ************************************************************************/ + +#define CUR (*cur) +#define SKIP(val) cur += (val) +#define NXT(val) cur[(val)] +#define SKIP_BLANKS \ + while (IS_BLANK(CUR)) NEXT +#define NEXT ((*cur) ? cur++ : cur) + +/** + * xsltParseStylesheetPI: + * @value: the value of the PI + * + * This function checks that the type is text/xml and extracts + * the URI-Reference for the stylesheet + * + * Returns the URI-Reference for the stylesheet or NULL (it need to + * be freed by the caller) + */ +static xmlChar * +xsltParseStylesheetPI(const xmlChar *value) { + const xmlChar *cur; + const xmlChar *start; + xmlChar *val; + xmlChar tmp; + xmlChar *href = NULL; + int isXml = 0; + + if (value == NULL) + return(NULL); + + cur = value; + while (CUR != 0) { + SKIP_BLANKS; + if ((CUR == 't') && (NXT(1) == 'y') && (NXT(2) == 'p') && + (NXT(3) == 'e')) { + SKIP(4); + SKIP_BLANKS; + if (CUR != '=') + continue; + NEXT; + if ((CUR != '\'') && (CUR != '"')) + continue; + tmp = CUR; + NEXT; + start = cur; + while ((CUR != 0) && (CUR != tmp)) + NEXT; + if (CUR != tmp) + continue; + val = xmlStrndup(start, cur - start); + NEXT; + if (val == NULL) + return(NULL); + if ((xmlStrcasecmp(val, BAD_CAST "text/xml")) && + (xmlStrcasecmp(val, BAD_CAST "text/xsl")) && + (xmlStrcasecmp(val, BAD_CAST "application/xslt+xml"))) { + xmlFree(val); + break; + } + isXml = 1; + xmlFree(val); + } else if ((CUR == 'h') && (NXT(1) == 'r') && (NXT(2) == 'e') && + (NXT(3) == 'f')) { + SKIP(4); + SKIP_BLANKS; + if (CUR != '=') + continue; + NEXT; + if ((CUR != '\'') && (CUR != '"')) + continue; + tmp = CUR; + NEXT; + start = cur; + while ((CUR != 0) && (CUR != tmp)) + NEXT; + if (CUR != tmp) + continue; + if (href == NULL) + href = xmlStrndup(start, cur - start); + NEXT; + } else { + while ((CUR != 0) && (!IS_BLANK(CUR))) + NEXT; + } + + } + + if (!isXml) { + if (href != NULL) + xmlFree(href); + href = NULL; + } + return(href); +} + +/** + * xsltLoadStylesheetPI: + * @doc: a document to process + * + * This function tries to locate the stylesheet PI in the given document + * If found, and if contained within the document, it will extract + * that subtree to build the stylesheet to process @doc (doc itself will + * be modified). If found but referencing an external document it will + * attempt to load it and generate a stylesheet from it. In both cases, + * the resulting stylesheet and the document need to be freed once the + * transformation is done. + * + * Returns a new XSLT stylesheet structure or NULL if not found. + */ +xsltStylesheetPtr +xsltLoadStylesheetPI(xmlDocPtr doc) { + xmlNodePtr child; + xsltStylesheetPtr ret = NULL; + xmlChar *href = NULL; + xmlURIPtr URI; + + xsltInitGlobals(); + + if (doc == NULL) + return(NULL); + + /* + * Find the text/xml stylesheet PI id any before the root + */ + child = doc->children; + while ((child != NULL) && (child->type != XML_ELEMENT_NODE)) { + if ((child->type == XML_PI_NODE) && + (xmlStrEqual(child->name, BAD_CAST "xml-stylesheet"))) { + href = xsltParseStylesheetPI(child->content); + if (href != NULL) + break; + } + child = child->next; + } + + /* + * If found check the href to select processing + */ + if (href != NULL) { +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "xsltLoadStylesheetPI : found PI href=%s\n", href); +#endif + URI = xmlParseURI((const char *) href); + if (URI == NULL) { + xsltTransformError(NULL, NULL, child, + "xml-stylesheet : href %s is not valid\n", href); + xmlFree(href); + return(NULL); + } + if ((URI->fragment != NULL) && (URI->scheme == NULL) && + (URI->opaque == NULL) && (URI->authority == NULL) && + (URI->server == NULL) && (URI->user == NULL) && + (URI->path == NULL) && (URI->query == NULL)) { + xmlAttrPtr ID; + +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "xsltLoadStylesheetPI : Reference to ID %s\n", href); +#endif + if (URI->fragment[0] == '#') + ID = xmlGetID(doc, (const xmlChar *) &(URI->fragment[1])); + else + ID = xmlGetID(doc, (const xmlChar *) URI->fragment); + if (ID == NULL) { + xsltTransformError(NULL, NULL, child, + "xml-stylesheet : no ID %s found\n", URI->fragment); + } else { + xmlDocPtr fake; + xmlNodePtr subtree, newtree; + xmlNsPtr ns; + +#ifdef WITH_XSLT_DEBUG + xsltGenericDebug(xsltGenericDebugContext, + "creating new document from %s for embedded stylesheet\n", + doc->URL); +#endif + /* + * move the subtree in a new document passed to + * the stylesheet analyzer + */ + subtree = ID->parent; + fake = xmlNewDoc(NULL); + if (fake != NULL) { + /* + * Should the dictionary still be shared even though + * the nodes are being copied rather than moved? + */ + fake->dict = doc->dict; + xmlDictReference(doc->dict); +#ifdef WITH_XSLT_DEBUG + xsltGenericDebug(xsltGenericDebugContext, + "reusing dictionary from %s for embedded stylesheet\n", + doc->URL); +#endif + + newtree = xmlDocCopyNode(subtree, fake, 1); + + fake->URL = xmlNodeGetBase(doc, subtree->parent); +#ifdef WITH_XSLT_DEBUG + xsltGenericDebug(xsltGenericDebugContext, + "set base URI for embedded stylesheet as %s\n", + fake->URL); +#endif + + /* + * Add all namespaces in scope of embedded stylesheet to + * root element of newly created stylesheet document + */ + while ((subtree = subtree->parent) != (xmlNodePtr)doc) { + for (ns = subtree->ns; ns; ns = ns->next) { + xmlNewNs(newtree, ns->href, ns->prefix); + } + } + + xmlAddChild((xmlNodePtr)fake, newtree); + ret = xsltParseStylesheetDoc(fake); + if (ret == NULL) + xmlFreeDoc(fake); + } + } + } else { + xmlChar *URL, *base; + + /* + * Reference to an external stylesheet + */ + + base = xmlNodeGetBase(doc, (xmlNodePtr) doc); + URL = xmlBuildURI(href, base); + if (URL != NULL) { +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "xsltLoadStylesheetPI : fetching %s\n", URL); +#endif + ret = xsltParseStylesheetFile(URL); + xmlFree(URL); + } else { +#ifdef WITH_XSLT_DEBUG_PARSING + xsltGenericDebug(xsltGenericDebugContext, + "xsltLoadStylesheetPI : fetching %s\n", href); +#endif + ret = xsltParseStylesheetFile(href); + } + if (base != NULL) + xmlFree(base); + } + xmlFreeURI(URI); + xmlFree(href); + } + return(ret); +} diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/xslt.h chromium-145.0.7632.159/third_party/libxslt/src/libxslt/xslt.h --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/xslt.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/xslt.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,110 @@ +/* + * Summary: Interfaces, constants and types related to the XSLT engine + * Description: Interfaces, constants and types related to the XSLT engine + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLT_H__ +#define __XML_XSLT_H__ + +#include +#include "xsltexports.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * XSLT_DEFAULT_VERSION: + * + * The default version of XSLT supported. + */ +#define XSLT_DEFAULT_VERSION "1.0" + +/** + * XSLT_DEFAULT_VENDOR: + * + * The XSLT "vendor" string for this processor. + */ +#define XSLT_DEFAULT_VENDOR "libxslt" + +/** + * XSLT_DEFAULT_URL: + * + * The XSLT "vendor" URL for this processor. + */ +#define XSLT_DEFAULT_URL "http://xmlsoft.org/XSLT/" + +/** + * XSLT_NAMESPACE: + * + * The XSLT specification namespace. + */ +#define XSLT_NAMESPACE ((const xmlChar *)"http://www.w3.org/1999/XSL/Transform") + +/** + * XSLT_PARSE_OPTIONS: + * + * The set of options to pass to an xmlReadxxx when loading files for + * XSLT consumption. + */ +#define XSLT_PARSE_OPTIONS \ + XML_PARSE_NOENT | XML_PARSE_DTDLOAD | XML_PARSE_DTDATTR | XML_PARSE_NOCDATA + +/** + * xsltMaxDepth: + * + * This value is used to detect templates loops. + */ +XSLTPUBVAR int xsltMaxDepth; + +/** + * * xsltMaxVars: + * * + * * This value is used to detect templates loops. + * */ +XSLTPUBVAR int xsltMaxVars; + +/** + * xsltEngineVersion: + * + * The version string for libxslt. + */ +XSLTPUBVAR const char *xsltEngineVersion; + +/** + * xsltLibxsltVersion: + * + * The version of libxslt compiled. + */ +XSLTPUBVAR const int xsltLibxsltVersion; + +/** + * xsltLibxmlVersion: + * + * The version of libxml libxslt was compiled against. + */ +XSLTPUBVAR const int xsltLibxmlVersion; + +/* + * Global initialization function. + */ + +XSLTPUBFUN void XSLTCALL + xsltInit (void); + +/* + * Global cleanup function. + */ +XSLTPUBFUN void XSLTCALL + xsltCleanupGlobals (void); + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_H__ */ + diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/xsltInternals.h chromium-145.0.7632.159/third_party/libxslt/src/libxslt/xsltInternals.h --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/xsltInternals.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/xsltInternals.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,2004 @@ +/* + * Summary: internal data structures, constants and functions + * Description: Internal data structures, constants and functions used + * by the XSLT engine. + * They are not part of the API or ABI, i.e. they can change + * without prior notice, use carefully. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLT_INTERNALS_H__ +#define __XML_XSLT_INTERNALS_H__ + +#include +#include +#include +#include +#include +#include +#include +#include "xsltexports.h" +#include "numbersInternals.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* #define XSLT_DEBUG_PROFILE_CACHE */ + +/** + * XSLT_IS_TEXT_NODE: + * + * check if the argument is a text node + */ +#define XSLT_IS_TEXT_NODE(n) ((n != NULL) && \ + (((n)->type == XML_TEXT_NODE) || \ + ((n)->type == XML_CDATA_SECTION_NODE))) + + +/** + * XSLT_MARK_RES_TREE_FRAG: + * + * internal macro to set up tree fragments + */ +#define XSLT_MARK_RES_TREE_FRAG(n) \ + (n)->name = (char *) xmlStrdup(BAD_CAST " fake node libxslt"); + +/** + * XSLT_IS_RES_TREE_FRAG: + * + * internal macro to test tree fragments + */ +#define XSLT_IS_RES_TREE_FRAG(n) \ + ((n != NULL) && ((n)->type == XML_DOCUMENT_NODE) && \ + ((n)->name != NULL) && ((n)->name[0] == ' ')) + +/** + * XSLT_REFACTORED_KEYCOMP: + * + * Internal define to enable on-demand xsl:key computation. + * That's the only mode now but the define is kept for compatibility + */ +#define XSLT_REFACTORED_KEYCOMP + +/** + * XSLT_FAST_IF: + * + * Internal define to enable usage of xmlXPathCompiledEvalToBoolean() + * for XSLT "tests"; e.g. in + */ +#define XSLT_FAST_IF + +/** + * XSLT_REFACTORED: + * + * Internal define to enable the refactored parts of Libxslt. + */ +/* #define XSLT_REFACTORED */ +/* ==================================================================== */ + +/** + * XSLT_REFACTORED_VARS: + * + * Internal define to enable the refactored variable part of libxslt + */ +#define XSLT_REFACTORED_VARS + +#ifdef XSLT_REFACTORED + +extern const xmlChar *xsltXSLTAttrMarker; + + +/* TODO: REMOVE: #define XSLT_REFACTORED_EXCLRESNS */ + +/* TODO: REMOVE: #define XSLT_REFACTORED_NSALIAS */ + +/** + * XSLT_REFACTORED_XSLT_NSCOMP + * + * Internal define to enable the pointer-comparison of + * namespaces of XSLT elements. + */ +/* #define XSLT_REFACTORED_XSLT_NSCOMP */ + +#ifdef XSLT_REFACTORED_XSLT_NSCOMP + +extern const xmlChar *xsltConstNamespaceNameXSLT; + +/** + * IS_XSLT_ELEM_FAST: + * + * quick test to detect XSLT elements + */ +#define IS_XSLT_ELEM_FAST(n) \ + (((n) != NULL) && ((n)->ns != NULL) && \ + ((n)->ns->href == xsltConstNamespaceNameXSLT)) + +/** + * IS_XSLT_ATTR_FAST: + * + * quick test to detect XSLT attributes + */ +#define IS_XSLT_ATTR_FAST(a) \ + (((a) != NULL) && ((a)->ns != NULL) && \ + ((a)->ns->href == xsltConstNamespaceNameXSLT)) + +/** + * XSLT_HAS_INTERNAL_NSMAP: + * + * check for namespace mapping + */ +#define XSLT_HAS_INTERNAL_NSMAP(s) \ + (((s) != NULL) && ((s)->principal) && \ + ((s)->principal->principalData) && \ + ((s)->principal->principalData->nsMap)) + +/** + * XSLT_GET_INTERNAL_NSMAP: + * + * get pointer to namespace map + */ +#define XSLT_GET_INTERNAL_NSMAP(s) ((s)->principal->principalData->nsMap) + +#else /* XSLT_REFACTORED_XSLT_NSCOMP */ + +/** + * IS_XSLT_ELEM_FAST: + * + * quick check whether this is an xslt element + */ +#define IS_XSLT_ELEM_FAST(n) \ + (((n) != NULL) && ((n)->ns != NULL) && \ + (xmlStrEqual((n)->ns->href, XSLT_NAMESPACE))) + +/** + * IS_XSLT_ATTR_FAST: + * + * quick check for xslt namespace attribute + */ +#define IS_XSLT_ATTR_FAST(a) \ + (((a) != NULL) && ((a)->ns != NULL) && \ + (xmlStrEqual((a)->ns->href, XSLT_NAMESPACE))) + + +#endif /* XSLT_REFACTORED_XSLT_NSCOMP */ + + +/** + * XSLT_REFACTORED_MANDATORY_VERSION: + * + * TODO: Currently disabled to surpress regression test failures, since + * the old behaviour was that a missing version attribute + * produced a only a warning and not an error, which was incerrect. + * So the regression tests need to be fixed if this is enabled. + */ +/* #define XSLT_REFACTORED_MANDATORY_VERSION */ + +/** + * xsltPointerList: + * + * Pointer-list for various purposes. + */ +typedef struct _xsltPointerList xsltPointerList; +typedef xsltPointerList *xsltPointerListPtr; +struct _xsltPointerList { + void **items; + int number; + int size; +}; + +#endif + +/** + * XSLT_REFACTORED_PARSING: + * + * Internal define to enable the refactored parts of Libxslt + * related to parsing. + */ +/* #define XSLT_REFACTORED_PARSING */ + +/** + * XSLT_MAX_SORT: + * + * Max number of specified xsl:sort on an element. + */ +#define XSLT_MAX_SORT 15 + +/** + * XSLT_PAT_NO_PRIORITY: + * + * Specific value for pattern without priority expressed. + */ +#define XSLT_PAT_NO_PRIORITY -12345789 + +/** + * xsltRuntimeExtra: + * + * Extra information added to the transformation context. + */ +typedef struct _xsltRuntimeExtra xsltRuntimeExtra; +typedef xsltRuntimeExtra *xsltRuntimeExtraPtr; +struct _xsltRuntimeExtra { + void *info; /* pointer to the extra data */ + xmlFreeFunc deallocate; /* pointer to the deallocation routine */ + union { /* dual-purpose field */ + void *ptr; /* data not needing deallocation */ + int ival; /* integer value storage */ + } val; +}; + +/** + * XSLT_RUNTIME_EXTRA_LST: + * @ctxt: the transformation context + * @nr: the index + * + * Macro used to access extra information stored in the context + */ +#define XSLT_RUNTIME_EXTRA_LST(ctxt, nr) (ctxt)->extras[(nr)].info +/** + * XSLT_RUNTIME_EXTRA_FREE: + * @ctxt: the transformation context + * @nr: the index + * + * Macro used to free extra information stored in the context + */ +#define XSLT_RUNTIME_EXTRA_FREE(ctxt, nr) (ctxt)->extras[(nr)].deallocate +/** + * XSLT_RUNTIME_EXTRA: + * @ctxt: the transformation context + * @nr: the index + * + * Macro used to define extra information stored in the context + */ +#define XSLT_RUNTIME_EXTRA(ctxt, nr, typ) (ctxt)->extras[(nr)].val.typ + +/** + * xsltTemplate: + * + * The in-memory structure corresponding to an XSLT Template. + */ +typedef struct _xsltTemplate xsltTemplate; +typedef xsltTemplate *xsltTemplatePtr; +struct _xsltTemplate { + struct _xsltTemplate *next;/* chained list sorted by priority */ + struct _xsltStylesheet *style;/* the containing stylesheet */ + xmlChar *match; /* the matching string */ + float priority; /* as given from the stylesheet, not computed */ + const xmlChar *name; /* the local part of the name QName */ + const xmlChar *nameURI; /* the URI part of the name QName */ + const xmlChar *mode;/* the local part of the mode QName */ + const xmlChar *modeURI;/* the URI part of the mode QName */ + xmlNodePtr content; /* the template replacement value */ + xmlNodePtr elem; /* the source element */ + + /* + * TODO: @inheritedNsNr and @inheritedNs won't be used in the + * refactored code. + */ + int inheritedNsNr; /* number of inherited namespaces */ + xmlNsPtr *inheritedNs;/* inherited non-excluded namespaces */ + + /* Profiling information */ + int nbCalls; /* the number of time the template was called */ + unsigned long time; /* the time spent in this template */ + void *params; /* xsl:param instructions */ + + int templNr; /* Nb of templates in the stack */ + int templMax; /* Size of the templtes stack */ + xsltTemplatePtr *templCalledTab; /* templates called */ + int *templCountTab; /* .. and how often */ + + /* Conflict resolution */ + int position; +}; + +/** + * xsltDecimalFormat: + * + * Data structure of decimal-format. + */ +typedef struct _xsltDecimalFormat xsltDecimalFormat; +typedef xsltDecimalFormat *xsltDecimalFormatPtr; +struct _xsltDecimalFormat { + struct _xsltDecimalFormat *next; /* chained list */ + xmlChar *name; + /* Used for interpretation of pattern */ + xmlChar *digit; + xmlChar *patternSeparator; + /* May appear in result */ + xmlChar *minusSign; + xmlChar *infinity; + xmlChar *noNumber; /* Not-a-number */ + /* Used for interpretation of pattern and may appear in result */ + xmlChar *decimalPoint; + xmlChar *grouping; + xmlChar *percent; + xmlChar *permille; + xmlChar *zeroDigit; + const xmlChar *nsUri; +}; + +/** + * xsltDocument: + * + * Data structure associated to a parsed document. + */ +typedef struct _xsltDocument xsltDocument; +typedef xsltDocument *xsltDocumentPtr; +struct _xsltDocument { + struct _xsltDocument *next; /* documents are kept in a chained list */ + int main; /* is this the main document */ + xmlDocPtr doc; /* the parsed document */ + void *keys; /* key tables storage */ + struct _xsltDocument *includes; /* subsidiary includes */ + int preproc; /* pre-processing already done */ + int nbKeysComputed; +}; + +/** + * xsltKeyDef: + * + * Representation of an xsl:key. + */ +typedef struct _xsltKeyDef xsltKeyDef; +typedef xsltKeyDef *xsltKeyDefPtr; +struct _xsltKeyDef { + struct _xsltKeyDef *next; + xmlNodePtr inst; + xmlChar *name; + xmlChar *nameURI; + xmlChar *match; + xmlChar *use; + xmlXPathCompExprPtr comp; + xmlXPathCompExprPtr usecomp; + xmlNsPtr *nsList; /* the namespaces in scope */ + int nsNr; /* the number of namespaces in scope */ +}; + +/** + * xsltKeyTable: + * + * Holds the computed keys for key definitions of the same QName. + * Is owned by an xsltDocument. + */ +typedef struct _xsltKeyTable xsltKeyTable; +typedef xsltKeyTable *xsltKeyTablePtr; +struct _xsltKeyTable { + struct _xsltKeyTable *next; + xmlChar *name; + xmlChar *nameURI; + xmlHashTablePtr keys; +}; + +/* + * The in-memory structure corresponding to an XSLT Stylesheet. + * NOTE: most of the content is simply linked from the doc tree + * structure, no specific allocation is made. + */ +typedef struct _xsltStylesheet xsltStylesheet; +typedef xsltStylesheet *xsltStylesheetPtr; + +typedef struct _xsltTransformContext xsltTransformContext; +typedef xsltTransformContext *xsltTransformContextPtr; + +/** + * xsltElemPreComp: + * + * The in-memory structure corresponding to element precomputed data, + * designed to be extended by extension implementors. + */ +typedef struct _xsltElemPreComp xsltElemPreComp; +typedef xsltElemPreComp *xsltElemPreCompPtr; + +/** + * xsltTransformFunction: + * @ctxt: the XSLT transformation context + * @node: the input node + * @inst: the stylesheet node + * @comp: the compiled information from the stylesheet + * + * Signature of the function associated to elements part of the + * stylesheet language like xsl:if or xsl:apply-templates. + */ +typedef void (*xsltTransformFunction) (xsltTransformContextPtr ctxt, + xmlNodePtr node, + xmlNodePtr inst, + xsltElemPreCompPtr comp); + +/** + * xsltSortFunc: + * @ctxt: a transformation context + * @sorts: the node-set to sort + * @nbsorts: the number of sorts + * + * Signature of the function to use during sorting + */ +typedef void (*xsltSortFunc) (xsltTransformContextPtr ctxt, xmlNodePtr *sorts, + int nbsorts); + +typedef enum { + XSLT_FUNC_COPY=1, + XSLT_FUNC_SORT, + XSLT_FUNC_TEXT, + XSLT_FUNC_ELEMENT, + XSLT_FUNC_ATTRIBUTE, + XSLT_FUNC_COMMENT, + XSLT_FUNC_PI, + XSLT_FUNC_COPYOF, + XSLT_FUNC_VALUEOF, + XSLT_FUNC_NUMBER, + XSLT_FUNC_APPLYIMPORTS, + XSLT_FUNC_CALLTEMPLATE, + XSLT_FUNC_APPLYTEMPLATES, + XSLT_FUNC_CHOOSE, + XSLT_FUNC_IF, + XSLT_FUNC_FOREACH, + XSLT_FUNC_DOCUMENT, + XSLT_FUNC_WITHPARAM, + XSLT_FUNC_PARAM, + XSLT_FUNC_VARIABLE, + XSLT_FUNC_WHEN, + XSLT_FUNC_EXTENSION +#ifdef XSLT_REFACTORED + , + XSLT_FUNC_OTHERWISE, + XSLT_FUNC_FALLBACK, + XSLT_FUNC_MESSAGE, + XSLT_FUNC_INCLUDE, + XSLT_FUNC_ATTRSET, + XSLT_FUNC_LITERAL_RESULT_ELEMENT, + XSLT_FUNC_UNKOWN_FORWARDS_COMPAT +#endif +} xsltStyleType; + +/** + * xsltElemPreCompDeallocator: + * @comp: the #xsltElemPreComp to free up + * + * Deallocates an #xsltElemPreComp structure. + */ +typedef void (*xsltElemPreCompDeallocator) (xsltElemPreCompPtr comp); + +/** + * xsltElemPreComp: + * + * The basic structure for compiled items of the AST of the XSLT processor. + * This structure is also intended to be extended by extension implementors. + * TODO: This is somehow not nice, since it has a "free" field, which + * derived stylesheet-structs do not have. + */ +struct _xsltElemPreComp { + xsltElemPreCompPtr next; /* next item in the global chained + list held by xsltStylesheet. */ + xsltStyleType type; /* type of the element */ + xsltTransformFunction func; /* handling function */ + xmlNodePtr inst; /* the node in the stylesheet's tree + corresponding to this item */ + + /* end of common part */ + xsltElemPreCompDeallocator free; /* the deallocator */ +}; + +/** + * xsltStylePreComp: + * + * The abstract basic structure for items of the XSLT processor. + * This includes: + * 1) compiled forms of XSLT instructions (xsl:if, xsl:attribute, etc.) + * 2) compiled forms of literal result elements + * 3) compiled forms of extension elements + */ +typedef struct _xsltStylePreComp xsltStylePreComp; +typedef xsltStylePreComp *xsltStylePreCompPtr; + +#ifdef XSLT_REFACTORED + +/* +* Some pointer-list utility functions. +*/ +XSLTPUBFUN xsltPointerListPtr XSLTCALL + xsltPointerListCreate (int initialSize); +XSLTPUBFUN void XSLTCALL + xsltPointerListFree (xsltPointerListPtr list); +XSLTPUBFUN void XSLTCALL + xsltPointerListClear (xsltPointerListPtr list); +XSLTPUBFUN int XSLTCALL + xsltPointerListAddSize (xsltPointerListPtr list, + void *item, + int initialSize); + +/************************************************************************ + * * + * Refactored structures * + * * + ************************************************************************/ + +typedef struct _xsltNsListContainer xsltNsListContainer; +typedef xsltNsListContainer *xsltNsListContainerPtr; +struct _xsltNsListContainer { + xmlNsPtr *list; + int totalNumber; + int xpathNumber; +}; + +/** + * XSLT_ITEM_COMPATIBILITY_FIELDS: + * + * Fields for API compatibility to the structure + * _xsltElemPreComp which is used for extension functions. + * Note that @next is used for storage; it does not reflect a next + * sibling in the tree. + * TODO: Evaluate if we really need such a compatibility. + */ +#define XSLT_ITEM_COMPATIBILITY_FIELDS \ + xsltElemPreCompPtr next;\ + xsltStyleType type;\ + xsltTransformFunction func;\ + xmlNodePtr inst; + +/** + * XSLT_ITEM_NAVIGATION_FIELDS: + * + * Currently empty. + * TODO: It is intended to hold navigational fields in the future. + */ +#define XSLT_ITEM_NAVIGATION_FIELDS +/* + xsltStylePreCompPtr parent;\ + xsltStylePreCompPtr children;\ + xsltStylePreCompPtr nextItem; +*/ + +/** + * XSLT_ITEM_NSINSCOPE_FIELDS: + * + * The in-scope namespaces. + */ +#define XSLT_ITEM_NSINSCOPE_FIELDS xsltNsListContainerPtr inScopeNs; + +/** + * XSLT_ITEM_COMMON_FIELDS: + * + * Common fields used for all items. + */ +#define XSLT_ITEM_COMMON_FIELDS \ + XSLT_ITEM_COMPATIBILITY_FIELDS \ + XSLT_ITEM_NAVIGATION_FIELDS \ + XSLT_ITEM_NSINSCOPE_FIELDS + +/** + * _xsltStylePreComp: + * + * The abstract basic structure for items of the XSLT processor. + * This includes: + * 1) compiled forms of XSLT instructions (e.g. xsl:if, xsl:attribute, etc.) + * 2) compiled forms of literal result elements + * 3) various properties for XSLT instructions (e.g. xsl:when, + * xsl:with-param) + * + * REVISIT TODO: Keep this structure equal to the fields + * defined by XSLT_ITEM_COMMON_FIELDS + */ +struct _xsltStylePreComp { + xsltElemPreCompPtr next; /* next item in the global chained + list held by xsltStylesheet */ + xsltStyleType type; /* type of the item */ + xsltTransformFunction func; /* handling function */ + xmlNodePtr inst; /* the node in the stylesheet's tree + corresponding to this item. */ + /* Currently no navigational fields. */ + xsltNsListContainerPtr inScopeNs; +}; + +/** + * xsltStyleBasicEmptyItem: + * + * Abstract structure only used as a short-cut for + * XSLT items with no extra fields. + * NOTE that it is intended that this structure looks the same as + * _xsltStylePreComp. + */ +typedef struct _xsltStyleBasicEmptyItem xsltStyleBasicEmptyItem; +typedef xsltStyleBasicEmptyItem *xsltStyleBasicEmptyItemPtr; + +struct _xsltStyleBasicEmptyItem { + XSLT_ITEM_COMMON_FIELDS +}; + +/** + * xsltStyleBasicExpressionItem: + * + * Abstract structure only used as a short-cut for + * XSLT items with just an expression. + */ +typedef struct _xsltStyleBasicExpressionItem xsltStyleBasicExpressionItem; +typedef xsltStyleBasicExpressionItem *xsltStyleBasicExpressionItemPtr; + +struct _xsltStyleBasicExpressionItem { + XSLT_ITEM_COMMON_FIELDS + + const xmlChar *select; /* TODO: Change this to "expression". */ + xmlXPathCompExprPtr comp; /* TODO: Change this to compExpr. */ +}; + +/************************************************************************ + * * + * XSLT-instructions/declarations * + * * + ************************************************************************/ + +/** + * xsltStyleItemElement: + * + * + * + * + * + */ +typedef struct _xsltStyleItemElement xsltStyleItemElement; +typedef xsltStyleItemElement *xsltStyleItemElementPtr; + +struct _xsltStyleItemElement { + XSLT_ITEM_COMMON_FIELDS + + const xmlChar *use; + int has_use; + const xmlChar *name; + int has_name; + const xmlChar *ns; + const xmlChar *nsPrefix; + int has_ns; +}; + +/** + * xsltStyleItemAttribute: + * + * + * + * + * + */ +typedef struct _xsltStyleItemAttribute xsltStyleItemAttribute; +typedef xsltStyleItemAttribute *xsltStyleItemAttributePtr; + +struct _xsltStyleItemAttribute { + XSLT_ITEM_COMMON_FIELDS + const xmlChar *name; + int has_name; + const xmlChar *ns; + const xmlChar *nsPrefix; + int has_ns; +}; + +/** + * xsltStyleItemText: + * + * + * + * + * + */ +typedef struct _xsltStyleItemText xsltStyleItemText; +typedef xsltStyleItemText *xsltStyleItemTextPtr; + +struct _xsltStyleItemText { + XSLT_ITEM_COMMON_FIELDS + int noescape; /* text */ +}; + +/** + * xsltStyleItemComment: + * + * + * + * + * + */ +typedef xsltStyleBasicEmptyItem xsltStyleItemComment; +typedef xsltStyleItemComment *xsltStyleItemCommentPtr; + +/** + * xsltStyleItemPI: + * + * + * + * + * + */ +typedef struct _xsltStyleItemPI xsltStyleItemPI; +typedef xsltStyleItemPI *xsltStyleItemPIPtr; + +struct _xsltStyleItemPI { + XSLT_ITEM_COMMON_FIELDS + const xmlChar *name; + int has_name; +}; + +/** + * xsltStyleItemApplyImports: + * + * + * + */ +typedef xsltStyleBasicEmptyItem xsltStyleItemApplyImports; +typedef xsltStyleItemApplyImports *xsltStyleItemApplyImportsPtr; + +/** + * xsltStyleItemApplyTemplates: + * + * + * + * + * + */ +typedef struct _xsltStyleItemApplyTemplates xsltStyleItemApplyTemplates; +typedef xsltStyleItemApplyTemplates *xsltStyleItemApplyTemplatesPtr; + +struct _xsltStyleItemApplyTemplates { + XSLT_ITEM_COMMON_FIELDS + + const xmlChar *mode; /* apply-templates */ + const xmlChar *modeURI; /* apply-templates */ + const xmlChar *select; /* sort, copy-of, value-of, apply-templates */ + xmlXPathCompExprPtr comp; /* a precompiled XPath expression */ + /* TODO: with-params */ +}; + +/** + * xsltStyleItemCallTemplate: + * + * + * + * + * + */ +typedef struct _xsltStyleItemCallTemplate xsltStyleItemCallTemplate; +typedef xsltStyleItemCallTemplate *xsltStyleItemCallTemplatePtr; + +struct _xsltStyleItemCallTemplate { + XSLT_ITEM_COMMON_FIELDS + + xsltTemplatePtr templ; /* call-template */ + const xmlChar *name; /* element, attribute, pi */ + int has_name; /* element, attribute, pi */ + const xmlChar *ns; /* element */ + int has_ns; /* element */ + /* TODO: with-params */ +}; + +/** + * xsltStyleItemCopy: + * + * + * + * + * + */ +typedef struct _xsltStyleItemCopy xsltStyleItemCopy; +typedef xsltStyleItemCopy *xsltStyleItemCopyPtr; + +struct _xsltStyleItemCopy { + XSLT_ITEM_COMMON_FIELDS + const xmlChar *use; /* copy, element */ + int has_use; /* copy, element */ +}; + +/** + * xsltStyleItemIf: + * + * + * + * + * + */ +typedef struct _xsltStyleItemIf xsltStyleItemIf; +typedef xsltStyleItemIf *xsltStyleItemIfPtr; + +struct _xsltStyleItemIf { + XSLT_ITEM_COMMON_FIELDS + + const xmlChar *test; /* if */ + xmlXPathCompExprPtr comp; /* a precompiled XPath expression */ +}; + + +/** + * xsltStyleItemCopyOf: + * + * + * + */ +typedef xsltStyleBasicExpressionItem xsltStyleItemCopyOf; +typedef xsltStyleItemCopyOf *xsltStyleItemCopyOfPtr; + +/** + * xsltStyleItemValueOf: + * + * + * + */ +typedef struct _xsltStyleItemValueOf xsltStyleItemValueOf; +typedef xsltStyleItemValueOf *xsltStyleItemValueOfPtr; + +struct _xsltStyleItemValueOf { + XSLT_ITEM_COMMON_FIELDS + + const xmlChar *select; + xmlXPathCompExprPtr comp; /* a precompiled XPath expression */ + int noescape; +}; + +/** + * xsltStyleItemNumber: + * + * + * + */ +typedef struct _xsltStyleItemNumber xsltStyleItemNumber; +typedef xsltStyleItemNumber *xsltStyleItemNumberPtr; + +struct _xsltStyleItemNumber { + XSLT_ITEM_COMMON_FIELDS + xsltNumberData numdata; /* number */ +}; + +/** + * xsltStyleItemChoose: + * + * + * + * + * + */ +typedef xsltStyleBasicEmptyItem xsltStyleItemChoose; +typedef xsltStyleItemChoose *xsltStyleItemChoosePtr; + +/** + * xsltStyleItemFallback: + * + * + * + * + * + */ +typedef xsltStyleBasicEmptyItem xsltStyleItemFallback; +typedef xsltStyleItemFallback *xsltStyleItemFallbackPtr; + +/** + * xsltStyleItemForEach: + * + * + * + * + * + */ +typedef xsltStyleBasicExpressionItem xsltStyleItemForEach; +typedef xsltStyleItemForEach *xsltStyleItemForEachPtr; + +/** + * xsltStyleItemMessage: + * + * + * + * + * + */ +typedef struct _xsltStyleItemMessage xsltStyleItemMessage; +typedef xsltStyleItemMessage *xsltStyleItemMessagePtr; + +struct _xsltStyleItemMessage { + XSLT_ITEM_COMMON_FIELDS + int terminate; +}; + +/** + * xsltStyleItemDocument: + * + * NOTE: This is not an instruction of XSLT 1.0. + */ +typedef struct _xsltStyleItemDocument xsltStyleItemDocument; +typedef xsltStyleItemDocument *xsltStyleItemDocumentPtr; + +struct _xsltStyleItemDocument { + XSLT_ITEM_COMMON_FIELDS + int ver11; /* assigned: in xsltDocumentComp; + read: nowhere; + TODO: Check if we need. */ + const xmlChar *filename; /* document URL */ + int has_filename; +}; + +/************************************************************************ + * * + * Non-instructions (actually properties of instructions/declarations) * + * * + ************************************************************************/ + +/** + * xsltStyleBasicItemVariable: + * + * Basic struct for xsl:variable, xsl:param and xsl:with-param. + * It's currently important to have equal fields, since + * xsltParseStylesheetCallerParam() is used with xsl:with-param from + * the xslt side and with xsl:param from the exslt side (in + * exsltFuncFunctionFunction()). + * + * FUTURE NOTE: In XSLT 2.0 xsl:param, xsl:variable and xsl:with-param + * have additional different fields. + */ +typedef struct _xsltStyleBasicItemVariable xsltStyleBasicItemVariable; +typedef xsltStyleBasicItemVariable *xsltStyleBasicItemVariablePtr; + +struct _xsltStyleBasicItemVariable { + XSLT_ITEM_COMMON_FIELDS + + const xmlChar *select; + xmlXPathCompExprPtr comp; + + const xmlChar *name; + int has_name; + const xmlChar *ns; + int has_ns; +}; + +/** + * xsltStyleItemVariable: + * + * + * + * + * + */ +typedef xsltStyleBasicItemVariable xsltStyleItemVariable; +typedef xsltStyleItemVariable *xsltStyleItemVariablePtr; + +/** + * xsltStyleItemParam: + * + * + * + * + * + */ +typedef struct _xsltStyleItemParam xsltStyleItemParam; +typedef xsltStyleItemParam *xsltStyleItemParamPtr; + +struct _xsltStyleItemParam { + XSLT_ITEM_COMMON_FIELDS + + const xmlChar *select; + xmlXPathCompExprPtr comp; + + const xmlChar *name; + int has_name; + const xmlChar *ns; + int has_ns; +}; + +/** + * xsltStyleItemWithParam: + * + * + * + * + */ +typedef xsltStyleBasicItemVariable xsltStyleItemWithParam; +typedef xsltStyleItemWithParam *xsltStyleItemWithParamPtr; + +/** + * xsltStyleItemSort: + * + * Reflects the XSLT xsl:sort item. + * Allowed parents: xsl:apply-templates, xsl:for-each + * + */ +typedef struct _xsltStyleItemSort xsltStyleItemSort; +typedef xsltStyleItemSort *xsltStyleItemSortPtr; + +struct _xsltStyleItemSort { + XSLT_ITEM_COMMON_FIELDS + + const xmlChar *stype; /* sort */ + int has_stype; /* sort */ + int number; /* sort */ + const xmlChar *order; /* sort */ + int has_order; /* sort */ + int descending; /* sort */ + const xmlChar *lang; /* sort */ + int has_lang; /* sort */ + const xmlChar *case_order; /* sort */ + int lower_first; /* sort */ + + const xmlChar *use; + int has_use; + + const xmlChar *select; /* sort, copy-of, value-of, apply-templates */ + + xmlXPathCompExprPtr comp; /* a precompiled XPath expression */ +}; + + +/** + * xsltStyleItemWhen: + * + * + * + * + * Allowed parent: xsl:choose + */ +typedef struct _xsltStyleItemWhen xsltStyleItemWhen; +typedef xsltStyleItemWhen *xsltStyleItemWhenPtr; + +struct _xsltStyleItemWhen { + XSLT_ITEM_COMMON_FIELDS + + const xmlChar *test; + xmlXPathCompExprPtr comp; +}; + +/** + * xsltStyleItemOtherwise: + * + * Allowed parent: xsl:choose + * + * + * + */ +typedef struct _xsltStyleItemOtherwise xsltStyleItemOtherwise; +typedef xsltStyleItemOtherwise *xsltStyleItemOtherwisePtr; + +struct _xsltStyleItemOtherwise { + XSLT_ITEM_COMMON_FIELDS +}; + +typedef struct _xsltStyleItemInclude xsltStyleItemInclude; +typedef xsltStyleItemInclude *xsltStyleItemIncludePtr; + +struct _xsltStyleItemInclude { + XSLT_ITEM_COMMON_FIELDS + xsltDocumentPtr include; +}; + +/************************************************************************ + * * + * XSLT elements in forwards-compatible mode * + * * + ************************************************************************/ + +typedef struct _xsltStyleItemUknown xsltStyleItemUknown; +typedef xsltStyleItemUknown *xsltStyleItemUknownPtr; +struct _xsltStyleItemUknown { + XSLT_ITEM_COMMON_FIELDS +}; + + +/************************************************************************ + * * + * Extension elements * + * * + ************************************************************************/ + +/* + * xsltStyleItemExtElement: + * + * Reflects extension elements. + * + * NOTE: Due to the fact that the structure xsltElemPreComp is most + * probably already heavily in use out there by users, so we cannot + * easily change it, we'll create an intermediate structure which will + * hold an xsltElemPreCompPtr. + * BIG NOTE: The only problem I see here is that the user processes the + * content of the stylesheet tree, possibly he'll lookup the node->psvi + * fields in order to find subsequent extension functions. + * In this case, the user's code will break, since the node->psvi + * field will hold now the xsltStyleItemExtElementPtr and not + * the xsltElemPreCompPtr. + * However the place where the structure is anchored in the node-tree, + * namely node->psvi, has beed already once been moved from node->_private + * to node->psvi, so we have a precedent here, which, I think, should allow + * us to change such semantics without headaches. + */ +typedef struct _xsltStyleItemExtElement xsltStyleItemExtElement; +typedef xsltStyleItemExtElement *xsltStyleItemExtElementPtr; +struct _xsltStyleItemExtElement { + XSLT_ITEM_COMMON_FIELDS + xsltElemPreCompPtr item; +}; + +/************************************************************************ + * * + * Literal result elements * + * * + ************************************************************************/ + +typedef struct _xsltEffectiveNs xsltEffectiveNs; +typedef xsltEffectiveNs *xsltEffectiveNsPtr; +struct _xsltEffectiveNs { + xsltEffectiveNsPtr nextInStore; /* storage next */ + xsltEffectiveNsPtr next; /* next item in the list */ + const xmlChar *prefix; + const xmlChar *nsName; + /* + * Indicates if eclared on the literal result element; dunno if really + * needed. + */ + int holdByElem; +}; + +/* + * Info for literal result elements. + * This will be set on the elem->psvi field and will be + * shared by literal result elements, which have the same + * excluded result namespaces; i.e., this *won't* be created uniquely + * for every literal result element. + */ +typedef struct _xsltStyleItemLRElementInfo xsltStyleItemLRElementInfo; +typedef xsltStyleItemLRElementInfo *xsltStyleItemLRElementInfoPtr; +struct _xsltStyleItemLRElementInfo { + XSLT_ITEM_COMMON_FIELDS + /* + * @effectiveNs is the set of effective ns-nodes + * on the literal result element, which will be added to the result + * element if not already existing in the result tree. + * This means that excluded namespaces (via exclude-result-prefixes, + * extension-element-prefixes and the XSLT namespace) not added + * to the set. + * Namespace-aliasing was applied on the @effectiveNs. + */ + xsltEffectiveNsPtr effectiveNs; + +}; + +#ifdef XSLT_REFACTORED + +typedef struct _xsltNsAlias xsltNsAlias; +typedef xsltNsAlias *xsltNsAliasPtr; +struct _xsltNsAlias { + xsltNsAliasPtr next; /* next in the list */ + xmlNsPtr literalNs; + xmlNsPtr targetNs; + xmlDocPtr docOfTargetNs; +}; +#endif + +#ifdef XSLT_REFACTORED_XSLT_NSCOMP + +typedef struct _xsltNsMap xsltNsMap; +typedef xsltNsMap *xsltNsMapPtr; +struct _xsltNsMap { + xsltNsMapPtr next; /* next in the list */ + xmlDocPtr doc; + xmlNodePtr elem; /* the element holding the ns-decl */ + xmlNsPtr ns; /* the xmlNs structure holding the XML namespace name */ + const xmlChar *origNsName; /* the original XML namespace name */ + const xmlChar *newNsName; /* the mapped XML namespace name */ +}; +#endif + +/************************************************************************ + * * + * Compile-time structures for *internal* use only * + * * + ************************************************************************/ + +typedef struct _xsltPrincipalStylesheetData xsltPrincipalStylesheetData; +typedef xsltPrincipalStylesheetData *xsltPrincipalStylesheetDataPtr; + +typedef struct _xsltNsList xsltNsList; +typedef xsltNsList *xsltNsListPtr; +struct _xsltNsList { + xsltNsListPtr next; /* next in the list */ + xmlNsPtr ns; +}; + +/* +* xsltVarInfo: +* +* Used at compilation time for parameters and variables. +*/ +typedef struct _xsltVarInfo xsltVarInfo; +typedef xsltVarInfo *xsltVarInfoPtr; +struct _xsltVarInfo { + xsltVarInfoPtr next; /* next in the list */ + xsltVarInfoPtr prev; + int depth; /* the depth in the tree */ + const xmlChar *name; + const xmlChar *nsName; +}; + +/** + * xsltCompilerNodeInfo: + * + * Per-node information during compile-time. + */ +typedef struct _xsltCompilerNodeInfo xsltCompilerNodeInfo; +typedef xsltCompilerNodeInfo *xsltCompilerNodeInfoPtr; +struct _xsltCompilerNodeInfo { + xsltCompilerNodeInfoPtr next; + xsltCompilerNodeInfoPtr prev; + xmlNodePtr node; + int depth; + xsltTemplatePtr templ; /* The owning template */ + int category; /* XSLT element, LR-element or + extension element */ + xsltStyleType type; + xsltElemPreCompPtr item; /* The compiled information */ + /* The current in-scope namespaces */ + xsltNsListContainerPtr inScopeNs; + /* The current excluded result namespaces */ + xsltPointerListPtr exclResultNs; + /* The current extension instruction namespaces */ + xsltPointerListPtr extElemNs; + + /* The current info for literal result elements. */ + xsltStyleItemLRElementInfoPtr litResElemInfo; + /* + * Set to 1 if in-scope namespaces changed, + * or excluded result namespaces changed, + * or extension element namespaces changed. + * This will trigger creation of new infos + * for literal result elements. + */ + int nsChanged; + int preserveWhitespace; + int stripWhitespace; + int isRoot; /* whether this is the stylesheet's root node */ + int forwardsCompat; /* whether forwards-compatible mode is enabled */ + /* whether the content of an extension element was processed */ + int extContentHandled; + /* the type of the current child */ + xsltStyleType curChildType; +}; + +/** + * XSLT_CCTXT: + * + * get pointer to compiler context + */ +#define XSLT_CCTXT(style) ((xsltCompilerCtxtPtr) style->compCtxt) + +typedef enum { + XSLT_ERROR_SEVERITY_ERROR = 0, + XSLT_ERROR_SEVERITY_WARNING +} xsltErrorSeverityType; + +typedef struct _xsltCompilerCtxt xsltCompilerCtxt; +typedef xsltCompilerCtxt *xsltCompilerCtxtPtr; +struct _xsltCompilerCtxt { + void *errorCtxt; /* user specific error context */ + /* + * used for error/warning reports; e.g. XSLT_ERROR_SEVERITY_WARNING */ + xsltErrorSeverityType errSeverity; + int warnings; /* TODO: number of warnings found at + compilation */ + int errors; /* TODO: number of errors found at + compilation */ + xmlDictPtr dict; + xsltStylesheetPtr style; + int simplified; /* whether this is a simplified stylesheet */ + /* TODO: structured/unstructured error contexts. */ + int depth; /* Current depth of processing */ + + xsltCompilerNodeInfoPtr inode; + xsltCompilerNodeInfoPtr inodeList; + xsltCompilerNodeInfoPtr inodeLast; + xsltPointerListPtr tmpList; /* Used for various purposes */ + /* + * The XSLT version as specified by the stylesheet's root element. + */ + int isInclude; + int hasForwardsCompat; /* whether forwards-compatible mode was used + in a parsing episode */ + int maxNodeInfos; /* TEMP TODO: just for the interest */ + int maxLREs; /* TEMP TODO: just for the interest */ + /* + * In order to keep the old behaviour, applying strict rules of + * the spec can be turned off. This has effect only on special + * mechanisms like whitespace-stripping in the stylesheet. + */ + int strict; + xsltPrincipalStylesheetDataPtr psData; + xsltStyleItemUknownPtr unknownItem; + int hasNsAliases; /* Indicator if there was an xsl:namespace-alias. */ + xsltNsAliasPtr nsAliases; + xsltVarInfoPtr ivars; /* Storage of local in-scope variables/params. */ + xsltVarInfoPtr ivar; /* topmost local variable/param. */ +}; + +#else /* XSLT_REFACTORED */ +/* +* The old structures before refactoring. +*/ + +/** + * _xsltStylePreComp: + * + * The in-memory structure corresponding to XSLT stylesheet constructs + * precomputed data. + */ +struct _xsltStylePreComp { + xsltElemPreCompPtr next; /* chained list */ + xsltStyleType type; /* type of the element */ + xsltTransformFunction func; /* handling function */ + xmlNodePtr inst; /* the instruction */ + + /* + * Pre computed values. + */ + + const xmlChar *stype; /* sort */ + int has_stype; /* sort */ + int number; /* sort */ + const xmlChar *order; /* sort */ + int has_order; /* sort */ + int descending; /* sort */ + const xmlChar *lang; /* sort */ + int has_lang; /* sort */ + const xmlChar *case_order; /* sort */ + int lower_first; /* sort */ + + const xmlChar *use; /* copy, element */ + int has_use; /* copy, element */ + + int noescape; /* text */ + + const xmlChar *name; /* element, attribute, pi */ + int has_name; /* element, attribute, pi */ + const xmlChar *ns; /* element */ + int has_ns; /* element */ + + const xmlChar *mode; /* apply-templates */ + const xmlChar *modeURI; /* apply-templates */ + + const xmlChar *test; /* if */ + + xsltTemplatePtr templ; /* call-template */ + + const xmlChar *select; /* sort, copy-of, value-of, apply-templates */ + + int ver11; /* document */ + const xmlChar *filename; /* document URL */ + int has_filename; /* document */ + + xsltNumberData numdata; /* number */ + + xmlXPathCompExprPtr comp; /* a precompiled XPath expression */ + xmlNsPtr *nsList; /* the namespaces in scope */ + int nsNr; /* the number of namespaces in scope */ +}; + +#endif /* XSLT_REFACTORED */ + +typedef struct _xsltRVTList xsltRVTList; +typedef xsltRVTList *xsltRVTListPtr; + +/* + * The in-memory structure corresponding to an XSLT Variable + * or Param. + */ +typedef struct _xsltStackElem xsltStackElem; +typedef xsltStackElem *xsltStackElemPtr; +struct _xsltStackElem { + struct _xsltStackElem *next;/* chained list */ + xsltStylePreCompPtr comp; /* the compiled form */ + int computed; /* was the evaluation done */ + const xmlChar *name; /* the local part of the name QName */ + const xmlChar *nameURI; /* the URI part of the name QName */ + const xmlChar *select; /* the eval string */ + xmlNodePtr tree; /* the sequence constructor if no eval + string or the location */ + xmlXPathObjectPtr value; /* The value if computed */ + xsltRVTListPtr fragment; /* The Result Tree Fragments (needed for XSLT 1.0) + which are bound to the variable's lifetime. */ + int level; /* the depth in the tree; + -1 if persistent (e.g. a given xsl:with-param) */ + xsltTransformContextPtr context; /* The transformation context; needed to cache + the variables */ + int flags; +}; + +#ifdef XSLT_REFACTORED + +struct _xsltPrincipalStylesheetData { + /* + * Namespace dictionary for ns-prefixes and ns-names: + * TODO: Shared between stylesheets, and XPath mechanisms. + * Not used yet. + */ + xmlDictPtr namespaceDict; + /* + * Global list of in-scope namespaces. + */ + xsltPointerListPtr inScopeNamespaces; + /* + * Global list of information for [xsl:]excluded-result-prefixes. + */ + xsltPointerListPtr exclResultNamespaces; + /* + * Global list of information for [xsl:]extension-element-prefixes. + */ + xsltPointerListPtr extElemNamespaces; + xsltEffectiveNsPtr effectiveNs; +#ifdef XSLT_REFACTORED_XSLT_NSCOMP + /* + * Namespace name map to get rid of string comparison of namespace names. + */ + xsltNsMapPtr nsMap; +#endif +}; + + +#endif +/* + * Note that we added a @compCtxt field to anchor an stylesheet compilation + * context, since, due to historical reasons, various compile-time function + * take only the stylesheet as argument and not a compilation context. + */ +struct _xsltStylesheet { + /* + * The stylesheet import relation is kept as a tree. + */ + struct _xsltStylesheet *parent; + struct _xsltStylesheet *next; + struct _xsltStylesheet *imports; + + xsltDocumentPtr docList; /* the include document list */ + + /* + * General data on the style sheet document. + */ + xmlDocPtr doc; /* the parsed XML stylesheet */ + xmlHashTablePtr stripSpaces;/* the hash table of the strip-space and + preserve space elements */ + int stripAll; /* strip-space * (1) preserve-space * (-1) */ + xmlHashTablePtr cdataSection;/* the hash table of the cdata-section */ + + /* + * Global variable or parameters. + */ + xsltStackElemPtr variables; /* linked list of param and variables */ + + /* + * Template descriptions. + */ + xsltTemplatePtr templates; /* the ordered list of templates */ + xmlHashTablePtr templatesHash; /* hash table or wherever compiled + templates information is stored */ + struct _xsltCompMatch *rootMatch; /* template based on / */ + struct _xsltCompMatch *keyMatch; /* template based on key() */ + struct _xsltCompMatch *elemMatch; /* template based on * */ + struct _xsltCompMatch *attrMatch; /* template based on @* */ + struct _xsltCompMatch *parentMatch; /* template based on .. */ + struct _xsltCompMatch *textMatch; /* template based on text() */ + struct _xsltCompMatch *piMatch; /* template based on + processing-instruction() */ + struct _xsltCompMatch *commentMatch; /* template based on comment() */ + + /* + * Namespace aliases. + * NOTE: Not used in the refactored code. + */ + xmlHashTablePtr nsAliases; /* the namespace alias hash tables */ + + /* + * Attribute sets. + */ + xmlHashTablePtr attributeSets;/* the attribute sets hash tables */ + + /* + * Namespaces. + * TODO: Eliminate this. + */ + xmlHashTablePtr nsHash; /* the set of namespaces in use: + ATTENTION: This is used for + execution of XPath expressions; unfortunately + it restricts the stylesheet to have distinct + prefixes. + TODO: We need to get rid of this. + */ + void *nsDefs; /* ATTENTION TODO: This is currently used to store + xsltExtDefPtr (in extensions.c) and + *not* xmlNsPtr. + */ + + /* + * Key definitions. + */ + void *keys; /* key definitions */ + + /* + * Output related stuff. + */ + xmlChar *method; /* the output method */ + xmlChar *methodURI; /* associated namespace if any */ + xmlChar *version; /* version string */ + xmlChar *encoding; /* encoding string */ + int omitXmlDeclaration; /* omit-xml-declaration = "yes" | "no" */ + + /* + * Number formatting. + */ + xsltDecimalFormatPtr decimalFormat; + int standalone; /* standalone = "yes" | "no" */ + xmlChar *doctypePublic; /* doctype-public string */ + xmlChar *doctypeSystem; /* doctype-system string */ + int indent; /* should output being indented */ + xmlChar *mediaType; /* media-type string */ + + /* + * Precomputed blocks. + */ + xsltElemPreCompPtr preComps;/* list of precomputed blocks */ + int warnings; /* number of warnings found at compilation */ + int errors; /* number of errors found at compilation */ + + xmlChar *exclPrefix; /* last excluded prefixes */ + xmlChar **exclPrefixTab; /* array of excluded prefixes */ + int exclPrefixNr; /* number of excluded prefixes in scope */ + int exclPrefixMax; /* size of the array */ + + void *_private; /* user defined data */ + + /* + * Extensions. + */ + xmlHashTablePtr extInfos; /* the extension data */ + int extrasNr; /* the number of extras required */ + + /* + * For keeping track of nested includes + */ + xsltDocumentPtr includes; /* points to last nested include */ + + /* + * dictionary: shared between stylesheet, context and documents. + */ + xmlDictPtr dict; + /* + * precompiled attribute value templates. + */ + void *attVTs; + /* + * if namespace-alias has an alias for the default stylesheet prefix + * NOTE: Not used in the refactored code. + */ + const xmlChar *defaultAlias; + /* + * bypass pre-processing (already done) (used in imports) + */ + int nopreproc; + /* + * all document text strings were internalized + */ + int internalized; + /* + * Literal Result Element as Stylesheet c.f. section 2.3 + */ + int literal_result; + /* + * The principal stylesheet + */ + xsltStylesheetPtr principal; +#ifdef XSLT_REFACTORED + /* + * Compilation context used during compile-time. + */ + xsltCompilerCtxtPtr compCtxt; /* TODO: Change this to (void *). */ + + xsltPrincipalStylesheetDataPtr principalData; +#endif + /* + * Forwards-compatible processing + */ + int forwards_compatible; + + xmlHashTablePtr namedTemplates; /* hash table of named templates */ + + xmlXPathContextPtr xpathCtxt; + + unsigned long opLimit; + unsigned long opCount; +}; + +struct _xsltRVTList { + xmlDocPtr RVT; + xsltRVTListPtr next; +}; + +typedef struct _xsltTransformCache xsltTransformCache; +typedef xsltTransformCache *xsltTransformCachePtr; +struct _xsltTransformCache { + xsltRVTListPtr rvtList; + int nbRVT; + xsltStackElemPtr stackItems; + int nbStackItems; +#ifdef XSLT_DEBUG_PROFILE_CACHE + int dbgCachedRVTs; + int dbgReusedRVTs; + int dbgCachedVars; + int dbgReusedVars; +#endif +}; + +/* + * The in-memory structure corresponding to an XSLT Transformation. + */ +typedef enum { + XSLT_OUTPUT_XML = 0, + XSLT_OUTPUT_HTML, + XSLT_OUTPUT_TEXT +} xsltOutputType; + +typedef void * +(*xsltNewLocaleFunc)(const xmlChar *lang, int lowerFirst); +typedef void +(*xsltFreeLocaleFunc)(void *locale); +typedef xmlChar * +(*xsltGenSortKeyFunc)(void *locale, const xmlChar *lang); + +typedef enum { + XSLT_STATE_OK = 0, + XSLT_STATE_ERROR, + XSLT_STATE_STOPPED +} xsltTransformState; + +struct _xsltTransformContext { + xsltStylesheetPtr style; /* the stylesheet used */ + xsltOutputType type; /* the type of output */ + + xsltTemplatePtr templ; /* the current template */ + int templNr; /* Nb of templates in the stack */ + int templMax; /* Size of the templtes stack */ + xsltTemplatePtr *templTab; /* the template stack */ + + xsltStackElemPtr vars; /* the current variable list */ + int varsNr; /* Nb of variable list in the stack */ + int varsMax; /* Size of the variable list stack */ + xsltStackElemPtr *varsTab; /* the variable list stack */ + int varsBase; /* the var base for current templ */ + + /* + * Extensions + */ + xmlHashTablePtr extFunctions; /* the extension functions */ + xmlHashTablePtr extElements; /* the extension elements */ + xmlHashTablePtr extInfos; /* the extension data */ + + const xmlChar *mode; /* the current mode */ + const xmlChar *modeURI; /* the current mode URI */ + + xsltDocumentPtr docList; /* the document list */ + + xsltDocumentPtr document; /* the current source document; can be NULL if an RTF */ + xmlNodePtr node; /* the current node being processed */ + xmlNodeSetPtr nodeList; /* the current node list */ + /* xmlNodePtr current; the node */ + + xmlDocPtr output; /* the resulting document */ + xmlNodePtr insert; /* the insertion node */ + + xmlXPathContextPtr xpathCtxt; /* the XPath context */ + xsltTransformState state; /* the current state */ + + /* + * Global variables + */ + xmlHashTablePtr globalVars; /* the global variables and params */ + + xmlNodePtr inst; /* the instruction in the stylesheet */ + + int xinclude; /* should XInclude be processed */ + + const char * outputFile; /* the output URI if known */ + + int profile; /* is this run profiled */ + long prof; /* the current profiled value */ + int profNr; /* Nb of templates in the stack */ + int profMax; /* Size of the templtaes stack */ + long *profTab; /* the profile template stack */ + + void *_private; /* user defined data */ + + int extrasNr; /* the number of extras used */ + int extrasMax; /* the number of extras allocated */ + xsltRuntimeExtraPtr extras; /* extra per runtime information */ + + xsltDocumentPtr styleList; /* the stylesheet docs list */ + void * sec; /* the security preferences if any */ + + xmlGenericErrorFunc error; /* a specific error handler */ + void * errctx; /* context for the error handler */ + + xsltSortFunc sortfunc; /* a ctxt specific sort routine */ + + /* + * handling of temporary Result Value Tree + * (XSLT 1.0 term: "Result Tree Fragment") + */ + xsltRVTListPtr tmpRVTList; /* list of RVT without persistance */ + xsltRVTListPtr persistRVTList; /* list of persistant RVTs */ + int ctxtflags; /* context processing flags */ + + /* + * Speed optimization when coalescing text nodes + */ + const xmlChar *lasttext; /* last text node content */ + int lasttsize; /* last text node size */ + int lasttuse; /* last text node use */ + /* + * Per Context Debugging + */ + int debugStatus; /* the context level debug status */ + unsigned long* traceCode; /* pointer to the variable holding the mask */ + + int parserOptions; /* parser options xmlParserOption */ + + /* + * dictionary: shared between stylesheet, context and documents. + */ + xmlDictPtr dict; + xmlDocPtr tmpDoc; /* Obsolete; not used in the library. */ + /* + * all document text strings are internalized + */ + int internalized; + int nbKeys; + int hasTemplKeyPatterns; + xsltTemplatePtr currentTemplateRule; /* the Current Template Rule */ + xmlNodePtr initialContextNode; + xmlDocPtr initialContextDoc; + xsltTransformCachePtr cache; + void *contextVariable; /* the current variable item */ + xsltRVTListPtr localRVTList; /* list of local tree fragments; will be freed when + the instruction which created the fragment + exits */ + xmlDocPtr localRVTBase; /* Obsolete */ + int keyInitLevel; /* Needed to catch recursive keys issues */ + int depth; /* Needed to catch recursions */ + int maxTemplateDepth; + int maxTemplateVars; + unsigned long opLimit; + unsigned long opCount; + int sourceDocDirty; + unsigned long currentId; /* For generate-id() */ + + xsltNewLocaleFunc newLocale; + xsltFreeLocaleFunc freeLocale; + xsltGenSortKeyFunc genSortKey; +}; + +/** + * CHECK_STOPPED: + * + * Macro to check if the XSLT processing should be stopped. + * Will return from the function. + */ +#define CHECK_STOPPED if (ctxt->state == XSLT_STATE_STOPPED) return; + +/** + * CHECK_STOPPEDE: + * + * Macro to check if the XSLT processing should be stopped. + * Will goto the error: label. + */ +#define CHECK_STOPPEDE if (ctxt->state == XSLT_STATE_STOPPED) goto error; + +/** + * CHECK_STOPPED0: + * + * Macro to check if the XSLT processing should be stopped. + * Will return from the function with a 0 value. + */ +#define CHECK_STOPPED0 if (ctxt->state == XSLT_STATE_STOPPED) return(0); + +/* + * The macro XML_CAST_FPTR is a hack to avoid a gcc warning about + * possible incompatibilities between function pointers and object + * pointers. It is defined in libxml/hash.h within recent versions + * of libxml2, but is put here for compatibility. + */ +#ifndef XML_CAST_FPTR +/** + * XML_CAST_FPTR: + * @fptr: pointer to a function + * + * Macro to do a casting from an object pointer to a + * function pointer without encountering a warning from + * gcc + * + * #define XML_CAST_FPTR(fptr) (*(void **)(&fptr)) + * This macro violated ISO C aliasing rules (gcc4 on s390 broke) + * so it is disabled now + */ + +#define XML_CAST_FPTR(fptr) fptr +#endif +/* + * Functions associated to the internal types +xsltDecimalFormatPtr xsltDecimalFormatGetByName(xsltStylesheetPtr sheet, + xmlChar *name); + */ +XSLTPUBFUN xsltStylesheetPtr XSLTCALL + xsltNewStylesheet (void); +XSLTPUBFUN xsltStylesheetPtr XSLTCALL + xsltParseStylesheetFile (const xmlChar* filename); +XSLTPUBFUN void XSLTCALL + xsltFreeStylesheet (xsltStylesheetPtr style); +XSLTPUBFUN int XSLTCALL + xsltIsBlank (xmlChar *str); +XSLTPUBFUN void XSLTCALL + xsltFreeStackElemList (xsltStackElemPtr elem); +XSLTPUBFUN xsltDecimalFormatPtr XSLTCALL + xsltDecimalFormatGetByName(xsltStylesheetPtr style, + xmlChar *name); +XSLTPUBFUN xsltDecimalFormatPtr XSLTCALL + xsltDecimalFormatGetByQName(xsltStylesheetPtr style, + const xmlChar *nsUri, + const xmlChar *name); + +XSLTPUBFUN xsltStylesheetPtr XSLTCALL + xsltParseStylesheetProcess(xsltStylesheetPtr ret, + xmlDocPtr doc); +XSLTPUBFUN void XSLTCALL + xsltParseStylesheetOutput(xsltStylesheetPtr style, + xmlNodePtr cur); +XSLTPUBFUN xsltStylesheetPtr XSLTCALL + xsltParseStylesheetDoc (xmlDocPtr doc); +XSLTPUBFUN xsltStylesheetPtr XSLTCALL + xsltParseStylesheetImportedDoc(xmlDocPtr doc, + xsltStylesheetPtr style); +XSLTPUBFUN int XSLTCALL + xsltParseStylesheetUser(xsltStylesheetPtr style, + xmlDocPtr doc); +XSLTPUBFUN xsltStylesheetPtr XSLTCALL + xsltLoadStylesheetPI (xmlDocPtr doc); +XSLTPUBFUN void XSLTCALL + xsltNumberFormat (xsltTransformContextPtr ctxt, + xsltNumberDataPtr data, + xmlNodePtr node); +XSLTPUBFUN xmlXPathError XSLTCALL + xsltFormatNumberConversion(xsltDecimalFormatPtr self, + xmlChar *format, + double number, + xmlChar **result); + +XSLTPUBFUN void XSLTCALL + xsltParseTemplateContent(xsltStylesheetPtr style, + xmlNodePtr templ); +XSLTPUBFUN int XSLTCALL + xsltAllocateExtra (xsltStylesheetPtr style); +XSLTPUBFUN int XSLTCALL + xsltAllocateExtraCtxt (xsltTransformContextPtr ctxt); +/* + * Extra functions for Result Value Trees + */ +XSLTPUBFUN xmlDocPtr XSLTCALL + xsltCreateRVT (xsltTransformContextPtr ctxt); +XSLTPUBFUN int XSLTCALL + xsltRegisterTmpRVT (xsltTransformContextPtr ctxt, + xmlDocPtr RVT); +XSLTPUBFUN int XSLTCALL + xsltRegisterLocalRVT (xsltTransformContextPtr ctxt, + xmlDocPtr RVT); +XSLTPUBFUN int XSLTCALL + xsltRegisterPersistRVT (xsltTransformContextPtr ctxt, + xmlDocPtr RVT); +XSLTPUBFUN int XSLTCALL + xsltExtensionInstructionResultRegister( + xsltTransformContextPtr ctxt, + xmlXPathObjectPtr obj); +XSLTPUBFUN int XSLTCALL + xsltExtensionInstructionResultFinalize( + xsltTransformContextPtr ctxt); +XSLTPUBFUN int XSLTCALL + xsltFlagRVTs( + xsltTransformContextPtr ctxt, + xmlXPathObjectPtr obj, + int val); +XSLTPUBFUN void XSLTCALL + xsltFreeRVTs (xsltTransformContextPtr ctxt); +XSLTPUBFUN void XSLTCALL + xsltReleaseRVT (xsltTransformContextPtr ctxt, + xmlDocPtr RVT); +XSLTPUBFUN void XSLTCALL + xsltReleaseRVTList (xsltTransformContextPtr ctxt, + xsltRVTListPtr list); +/* + * Extra functions for Attribute Value Templates + */ +XSLTPUBFUN void XSLTCALL + xsltCompileAttr (xsltStylesheetPtr style, + xmlAttrPtr attr); +XSLTPUBFUN xmlChar * XSLTCALL + xsltEvalAVT (xsltTransformContextPtr ctxt, + void *avt, + xmlNodePtr node); +XSLTPUBFUN void XSLTCALL + xsltFreeAVTList (void *avt); + +/* + * Extra function for successful xsltCleanupGlobals / xsltInit sequence. + */ + +XSLTPUBFUN void XSLTCALL + xsltUninit (void); + +/************************************************************************ + * * + * Compile-time functions for *internal* use only * + * * + ************************************************************************/ + +#ifdef XSLT_REFACTORED +XSLTPUBFUN void XSLTCALL + xsltParseSequenceConstructor( + xsltCompilerCtxtPtr cctxt, + xmlNodePtr start); +XSLTPUBFUN int XSLTCALL + xsltParseAnyXSLTElem (xsltCompilerCtxtPtr cctxt, + xmlNodePtr elem); +#ifdef XSLT_REFACTORED_XSLT_NSCOMP +XSLTPUBFUN int XSLTCALL + xsltRestoreDocumentNamespaces( + xsltNsMapPtr ns, + xmlDocPtr doc); +#endif +#endif /* XSLT_REFACTORED */ + +/************************************************************************ + * * + * Transformation-time functions for *internal* use only * + * * + ************************************************************************/ +XSLTPUBFUN int XSLTCALL + xsltInitCtxtKey (xsltTransformContextPtr ctxt, + xsltDocumentPtr doc, + xsltKeyDefPtr keyd); +XSLTPUBFUN int XSLTCALL + xsltInitAllDocKeys (xsltTransformContextPtr ctxt); +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLT_H__ */ diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/xsltconfig.h chromium-145.0.7632.159/third_party/libxslt/src/libxslt/xsltconfig.h --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/xsltconfig.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/xsltconfig.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,146 @@ +/* + * Summary: compile-time version information for the XSLT engine + * Description: compile-time version information for the XSLT engine + * this module is autogenerated. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLTCONFIG_H__ +#define __XML_XSLTCONFIG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * LIBXSLT_DOTTED_VERSION: + * + * the version string like "1.2.3" + */ +#define LIBXSLT_DOTTED_VERSION "1.1.45" + +/** + * LIBXSLT_VERSION: + * + * the version number: 1.2.3 value is 10203 + */ +#define LIBXSLT_VERSION 10145 + +/** + * LIBXSLT_VERSION_STRING: + * + * the version number string, 1.2.3 value is "10203" + */ +#define LIBXSLT_VERSION_STRING "10145" + +/** + * LIBXSLT_VERSION_EXTRA: + * + * extra version information, used to show a Git commit description + */ +#define LIBXSLT_VERSION_EXTRA "" + +/** + * WITH_XSLT_DEBUG: + * + * Activate the compilation of the debug reporting. Speed penalty + * is insignifiant and being able to run xsltpoc -v is useful. On + * by default unless --without-debug is passed to configure + */ +#if 0 +#define WITH_XSLT_DEBUG +#endif + +/** + * XSLT_NEED_TRIO: + * + * should be activated if the existing libc library lacks some of the + * string formatting function, in that case reuse the Trio ones already + * compiled in the libxml2 library. + */ + +#if 0 +#define XSLT_NEED_TRIO +#endif +#ifdef __VMS +#define HAVE_SYS_STAT_H 1 +#ifndef XSLT_NEED_TRIO +#define XSLT_NEED_TRIO +#endif +#endif + +#ifdef XSLT_NEED_TRIO +#define TRIO_REPLACE_STDIO +#endif + +/** + * WITH_XSLT_DEBUGGER: + * + * Activate the compilation of the debugger support. Speed penalty + * is insignifiant. + * On by default unless --without-debugger is passed to configure + */ +#if 0 +#ifndef WITH_DEBUGGER +#define WITH_DEBUGGER +#endif +#endif + +/** + * WITH_PROFILER: + * + * Activate the compilation of the profiler. Speed penalty + * is insignifiant. + * On by default unless --without-profiler is passed to configure + */ +#if 1 +#ifndef WITH_PROFILER +#define WITH_PROFILER +#endif +#endif + +/** + * WITH_MODULES: + * + * Whether module support is configured into libxslt + * Note: no default module path for win32 platforms + */ +#if 0 +#ifndef WITH_MODULES +#define WITH_MODULES +#endif +#define LIBXSLT_DEFAULT_PLUGINS_PATH() "" +#endif + +/** + * LIBXSLT_ATTR_FORMAT: + * + * This macro is used to indicate to GCC the parameters are printf-like + */ +#ifdef __GNUC__ +#define LIBXSLT_ATTR_FORMAT(fmt,args) __attribute__((__format__(__printf__,fmt,args))) +#else +#define LIBXSLT_ATTR_FORMAT(fmt,args) +#endif + +/** + * LIBXSLT_PUBLIC: + * + * This macro is used to declare PUBLIC variables for Cygwin and for MSC on Windows + */ +#if !defined LIBXSLT_PUBLIC +#if (defined(__CYGWIN__) || defined _MSC_VER) && !defined IN_LIBXSLT && !defined LIBXSLT_STATIC +#define LIBXSLT_PUBLIC __declspec(dllimport) +#else +#define LIBXSLT_PUBLIC +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLTCONFIG_H__ */ diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/xsltconfig.h.in chromium-145.0.7632.159/third_party/libxslt/src/libxslt/xsltconfig.h.in --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/xsltconfig.h.in 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/xsltconfig.h.in 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,146 @@ +/* + * Summary: compile-time version information for the XSLT engine + * Description: compile-time version information for the XSLT engine + * this module is autogenerated. + * + * Copy: See Copyright for the status of this software. + * + * Author: Daniel Veillard + */ + +#ifndef __XML_XSLTCONFIG_H__ +#define __XML_XSLTCONFIG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * LIBXSLT_DOTTED_VERSION: + * + * the version string like "1.2.3" + */ +#define LIBXSLT_DOTTED_VERSION "@VERSION@" + +/** + * LIBXSLT_VERSION: + * + * the version number: 1.2.3 value is 10203 + */ +#define LIBXSLT_VERSION @LIBXSLT_VERSION_NUMBER@ + +/** + * LIBXSLT_VERSION_STRING: + * + * the version number string, 1.2.3 value is "10203" + */ +#define LIBXSLT_VERSION_STRING "@LIBXSLT_VERSION_NUMBER@" + +/** + * LIBXSLT_VERSION_EXTRA: + * + * extra version information, used to show a Git commit description + */ +#define LIBXSLT_VERSION_EXTRA "@LIBXSLT_VERSION_EXTRA@" + +/** + * WITH_XSLT_DEBUG: + * + * Activate the compilation of the debug reporting. Speed penalty + * is insignifiant and being able to run xsltpoc -v is useful. On + * by default unless --without-debug is passed to configure + */ +#if @WITH_XSLT_DEBUG@ +#define WITH_XSLT_DEBUG +#endif + +/** + * XSLT_NEED_TRIO: + * + * should be activated if the existing libc library lacks some of the + * string formatting function, in that case reuse the Trio ones already + * compiled in the libxml2 library. + */ + +#if @WITH_TRIO@ +#define XSLT_NEED_TRIO +#endif +#ifdef __VMS +#define HAVE_SYS_STAT_H 1 +#ifndef XSLT_NEED_TRIO +#define XSLT_NEED_TRIO +#endif +#endif + +#ifdef XSLT_NEED_TRIO +#define TRIO_REPLACE_STDIO +#endif + +/** + * WITH_XSLT_DEBUGGER: + * + * Activate the compilation of the debugger support. Speed penalty + * is insignifiant. + * On by default unless --without-debugger is passed to configure + */ +#if @WITH_DEBUGGER@ +#ifndef WITH_DEBUGGER +#define WITH_DEBUGGER +#endif +#endif + +/** + * WITH_PROFILER: + * + * Activate the compilation of the profiler. Speed penalty + * is insignifiant. + * On by default unless --without-profiler is passed to configure + */ +#if @WITH_PROFILER@ +#ifndef WITH_PROFILER +#define WITH_PROFILER +#endif +#endif + +/** + * WITH_MODULES: + * + * Whether module support is configured into libxslt + * Note: no default module path for win32 platforms + */ +#if @WITH_MODULES@ +#ifndef WITH_MODULES +#define WITH_MODULES +#endif +#define LIBXSLT_DEFAULT_PLUGINS_PATH() "@LIBXSLT_DEFAULT_PLUGINS_PATH@" +#endif + +/** + * LIBXSLT_ATTR_FORMAT: + * + * This macro is used to indicate to GCC the parameters are printf-like + */ +#ifdef __GNUC__ +#define LIBXSLT_ATTR_FORMAT(fmt,args) __attribute__((__format__(__printf__,fmt,args))) +#else +#define LIBXSLT_ATTR_FORMAT(fmt,args) +#endif + +/** + * LIBXSLT_PUBLIC: + * + * This macro is used to declare PUBLIC variables for Cygwin and for MSC on Windows + */ +#if !defined LIBXSLT_PUBLIC +#if (defined(__CYGWIN__) || defined _MSC_VER) && !defined IN_LIBXSLT && !defined LIBXSLT_STATIC +#define LIBXSLT_PUBLIC __declspec(dllimport) +#else +#define LIBXSLT_PUBLIC +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLTCONFIG_H__ */ diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/xsltexports.h chromium-145.0.7632.159/third_party/libxslt/src/libxslt/xsltexports.h --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/xsltexports.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/xsltexports.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,64 @@ +/* + * Summary: macros for marking symbols as exportable/importable. + * Description: macros for marking symbols as exportable/importable. + * + * Copy: See Copyright for the status of this software. + */ + +#ifndef __XSLT_EXPORTS_H__ +#define __XSLT_EXPORTS_H__ + +#if defined(_WIN32) || defined(__CYGWIN__) +/** DOC_DISABLE */ + +#ifdef LIBXSLT_STATIC + #define XSLTPUBLIC +#elif defined(IN_LIBXSLT) + #define XSLTPUBLIC __declspec(dllexport) +#else + #define XSLTPUBLIC __declspec(dllimport) +#endif + +#define XSLTCALL __cdecl + +/** DOC_ENABLE */ +#else /* not Windows */ + +/** + * XSLTPUBLIC: + * + * Macro which declares a public symbol + */ +#define XSLTPUBLIC + +/** + * XSLTCALL: + * + * Macro which declares the calling convention for exported functions + */ +#define XSLTCALL + +#endif /* platform switch */ + +/* + * XSLTPUBFUN: + * + * Macro which declares an exportable function + */ +#define XSLTPUBFUN XSLTPUBLIC + +/** + * XSLTPUBVAR: + * + * Macro which declares an exportable variable + */ +#define XSLTPUBVAR XSLTPUBLIC extern + +/* Compatibility */ +#if !defined(LIBXSLT_PUBLIC) +#define LIBXSLT_PUBLIC XSLTPUBVAR +#endif + +#endif /* __XSLT_EXPORTS_H__ */ + + diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/xsltlocale.c chromium-145.0.7632.159/third_party/libxslt/src/libxslt/xsltlocale.c --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/xsltlocale.c 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/xsltlocale.c 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,538 @@ +/* + * xsltlocale.c: locale handling + * + * Reference: + * RFC 3066: Tags for the Identification of Languages + * http://www.ietf.org/rfc/rfc3066.txt + * ISO 639-1, ISO 3166-1 + * + * Author: Nick Wellnhofer + * winapi port: Roumen Petrov + */ + +#define IN_LIBXSLT +#include "libxslt.h" + +#include +#include +#include + +#include "xsltlocale.h" +#include "xsltutils.h" + +#define XSLT_LOCALE_NONE + +#define TOUPPER(c) (c & ~0x20) +#define TOLOWER(c) (c | 0x20) +#define ISALPHA(c) ((unsigned)(TOUPPER(c) - 'A') < 26) + +/*without terminating null character*/ +#define XSLTMAX_ISO639LANGLEN 8 +#define XSLTMAX_ISO3166CNTRYLEN 8 + /* - */ +#define XSLTMAX_LANGTAGLEN (XSLTMAX_ISO639LANGLEN+1+XSLTMAX_ISO3166CNTRYLEN) + +static const xmlChar* xsltDefaultRegion(const xmlChar *localeName); + +#ifdef XSLT_LOCALE_WINAPI +xmlRMutexPtr xsltLocaleMutex = NULL; + +struct xsltRFC1766Info_s { + /*note typedef unsigned char xmlChar !*/ + xmlChar tag[XSLTMAX_LANGTAGLEN+1]; + LCID lcid; +}; +typedef struct xsltRFC1766Info_s xsltRFC1766Info; + +static int xsltLocaleListSize = 0; +static xsltRFC1766Info *xsltLocaleList = NULL; + + +static void * +xslt_locale_WINAPI(const xmlChar *languageTag) { + int k; + xsltRFC1766Info *p = xsltLocaleList; + + for (k=0; ktag, languageTag) == 0) + return(&p->lcid); + return(NULL); +} + +static void xsltEnumSupportedLocales(void); +#endif + +/** + * xsltFreeLocales: + * + * Cleanup function for the locale support on shutdown + */ +void +xsltFreeLocales(void) { +#ifdef XSLT_LOCALE_WINAPI + xmlRMutexLock(xsltLocaleMutex); + xmlFree(xsltLocaleList); + xsltLocaleList = NULL; + xmlRMutexUnlock(xsltLocaleMutex); +#endif +} + +/** + * xsltNewLocale: + * @languageTag: RFC 3066 language tag + * + * Creates a new locale of an opaque system dependent type based on the + * language tag. + * + * Returns the locale or NULL on error or if no matching locale was found + */ +void * +xsltNewLocale(const xmlChar *languageTag, int lowerFirst ATTRIBUTE_UNUSED) { +#ifdef XSLT_LOCALE_POSIX + locale_t locale; + char localeName[XSLTMAX_LANGTAGLEN+7]; /* 7 chars for ".UTF-8\0" */ + const xmlChar *p = languageTag; + const char *region = NULL; + char *q = localeName; + int i, llen; + + /* Convert something like "pt-br" to "pt_BR.UTF-8" */ + + if (languageTag == NULL) + return(NULL); + + for (i=0; i= xstrlen) { + xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : strxfrm failed\n"); + xmlFree(xstr); + return(NULL); + } +#endif + +#ifdef XSLT_LOCALE_WINAPI + int wstrlen, xstrlen, r; + wchar_t *wstr; + LCID *lcid = vlocale; + + wstrlen = MultiByteToWideChar(CP_UTF8, 0, (char *) string, -1, NULL, 0); + if (wstrlen == 0) { + xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : MultiByteToWideChar check failed\n"); + return(NULL); + } + wstr = (wchar_t *) xmlMalloc(wstrlen * sizeof(wchar_t)); + if (wstr == NULL) { + xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : out of memory\n"); + return(NULL); + } + r = MultiByteToWideChar(CP_UTF8, 0, (char *) string, -1, wstr, wstrlen); + if (r == 0) { + xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : MultiByteToWideChar failed\n"); + xmlFree(wstr); + return(NULL); + } + /* This returns the size in bytes. */ + xstrlen = LCMapStringW(*lcid, LCMAP_SORTKEY, wstr, wstrlen, NULL, 0); + if (xstrlen == 0) { + xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : LCMapStringW failed\n"); + xmlFree(wstr); + return(NULL); + } + xstr = (xmlChar*) xmlMalloc(xstrlen); + if (xstr == NULL) { + xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : out of memory\n"); + xmlFree(wstr); + return(NULL); + } + r = LCMapStringW(*lcid, LCMAP_SORTKEY, wstr, wstrlen, (wchar_t *) xstr, + xstrlen); + xmlFree(wstr); + if (r == 0) { + xsltTransformError(NULL, NULL, NULL, "xsltStrxfrm : LCMapStringW failed\n"); + xmlFree(xstr); + return(NULL); + } +#endif /* XSLT_LOCALE_WINAPI */ + + return(xstr); +#endif /* XSLT_LOCALE_NONE */ +} + +/** + * xsltLocaleStrcmp: + * @locale: unused + * @str1: a string transformed with xsltStrxfrm + * @str2: a string transformed with xsltStrxfrm + * + * DEPRECATED: Same as xmlStrcmp. + * + * Compares two strings transformed with xsltStrxfrm. + * + * Returns a value < 0 if str1 sorts before str2, + * a value > 0 if str1 sorts after str2, + * 0 if str1 and str2 are equal wrt sorting + */ +int +xsltLocaleStrcmp(void *locale, const xmlChar *str1, const xmlChar *str2) { + (void)locale; + return(xmlStrcmp(str1, str2)); +} + +#ifdef XSLT_LOCALE_WINAPI +/** + * xsltCountSupportedLocales: + * @lcid: not used + * + * callback used to count locales + * + * Returns TRUE + */ +static BOOL CALLBACK +xsltCountSupportedLocales(LPSTR lcid) { + (void) lcid; + ++xsltLocaleListSize; + return(TRUE); +} + +/** + * xsltIterateSupportedLocales: + * @lcid: not used + * + * callback used to track locales + * + * Returns TRUE if not at the end of the array + */ +static BOOL CALLBACK +xsltIterateSupportedLocales(LPSTR lcid) { + static int count = 0; + xmlChar iso639lang [XSLTMAX_ISO639LANGLEN +1]; + xmlChar iso3136ctry[XSLTMAX_ISO3166CNTRYLEN+1]; + int k, l; + xsltRFC1766Info *p = xsltLocaleList + count; + + k = sscanf(lcid, "%lx", (unsigned long*)&p->lcid); + if (k < 1) goto end; + /*don't count terminating null character*/ + k = GetLocaleInfoA(p->lcid, LOCALE_SISO639LANGNAME, + (char *) iso639lang, sizeof(iso639lang)); + if (--k < 1) goto end; + l = GetLocaleInfoA(p->lcid, LOCALE_SISO3166CTRYNAME, + (char *) iso3136ctry, sizeof(iso3136ctry)); + if (--l < 1) goto end; + + { /*fill results*/ + xmlChar *q = p->tag; + memcpy(q, iso639lang, k); + q += k; + *q++ = '-'; + memcpy(q, iso3136ctry, l); + q += l; + *q = '\0'; + } + ++count; +end: + return((count < xsltLocaleListSize) ? TRUE : FALSE); +} + + +static void +xsltEnumSupportedLocales(void) { + xmlRMutexLock(xsltLocaleMutex); + if (xsltLocaleListSize <= 0) { + size_t len; + + EnumSystemLocalesA(xsltCountSupportedLocales, LCID_SUPPORTED); + + len = xsltLocaleListSize * sizeof(xsltRFC1766Info); + xsltLocaleList = xmlMalloc(len); + memset(xsltLocaleList, 0, len); + EnumSystemLocalesA(xsltIterateSupportedLocales, LCID_SUPPORTED); + } + xmlRMutexUnlock(xsltLocaleMutex); +} + +#endif /*def XSLT_LOCALE_WINAPI*/ diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/xsltlocale.h chromium-145.0.7632.159/third_party/libxslt/src/libxslt/xsltlocale.h --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/xsltlocale.h 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/xsltlocale.h 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,44 @@ +/* + * Summary: Locale handling + * Description: Interfaces for locale handling. Needed for language dependent + * sorting. + * + * Copy: See Copyright for the status of this software. + * + * Author: Nick Wellnhofer + */ + +#ifndef __XML_XSLTLOCALE_H__ +#define __XML_XSLTLOCALE_H__ + +#include +#include "xsltexports.h" + +#ifdef __cplusplus +extern "C" { +#endif + +XSLTPUBFUN void * XSLTCALL + xsltNewLocale (const xmlChar *langName, + int lowerFirst); +XSLTPUBFUN void XSLTCALL + xsltFreeLocale (void *locale); +XSLTPUBFUN xmlChar * XSLTCALL + xsltStrxfrm (void *locale, + const xmlChar *string); +XSLTPUBFUN void XSLTCALL + xsltFreeLocales (void); + +/* Backward compatibility */ +typedef void *xsltLocale; +typedef xmlChar xsltLocaleChar; +XSLTPUBFUN int XSLTCALL + xsltLocaleStrcmp (void *locale, + const xmlChar *str1, + const xmlChar *str2); + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_XSLTLOCALE_H__ */ diff -Nru chromium-145.0.7632.116/third_party/libxslt/src/libxslt/xsltutils.c chromium-145.0.7632.159/third_party/libxslt/src/libxslt/xsltutils.c --- chromium-145.0.7632.116/third_party/libxslt/src/libxslt/xsltutils.c 1970-01-01 00:00:00.000000000 +0000 +++ chromium-145.0.7632.159/third_party/libxslt/src/libxslt/xsltutils.c 2026-03-02 23:00:09.000000000 +0000 @@ -0,0 +1,2725 @@ +/* + * xsltutils.c: Utilities for the XSL Transformation 1.0 engine + * + * Reference: + * http://www.w3.org/TR/1999/REC-xslt-19991116 + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + */ + +#define IN_LIBXSLT +#include "libxslt.h" + +#ifndef XSLT_NEED_TRIO +#include +#else +#include +#endif + +#include +#include +#include +#include + +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif + +#include +#include +#include +#include +#include +#include "xsltutils.h" +#include "templates.h" +#include "xsltInternals.h" +#include "imports.h" +#include "transform.h" + +#if defined(_WIN32) +#include +#define XSLT_WIN32_PERFORMANCE_COUNTER +#endif + +/************************************************************************ + * * + * Convenience function * + * * + ************************************************************************/ + +/** + * xsltGetCNsProp: + * @style: the stylesheet + * @node: the node + * @name: the attribute name + * @nameSpace: the URI of the namespace + * + * Similar to xmlGetNsProp() but with a slightly different semantic + * + * Search and get the value of an attribute associated to a node + * This attribute has to be anchored in the namespace specified, + * or has no namespace and the element is in that namespace. + * + * This does the entity substitution. + * This function looks in DTD attribute declaration for #FIXED or + * default declaration values unless DTD use has been turned off. + * + * Returns the attribute value or NULL if not found. The string is allocated + * in the stylesheet dictionary. + */ +const xmlChar * +xsltGetCNsProp(xsltStylesheetPtr style, xmlNodePtr node, + const xmlChar *name, const xmlChar *nameSpace) { + xmlAttrPtr prop; + xmlDocPtr doc; + xmlNsPtr ns; + xmlChar *tmp; + const xmlChar *ret; + + if ((node == NULL) || (style == NULL) || (style->dict == NULL)) + return(NULL); + + if (nameSpace == NULL) + return xmlGetProp(node, name); + + if (node->type == XML_NAMESPACE_DECL) + return(NULL); + if (node->type == XML_ELEMENT_NODE) + prop = node->properties; + else + prop = NULL; + while (prop != NULL) { + /* + * One need to have + * - same attribute names + * - and the attribute carrying that namespace + */ + if ((xmlStrEqual(prop->name, name)) && + (((prop->ns == NULL) && (node->ns != NULL) && + (xmlStrEqual(node->ns->href, nameSpace))) || + ((prop->ns != NULL) && + (xmlStrEqual(prop->ns->href, nameSpace))))) { + + tmp = xmlNodeListGetString(node->doc, prop->children, 1); + if (tmp == NULL) + ret = xmlDictLookup(style->dict, BAD_CAST "", 0); + else { + ret = xmlDictLookup(style->dict, tmp, -1); + xmlFree(tmp); + } + return ret; + } + prop = prop->next; + } + tmp = NULL; + /* + * Check if there is a default declaration in the internal + * or external subsets + */ + doc = node->doc; + if (doc != NULL) { + if (doc->intSubset != NULL) { + xmlAttributePtr attrDecl; + + attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name); + if ((attrDecl == NULL) && (doc->extSubset != NULL)) + attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name); + + if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) { + /* + * The DTD declaration only allows a prefix search + */ + ns = xmlSearchNs(doc, node, attrDecl->prefix); + if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace))) + return(xmlDictLookup(style->dict, + attrDecl->defaultValue, -1)); + } + } + } + return(NULL); +} +/** + * xsltGetNsProp: + * @node: the node + * @name: the attribute name + * @nameSpace: the URI of the namespace + * + * Similar to xmlGetNsProp() but with a slightly different semantic + * + * Search and get the value of an attribute associated to a node + * This attribute has to be anchored in the namespace specified, + * or has no namespace and the element is in that namespace. + * + * This does the entity substitution. + * This function looks in DTD attribute declaration for #FIXED or + * default declaration values unless DTD use has been turned off. + * + * Returns the attribute value or NULL if not found. + * It's up to the caller to free the memory. + */ +xmlChar * +xsltGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *nameSpace) { + xmlAttrPtr prop; + xmlDocPtr doc; + xmlNsPtr ns; + + if (node == NULL) + return(NULL); + + if (nameSpace == NULL) + return xmlGetProp(node, name); + + if (node->type == XML_NAMESPACE_DECL) + return(NULL); + if (node->type == XML_ELEMENT_NODE) + prop = node->properties; + else + prop = NULL; + /* + * TODO: Substitute xmlGetProp() for xmlGetNsProp(), since the former + * is not namespace-aware and will return an attribute with equal + * name regardless of its namespace. + * Example: + * + * So this would return "myName" even if an attribute @name + * in the XSLT was requested. + */ + while (prop != NULL) { + /* + * One need to have + * - same attribute names + * - and the attribute carrying that namespace + */ + if ((xmlStrEqual(prop->name, name)) && + (((prop->ns == NULL) && (node->ns != NULL) && + (xmlStrEqual(node->ns->href, nameSpace))) || + ((prop->ns != NULL) && + (xmlStrEqual(prop->ns->href, nameSpace))))) { + xmlChar *ret; + + ret = xmlNodeListGetString(node->doc, prop->children, 1); + if (ret == NULL) return(xmlStrdup((xmlChar *)"")); + return(ret); + } + prop = prop->next; + } + + /* + * Check if there is a default declaration in the internal + * or external subsets + */ + doc = node->doc; + if (doc != NULL) { + if (doc->intSubset != NULL) { + xmlAttributePtr attrDecl; + + attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name); + if ((attrDecl == NULL) && (doc->extSubset != NULL)) + attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name); + + if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) { + /* + * The DTD declaration only allows a prefix search + */ + ns = xmlSearchNs(doc, node, attrDecl->prefix); + if ((ns != NULL) && (xmlStrEqual(ns->href, nameSpace))) + return(xmlStrdup(attrDecl->defaultValue)); + } + } + } + return(NULL); +} + +/** + * xsltGetUTF8Char: + * @utf: a sequence of UTF-8 encoded bytes + * @len: a pointer to @bytes len + * + * Read one UTF8 Char from @utf + * Function copied from libxml2 xmlGetUTF8Char() ... to discard ultimately + * and use the original API + * + * Returns the char value or -1 in case of error and update @len with the + * number of bytes used + */ +int +xsltGetUTF8Char(const unsigned char *utf, int *len) { + unsigned int c; + + if (utf == NULL) + goto error; + if (len == NULL) + goto error; + if (*len < 1) + goto error; + + c = utf[0]; + if (c & 0x80) { + if (*len < 2) + goto error; + if ((utf[1] & 0xc0) != 0x80) + goto error; + if ((c & 0xe0) == 0xe0) { + if (*len < 3) + goto error; + if ((utf[2] & 0xc0) != 0x80) + goto error; + if ((c & 0xf0) == 0xf0) { + if (*len < 4) + goto error; + if ((c & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80) + goto error; + *len = 4; + /* 4-byte code */ + c = (utf[0] & 0x7) << 18; + c |= (utf[1] & 0x3f) << 12; + c |= (utf[2] & 0x3f) << 6; + c |= utf[3] & 0x3f; + } else { + /* 3-byte code */ + *len = 3; + c = (utf[0] & 0xf) << 12; + c |= (utf[1] & 0x3f) << 6; + c |= utf[2] & 0x3f; + } + } else { + /* 2-byte code */ + *len = 2; + c = (utf[0] & 0x1f) << 6; + c |= utf[1] & 0x3f; + } + } else { + /* 1-byte code */ + *len = 1; + } + return(c); + +error: + if (len != NULL) + *len = 0; + return(-1); +} + +/** + * xsltGetUTF8CharZ: + * @utf: a sequence of UTF-8 encoded bytes + * @len: a pointer to @bytes len + * + * Read one UTF8 Char from a null-terminated string. + * + * Returns the char value or -1 in case of error and update @len with the + * number of bytes used + */ +int +xsltGetUTF8CharZ(const unsigned char *utf, int *len) { + unsigned int c; + + if (utf == NULL) + goto error; + if (len == NULL) + goto error; + + c = utf[0]; + if (c & 0x80) { + if ((utf[1] & 0xc0) != 0x80) + goto error; + if ((c & 0xe0) == 0xe0) { + if ((utf[2] & 0xc0) != 0x80) + goto error; + if ((c & 0xf0) == 0xf0) { + if ((c & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80) + goto error; + *len = 4; + /* 4-byte code */ + c = (utf[0] & 0x7) << 18; + c |= (utf[1] & 0x3f) << 12; + c |= (utf[2] & 0x3f) << 6; + c |= utf[3] & 0x3f; + } else { + /* 3-byte code */ + *len = 3; + c = (utf[0] & 0xf) << 12; + c |= (utf[1] & 0x3f) << 6; + c |= utf[2] & 0x3f; + } + } else { + /* 2-byte code */ + *len = 2; + c = (utf[0] & 0x1f) << 6; + c |= utf[1] & 0x3f; + } + } else { + /* 1-byte code */ + *len = 1; + } + return(c); + +error: + if (len != NULL) + *len = 0; + return(-1); +} + +#ifdef XSLT_REFACTORED + +/** + * xsltPointerListAddSize: + * @list: the pointer list structure + * @item: the item to be stored + * @initialSize: the initial size of the list + * + * Adds an item to the list. + * + * Returns the position of the added item in the list or + * -1 in case of an error. + */ +int +xsltPointerListAddSize(xsltPointerListPtr list, + void *item, + int initialSize) +{ + if (list->items == NULL) { + if (initialSize <= 0) + initialSize = 1; + list->items = (void **) xmlMalloc( + initialSize * sizeof(void *)); + if (list->items == NULL) { + xsltGenericError(xsltGenericErrorContext, + "xsltPointerListAddSize: memory allocation failure.\n"); + return(-1); + } + list->number = 0; + list->size = initialSize; + } else if (list->size <= list->number) { + list->size *= 2; + list->items = (void **) xmlRealloc(list->items, + list->size * sizeof(void *)); + if (list->items == NULL) { + xsltGenericError(xsltGenericErrorContext, + "xsltPointerListAddSize: memory re-allocation failure.\n"); + list->size = 0; + return(-1); + } + } + list->items[list->number++] = item; + return(0); +} + +/** + * xsltPointerListCreate: + * @initialSize: the initial size for the list + * + * Creates an xsltPointerList structure. + * + * Returns a xsltPointerList structure or NULL in case of an error. + */ +xsltPointerListPtr +xsltPointerListCreate(int initialSize) +{ + xsltPointerListPtr ret; + + ret = xmlMalloc(sizeof(xsltPointerList)); + if (ret == NULL) { + xsltGenericError(xsltGenericErrorContext, + "xsltPointerListCreate: memory allocation failure.\n"); + return (NULL); + } + memset(ret, 0, sizeof(xsltPointerList)); + if (initialSize > 0) { + xsltPointerListAddSize(ret, NULL, initialSize); + ret->number = 0; + } + return (ret); +} + +/** + * xsltPointerListFree: + * @list: pointer to the list to be freed + * + * Frees the xsltPointerList structure. This does not free + * the content of the list. + */ +void +xsltPointerListFree(xsltPointerListPtr list) +{ + if (list == NULL) + return; + if (list->items != NULL) + xmlFree(list->items); + xmlFree(list); +} + +/** + * xsltPointerListClear: + * @list: pointer to the list to be cleared + * + * Resets the list, but does not free the allocated array + * and does not free the content of the list. + */ +void +xsltPointerListClear(xsltPointerListPtr list) +{ + if (list->items != NULL) { + xmlFree(list->items); + list->items = NULL; + } + list->number = 0; + list->size = 0; +} + +#endif /* XSLT_REFACTORED */ + +/************************************************************************ + * * + * Handling of XSLT stylesheets messages * + * * + ************************************************************************/ + +/** + * xsltMessage: + * @ctxt: an XSLT processing context + * @node: The current node + * @inst: The node containing the message instruction + * + * Process and xsl:message construct + */ +void +xsltMessage(xsltTransformContextPtr ctxt, xmlNodePtr node, xmlNodePtr inst) { + xmlGenericErrorFunc error = xsltGenericError; + void *errctx = xsltGenericErrorContext; + xmlChar *prop, *message; + int terminate = 0; + + if ((ctxt == NULL) || (inst == NULL)) + return; + + if (ctxt->error != NULL) { + error = ctxt->error; + errctx = ctxt->errctx; + } + + prop = xmlGetNsProp(inst, (const xmlChar *)"terminate", NULL); + if (prop != NULL) { + if (xmlStrEqual(prop, (const xmlChar *)"yes")) { + terminate = 1; + } else if (xmlStrEqual(prop, (const xmlChar *)"no")) { + terminate = 0; + } else { + xsltTransformError(ctxt, NULL, inst, + "xsl:message : terminate expecting 'yes' or 'no'\n"); + } + xmlFree(prop); + } + message = xsltEvalTemplateString(ctxt, node, inst); + if (message != NULL) { + int len = xmlStrlen(message); + + error(errctx, "%s", (const char *)message); + if ((len > 0) && (message[len - 1] != '\n')) + error(errctx, "\n"); + xmlFree(message); + } + if (terminate) + ctxt->state = XSLT_STATE_STOPPED; +} + +/************************************************************************ + * * + * Handling of out of context errors * + * * + ************************************************************************/ + +#define XSLT_GET_VAR_STR(msg, str) { \ + int size; \ + int chars; \ + char *larger; \ + va_list ap; \ + \ + str = (char *) xmlMalloc(150); \ + if (str == NULL) \ + return; \ + \ + size = 150; \ + \ + while (size < 64000) { \ + va_start(ap, msg); \ + chars = vsnprintf(str, size, msg, ap); \ + va_end(ap); \ + if ((chars > -1) && (chars < size)) \ + break; \ + if (chars > -1) \ + size += chars + 1; \ + else \ + size += 100; \ + if ((larger = (char *) xmlRealloc(str, size)) == NULL) {\ + xmlFree(str); \ + return; \ + } \ + str = larger; \ + } \ +} +/** + * xsltGenericErrorDefaultFunc: + * @ctx: an error context + * @msg: the message to display/transmit + * @...: extra parameters for the message display + * + * Default handler for out of context error messages. + */ +static void LIBXSLT_ATTR_FORMAT(2,3) +xsltGenericErrorDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) { + va_list args; + + if (xsltGenericErrorContext == NULL) + xsltGenericErrorContext = (void *) stderr; + + va_start(args, msg); + vfprintf((FILE *)xsltGenericErrorContext, msg, args); + va_end(args); +} + +xmlGenericErrorFunc xsltGenericError = xsltGenericErrorDefaultFunc; +void *xsltGenericErrorContext = NULL; + + +/** + * xsltSetGenericErrorFunc: + * @ctx: the new error handling context + * @handler: the new handler function + * + * Function to reset the handler and the error context for out of + * context error messages. + * This simply means that @handler will be called for subsequent + * error messages while not parsing nor validating. And @ctx will + * be passed as first argument to @handler + * One can simply force messages to be emitted to another FILE * than + * stderr by setting @ctx to this file handle and @handler to NULL. + */ +void +xsltSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) { + xsltGenericErrorContext = ctx; + if (handler != NULL) + xsltGenericError = handler; + else + xsltGenericError = xsltGenericErrorDefaultFunc; +} + +/** + * xsltGenericDebugDefaultFunc: + * @ctx: an error context + * @msg: the message to display/transmit + * @...: extra parameters for the message display + * + * Default handler for out of context error messages. + */ +static void LIBXSLT_ATTR_FORMAT(2,3) +xsltGenericDebugDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) { + va_list args; + + if (xsltGenericDebugContext == NULL) + return; + + va_start(args, msg); + vfprintf((FILE *)xsltGenericDebugContext, msg, args); + va_end(args); +} + +xmlGenericErrorFunc xsltGenericDebug = xsltGenericDebugDefaultFunc; +void *xsltGenericDebugContext = NULL; + + +/** + * xsltSetGenericDebugFunc: + * @ctx: the new error handling context + * @handler: the new handler function + * + * Function to reset the handler and the error context for out of + * context error messages. + * This simply means that @handler will be called for subsequent + * error messages while not parsing or validating. And @ctx will + * be passed as first argument to @handler + * One can simply force messages to be emitted to another FILE * than + * stderr by setting @ctx to this file handle and @handler to NULL. + */ +void +xsltSetGenericDebugFunc(void *ctx, xmlGenericErrorFunc handler) { + xsltGenericDebugContext = ctx; + if (handler != NULL) + xsltGenericDebug = handler; + else + xsltGenericDebug = xsltGenericDebugDefaultFunc; +} + +/** + * xsltPrintErrorContext: + * @ctxt: the transformation context + * @style: the stylesheet + * @node: the current node being processed + * + * Display the context of an error. + */ +void +xsltPrintErrorContext(xsltTransformContextPtr ctxt, + xsltStylesheetPtr style, xmlNodePtr node) { + int line = 0; + const xmlChar *file = NULL; + const xmlChar *name = NULL; + const char *type = "error"; + xmlGenericErrorFunc error = xsltGenericError; + void *errctx = xsltGenericErrorContext; + + if (ctxt != NULL) { + if (ctxt->state == XSLT_STATE_OK) + ctxt->state = XSLT_STATE_ERROR; + if (ctxt->error != NULL) { + error = ctxt->error; + errctx = ctxt->errctx; + } + } + if ((node == NULL) && (ctxt != NULL)) + node = ctxt->inst; + + if (node != NULL) { + if ((node->type == XML_DOCUMENT_NODE) || + (node->type == XML_HTML_DOCUMENT_NODE)) { + xmlDocPtr doc = (xmlDocPtr) node; + + file = doc->URL; + } else { + line = xmlGetLineNo(node); + if ((node->doc != NULL) && (node->doc->URL != NULL)) + file = node->doc->URL; + if (node->name != NULL) + name = node->name; + } + } + + if (ctxt != NULL) + type = "runtime error"; + else if (style != NULL) { +#ifdef XSLT_REFACTORED + if (XSLT_CCTXT(style)->errSeverity == XSLT_ERROR_SEVERITY_WARNING) + type = "compilation warning"; + else + type = "compilation error"; +#else + type = "compilation error"; +#endif + } + + if ((file != NULL) && (line != 0) && (name != NULL)) + error(errctx, "%s: file %s line %d element %s\n", + type, file, line, name); + else if ((file != NULL) && (name != NULL)) + error(errctx, "%s: file %s element %s\n", type, file, name); + else if ((file != NULL) && (line != 0)) + error(errctx, "%s: file %s line %d\n", type, file, line); + else if (file != NULL) + error(errctx, "%s: file %s\n", type, file); + else if (name != NULL) + error(errctx, "%s: element %s\n", type, name); + else + error(errctx, "%s\n", type); +} + +/** + * xsltSetTransformErrorFunc: + * @ctxt: the XSLT transformation context + * @ctx: the new error handling context + * @handler: the new handler function + * + * Function to reset the handler and the error context for out of + * context error messages specific to a given XSLT transromation. + * + * This simply means that @handler will be called for subsequent + * error messages while running the transformation. + */ +void +xsltSetTransformErrorFunc(xsltTransformContextPtr ctxt, + void *ctx, xmlGenericErrorFunc handler) +{ + ctxt->error = handler; + ctxt->errctx = ctx; +} + +/** + * xsltTransformError: + * @ctxt: an XSLT transformation context + * @style: the XSLT stylesheet used + * @node: the current node in the stylesheet + * @msg: the message to display/transmit + * @...: extra parameters for the message display + * + * Display and format an error messages, gives file, line, position and + * extra parameters, will use the specific transformation context if available + */ +void +xsltTransformError(xsltTransformContextPtr ctxt, + xsltStylesheetPtr style, + xmlNodePtr node, + const char *msg, ...) { + xmlGenericErrorFunc error = xsltGenericError; + void *errctx = xsltGenericErrorContext; + char * str; + + if (ctxt != NULL) { + if (ctxt->state == XSLT_STATE_OK) + ctxt->state = XSLT_STATE_ERROR; + if (ctxt->error != NULL) { + error = ctxt->error; + errctx = ctxt->errctx; + } + } + if ((node == NULL) && (ctxt != NULL)) + node = ctxt->inst; + xsltPrintErrorContext(ctxt, style, node); + XSLT_GET_VAR_STR(msg, str); + error(errctx, "%s", str); + if (str != NULL) + xmlFree(str); +} + +/************************************************************************ + * * + * QNames * + * * + ************************************************************************/ + +/** + * xsltSplitQName: + * @dict: a dictionary + * @name: the full QName + * @prefix: the return value + * + * Split QNames into prefix and local names, both allocated from a dictionary. + * + * Returns: the localname or NULL in case of error. + */ +const xmlChar * +xsltSplitQName(xmlDictPtr dict, const xmlChar *name, const xmlChar **prefix) { + int len = 0; + const xmlChar *ret = NULL; + + *prefix = NULL; + if ((name == NULL) || (dict == NULL)) return(NULL); + if (name[0] == ':') + return(xmlDictLookup(dict, name, -1)); + while ((name[len] != 0) && (name[len] != ':')) len++; + if (name[len] == 0) return(xmlDictLookup(dict, name, -1)); + *prefix = xmlDictLookup(dict, name, len); + ret = xmlDictLookup(dict, &name[len + 1], -1); + return(ret); +} + +/** + * xsltGetQNameURI: + * @node: the node holding the QName + * @name: pointer to the initial QName value + * + * This function analyzes @name, if the name contains a prefix, + * the function seaches the associated namespace in scope for it. + * It will also replace @name value with the NCName, the old value being + * freed. + * Errors in the prefix lookup are signalled by setting @name to NULL. + * + * NOTE: the namespace returned is a pointer to the place where it is + * defined and hence has the same lifespan as the document holding it. + * + * Returns the namespace URI if there is a prefix, or NULL if @name is + * not prefixed. + */ +const xmlChar * +xsltGetQNameURI(xmlNodePtr node, xmlChar ** name) +{ + int len = 0; + xmlChar *qname; + xmlNsPtr ns; + + if (name == NULL) + return(NULL); + qname = *name; + if ((qname == NULL) || (*qname == 0)) + return(NULL); + if (node == NULL) { + xsltGenericError(xsltGenericErrorContext, + "QName: no element for namespace lookup %s\n", + qname); + xmlFree(qname); + *name = NULL; + return(NULL); + } + + /* nasty but valid */ + if (qname[0] == ':') + return(NULL); + + /* + * we are not trying to validate but just to cut, and yes it will + * work even if this is a set of UTF-8 encoded chars + */ + while ((qname[len] != 0) && (qname[len] != ':')) + len++; + + if (qname[len] == 0) + return(NULL); + + /* + * handle xml: separately, this one is magical + */ + if ((qname[0] == 'x') && (qname[1] == 'm') && + (qname[2] == 'l') && (qname[3] == ':')) { + if (qname[4] == 0) + return(NULL); + *name = xmlStrdup(&qname[4]); + xmlFree(qname); + return(XML_XML_NAMESPACE); + } + + qname[len] = 0; + ns = xmlSearchNs(node->doc, node, qname); + if (ns == NULL) { + xsltGenericError(xsltGenericErrorContext, + "%s:%s : no namespace bound to prefix %s\n", + qname, &qname[len + 1], qname); + *name = NULL; + xmlFree(qname); + return(NULL); + } + *name = xmlStrdup(&qname[len + 1]); + xmlFree(qname); + return(ns->href); +} + +/** + * xsltGetQNameURI2: + * @style: stylesheet pointer + * @node: the node holding the QName + * @name: pointer to the initial QName value + * + * This function is similar to xsltGetQNameURI, but is used when + * @name is a dictionary entry. + * + * Returns the namespace URI if there is a prefix, or NULL if @name is + * not prefixed. + */ +const xmlChar * +xsltGetQNameURI2(xsltStylesheetPtr style, xmlNodePtr node, + const xmlChar **name) { + int len = 0; + xmlChar *qname; + xmlNsPtr ns; + + if (name == NULL) + return(NULL); + qname = (xmlChar *)*name; + if ((qname == NULL) || (*qname == 0)) + return(NULL); + if (node == NULL) { + xsltGenericError(xsltGenericErrorContext, + "QName: no element for namespace lookup %s\n", + qname); + *name = NULL; + return(NULL); + } + + /* + * we are not trying to validate but just to cut, and yes it will + * work even if this is a set of UTF-8 encoded chars + */ + while ((qname[len] != 0) && (qname[len] != ':')) + len++; + + if (qname[len] == 0) + return(NULL); + + /* + * handle xml: separately, this one is magical + */ + if ((qname[0] == 'x') && (qname[1] == 'm') && + (qname[2] == 'l') && (qname[3] == ':')) { + if (qname[4] == 0) + return(NULL); + *name = xmlDictLookup(style->dict, &qname[4], -1); + return(XML_XML_NAMESPACE); + } + + qname = xmlStrndup(*name, len); + ns = xmlSearchNs(node->doc, node, qname); + if (ns == NULL) { + if (style) { + xsltTransformError(NULL, style, node, + "No namespace bound to prefix '%s'.\n", + qname); + style->errors++; + } else { + xsltGenericError(xsltGenericErrorContext, + "%s : no namespace bound to prefix %s\n", + *name, qname); + } + *name = NULL; + xmlFree(qname); + return(NULL); + } + *name = xmlDictLookup(style->dict, (*name)+len+1, -1); + xmlFree(qname); + return(ns->href); +} + +/************************************************************************ + * * + * Sorting * + * * + ************************************************************************/ + +/** + * xsltDocumentSortFunction: + * @list: the node set + * + * reorder the current node list @list accordingly to the document order + * This function is slow, obsolete and should not be used anymore. + */ +void +xsltDocumentSortFunction(xmlNodeSetPtr list) { + int i, j; + int len, tst; + xmlNodePtr node; + + if (list == NULL) + return; + len = list->nodeNr; + if (len <= 1) + return; + /* TODO: sort is really not optimized, does it needs to ? */ + for (i = 0;i < len -1;i++) { + for (j = i + 1; j < len; j++) { + tst = xmlXPathCmpNodes(list->nodeTab[i], list->nodeTab[j]); + if (tst == -1) { + node = list->nodeTab[i]; + list->nodeTab[i] = list->nodeTab[j]; + list->nodeTab[j] = node; + } + } + } +} + +/** + * xsltComputeSortResultInternal: + * @ctxt: a XSLT process context + * @sort: xsl:sort node + * @number: data-type is number + * @locale: transform strings according to locale + * + * reorder the current node list accordingly to the set of sorting + * requirement provided by the array of nodes. + * + * Returns a ordered XPath nodeset or NULL in case of error. + */ +static xmlXPathObjectPtr * +xsltComputeSortResultInternal(xsltTransformContextPtr ctxt, xmlNodePtr sort, + int number, void *locale) { +#ifdef XSLT_REFACTORED + xsltStyleItemSortPtr comp; +#else + const xsltStylePreComp *comp; +#endif + xmlXPathObjectPtr *results = NULL; + xmlNodeSetPtr list = NULL; + xmlXPathObjectPtr res; + int len = 0; + int i; + xmlNodePtr oldNode; + xmlNodePtr oldInst; + int oldPos, oldSize ; + int oldNsNr; + xmlNsPtr *oldNamespaces; + + comp = sort->psvi; + if (comp == NULL) { + xsltGenericError(xsltGenericErrorContext, + "xsl:sort : compilation failed\n"); + return(NULL); + } + + if ((comp->select == NULL) || (comp->comp == NULL)) + return(NULL); + + list = ctxt->nodeList; + if ((list == NULL) || (list->nodeNr <= 1)) + return(NULL); + + len = list->nodeNr; + + /* TODO: xsl:sort lang attribute */ + /* TODO: xsl:sort case-order attribute */ + + + results = xmlMalloc(len * sizeof(xmlXPathObjectPtr)); + if (results == NULL) { + xsltGenericError(xsltGenericErrorContext, + "xsltComputeSortResult: memory allocation failure\n"); + return(NULL); + } + + oldInst = ctxt->inst; + oldNode = ctxt->xpathCtxt->node; + oldPos = ctxt->xpathCtxt->proximityPosition; + oldSize = ctxt->xpathCtxt->contextSize; + oldNsNr = ctxt->xpathCtxt->nsNr; + oldNamespaces = ctxt->xpathCtxt->namespaces; + for (i = 0;i < len;i++) { + ctxt->inst = sort; + ctxt->xpathCtxt->contextSize = len; + ctxt->xpathCtxt->proximityPosition = i + 1; + ctxt->node = list->nodeTab[i]; + ctxt->xpathCtxt->node = ctxt->node; +#ifdef XSLT_REFACTORED + if (comp->inScopeNs != NULL) { + ctxt->xpathCtxt->namespaces = comp->inScopeNs->list; + ctxt->xpathCtxt->nsNr = comp->inScopeNs->xpathNumber; + } else { + ctxt->xpathCtxt->namespaces = NULL; + ctxt->xpathCtxt->nsNr = 0; + } +#else + ctxt->xpathCtxt->namespaces = comp->nsList; + ctxt->xpathCtxt->nsNr = comp->nsNr; +#endif + res = xmlXPathCompiledEval(comp->comp, ctxt->xpathCtxt); + if (res != NULL) { + if (res->type != XPATH_STRING) + res = xmlXPathConvertString(res); + if (number) + res = xmlXPathConvertNumber(res); + } + if (res != NULL) { + res->index = i; /* Save original pos for dupl resolv */ + if (number) { + if (res->type == XPATH_NUMBER) { + results[i] = res; + } else { +#ifdef WITH_XSLT_DEBUG_PROCESS + xsltGenericDebug(xsltGenericDebugContext, + "xsltComputeSortResult: select didn't evaluate to a number\n"); +#endif + results[i] = NULL; + } + } else { + if (res->type == XPATH_STRING) { + if (locale != NULL) { + xmlChar *str = res->stringval; + xmlChar *sortKey = ctxt->genSortKey(locale, str); + + if (sortKey == NULL) { + xsltTransformError(ctxt, NULL, sort, + "xsltComputeSortResult: sort key is null\n"); + } else { + res->stringval = sortKey; + xmlFree(str); + } + } + + results[i] = res; + } else { +#ifdef WITH_XSLT_DEBUG_PROCESS + xsltGenericDebug(xsltGenericDebugContext, + "xsltComputeSortResult: select didn't evaluate to a string\n"); +#endif + results[i] = NULL; + } + } + } else { + ctxt->state = XSLT_STATE_STOPPED; + results[i] = NULL; + } + } + ctxt->inst = oldInst; + ctxt->xpathCtxt->node = oldNode; + ctxt->xpathCtxt->contextSize = oldSize; + ctxt->xpathCtxt->proximityPosition = oldPos; + ctxt->xpathCtxt->nsNr = oldNsNr; + ctxt->xpathCtxt->namespaces = oldNamespaces; + + return(results); +} + +/** + * xsltComputeSortResult: + * @ctxt: a XSLT process context + * @sort: node list + * + * reorder the current node list accordingly to the set of sorting + * requirement provided by the array of nodes. + * + * Returns a ordered XPath nodeset or NULL in case of error. + */ +xmlXPathObjectPtr * +xsltComputeSortResult(xsltTransformContextPtr ctxt, xmlNodePtr sort) { + const xsltStylePreComp *comp = sort->psvi; + int number = 0; + + if (comp != NULL) + number = comp->number; + return xsltComputeSortResultInternal(ctxt, sort, number, + /* locale */ NULL); +} + +/** + * xsltDefaultSortFunction: + * @ctxt: a XSLT process context + * @sorts: array of sort nodes + * @nbsorts: the number of sorts in the array + * + * reorder the current node list accordingly to the set of sorting + * requirement provided by the arry of nodes. + */ +void +xsltDefaultSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr *sorts, + int nbsorts) { +#ifdef XSLT_REFACTORED + xsltStyleItemSortPtr comp; +#else + const xsltStylePreComp *comp; +#endif + xmlXPathObjectPtr *resultsTab[XSLT_MAX_SORT]; + xmlXPathObjectPtr *results = NULL, *res; + xmlNodeSetPtr list = NULL; + int len = 0; + int i, j, incr; + int tst; + int depth; + xmlNodePtr node; + xmlXPathObjectPtr tmp; + int number[XSLT_MAX_SORT], desc[XSLT_MAX_SORT]; + void *locale[XSLT_MAX_SORT]; + + if ((ctxt == NULL) || (sorts == NULL) || (nbsorts <= 0) || + (nbsorts >= XSLT_MAX_SORT)) + return; + if (sorts[0] == NULL) + return; + comp = sorts[0]->psvi; + if (comp == NULL) + return; + + list = ctxt->nodeList; + if ((list == NULL) || (list->nodeNr <= 1)) + return; /* nothing to do */ + + for (j = 0; j < nbsorts; j++) { + xmlChar *lang; + + comp = sorts[j]->psvi; + if ((comp->stype == NULL) && (comp->has_stype != 0)) { + xmlChar *stype = + xsltEvalAttrValueTemplate(ctxt, sorts[j], + BAD_CAST "data-type", NULL); + number[j] = 0; + if (stype != NULL) { + if (xmlStrEqual(stype, (const xmlChar *) "text")) + ; + else if (xmlStrEqual(stype, (const xmlChar *) "number")) + number[j] = 1; + else { + xsltTransformError(ctxt, NULL, sorts[j], + "xsltDoSortFunction: no support for data-type = %s\n", + stype); + } + xmlFree(stype); + } + } else { + number[j] = comp->number; + } + if ((comp->order == NULL) && (comp->has_order != 0)) { + xmlChar *order = xsltEvalAttrValueTemplate(ctxt, sorts[j], + BAD_CAST "order", NULL); + desc[j] = 0; + if (order != NULL) { + if (xmlStrEqual(order, (const xmlChar *) "ascending")) + ; + else if (xmlStrEqual(order, (const xmlChar *) "descending")) + desc[j] = 1; + else { + xsltTransformError(ctxt, NULL, sorts[j], + "xsltDoSortFunction: invalid value %s for order\n", + order); + } + xmlFree(order); + } + } else { + desc[j] = comp->descending; + } + if ((comp->lang == NULL) && (comp->has_lang != 0)) { + lang = xsltEvalAttrValueTemplate(ctxt, sorts[j], + (xmlChar *) "lang", + NULL); + } else { + lang = (xmlChar *) comp->lang; + } + if (lang != NULL) { + locale[j] = ctxt->newLocale(lang, comp->lower_first); + if (lang != comp->lang) + xmlFree(lang); + } else { + locale[j] = NULL; + } + } + + len = list->nodeNr; + + resultsTab[0] = xsltComputeSortResultInternal(ctxt, sorts[0], number[0], + locale[0]); + for (i = 1;i < XSLT_MAX_SORT;i++) + resultsTab[i] = NULL; + + results = resultsTab[0]; + + comp = sorts[0]->psvi; + if (results == NULL) + goto cleanup; + + /* Shell's sort of node-set */ + for (incr = len / 2; incr > 0; incr /= 2) { + for (i = incr; i < len; i++) { + j = i - incr; + if (results[i] == NULL) + continue; + + while (j >= 0) { + if (results[j] == NULL) + tst = 1; + else { + if (number[0]) { + /* We make NaN smaller than number in accordance + with XSLT spec */ + if (xmlXPathIsNaN(results[j]->floatval)) { + if (xmlXPathIsNaN(results[j + incr]->floatval)) + tst = 0; + else + tst = -1; + } else if (xmlXPathIsNaN(results[j + incr]->floatval)) + tst = 1; + else if (results[j]->floatval == + results[j + incr]->floatval) + tst = 0; + else if (results[j]->floatval > + results[j + incr]->floatval) + tst = 1; + else tst = -1; + } else { + tst = xmlStrcmp(results[j]->stringval, + results[j + incr]->stringval); + } + if (desc[0]) + tst = -tst; + } + if (tst == 0) { + /* + * Okay we need to use multi level sorts + */ + depth = 1; + while (depth < nbsorts) { + if (sorts[depth] == NULL) + break; + comp = sorts[depth]->psvi; + if (comp == NULL) + break; + + /* + * Compute the result of the next level for the + * full set, this might be optimized ... or not + */ + if (resultsTab[depth] == NULL) + resultsTab[depth] = + xsltComputeSortResultInternal(ctxt, + sorts[depth], + number[depth], + locale[depth]); + res = resultsTab[depth]; + if (res == NULL) + break; + if (res[j] == NULL) { + if (res[j+incr] != NULL) + tst = 1; + } else if (res[j+incr] == NULL) { + tst = -1; + } else { + if (number[depth]) { + /* We make NaN smaller than number in + accordance with XSLT spec */ + if (xmlXPathIsNaN(res[j]->floatval)) { + if (xmlXPathIsNaN(res[j + + incr]->floatval)) + tst = 0; + else + tst = -1; + } else if (xmlXPathIsNaN(res[j + incr]-> + floatval)) + tst = 1; + else if (res[j]->floatval == res[j + incr]-> + floatval) + tst = 0; + else if (res[j]->floatval > + res[j + incr]->floatval) + tst = 1; + else tst = -1; + } else { + tst = xmlStrcmp(res[j]->stringval, + res[j + incr]->stringval); + } + if (desc[depth]) + tst = -tst; + } + + /* + * if we still can't differenciate at this level + * try one level deeper. + */ + if (tst != 0) + break; + depth++; + } + } + if (tst == 0) { + tst = results[j]->index > results[j + incr]->index; + } + if (tst > 0) { + tmp = results[j]; + results[j] = results[j + incr]; + results[j + incr] = tmp; + node = list->nodeTab[j]; + list->nodeTab[j] = list->nodeTab[j + incr]; + list->nodeTab[j + incr] = node; + depth = 1; + while (depth < nbsorts) { + if (sorts[depth] == NULL) + break; + if (resultsTab[depth] == NULL) + break; + res = resultsTab[depth]; + tmp = res[j]; + res[j] = res[j + incr]; + res[j + incr] = tmp; + depth++; + } + j -= incr; + } else + break; + } + } + } + +cleanup: + for (j = 0; j < nbsorts; j++) { + if (locale[j] != NULL) { + ctxt->freeLocale(locale[j]); + } + if (resultsTab[j] != NULL) { + for (i = 0;i < len;i++) + xmlXPathFreeObject(resultsTab[j][i]); + xmlFree(resultsTab[j]); + } + } +} + + +static xsltSortFunc xsltSortFunction = xsltDefaultSortFunction; + +/** + * xsltDoSortFunction: + * @ctxt: a XSLT process context + * @sorts: array of sort nodes + * @nbsorts: the number of sorts in the array + * + * reorder the current node list accordingly to the set of sorting + * requirement provided by the arry of nodes. + * This is a wrapper function, the actual function used is specified + * using xsltSetCtxtSortFunc() to set the context specific sort function, + * or xsltSetSortFunc() to set the global sort function. + * If a sort function is set on the context, this will get called. + * Otherwise the global sort function is called. + */ +void +xsltDoSortFunction(xsltTransformContextPtr ctxt, xmlNodePtr * sorts, + int nbsorts) +{ + if (ctxt->sortfunc != NULL) + (ctxt->sortfunc)(ctxt, sorts, nbsorts); + else if (xsltSortFunction != NULL) + xsltSortFunction(ctxt, sorts, nbsorts); +} + +/** + * xsltSetSortFunc: + * @handler: the new handler function + * + * DEPRECATED: Use xsltSetCtxtLocaleHandlers. + * + * Function to reset the global handler for XSLT sorting. + * If the handler is NULL, the default sort function will be used. + */ +void +xsltSetSortFunc(xsltSortFunc handler) { + if (handler != NULL) + xsltSortFunction = handler; + else + xsltSortFunction = xsltDefaultSortFunction; +} + +/** + * xsltSetCtxtSortFunc: + * @ctxt: a XSLT process context + * @handler: the new handler function + * + * DEPRECATED: Use xsltSetCtxtLocaleHandlers. + * + * Function to set the handler for XSLT sorting + * for the specified context. + * If the handler is NULL, then the global + * sort function will be called + */ +void +xsltSetCtxtSortFunc(xsltTransformContextPtr ctxt, xsltSortFunc handler) { + ctxt->sortfunc = handler; +} + +/** + * xsltSetCtxtLocaleHandlers: + * @ctxt: an XSLT transform context + * @newLocale: locale constructor + * @freeLocale: locale destructor + * @genSortKey: sort key generator + * + * Set the locale handlers. + */ +void +xsltSetCtxtLocaleHandlers(xsltTransformContextPtr ctxt, + xsltNewLocaleFunc newLocale, + xsltFreeLocaleFunc freeLocale, + xsltGenSortKeyFunc genSortKey) { + if (ctxt == NULL) + return; + + ctxt->newLocale = newLocale; + ctxt->freeLocale = freeLocale; + ctxt->genSortKey = genSortKey; +} + +/************************************************************************ + * * + * Parsing options * + * * + ************************************************************************/ + +/** + * xsltSetCtxtParseOptions: + * @ctxt: a XSLT process context + * @options: a combination of libxml2 xmlParserOption + * + * Change the default parser option passed by the XSLT engine to the + * parser when using document() loading. + * + * Returns the previous options or -1 in case of error + */ +int +xsltSetCtxtParseOptions(xsltTransformContextPtr ctxt, int options) +{ + int oldopts; + + if (ctxt == NULL) + return(-1); + oldopts = ctxt->parserOptions; + if (ctxt->xinclude) + oldopts |= XML_PARSE_XINCLUDE; + ctxt->parserOptions = options; + if (options & XML_PARSE_XINCLUDE) + ctxt->xinclude = 1; + else + ctxt->xinclude = 0; + return(oldopts); +} + +/************************************************************************ + * * + * Output * + * * + ************************************************************************/ + +/** + * xsltSaveResultTo: + * @buf: an output buffer + * @result: the result xmlDocPtr + * @style: the stylesheet + * + * Save the result @result obtained by applying the @style stylesheet + * to an I/O output channel @buf + * + * Returns the number of byte written or -1 in case of failure. + */ +int +xsltSaveResultTo(xmlOutputBufferPtr buf, xmlDocPtr result, + xsltStylesheetPtr style) { + const xmlChar *encoding; + int base; + const xmlChar *method; + int indent; + + if ((buf == NULL) || (result == NULL) || (style == NULL)) + return(-1); + if ((result->children == NULL) || + ((result->children->type == XML_DTD_NODE) && + (result->children->next == NULL))) + return(0); + + if ((style->methodURI != NULL) && + ((style->method == NULL) || + (!xmlStrEqual(style->method, (const xmlChar *) "xhtml")))) { + xsltGenericError(xsltGenericErrorContext, + "xsltSaveResultTo : unknown output method\n"); + return(-1); + } + + base = buf->written; + + XSLT_GET_IMPORT_PTR(method, style, method) + XSLT_GET_IMPORT_PTR(encoding, style, encoding) + XSLT_GET_IMPORT_INT(indent, style, indent); + + if ((method == NULL) && (result->type == XML_HTML_DOCUMENT_NODE)) + method = (const xmlChar *) "html"; + + if ((method != NULL) && + (xmlStrEqual(method, (const xmlChar *) "html"))) { + if (encoding != NULL) { + htmlSetMetaEncoding(result, (const xmlChar *) encoding); + } else { + htmlSetMetaEncoding(result, (const xmlChar *) "UTF-8"); + } + if (indent == -1) + indent = 1; + htmlDocContentDumpFormatOutput(buf, result, (const char *) encoding, + indent); + xmlOutputBufferFlush(buf); + } else if ((method != NULL) && + (xmlStrEqual(method, (const xmlChar *) "xhtml"))) { + if (encoding != NULL) { + htmlSetMetaEncoding(result, (const xmlChar *) encoding); + } else { + htmlSetMetaEncoding(result, (const xmlChar *) "UTF-8"); + } + htmlDocContentDumpOutput(buf, result, (const char *) encoding); + xmlOutputBufferFlush(buf); + } else if ((method != NULL) && + (xmlStrEqual(method, (const xmlChar *) "text"))) { + xmlNodePtr cur; + + cur = result->children; + while (cur != NULL) { + if (cur->type == XML_TEXT_NODE) + xmlOutputBufferWriteString(buf, (const char *) cur->content); + + /* + * Skip to next node + */ + if (cur->children != NULL) { + if ((cur->children->type != XML_ENTITY_DECL) && + (cur->children->type != XML_ENTITY_REF_NODE) && + (cur->children->type != XML_ENTITY_NODE)) { + cur = cur->children; + continue; + } + } + if (cur->next != NULL) { + cur = cur->next; + continue; + } + + do { + cur = cur->parent; + if (cur == NULL) + break; + if (cur == (xmlNodePtr) style->doc) { + cur = NULL; + break; + } + if (cur->next != NULL) { + cur = cur->next; + break; + } + } while (cur != NULL); + } + xmlOutputBufferFlush(buf); + } else { + int omitXmlDecl; + int standalone; + + XSLT_GET_IMPORT_INT(omitXmlDecl, style, omitXmlDeclaration); + XSLT_GET_IMPORT_INT(standalone, style, standalone); + + if (omitXmlDecl != 1) { + xmlOutputBufferWriteString(buf, "version != NULL) { + xmlOutputBufferWriteString(buf, "\""); + xmlOutputBufferWriteString(buf, (const char *)result->version); + xmlOutputBufferWriteString(buf, "\""); + } else + xmlOutputBufferWriteString(buf, "\"1.0\""); + if (encoding == NULL) { + if (result->encoding != NULL) + encoding = result->encoding; + else if (result->charset != XML_CHAR_ENCODING_UTF8) + encoding = (const xmlChar *) + xmlGetCharEncodingName((xmlCharEncoding) + result->charset); + } + if (encoding != NULL) { + xmlOutputBufferWriteString(buf, " encoding="); + xmlOutputBufferWriteString(buf, "\""); + xmlOutputBufferWriteString(buf, (const char *) encoding); + xmlOutputBufferWriteString(buf, "\""); + } + switch (standalone) { + case 0: + xmlOutputBufferWriteString(buf, " standalone=\"no\""); + break; + case 1: + xmlOutputBufferWriteString(buf, " standalone=\"yes\""); + break; + default: + break; + } + xmlOutputBufferWriteString(buf, "?>\n"); + } + if (result->children != NULL) { + xmlNodePtr children = result->children; + xmlNodePtr child = children; + + /* + * Hack to avoid quadratic behavior when scanning + * result->children in xmlGetIntSubset called by + * xmlNodeDumpOutput. + */ + result->children = NULL; + + while (child != NULL) { + xmlNodeDumpOutput(buf, result, child, 0, (indent == 1), + (const char *) encoding); + if (indent && ((child->type == XML_DTD_NODE) || + ((child->type == XML_COMMENT_NODE) && + (child->next != NULL)))) + xmlOutputBufferWriteString(buf, "\n"); + child = child->next; + } + if (indent) + xmlOutputBufferWriteString(buf, "\n"); + + result->children = children; + } + xmlOutputBufferFlush(buf); + } + return(buf->written - base); +} + +/** + * xsltSaveResultToFilename: + * @URL: a filename or URL + * @result: the result xmlDocPtr + * @style: the stylesheet + * @compression: the compression factor (0 - 9 included) + * + * Save the result @result obtained by applying the @style stylesheet + * to a file or @URL + * + * Returns the number of byte written or -1 in case of failure. + */ +int +xsltSaveResultToFilename(const char *URL, xmlDocPtr result, + xsltStylesheetPtr style, int compression) { + xmlOutputBufferPtr buf; + const xmlChar *encoding; + int ret; + + if ((URL == NULL) || (result == NULL) || (style == NULL)) + return(-1); + if (result->children == NULL) + return(0); + + XSLT_GET_IMPORT_PTR(encoding, style, encoding) + if (encoding != NULL) { + xmlCharEncodingHandlerPtr encoder = NULL; + + /* Don't use UTF-8 dummy encoder */ + if ((xmlStrcasecmp(encoding, BAD_CAST "UTF-8") != 0) && + (xmlStrcasecmp(encoding, BAD_CAST "UTF8") != 0)) + encoder = xmlFindCharEncodingHandler((char *) encoding); + buf = xmlOutputBufferCreateFilename(URL, encoder, compression); + } else { + buf = xmlOutputBufferCreateFilename(URL, NULL, compression); + } + if (buf == NULL) + return(-1); + xsltSaveResultTo(buf, result, style); + ret = xmlOutputBufferClose(buf); + return(ret); +} + +/** + * xsltSaveResultToFile: + * @file: a FILE * I/O + * @result: the result xmlDocPtr + * @style: the stylesheet + * + * Save the result @result obtained by applying the @style stylesheet + * to an open FILE * I/O. + * This does not close the FILE @file + * + * Returns the number of bytes written or -1 in case of failure. + */ +int +xsltSaveResultToFile(FILE *file, xmlDocPtr result, xsltStylesheetPtr style) { + xmlOutputBufferPtr buf; + const xmlChar *encoding; + int ret; + + if ((file == NULL) || (result == NULL) || (style == NULL)) + return(-1); + if (result->children == NULL) + return(0); + + XSLT_GET_IMPORT_PTR(encoding, style, encoding) + if (encoding != NULL) { + xmlCharEncodingHandlerPtr encoder = NULL; + + /* Don't use UTF-8 dummy encoder */ + if ((xmlStrcasecmp(encoding, BAD_CAST "UTF-8") != 0) && + (xmlStrcasecmp(encoding, BAD_CAST "UTF8") != 0)) + encoder = xmlFindCharEncodingHandler((char *) encoding); + buf = xmlOutputBufferCreateFile(file, encoder); + } else { + buf = xmlOutputBufferCreateFile(file, NULL); + } + + if (buf == NULL) + return(-1); + xsltSaveResultTo(buf, result, style); + ret = xmlOutputBufferClose(buf); + return(ret); +} + +/** + * xsltSaveResultToFd: + * @fd: a file descriptor + * @result: the result xmlDocPtr + * @style: the stylesheet + * + * Save the result @result obtained by applying the @style stylesheet + * to an open file descriptor + * This does not close the descriptor. + * + * Returns the number of bytes written or -1 in case of failure. + */ +int +xsltSaveResultToFd(int fd, xmlDocPtr result, xsltStylesheetPtr style) { + xmlOutputBufferPtr buf; + const xmlChar *encoding; + int ret; + + if ((fd < 0) || (result == NULL) || (style == NULL)) + return(-1); + if (result->children == NULL) + return(0); + + XSLT_GET_IMPORT_PTR(encoding, style, encoding) + if (encoding != NULL) { + xmlCharEncodingHandlerPtr encoder = NULL; + + /* Don't use UTF-8 dummy encoder */ + if ((xmlStrcasecmp(encoding, BAD_CAST "UTF-8") != 0) && + (xmlStrcasecmp(encoding, BAD_CAST "UTF8") != 0)) + encoder = xmlFindCharEncodingHandler((char *) encoding); + buf = xmlOutputBufferCreateFd(fd, encoder); + } else { + buf = xmlOutputBufferCreateFd(fd, NULL); + } + if (buf == NULL) + return(-1); + xsltSaveResultTo(buf, result, style); + ret = xmlOutputBufferClose(buf); + return(ret); +} + +/** + * xsltSaveResultToString: + * @doc_txt_ptr: Memory pointer for allocated XML text + * @doc_txt_len: Length of the generated XML text + * @result: the result xmlDocPtr + * @style: the stylesheet + * + * Save the result @result obtained by applying the @style stylesheet + * to a new allocated string. + * + * Returns 0 in case of success and -1 in case of error + */ +int +xsltSaveResultToString(xmlChar **doc_txt_ptr, int * doc_txt_len, + xmlDocPtr result, xsltStylesheetPtr style) { + xmlOutputBufferPtr buf; + const xmlChar *encoding; + + *doc_txt_ptr = NULL; + *doc_txt_len = 0; + if (result->children == NULL) + return(0); + + XSLT_GET_IMPORT_PTR(encoding, style, encoding) + if (encoding != NULL) { + xmlCharEncodingHandlerPtr encoder = NULL; + + /* Don't use UTF-8 dummy encoder */ + if ((xmlStrcasecmp(encoding, BAD_CAST "UTF-8") != 0) && + (xmlStrcasecmp(encoding, BAD_CAST "UTF8") != 0)) + encoder = xmlFindCharEncodingHandler((char *) encoding); + buf = xmlAllocOutputBuffer(encoder); + } else { + buf = xmlAllocOutputBuffer(NULL); + } + if (buf == NULL) + return(-1); + xsltSaveResultTo(buf, result, style); +#ifdef LIBXML2_NEW_BUFFER + if (buf->conv != NULL) { + *doc_txt_len = xmlBufUse(buf->conv); + *doc_txt_ptr = xmlStrndup(xmlBufContent(buf->conv), *doc_txt_len); + } else { + *doc_txt_len = xmlBufUse(buf->buffer); + *doc_txt_ptr = xmlStrndup(xmlBufContent(buf->buffer), *doc_txt_len); + } +#else + if (buf->conv != NULL) { + *doc_txt_len = buf->conv->use; + *doc_txt_ptr = xmlStrndup(buf->conv->content, *doc_txt_len); + } else { + *doc_txt_len = buf->buffer->use; + *doc_txt_ptr = xmlStrndup(buf->buffer->content, *doc_txt_len); + } +#endif + (void)xmlOutputBufferClose(buf); + return 0; +} + +/** + * xsltGetSourceNodeFlags: + * @node: Node from source document + * + * Returns the flags for a source node. + */ +int +xsltGetSourceNodeFlags(xmlNodePtr node) { + /* + * Squeeze the bit flags into the upper bits of + * + * - 'int properties' member in struct _xmlDoc + * - 'xmlAttributeType atype' member in struct _xmlAttr + * - 'unsigned short extra' member in struct _xmlNode + */ + switch (node->type) { + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + return ((xmlDocPtr) node)->properties >> 27; + + case XML_ATTRIBUTE_NODE: + return ((xmlAttrPtr) node)->atype >> 27; + + case XML_ELEMENT_NODE: + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_PI_NODE: + case XML_COMMENT_NODE: + return node->extra >> 12; + + default: + return 0; + } +} + +/** + * xsltSetSourceNodeFlags: + * @node: Node from source document + * @flags: Flags + * + * Sets the specified flags to 1. + * + * Returns 0 on success, -1 on error. + */ +int +xsltSetSourceNodeFlags(xsltTransformContextPtr ctxt, xmlNodePtr node, + int flags) { + if (node->doc == ctxt->initialContextDoc) + ctxt->sourceDocDirty = 1; + + switch (node->type) { + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + ((xmlDocPtr) node)->properties |= flags << 27; + return 0; + + case XML_ATTRIBUTE_NODE: + ((xmlAttrPtr) node)->atype |= flags << 27; + return 0; + + case XML_ELEMENT_NODE: + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_PI_NODE: + case XML_COMMENT_NODE: + node->extra |= flags << 12; + return 0; + + default: + return -1; + } +} + +/** + * xsltClearSourceNodeFlags: + * @node: Node from source document + * @flags: Flags + * + * Sets the specified flags to 0. + * + * Returns 0 on success, -1 on error. + */ +int +xsltClearSourceNodeFlags(xmlNodePtr node, int flags) { + switch (node->type) { + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + ((xmlDocPtr) node)->properties &= ~(flags << 27); + return 0; + + case XML_ATTRIBUTE_NODE: + ((xmlAttrPtr) node)->atype &= ~(flags << 27); + return 0; + + case XML_ELEMENT_NODE: + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_PI_NODE: + case XML_COMMENT_NODE: + node->extra &= ~(flags << 12); + return 0; + + default: + return -1; + } +} + +/** + * xsltGetPSVIPtr: + * @cur: Node + * + * Returns a pointer to the psvi member of a node or NULL on error. + */ +void ** +xsltGetPSVIPtr(xmlNodePtr cur) { + switch (cur->type) { + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: + return &((xmlDocPtr) cur)->psvi; + + case XML_ATTRIBUTE_NODE: + return &((xmlAttrPtr) cur)->psvi; + + case XML_ELEMENT_NODE: + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_PI_NODE: + case XML_COMMENT_NODE: + return &cur->psvi; + + default: + return NULL; + } +} + +#ifdef WITH_PROFILER + +/************************************************************************ + * * + * Generating profiling information * + * * + ************************************************************************/ + +static long calibration = -1; + +/** + * xsltCalibrateTimestamps: + * + * Used for to calibrate the xsltTimestamp() function + * Should work if launched at startup and we don't loose our quantum :-) + * + * Returns the number of milliseconds used by xsltTimestamp() + */ +#if !defined(XSLT_WIN32_PERFORMANCE_COUNTER) && \ + (defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETTIMEOFDAY)) +static long +xsltCalibrateTimestamps(void) { + register int i; + + for (i = 0;i < 999;i++) + xsltTimestamp(); + return(xsltTimestamp() / 1000); +} +#endif + +/** + * xsltCalibrateAdjust: + * @delta: a negative dealy value found + * + * Used for to correct the calibration for xsltTimestamp() + */ +void +xsltCalibrateAdjust(long delta) { + calibration += delta; +} + +/** + * xsltTimestamp: + * + * Used for gathering profiling data + * + * Returns the number of tenth of milliseconds since the beginning of the + * profiling + */ +long +xsltTimestamp(void) +{ +#ifdef XSLT_WIN32_PERFORMANCE_COUNTER + BOOL ok; + LARGE_INTEGER performanceCount; + LARGE_INTEGER performanceFrequency; + LONGLONG quadCount; + double seconds; + static LONGLONG startupQuadCount = 0; + static LONGLONG startupQuadFreq = 0; + + ok = QueryPerformanceCounter(&performanceCount); + if (!ok) + return 0; + quadCount = performanceCount.QuadPart; + if (calibration < 0) { + calibration = 0; + ok = QueryPerformanceFrequency(&performanceFrequency); + if (!ok) + return 0; + startupQuadFreq = performanceFrequency.QuadPart; + startupQuadCount = quadCount; + return (0); + } + if (startupQuadFreq == 0) + return 0; + seconds = (quadCount - startupQuadCount) / (double) startupQuadFreq; + return (long) (seconds * XSLT_TIMESTAMP_TICS_PER_SEC); + +#else /* XSLT_WIN32_PERFORMANCE_COUNTER */ +#ifdef HAVE_CLOCK_GETTIME +# if defined(CLOCK_MONOTONIC) +# define XSLT_CLOCK CLOCK_MONOTONIC +# elif defined(CLOCK_HIGHRES) +# define XSLT_CLOCK CLOCK_HIGHRES +# else +# define XSLT_CLOCK CLOCK_REALTIME +# endif + static struct timespec startup; + struct timespec cur; + long tics; + + if (calibration < 0) { + clock_gettime(XSLT_CLOCK, &startup); + calibration = 0; + calibration = xsltCalibrateTimestamps(); + clock_gettime(XSLT_CLOCK, &startup); + return (0); + } + + clock_gettime(XSLT_CLOCK, &cur); + tics = (cur.tv_sec - startup.tv_sec) * XSLT_TIMESTAMP_TICS_PER_SEC; + tics += (cur.tv_nsec - startup.tv_nsec) / + (1000000000l / XSLT_TIMESTAMP_TICS_PER_SEC); + + tics -= calibration; + return(tics); + +#elif HAVE_GETTIMEOFDAY + static struct timeval startup; + struct timeval cur; + long tics; + + if (calibration < 0) { + gettimeofday(&startup, NULL); + calibration = 0; + calibration = xsltCalibrateTimestamps(); + gettimeofday(&startup, NULL); + return (0); + } + + gettimeofday(&cur, NULL); + tics = (cur.tv_sec - startup.tv_sec) * XSLT_TIMESTAMP_TICS_PER_SEC; + tics += (cur.tv_usec - startup.tv_usec) / + (1000000l / XSLT_TIMESTAMP_TICS_PER_SEC); + + tics -= calibration; + return(tics); +#else + + /* Neither gettimeofday() nor Win32 performance counter available */ + + return (0); + +#endif /* HAVE_GETTIMEOFDAY */ +#endif /* XSLT_WIN32_PERFORMANCE_COUNTER */ +} + +static char * +pretty_templ_match(xsltTemplatePtr templ) { + static char dst[1001]; + char *src = (char *)templ->match; + int i=0,j; + + /* strip white spaces */ + for (j=0; i<1000 && src[j]; i++,j++) { + for(;src[j]==' ';j++); + dst[i]=src[j]; + } + if(i<998 && templ->mode) { + /* append [mode] */ + dst[i++]='['; + src=(char *)templ->mode; + for (j=0; i<999 && src[j]; i++,j++) { + dst[i]=src[j]; + } + dst[i++]=']'; + } + dst[i]='\0'; + return dst; +} + +#define MAX_TEMPLATES 10000 + +/** + * xsltSaveProfiling: + * @ctxt: an XSLT context + * @output: a FILE * for saving the information + * + * Save the profiling information on @output + */ +void +xsltSaveProfiling(xsltTransformContextPtr ctxt, FILE *output) { + int nb, i,j,k,l; + int max; + int total; + unsigned long totalt; + xsltTemplatePtr *templates; + xsltStylesheetPtr style; + xsltTemplatePtr templ1,templ2; + int *childt; + + if ((output == NULL) || (ctxt == NULL)) + return; + if (ctxt->profile == 0) + return; + + nb = 0; + max = MAX_TEMPLATES; + templates = xmlMalloc(max * sizeof(xsltTemplatePtr)); + if (templates == NULL) + return; + + style = ctxt->style; + while (style != NULL) { + templ1 = style->templates; + while (templ1 != NULL) { + if (nb >= max) + break; + + if (templ1->nbCalls > 0) + templates[nb++] = templ1; + templ1 = templ1->next; + } + + style = xsltNextImport(style); + } + + for (i = 0;i < nb -1;i++) { + for (j = i + 1; j < nb; j++) { + if ((templates[i]->time <= templates[j]->time) || + ((templates[i]->time == templates[j]->time) && + (templates[i]->nbCalls <= templates[j]->nbCalls))) { + templ1 = templates[j]; + templates[j] = templates[i]; + templates[i] = templ1; + } + } + } + + + /* print flat profile */ + + fprintf(output, "%6s%20s%20s%10s Calls Tot 100us Avg\n\n", + "number", "match", "name", "mode"); + total = 0; + totalt = 0; + for (i = 0;i < nb;i++) { + templ1 = templates[i]; + fprintf(output, "%5d ", i); + if (templ1->match != NULL) { + if (xmlStrlen(templ1->match) > 20) + fprintf(output, "%s\n%26s", templ1->match, ""); + else + fprintf(output, "%20s", templ1->match); + } else { + fprintf(output, "%20s", ""); + } + if (templ1->name != NULL) { + if (xmlStrlen(templ1->name) > 20) + fprintf(output, "%s\n%46s", templ1->name, ""); + else + fprintf(output, "%20s", templ1->name); + } else { + fprintf(output, "%20s", ""); + } + if (templ1->mode != NULL) { + if (xmlStrlen(templ1->mode) > 10) + fprintf(output, "%s\n%56s", templ1->mode, ""); + else + fprintf(output, "%10s", templ1->mode); + } else { + fprintf(output, "%10s", ""); + } + fprintf(output, " %6d", templ1->nbCalls); + fprintf(output, " %6ld %6ld\n", templ1->time, + templ1->time / templ1->nbCalls); + total += templ1->nbCalls; + totalt += templ1->time; + } + fprintf(output, "\n%30s%26s %6d %6ld\n", "Total", "", total, totalt); + + + /* print call graph */ + + childt = xmlMalloc((nb + 1) * sizeof(int)); + if (childt == NULL) + return; + + /* precalculate children times */ + for (i = 0; i < nb; i++) { + templ1 = templates[i]; + + childt[i] = 0; + for (k = 0; k < nb; k++) { + templ2 = templates[k]; + for (l = 0; l < templ2->templNr; l++) { + if (templ2->templCalledTab[l] == templ1) { + childt[i] +=templ2->time; + } + } + } + } + childt[i] = 0; + + fprintf(output, "\nindex %% time self children called name\n"); + + for (i = 0; i < nb; i++) { + char ix_str[20], timep_str[20], times_str[20], timec_str[20], called_str[20]; + unsigned long t; + + templ1 = templates[i]; + /* callers */ + for (j = 0; j < templ1->templNr; j++) { + templ2 = templ1->templCalledTab[j]; + for (k = 0; k < nb; k++) { + if (templates[k] == templ2) + break; + } + t=templ2?templ2->time:totalt; + snprintf(times_str,sizeof(times_str),"%8.3f",(float)t/XSLT_TIMESTAMP_TICS_PER_SEC); + snprintf(timec_str,sizeof(timec_str),"%8.3f",(float)childt[k]/XSLT_TIMESTAMP_TICS_PER_SEC); + snprintf(called_str,sizeof(called_str),"%6d/%d", + templ1->templCountTab[j], /* number of times caller calls 'this' */ + templ1->nbCalls); /* total number of calls to 'this' */ + + fprintf(output, " %-8s %-8s %-12s %s [%d]\n", + times_str,timec_str,called_str, + (templ2?(templ2->name?(char *)templ2->name:pretty_templ_match(templ2)):"-"),k); + } + /* this */ + snprintf(ix_str,sizeof(ix_str),"[%d]",i); + snprintf(timep_str,sizeof(timep_str),"%6.2f",(float)templ1->time*100.0/totalt); + snprintf(times_str,sizeof(times_str),"%8.3f",(float)templ1->time/XSLT_TIMESTAMP_TICS_PER_SEC); + snprintf(timec_str,sizeof(timec_str),"%8.3f",(float)childt[i]/XSLT_TIMESTAMP_TICS_PER_SEC); + fprintf(output, "%-5s %-6s %-8s %-8s %6d %s [%d]\n", + ix_str, timep_str,times_str,timec_str, + templ1->nbCalls, + templ1->name?(char *)templ1->name:pretty_templ_match(templ1),i); + /* callees + * - go over templates[0..nb] and their templCalledTab[] + * - print those where we in the the call-stack + */ + total = 0; + for (k = 0; k < nb; k++) { + templ2 = templates[k]; + for (l = 0; l < templ2->templNr; l++) { + if (templ2->templCalledTab[l] == templ1) { + total+=templ2->templCountTab[l]; + } + } + } + for (k = 0; k < nb; k++) { + templ2 = templates[k]; + for (l = 0; l < templ2->templNr; l++) { + if (templ2->templCalledTab[l] == templ1) { + snprintf(times_str,sizeof(times_str),"%8.3f",(float)templ2->time/XSLT_TIMESTAMP_TICS_PER_SEC); + snprintf(timec_str,sizeof(timec_str),"%8.3f",(float)childt[k]/XSLT_TIMESTAMP_TICS_PER_SEC); + snprintf(called_str,sizeof(called_str),"%6d/%d", + templ2->templCountTab[l], /* number of times 'this' calls callee */ + total); /* total number of calls from 'this' */ + fprintf(output, " %-8s %-8s %-12s %s [%d]\n", + times_str,timec_str,called_str, + templ2->name?(char *)templ2->name:pretty_templ_match(templ2),k); + } + } + } + fprintf(output, "-----------------------------------------------\n"); + } + + fprintf(output, "\f\nIndex by function name\n"); + for (i = 0; i < nb; i++) { + templ1 = templates[i]; + fprintf(output, "[%d] %s (%s:%d)\n", + i, templ1->name?(char *)templ1->name:pretty_templ_match(templ1), + templ1->style->doc->URL,templ1->elem->line); + } + + fprintf(output, "\f\n"); + xmlFree(childt); + + xmlFree(templates); +} + +/************************************************************************ + * * + * Fetching profiling information * + * * + ************************************************************************/ + +/** + * xsltGetProfileInformation: + * @ctxt: a transformation context + * + * This function should be called after the transformation completed + * to extract template processing profiling information if available. + * The information is returned as an XML document tree like + * + * + *