[
  {
    "path": ".gitattributes",
    "content": "# build config\n/.scrutinizer.yml export-ignore\n/.github export-ignore\n/php_cs.dist export-ignore\n/phpmd.xml.dist export-ignore\n/phpstan.neon export-ignore\n\n/composer.lock export-ignore\n\n# git files\n/.gitignore export-ignore\n/.gitattributes export-ignore\n\n# project directories\n/build export-ignore\n/docs export-ignore\n/samples export-ignore\n\n# tests\n/phpunit.xml.dist export-ignore\n/tests export-ignore\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/1_bug_report.yml",
    "content": "name: 🐛 Bug Report\ndescription: Create a report to help improve PHPWord\nlabels: [ \"Bug Report\" ]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n         ### ❗️ Read this before submitting your bug report:\n         - **Write in English/French.** Reports in all other languages will be closed.\n         - **Provide as much detail as possible** \n           - Attachments : Error logs, Screenshots, Document files (generated and expected).\n           - If the issue cannot be reproduced, it cannot be fixed.\n  - type: textarea\n    id: what-happened\n    attributes:\n      label: Describe the bug and add attachments\n      description: What went wrong? If possible, add screenshots, error logs, document files (generated and expected) or screen recordings to help explain your problem.\n    validations:\n      required: true\n  - type: textarea\n    id: expected-behavior\n    attributes:\n      label: Expected behavior\n      description: A clear and concise description of what you expected to happen.\n    validations:\n      required: true\n  - type: textarea\n    id: steps-reproduce\n    attributes:\n      label: Steps to reproduce\n      description: Please provide a code sample that reproduces the issue.\n      placeholder: |\n        ```php\n        <?php\n        require __DIR__ . '/vendor/autoload.php';\n\n        $phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n        $section = $phpWord->addSection();\n        $section->...\n        ```\n    validations:\n      required: true\n  - type: input\n    id: phpword-version\n    attributes:\n      label: PHPWord version(s) where the bug happened\n      placeholder: \"e.g., 1.2.0 or master\"\n    validations:\n      required: true\n  - type: input\n    id: php-version\n    attributes:\n      label: PHP version(s) where the bug happened\n      placeholder: \"e.g., 7.1 or 8.2\"\n    validations:\n      required: true\n  - type: checkboxes\n    attributes:\n      label: Priority\n      description: Funded tickets have a higher priority.\n      options:\n        - label: I want to crowdfund the bug fix (with [@algora-io](https://docs.algora.io/bounties/overview)) and fund a community developer.\n          required: false\n        - label: I want to pay the bug fix and fund a maintainer for that. (Contact @Progi1984)\n          required: false"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/2_feature_request.yml",
    "content": "name: 💡 Feature request\ndescription: Suggest an idea for this project\nlabels: [ \"Change Request\" ]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n         ### ❗️ Read this before submitting your bug report:\n         - **Write in English/French.** Reports in all other languages will be closed.\n         - **Provide as much detail as possible** \n           - Attachments : Error logs, Screenshots, Document files (generated and expected).\n           - If the issue cannot be reproduced, it cannot be fixed.\n  - type: textarea\n    id: problem\n    attributes:\n      label: Describe the problem\n      description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n    validations:\n      required: true\n  - type: textarea\n    id: expected-behavior\n    attributes:\n      label: Describe the expected behavior\n      description: A clear and concise description of what you expected to happen. If possible, add screenshots, document files (expected).\n    validations:\n      required: true\n  - type: checkboxes\n    attributes:\n      label: Priority\n      description: Funded tickets have a higher priority.\n      options:\n        - label: I want to crowdfund the feature (with [@algora-io](https://docs.algora.io/bounties/overview)) and fund a community developer.\n          required: false\n        - label: I want to pay the feature and fund a maintainer for that. (Contact @Progi1984)\n          required: false"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "### Description\n\nPlease include a summary of the change and which issue is fixed. Please also include relevant motivation and context.\n\nFixes # (issue)\n\n### Checklist:\n\n- [ ] My CI is :green_circle:\n- [ ] I have covered by unit tests my new code (check build/coverage for coverage report)\n- [ ] I have updated the [documentation](https://github.com/PHPOffice/PHPWord/tree/master/docs) to describe the changes\n- [ ] I have updated the [changelog](https://github.com/PHPOffice/PHPWord/blob/master/docs/changes/1.x/1.5.0.md)\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n- package-ecosystem: composer\n  directory: \"/\"\n  schedule:\n    interval: monthly\n    time: \"11:00\"\n  open-pull-requests-limit: 10\n"
  },
  {
    "path": ".github/support.yml",
    "content": "# Label used to mark issues as support requests\nsupportLabel: Question\n# Comment to post on issues marked as support requests. Add a link\n# to a support page, or set to `false` to disable\nsupportComment: >\n  This looks like a support question. Please ask your support questions on\n  [StackOverflow](http://stackoverflow.com/questions/tagged/phpword),\n  or [Gitter](https://gitter.im/PHPOffice/PHPWord).\n\n  Thank you for your contributions.\n\n# Whether to close issues marked as support requests\nclose: true\n# Whether to lock issues marked as support requests\nlock: false\n"
  },
  {
    "path": ".github/workflows/deploy.yml",
    "content": "name: Deploy\n\non:\n  push:\n    branches: \n      - master\n  pull_request:\n\njobs:\n  deploy:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v2\n      ### MkDocs\n      - name: Setup Python\n        uses: actions/setup-python@v2\n        with:\n          python-version: 3.x\n      - name: Install Python Dependencies\n        run: pip install mkdocs-material autolink-references-mkdocs-plugin\n      - name: Build documentation\n        run: mkdocs build --site-dir public\n      ### PHPUnit\n      - name: Setup PHP\n        uses: shivammathur/setup-php@v2\n        with:\n          php-version: 8.1\n          extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib\n          coverage: xdebug\n      - name: Create directory public/coverage\n        run: mkdir ./public/coverage\n      - name: Install PHP Dependencies\n        run: composer install --ansi --prefer-dist --no-interaction --no-progress\n      - name: Build Coverage Report\n        run: XDEBUG_MODE=coverage ./vendor/bin/phpunit -c ./ --coverage-text --coverage-html ./public/coverage\n        ### PHPDoc\n      - name: Create directory public/docs\n        run: mkdir ./public/docs\n      - name: Install PhpDocumentor\n        run: wget https://phpdoc.org/phpDocumentor.phar && chmod +x phpDocumentor.phar\n      - name: Build Documentation\n        run: ./phpDocumentor.phar run -d ./src -t ./public/docs\n\n      ### Deploy\n      - name: Deploy\n        uses: peaceiris/actions-gh-pages@v3\n        if: github.ref == 'refs/heads/master'\n        with:\n          github_token: ${{ secrets.GITHUB_TOKEN }}\n          publish_dir: ./public\n"
  },
  {
    "path": ".github/workflows/php.yml",
    "content": "name: PHPWord\non: [push, pull_request]\njobs:\n  php-cs-fixer:\n    name: PHP CS Fixer\n    runs-on: ubuntu-latest\n    steps:\n      - name: Setup PHP\n        uses: shivammathur/setup-php@v2\n        with:\n          php-version: '8.3'\n          extensions: mbstring, intl, gd, xml, dom, json, fileinfo, curl, zip, iconv\n      - uses: actions/checkout@v2\n\n      -   name: Validate composer config\n          run: composer validate --strict\n\n      -   name: Composer Install\n          run: composer global require friendsofphp/php-cs-fixer\n\n      -   name: Add environment path\n          run: export PATH=\"$PATH:$HOME/.composer/vendor/bin\"\n\n      -   name: Run PHPCSFixer\n          run: php-cs-fixer fix --dry-run --diff\n\n  phpmd:\n    name: PHP Mess Detector\n    runs-on: ubuntu-latest\n    steps:\n        -   name: Setup PHP\n            uses: shivammathur/setup-php@v2\n            with:\n                php-version: '8.4'\n                extensions: gd, xml, zip\n        -   uses: actions/checkout@v2\n\n        -   name: Composer Install\n            run: composer install --ansi --prefer-dist --no-interaction --no-progress\n\n        -   name: Run phpmd\n            run: ./vendor/bin/phpmd src/,tests/ text ./phpmd.xml.dist --exclude \"src/PhpWord/Shared/PCLZip/*\"\n\n  phpstan:\n    name: PHP Static Analysis\n    runs-on: ubuntu-latest\n    strategy:\n      fail-fast: false\n      matrix:\n        # Disabled PHPStan in '7.1'\n        php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4']\n    steps:\n        -   name: Setup PHP\n            uses: shivammathur/setup-php@v2\n            with:\n                php-version: ${{ matrix.php }}\n                extensions: gd, xml, zip\n        -   uses: actions/checkout@v2\n\n        -   name: Composer Install\n            run: composer install --ansi --prefer-dist --no-interaction --no-progress\n\n        -   name: Run phpstan\n            run: ./vendor/bin/phpstan analyse -c phpstan.neon.dist\n\n  phpunit:\n    name: PHPUnit ${{ matrix.php }}\n    runs-on: ubuntu-latest\n    strategy:\n      fail-fast: false\n      matrix:\n        php: ['7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4']\n    steps:\n      -   name: Setup PHP\n          uses: shivammathur/setup-php@v2\n          with:\n              php-version: ${{ matrix.php }}\n              extensions: gd, xml, zip\n              coverage: ${{ (matrix.php == '7.3') && 'xdebug' || 'none' }}\n\n      -   uses: actions/checkout@v2\n\n      -   name: Composer Install\n          run: composer install --ansi --prefer-dist --no-interaction --no-progress\n\n      -   name: Run phpunit\n          if: matrix.php != '7.3'\n          run: ./vendor/bin/phpunit -c phpunit.xml.dist --no-coverage\n\n      -   name: Run phpunit\n          if: matrix.php == '7.3'\n          run: ./vendor/bin/phpunit -c phpunit.xml.dist --coverage-clover build/clover.xml\n\n      -   name: Upload coverage results to Coveralls\n          if: matrix.php == '7.3'\n          env:\n            COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          run: |\n            wget https://github.com/php-coveralls/php-coveralls/releases/download/v2.4.3/php-coveralls.phar\n            chmod +x php-coveralls.phar\n            php php-coveralls.phar --coverage_clover=build/clover.xml --json_path=build/coveralls-upload.json -vvv\n\n  samples:\n    name: Check samples\n    runs-on: ubuntu-latest\n    strategy:\n      fail-fast: false\n      matrix:\n        php: ['7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4']\n    steps:\n      -   name: Setup PHP\n          uses: shivammathur/setup-php@v2\n          with:\n              php-version: ${{ matrix.php }}\n              extensions: gd, xml, zip\n              coverage: xdebug\n\n      -   uses: actions/checkout@v2\n\n      -   name: Composer Install\n          run: composer install --ansi --prefer-dist --no-interaction --no-progress\n\n      -   name: Generate samples files\n          run: composer run samples\n"
  },
  {
    "path": ".github_changelog_generator",
    "content": "user=PHPOffice\nproject=PHPWord\n\nsince-tag=0.18.1\nfuture-release=0.18.2\n\nissues=false\npulls=true\n"
  },
  {
    "path": ".gitignore",
    "content": "/composer.lock\n\n\n.DS_Store\n._*\n.Spotlight-V100\n.Trashes\nThumbs.db\nDesktop.ini\n.idea\n_build\n/build\nphpunit.xml\ncomposer.phar\ncomposer.lock\nvendor\n/report\n/build\n/samples/results\n/.settings\nphpword.ini\n/.buildpath\n/.scannerwork\n/.project\n/nbproject\n/.php_cs.cache\n/.phpunit.result.cache\n/public"
  },
  {
    "path": ".php-cs-fixer.dist.php",
    "content": "<?php\n\n$finder = PhpCsFixer\\Finder::create()\n    ->notName('pclzip.lib.php')\n    ->notName('OLERead.php')\n    ->in('samples')\n    ->in('src')\n    ->in('tests');\n\n$config = new PhpCsFixer\\Config();\n$config\n    ->setRiskyAllowed(true)\n    ->setFinder($finder)\n    ->setCacheFile(sys_get_temp_dir() . '/php-cs-fixer' . preg_replace('~\\W~', '-', __DIR__))\n    ->setRules([\n        'align_multiline_comment' => true,\n        'array_indentation' => true,\n        'array_syntax' => ['syntax' => 'short'],\n        'backtick_to_shell_exec' => true,\n        'binary_operator_spaces' => true,\n        'blank_line_after_namespace' => true,\n        'blank_line_after_opening_tag' => true,\n        'blank_line_before_statement' => true,\n        'braces' => true,\n        'cast_spaces' => true,\n        'class_attributes_separation' => ['elements' => ['method' => 'one', 'property' => 'one']], // const are often grouped with other related const\n        'class_definition' => false,\n        'class_keyword_remove' => false, // ::class keyword gives us better support in IDE\n        'combine_consecutive_issets' => true,\n        'combine_consecutive_unsets' => true,\n        'combine_nested_dirname' => true,\n        'comment_to_phpdoc' => false, // interferes with annotations\n        'compact_nullable_typehint' => true,\n        'concat_space' => ['spacing' => 'one'],\n        'constant_case' => true,\n        'date_time_immutable' => false, // Break our unit tests\n        'declare_equal_normalize' => true,\n        'declare_strict_types' => false, // Too early to adopt strict types\n        'dir_constant' => true,\n        'doctrine_annotation_array_assignment' => true,\n        'doctrine_annotation_braces' => true,\n        'doctrine_annotation_indentation' => true,\n        'doctrine_annotation_spaces' => true,\n        'elseif' => true,\n        'encoding' => true,\n        'ereg_to_preg' => true,\n        'escape_implicit_backslashes' => true,\n        'explicit_indirect_variable' => false, // I feel it makes the code actually harder to read\n        'explicit_string_variable' => false, // I feel it makes the code actually harder to read\n        'final_class' => false, // We need non-final classes\n        'final_internal_class' => true,\n        'final_public_method_for_abstract_class' => false, // We need non-final methods\n        'fopen_flag_order' => true,\n        'fopen_flags' => true,\n        'full_opening_tag' => true,\n        'fully_qualified_strict_types' => true,\n        'function_declaration' => true,\n        'function_to_constant' => true,\n        'function_typehint_space' => true,\n        'general_phpdoc_annotation_remove' => ['annotations' => ['access', 'category', 'copyright', 'throws']],\n        'global_namespace_import' => true,\n        'header_comment' => false, // We don't use common header in all our files\n        'heredoc_indentation' => false, // Requires PHP >= 7.3\n        'heredoc_to_nowdoc' => false, // Not sure about this one\n        'implode_call' => true,\n        'include' => true,\n        'increment_style' => true,\n        'indentation_type' => true,\n        'is_null' => true,\n        'line_ending' => true,\n        'linebreak_after_opening_tag' => true,\n        'list_syntax' => ['syntax' => 'short'],\n        'logical_operators' => true,\n        'lowercase_cast' => true,\n        'lowercase_keywords' => true,\n        'lowercase_static_reference' => true,\n        'magic_constant_casing' => true,\n        'magic_method_casing' => true,\n        'mb_str_functions' => false, // No, too dangerous to change that\n        'method_argument_space' => true,\n        'method_chaining_indentation' => true,\n        'modernize_types_casting' => true,\n        'multiline_comment_opening_closing' => true,\n        'multiline_whitespace_before_semicolons' => true,\n        'native_constant_invocation' => false, // Micro optimization that look messy\n        'native_function_casing' => true,\n        'native_function_invocation' => false, // I suppose this would be best, but I am still unconvinced about the visual aspect of it\n        'native_function_type_declaration_casing' => true,\n        'new_with_braces' => true,\n        'no_alias_functions' => true,\n        'no_alternative_syntax' => true,\n        'no_binary_string' => true,\n        'no_blank_lines_after_class_opening' => true,\n        'no_blank_lines_after_phpdoc' => true,\n        'no_blank_lines_before_namespace' => false, // we want 1 blank line before namespace\n        'no_break_comment' => true,\n        'no_closing_tag' => true,\n        'no_empty_comment' => true,\n        'no_empty_phpdoc' => true,\n        'no_empty_statement' => true,\n        'no_extra_blank_lines' => true,\n        'no_homoglyph_names' => true,\n        'no_leading_import_slash' => true,\n        'no_leading_namespace_whitespace' => true,\n        'no_mixed_echo_print' => true,\n        'no_multiline_whitespace_around_double_arrow' => true,\n        'no_null_property_initialization' => true,\n        'no_php4_constructor' => true,\n        'no_short_bool_cast' => true,\n        'echo_tag_syntax' => ['format' => 'long'],\n        'no_singleline_whitespace_before_semicolons' => true,\n        'no_spaces_after_function_name' => true,\n        'no_spaces_around_offset' => true,\n        'no_spaces_inside_parenthesis' => true,\n        'no_superfluous_elseif' => false, // Might be risky on a huge code base\n        'no_superfluous_phpdoc_tags' => ['allow_mixed' => true],\n        'no_trailing_comma_in_list_call' => true,\n        'no_trailing_comma_in_singleline_array' => true,\n        'no_trailing_whitespace' => true,\n        'no_trailing_whitespace_in_comment' => true,\n        'no_unneeded_control_parentheses' => true,\n        'no_unneeded_curly_braces' => true,\n        'no_unneeded_final_method' => true,\n        'no_unreachable_default_argument_value' => true,\n        'no_unset_cast' => true,\n        'no_unset_on_property' => true,\n        'no_unused_imports' => true,\n        'no_useless_else' => true,\n        'no_useless_return' => true,\n        'no_whitespace_before_comma_in_array' => true,\n        'no_whitespace_in_blank_line' => true,\n        'non_printable_character' => true,\n        'normalize_index_brace' => true,\n        'not_operator_with_space' => false, // No we prefer to keep '!' without spaces\n        'not_operator_with_successor_space' => false, // idem\n        'nullable_type_declaration_for_default_null_value' => true,\n        'object_operator_without_whitespace' => true,\n        'ordered_class_elements' => false, // We prefer to keep some freedom\n        'ordered_imports' => true,\n        'ordered_interfaces' => true,\n        'php_unit_construct' => true,\n        'php_unit_dedicate_assert' => true,\n        'php_unit_dedicate_assert_internal_type' => true,\n        'php_unit_expectation' => true,\n        'php_unit_fqcn_annotation' => true,\n        'php_unit_internal_class' => false, // Because tests are excluded from package\n        'php_unit_method_casing' => true,\n        'php_unit_mock' => true,\n        'php_unit_mock_short_will_return' => true,\n        'php_unit_namespaced' => true,\n        'php_unit_no_expectation_annotation' => true,\n        'phpdoc_order_by_value' => ['annotations' => ['covers']],\n        'php_unit_set_up_tear_down_visibility' => true,\n        'php_unit_size_class' => false, // That seems extra work to maintain for little benefits\n        'php_unit_strict' => false, // We sometime actually need assertEquals\n        'php_unit_test_annotation' => true,\n        'php_unit_test_case_static_method_calls' => ['call_type' => 'self'],\n        'php_unit_test_class_requires_covers' => false, // We don't care as much as we should about coverage\n        'phpdoc_add_missing_param_annotation' => false, // Don't add things that bring no value\n        'phpdoc_align' => false, // Waste of time\n        'phpdoc_annotation_without_dot' => true,\n        'phpdoc_indent' => true,\n        //'phpdoc_inline_tag' => true,\n        'phpdoc_line_span' => false, // Unfortunately our old comments turn even uglier with this\n        'phpdoc_no_access' => true,\n        'phpdoc_no_alias_tag' => true,\n        'phpdoc_no_empty_return' => true,\n        'phpdoc_no_package' => true,\n        'phpdoc_no_useless_inheritdoc' => true,\n        'phpdoc_order' => true,\n        'phpdoc_return_self_reference' => true,\n        'phpdoc_scalar' => true,\n        'phpdoc_separation' => true,\n        'phpdoc_single_line_var_spacing' => true,\n        'phpdoc_summary' => true,\n        'phpdoc_to_comment' => false, // interferes with annotations\n        'phpdoc_to_param_type' => false, // Because experimental, but interesting for one shot use\n        'phpdoc_to_return_type' => false, // idem\n        'phpdoc_trim' => true,\n        'phpdoc_trim_consecutive_blank_line_separation' => true,\n        'phpdoc_types' => true,\n        'phpdoc_types_order' => true,\n        'phpdoc_var_annotation_correct_order' => true,\n        'phpdoc_var_without_name' => true,\n        'pow_to_exponentiation' => true,\n        'protected_to_private' => true,\n        'psr_autoloading' => true,\n        'random_api_migration' => true,\n        'return_assignment' => false, // Sometimes useful for clarity or debug\n        'return_type_declaration' => true,\n        'self_accessor' => true,\n        'self_static_accessor' => true,\n        'semicolon_after_instruction' => false, // Buggy in `samples/index.php`\n        'set_type_to_cast' => true,\n        'short_scalar_cast' => true,\n        'simple_to_complex_string_variable' => false, // Would differ from TypeScript without obvious advantages\n        'simplified_null_return' => false, // Even if technically correct we prefer to be explicit\n        'single_blank_line_at_eof' => true,\n        'single_blank_line_before_namespace' => true,\n        'single_class_element_per_statement' => true,\n        'single_import_per_statement' => true,\n        'single_line_after_imports' => true,\n        'single_line_comment_style' => true,\n        'single_line_throw' => false, // I don't see any reason for having a special case for Exception\n        'single_quote' => true,\n        'single_trait_insert_per_statement' => true,\n        'space_after_semicolon' => true,\n        'standardize_increment' => true,\n        'standardize_not_equals' => true,\n        'static_lambda' => false, // Risky if we can't guarantee nobody use `bindTo()`\n        'strict_comparison' => false, // No, too dangerous to change that\n        'strict_param' => false, // No, too dangerous to change that\n        'string_line_ending' => true,\n        'switch_case_semicolon_to_colon' => true,\n        'switch_case_space' => true,\n        'ternary_operator_spaces' => true,\n        'ternary_to_null_coalescing' => true,\n        'trailing_comma_in_multiline' => true,\n        'trim_array_spaces' => true,\n        'unary_operator_spaces' => true,\n        'visibility_required' => ['elements' => ['property', 'method']], // not const\n        'void_return' => true,\n        'whitespace_after_comma_in_array' => true,\n        'yoda_style' => false,\n    ]);\n\nreturn $config;\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to PHPWord\n\nPHPWord is built by the crowd and for the crowd. Every contribution is welcome; either by [reporting a bug](https://github.com/PHPOffice/PHPWord/issues/new?labels=Bug+Report&template=bug_report.md) or [suggesting improvements](https://github.com/PHPOffice/PHPWord/issues/new?labels=Change+Request&template=feature_request.md), or in a more active form like [requesting a pull](https://github.com/PHPOffice/PHPWord/pulls).\n\nWe want to create a high quality document writer and reader library that people can use with more confidence and fewer bugs. We want to collaborate happily, code joyfully, and live merrily. Thus, below are some guidelines that we expect to be followed by each contributor:\n\n- **Be brief, but be bold**. State your issues briefly. But speak out your ideas loudly, even if you can't or don't know how to implement them right away. The world will be better with limitless innovations.\n- **Follow PHP-FIG standards**. We follow PHP Standards Recommendations (PSRs) by [PHP Framework Interoperability Group](http://www.php-fig.org/). If you're not familiar with these standards, [familiarize yourself now](https://github.com/php-fig/fig-standards). Also, please run `composer fix` to automatically fix your code to match these recommendations.\n- **Test your code**. No one knows your code better than you, so we depend on you to test the changes you make before pull request submission. We use [PHPUnit](https://phpunit.de/) for our testing purposes and request that you use this tool too. Tests can be ran with `composer test`. [Documentation for writing tests with PHPUnit is available on Read the Docs.](https://phpunit.readthedocs.io)\n- **Use best practices when submitting pull requests**. Create a separate branch named specifically for the issue that you are addressing. Read the [GitHub manual](https://help.github.com/articles/about-pull-requests) to learn more about pull requests and GitHub. If you are new to GitHub, read [this short manual](https://help.github.com/articles/fork-a-repo) to get yourself familiar with forks and how git works in general. [This video](http://www.youtube.com/watch?v=-zvHQXnBO6c) explains how to synchronize your fork on GitHub with the upstream branch from PHPWord.\n\n## Getting Started\n\n1. [Clone](https://help.github.com/en/articles/cloning-a-repository) [PHPWord](https://github.com/PHPOffice/PHPWord/)\n2. [Install Composer](https://getcomposer.org/download/) if you don't already have it\n3. Open your terminal and:\n  1. Switch to the directory PHPWord was cloned to (e.g., `cd ~/Projects/PHPWord/`)\n  2. Run `composer install` to install the dependencies\n\nYou're ready to start working on PHPWord! Tests belong in the `/tests/PhpWord/` directory, the source code is in `/src/PhpWord/`, and any documentation should go in `/docs/`. Familiarize yourself with the codebase and try your hand at fixing [one of our outstanding issues](https://github.com/PHPOffice/PHPWord/issues). Before you get started, check the [existing pull requests](https://github.com/PHPOffice/PHPWord/pulls) to make sure no one else is already working on it.\n\nOnce you have an issue you want to start working on, you'll need to write tests for it, and then you can start implementing the changes necessary to pass the new tests. To run the tests, you can run one of the following commands in your terminal:\n\n- `composer test-no-coverage` to run all of the tests\n- `composer test` to run all of the tests and generate test coverage reports\n\nWhen you're ready to submit your new (and fully tested) feature, ensure `composer check` passes and [submit a pull request to PHPWord](https://github.com/PHPOffice/PHPWord/issues/new).\n\nThat's it. Thank you for your interest in PHPWord, and welcome!\n\nMay the Force be with you.\n"
  },
  {
    "path": "COPYING",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<http://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<http://www.gnu.org/philosophy/why-not-lgpl.html>.\n"
  },
  {
    "path": "COPYING.LESSER",
    "content": "                   GNU LESSER GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n\n  This version of the GNU Lesser General Public License incorporates\nthe terms and conditions of version 3 of the GNU General Public\nLicense, supplemented by the additional permissions listed below.\n\n  0. Additional Definitions.\n\n  As used herein, \"this License\" refers to version 3 of the GNU Lesser\nGeneral Public License, and the \"GNU GPL\" refers to version 3 of the GNU\nGeneral Public License.\n\n  \"The Library\" refers to a covered work governed by this License,\nother than an Application or a Combined Work as defined below.\n\n  An \"Application\" is any work that makes use of an interface provided\nby the Library, but which is not otherwise based on the Library.\nDefining a subclass of a class defined by the Library is deemed a mode\nof using an interface provided by the Library.\n\n  A \"Combined Work\" is a work produced by combining or linking an\nApplication with the Library.  The particular version of the Library\nwith which the Combined Work was made is also called the \"Linked\nVersion\".\n\n  The \"Minimal Corresponding Source\" for a Combined Work means the\nCorresponding Source for the Combined Work, excluding any source code\nfor portions of the Combined Work that, considered in isolation, are\nbased on the Application, and not on the Linked Version.\n\n  The \"Corresponding Application Code\" for a Combined Work means the\nobject code and/or source code for the Application, including any data\nand utility programs needed for reproducing the Combined Work from the\nApplication, but excluding the System Libraries of the Combined Work.\n\n  1. Exception to Section 3 of the GNU GPL.\n\n  You may convey a covered work under sections 3 and 4 of this License\nwithout being bound by section 3 of the GNU GPL.\n\n  2. Conveying Modified Versions.\n\n  If you modify a copy of the Library, and, in your modifications, a\nfacility refers to a function or data to be supplied by an Application\nthat uses the facility (other than as an argument passed when the\nfacility is invoked), then you may convey a copy of the modified\nversion:\n\n   a) under this License, provided that you make a good faith effort to\n   ensure that, in the event an Application does not supply the\n   function or data, the facility still operates, and performs\n   whatever part of its purpose remains meaningful, or\n\n   b) under the GNU GPL, with none of the additional permissions of\n   this License applicable to that copy.\n\n  3. Object Code Incorporating Material from Library Header Files.\n\n  The object code form of an Application may incorporate material from\na header file that is part of the Library.  You may convey such object\ncode under terms of your choice, provided that, if the incorporated\nmaterial is not limited to numerical parameters, data structure\nlayouts and accessors, or small macros, inline functions and templates\n(ten or fewer lines in length), you do both of the following:\n\n   a) Give prominent notice with each copy of the object code that the\n   Library is used in it and that the Library and its use are\n   covered by this License.\n\n   b) Accompany the object code with a copy of the GNU GPL and this license\n   document.\n\n  4. Combined Works.\n\n  You may convey a Combined Work under terms of your choice that,\ntaken together, effectively do not restrict modification of the\nportions of the Library contained in the Combined Work and reverse\nengineering for debugging such modifications, if you also do each of\nthe following:\n\n   a) Give prominent notice with each copy of the Combined Work that\n   the Library is used in it and that the Library and its use are\n   covered by this License.\n\n   b) Accompany the Combined Work with a copy of the GNU GPL and this license\n   document.\n\n   c) For a Combined Work that displays copyright notices during\n   execution, include the copyright notice for the Library among\n   these notices, as well as a reference directing the user to the\n   copies of the GNU GPL and this license document.\n\n   d) Do one of the following:\n\n       0) Convey the Minimal Corresponding Source under the terms of this\n       License, and the Corresponding Application Code in a form\n       suitable for, and under terms that permit, the user to\n       recombine or relink the Application with a modified version of\n       the Linked Version to produce a modified Combined Work, in the\n       manner specified by section 6 of the GNU GPL for conveying\n       Corresponding Source.\n\n       1) Use a suitable shared library mechanism for linking with the\n       Library.  A suitable mechanism is one that (a) uses at run time\n       a copy of the Library already present on the user's computer\n       system, and (b) will operate properly with a modified version\n       of the Library that is interface-compatible with the Linked\n       Version.\n\n   e) Provide Installation Information, but only if you would otherwise\n   be required to provide such information under section 6 of the\n   GNU GPL, and only to the extent that such information is\n   necessary to install and execute a modified version of the\n   Combined Work produced by recombining or relinking the\n   Application with a modified version of the Linked Version. (If\n   you use option 4d0, the Installation Information must accompany\n   the Minimal Corresponding Source and Corresponding Application\n   Code. If you use option 4d1, you must provide the Installation\n   Information in the manner specified by section 6 of the GNU GPL\n   for conveying Corresponding Source.)\n\n  5. Combined Libraries.\n\n  You may place library facilities that are a work based on the\nLibrary side by side in a single library together with other library\nfacilities that are not Applications and are not covered by this\nLicense, and convey such a combined library under terms of your\nchoice, if you do both of the following:\n\n   a) Accompany the combined library with a copy of the same work based\n   on the Library, uncombined with any other library facilities,\n   conveyed under the terms of this License.\n\n   b) Give prominent notice with the combined library that part of it\n   is a work based on the Library, and explaining where to find the\n   accompanying uncombined form of the same work.\n\n  6. Revised Versions of the GNU Lesser General Public License.\n\n  The Free Software Foundation may publish revised and/or new versions\nof the GNU Lesser General Public License from time to time. Such new\nversions will be similar in spirit to the present version, but may\ndiffer in detail to address new problems or concerns.\n\n  Each version is given a distinguishing version number. If the\nLibrary as you received it specifies that a certain numbered version\nof the GNU Lesser General Public License \"or any later version\"\napplies to it, you have the option of following the terms and\nconditions either of that published version or of any later version\npublished by the Free Software Foundation. If the Library as you\nreceived it does not specify a version number of the GNU Lesser\nGeneral Public License, you may choose any version of the GNU Lesser\nGeneral Public License ever published by the Free Software Foundation.\n\n  If the Library as you received it specifies that a proxy can decide\nwhether future versions of the GNU Lesser General Public License shall\napply, that proxy's public statement of acceptance of any version is\npermanent authorization for you to choose that version for the\nLibrary.\n"
  },
  {
    "path": "LICENSE",
    "content": "PHPWord, a pure PHP library for reading and writing word processing documents.\n\nCopyright (c) 2010-2025 PHPWord.\n\nPHPWord is free software: you can redistribute it and/or modify\nit under the terms of the GNU Lesser General Public License version 3 as published by\nthe Free Software Foundation.\n\nPHPWord is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU Lesser General Public License version 3 for more details.\n\nYou should have received a copy of the GNU Lesser General Public License version 3\nalong with PHPWord. If not, see <http://www.gnu.org/licenses/>.\n"
  },
  {
    "path": "README.md",
    "content": "# ![PHPWord](https://rawgit.com/PHPOffice/PHPWord/develop/docs/images/phpword.svg \"PHPWord\")\n\n[![Latest Stable Version](https://poser.pugx.org/phpoffice/phpword/v)](https://packagist.org/packages/phpoffice/phpword)\n[![Coverage Status](https://coveralls.io/repos/github/PHPOffice/PHPWord/badge.svg?branch=master)](https://coveralls.io/github/PHPOffice/PHPWord?branch=master)\n[![Total Downloads](https://poser.pugx.org/phpoffice/phpword/downloads)](https://packagist.org/packages/phpoffice/phpword)\n[![License](https://poser.pugx.org/phpoffice/phpword/license)](https://packagist.org/packages/phpoffice/phpword)\n\nBranch Master : [![PHPWord](https://github.com/PHPOffice/PHPWord/actions/workflows/php.yml/badge.svg?branch=master)](https://github.com/PHPOffice/PHPWord/actions/workflows/php.yml)\n\nPHPWord is a library written in pure PHP that provides a set of classes to write to and read from different document file formats. The current version of PHPWord supports Microsoft [Office Open XML](http://en.wikipedia.org/wiki/Office_Open_XML) (OOXML or OpenXML), OASIS [Open Document Format for Office Applications](http://en.wikipedia.org/wiki/OpenDocument) (OpenDocument or ODF), [Rich Text Format](http://en.wikipedia.org/wiki/Rich_Text_Format) (RTF), HTML, and PDF.\n\nPHPWord is an open source project licensed under the terms of [LGPL version 3](COPYING.LESSER). PHPWord is aimed to be a high quality software product by incorporating [continuous integration](https://github.com/PHPOffice/PHPWord/actions) and unit testing. You can learn more about PHPWord by reading the [Developers' Documentation](https://phpoffice.github.io/PHPWord/).\n\nIf you have any questions, please ask on [StackOverFlow](https://stackoverflow.com/questions/tagged/phpword)\n\nRead more about PHPWord:\n\n- [Features](#features)\n- [Requirements](#requirements)\n- [Installation](#installation)\n- [Getting started](#getting-started)\n- [Contributing](#contributing)\n- [Developers' Documentation](https://phpoffice.github.io/PHPWord/)\n\n## Features\n\nWith PHPWord, you can create OOXML, ODF, or RTF documents dynamically using your PHP scripts. Below are some of the things that you can do with PHPWord library:\n\n- Set document properties, e.g. title, subject, and creator.\n- Create document sections with different settings, e.g. portrait/landscape, page size, and page numbering\n- Create header and footer for each sections\n- Set default font type, font size, and paragraph style\n- Use UTF-8 and East Asia fonts/characters\n- Define custom font styles (e.g. bold, italic, color) and paragraph styles (e.g. centered, multicolumns, spacing) either as named style or inline in text\n- Insert paragraphs, either as a simple text or complex one (a text run) that contains other elements\n- Insert titles (headers) and table of contents\n- Insert text breaks and page breaks\n- Insert and format images, either local, remote, or as page watermarks\n- Insert binary OLE Objects such as Excel or Visio\n- Insert and format table with customized properties for each rows (e.g. repeat as header row) and cells (e.g. background color, rowspan, colspan)\n- Insert list items as bulleted, numbered, or multilevel\n- Insert hyperlinks\n- Insert footnotes and endnotes\n- Insert drawing shapes (arc, curve, line, polyline, rect, oval)\n- Insert charts (pie, doughnut, bar, line, area, scatter, radar)\n- Insert form fields (textinput, checkbox, and dropdown)\n- Create document from templates\n- Use XSL 1.0 style sheets to transform headers, main document part, and footers of an OOXML template\n- ... and many more features on progress\n\n## Requirements\n\nPHPWord requires the following:\n\n- PHP 7.1+\n- [XML Parser extension](http://www.php.net/manual/en/xml.installation.php)\n- [Laminas Escaper component](https://docs.laminas.dev/laminas-escaper/intro/)\n- [Zip extension](http://php.net/manual/en/book.zip.php) (optional, used to write OOXML and ODF)\n- [GD extension](http://php.net/manual/en/book.image.php) (optional, used to add images)\n- [XMLWriter extension](http://php.net/manual/en/book.xmlwriter.php) (optional, used to write OOXML and ODF)\n- [XSL extension](http://php.net/manual/en/book.xsl.php) (optional, used to apply XSL style sheet to template )\n- [dompdf library](https://github.com/dompdf/dompdf) (optional, used to write PDF)\n\n## Installation\n\nPHPWord is installed via [Composer](https://getcomposer.org/).\nTo [add a dependency](https://getcomposer.org/doc/04-schema.md#package-links) to PHPWord in your project, either\n\nRun the following to use the latest stable version\n```sh\ncomposer require phpoffice/phpword\n```\nor if you want the latest unreleased version\n```sh\ncomposer require phpoffice/phpword:dev-master\n```\n\n## Getting started\n\nThe following is a basic usage example of the PHPWord library.\n\n```php\n<?php\n\n// Creating the new document...\n$phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n\n/* Note: any element you append to a document must reside inside of a Section. */\n\n// Adding an empty Section to the document...\n$section = $phpWord->addSection();\n// Adding Text element to the Section having font styled by default...\n$section->addText(\n    '\"Learn from yesterday, live for today, hope for tomorrow. '\n        . 'The important thing is not to stop questioning.\" '\n        . '(Albert Einstein)'\n);\n\n/*\n * Note: it's possible to customize font style of the Text element you add in three ways:\n * - inline;\n * - using named font style (new font style object will be implicitly created);\n * - using explicitly created font style object.\n */\n\n// Adding Text element with font customized inline...\n$section->addText(\n    '\"Great achievement is usually born of great sacrifice, '\n        . 'and is never the result of selfishness.\" '\n        . '(Napoleon Hill)',\n    array('name' => 'Tahoma', 'size' => 10)\n);\n\n// Adding Text element with font customized using named font style...\n$fontStyleName = 'oneUserDefinedStyle';\n$phpWord->addFontStyle(\n    $fontStyleName,\n    array('name' => 'Tahoma', 'size' => 10, 'color' => '1B2232', 'bold' => true)\n);\n$section->addText(\n    '\"The greatest accomplishment is not in never falling, '\n        . 'but in rising again after you fall.\" '\n        . '(Vince Lombardi)',\n    $fontStyleName\n);\n\n// Adding Text element with font customized using explicitly created font style object...\n$fontStyle = new \\PhpOffice\\PhpWord\\Style\\Font();\n$fontStyle->setBold(true);\n$fontStyle->setName('Tahoma');\n$fontStyle->setSize(13);\n$myTextElement = $section->addText('\"Believe you can and you\\'re halfway there.\" (Theodor Roosevelt)');\n$myTextElement->setFontStyle($fontStyle);\n\n// Saving the document as OOXML file...\n$objWriter = \\PhpOffice\\PhpWord\\IOFactory::createWriter($phpWord, 'Word2007');\n$objWriter->save('helloWorld.docx');\n\n// Saving the document as ODF file...\n$objWriter = \\PhpOffice\\PhpWord\\IOFactory::createWriter($phpWord, 'ODText');\n$objWriter->save('helloWorld.odt');\n\n// Saving the document as HTML file...\n$objWriter = \\PhpOffice\\PhpWord\\IOFactory::createWriter($phpWord, 'HTML');\n$objWriter->save('helloWorld.html');\n\n/* Note: we skip RTF, because it's not XML-based and requires a different example. */\n/* Note: we skip PDF, because \"HTML-to-PDF\" approach is used to create PDF documents. */\n```\n\nMore examples are provided in the [samples folder](samples/). For an easy access to those samples launch `php -S localhost:8000` in the samples directory then browse to [http://localhost:8000](http://localhost:8000) to view the samples.\nYou can also read the [Developers' Documentation](https://phpoffice.github.io/PHPWord/) for more detail.\n\n## Contributing\n\nWe welcome everyone to contribute to PHPWord. Below are some of the things that you can do to contribute.\n\n- Read [our contributing guide](CONTRIBUTING.md).\n- [Fork us](https://github.com/PHPOffice/PHPWord/fork) and [request a pull](https://github.com/PHPOffice/PHPWord/pulls) to the [master](https://github.com/PHPOffice/PHPWord/tree/master) branch.\n- Submit [bug reports or feature requests](https://github.com/PHPOffice/PHPWord/issues) to GitHub.\n- Follow [@PHPOffice](https://twitter.com/PHPOffice) on Twitter.\n"
  },
  {
    "path": "composer.json",
    "content": "{\n    \"name\": \"phpoffice/phpword\",\n    \"description\": \"PHPWord - A pure PHP library for reading and writing word processing documents (OOXML, ODF, RTF, HTML, PDF)\",\n    \"keywords\": [\n        \"PHP\", \"PHPOffice\", \"office\", \"PHPWord\", \"word\", \"template\", \"template processor\", \"reader\", \"writer\",\n        \"docx\", \"OOXML\", \"OpenXML\", \"Office Open XML\", \"ISO IEC 29500\", \"WordprocessingML\",\n        \"RTF\", \"Rich Text Format\", \"doc\", \"odt\", \"ODF\", \"OpenDocument\", \"PDF\", \"HTML\"\n    ],\n    \"homepage\": \"https://phpoffice.github.io/PHPWord/\",\n    \"type\": \"library\",\n    \"license\": \"LGPL-3.0-only\",\n    \"authors\": [\n        {\n            \"name\": \"Mark Baker\"\n        },\n        {\n            \"name\": \"Gabriel Bull\",\n            \"email\": \"me@gabrielbull.com\",\n            \"homepage\": \"http://gabrielbull.com/\"\n        },\n        {\n            \"name\": \"Franck Lefevre\",\n            \"homepage\": \"https://rootslabs.net/blog/\"\n        },\n        {\n            \"name\": \"Ivan Lanin\",\n            \"homepage\": \"http://ivan.lanin.org\"\n        },\n        {\n            \"name\": \"Roman Syroeshko\",\n            \"homepage\": \"http://ru.linkedin.com/pub/roman-syroeshko/34/a53/994/\"\n        },\n        {\n            \"name\": \"Antoine de Troostembergh\"\n        }\n    ],\n    \"scripts\": {\n        \"test\": [\n            \"@php vendor/bin/phpunit --color=always\"\n        ],\n        \"test-no-coverage\": [\n            \"@php vendor/bin/phpunit --color=always --no-coverage\"\n        ],\n        \"check\": [\n            \"@php vendor/bin/php-cs-fixer fix --ansi --dry-run --diff\",\n            \"@php vendor/bin/phpmd src/,tests/ text ./phpmd.xml.dist --exclude pclzip.lib.php\",\n            \"@test-no-coverage\",\n            \"@php vendor/bin/phpstan analyse --ansi\"\n        ],\n        \"fix\": [\n            \"@php vendor/bin/php-cs-fixer fix --ansi\"\n        ], \n        \"samples\": [\n            \"php samples/Sample_01_SimpleText.php\",\n            \"php samples/Sample_02_TabStops.php\",\n            \"php samples/Sample_03_Sections.php\",\n            \"php samples/Sample_04_Textrun.php\",\n            \"php samples/Sample_05_Multicolumn.php\",\n            \"php samples/Sample_06_Footnote.php\",\n            \"php samples/Sample_07_TemplateCloneRow.php\",\n            \"php samples/Sample_08_ParagraphPagination.php\",\n            \"php samples/Sample_09_Tables.php\",\n            \"php samples/Sample_10_EastAsianFontStyle.php\",\n            \"php samples/Sample_11_ReadWord97.php\",\n            \"php samples/Sample_11_ReadWord2007.php\",\n            \"php samples/Sample_12_HeaderFooter.php\",\n            \"php samples/Sample_13_Images.php\",\n            \"php samples/Sample_14_ListItem.php\",\n            \"php samples/Sample_15_Link.php\",\n            \"php samples/Sample_16_Object.php\",\n            \"php samples/Sample_17_TitleTOC.php\",\n            \"php samples/Sample_18_Watermark.php\",\n            \"php samples/Sample_19_TextBreak.php\",\n            \"php samples/Sample_20_BGColor.php\",\n            \"php samples/Sample_21_TableRowRules.php\",\n            \"php samples/Sample_22_CheckBox.php\",\n            \"php samples/Sample_23_TemplateBlock.php\",\n            \"php samples/Sample_24_ReadODText.php\",\n            \"php samples/Sample_25_TextBox.php\",\n            \"php samples/Sample_26_Html.php\",\n            \"php samples/Sample_27_Field.php\",\n            \"php samples/Sample_28_ReadRTF.php\",\n            \"php samples/Sample_29_Line.php\",\n            \"php samples/Sample_30_ReadHTML.php\",\n            \"php samples/Sample_31_Shape.php\",\n            \"php samples/Sample_32_Chart.php\",\n            \"php samples/Sample_33_FormField.php\",\n            \"php samples/Sample_34_SDT.php\",\n            \"php samples/Sample_35_InternalLink.php\",\n            \"php samples/Sample_36_RTL.php\",\n            \"php samples/Sample_37_Comments.php\",\n            \"php samples/Sample_38_Protection.php\",\n            \"php samples/Sample_39_TrackChanges.php\",\n            \"php samples/Sample_40_TemplateSetComplexValue.php\",\n            \"php samples/Sample_41_TemplateSetChart.php\",\n            \"php samples/Sample_42_TemplateSetCheckbox.php\",\n            \"php samples/Sample_43_RTLDefault.php\",\n            \"php samples/Sample_44_ExtractVariablesFromReaderWord2007.php\",\n            \"php samples/Sample_45_Autoloader.php\"\n        ]\n    },\n    \"scripts-descriptions\": {\n        \"test\": \"Runs all unit tests\",\n        \"test-no-coverage\": \"Runs all unit tests, without code coverage\",\n        \"check\": \"Runs PHP CheckStyle and PHP Mess detector\",\n        \"fix\": \"Fixes issues found by PHP-CS\"\n    },\n    \"require\": {\n        \"php\": \"^7.1|^8.0\",\n        \"ext-dom\": \"*\",\n        \"ext-gd\": \"*\",  \n        \"ext-zip\": \"*\",\n        \"ext-json\": \"*\",\n        \"ext-xml\": \"*\",\n        \"phpoffice/math\": \"^0.3\"\n    },\n    \"require-dev\": {\n        \"ext-libxml\": \"*\",\n        \"dompdf/dompdf\": \"^2.0 || ^3.0\",\n        \"friendsofphp/php-cs-fixer\": \"^3.3\",\n        \"mpdf/mpdf\": \"^7.0 || ^8.0\",\n        \"phpmd/phpmd\": \"^2.13\",\n        \"phpstan/phpstan\": \"^0.12.88 || ^1.0.0 || ^2.0.0\",\n        \"phpstan/phpstan-phpunit\": \"^1.0 || ^2.0\",\n        \"phpunit/phpunit\": \">=7.0\",\n        \"symfony/process\": \"^4.4 || ^5.0\",\n        \"tecnickcom/tcpdf\": \"^6.5\"\n    },\n    \"suggest\": {\n        \"ext-xmlwriter\": \"Allows writing OOXML and ODF\",\n        \"ext-xsl\": \"Allows applying XSL style sheet to headers, to main document part, and to footers of an OOXML template\",\n        \"dompdf/dompdf\": \"Allows writing PDF\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"PhpOffice\\\\PhpWord\\\\\": \"src/PhpWord\"\n        }\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"PhpOffice\\\\PhpWordTests\\\\\": \"tests/PhpWordTests\"\n        }\n    }\n}\n"
  },
  {
    "path": "docs/changes/0.x/0.10.0.md",
    "content": "\n# 0.10.0 (4 May 2014)\n\nThis release marked heavy refactorings on internal code structure with the creation of some abstract classes to reduce code duplication. `Element` subnamespace is introduced in this release to replace `Section`. Word2007 reader capability is greatly enhanced. Endnote is introduced. List numbering is now customizable. Basic HTML and PDF writing support is enabled. Basic ODText reader is introduced.\n\n### Features\n- Image: Get image dimensions without EXIF extension - @andrew-kzoo #184\n- Table: Add `tblGrid` element for Libre/Open Office table sizing - @gianis6 #183\n- Footnote: Ability to insert textbreak in footnote `$footnote->addTextBreak()` - @ivanlanin\n- Footnote: Ability to style footnote reference mark by using `FootnoteReference` style - @ivanlanin\n- Font: Add `bgColor` to font style to define background using HEX color - @jcarignan #168\n- Table: Add `exactHeight` to row style to define whether row height should be exact or atLeast - @jcarignan #168\n- Element: New `CheckBox` element for sections and table cells - @ozilion #156\n- Settings: Ability to use PCLZip as alternative to ZipArchive - @bskrtich @ivanlanin #106, #140, #185\n- Template: Ability to find & replace variables in headers & footers - @dgudgeon #190\n- Template: Ability to clone & delete block of text using `cloneBlock` and `deleteBlock` - @diego-vieira #191\n- TOC: Ability to have two or more TOC in one document and to set min and max depth for TOC - @Pyreweb #189\n- Table: Ability to add footnote in table cell - @ivanlanin #187\n- Footnote: Ability to add image in footnote - @ivanlanin #187\n- ListItem: Ability to add list item in header/footer - @ivanlanin #187\n- CheckBox: Ability to add checkbox in header/footer - @ivanlanin #187\n- Link: Ability to add link in header/footer - @ivanlanin #187\n- Object: Ability to add object in header, footer, textrun, and footnote - @ivanlanin #187\n- Media: Add `Media::resetElements()` to reset all media data - @juzi #19\n- General: Add `Style::resetStyles()` - @ivanlanin #187\n- DOCX Reader: Ability to read header, footer, footnotes, link, preservetext, textbreak, pagebreak, table, list, image, and title - @ivanlanin\n- Endnote: Ability to add endnotes - @ivanlanin\n- ListItem: Ability to create custom list and reset list number - @ivanlanin #10, #198\n- ODT Writer: Basic table writing support - @ivanlanin\n- Image: Keep image aspect ratio if only 1 dimension styled - @japonicus #194\n- HTML Writer: Basic HTML writer: text, textrun, link, title, textbreak, table, image (as Base64), footnote, endnote - @ivanlanin #203, #67, #147\n- PDF Writer: Basic PDF writer using DomPDF: All HTML element except image - @ivanlanin #68\n- DOCX Writer: Change `docProps/app.xml` `Application` to `PHPWord` - @ivanlanin\n- DOCX Writer: Create `word/settings.xml` and `word/webSettings.xml` dynamically - @ivanlanin\n- ODT Writer: Basic image writing - @ivanlanin\n- ODT Writer: Link writing - @ivanlanin\n- ODT Reader: Basic ODText Reader - @ivanlanin #71\n- Section: Ability to define gutter and line numbering - @ivanlanin\n- Font: Small caps, all caps, and double strikethrough - @ivanlanin #151\n- Settings: Ability to use measurement unit other than twips with `setMeasurementUnit` - @ivanlanin #199\n- Style: Remove `bgColor` from `Font`, `Table`, and `Cell` and put it into the new `Shading` style - @ivanlanin\n- Style: New `Indentation` and `Spacing` style - @ivanlanin\n- Paragraph: Ability to define first line and right indentation - @ivanlanin\n\n### Bugfixes\n- Footnote: Footnote content doesn't show footnote reference number - @ivanlanin #170\n- Documentation: Error in a function - @theBeerNut #195\n\n### Deprecated\n- `createTextRun` replaced by `addTextRun`\n- `createFootnote` replaced by `addFootnote`\n- `createHeader` replaced by `addHeader`\n- `createFooter` replaced by `addFooter`\n- `createSection` replaced by `addSection`\n- `Element\\Footnote::getReferenceId` replaced by `Element\\AbstractElement::getRelationId`\n- `Element\\Footnote::setReferenceId` replaced by `Element\\AbstractElement::setRelationId`\n- `Footnote::addFootnoteLinkElement` replaced by `Media::addElement`\n- `Footnote::getFootnoteLinkElements` replaced by `Media::getElements`\n- All current methods on `Media`\n- `Element\\Link::getLinkSrc` replaced by `Element\\Link::getTarget`\n- `Element\\Link::getLinkName` replaced by `Element\\Link::getText`\n- `Style\\Cell::getDefaultBorderColor`\n\n### Miscellaneous\n- Documentation: Simplify page level docblock - @ivanlanin #179\n- Writer: Refactor writer classes and create a new `Write\\AbstractWriter` abstract class - @ivanlanin #160\n- General: Refactor folders: `Element` and `Exception` - @ivanlanin #187\n- General: Remove legacy `HashTable` and `Shared\\ZipStreamWrapper` and all related properties/methods - @ivanlanin #187\n- Element: New `AbstractElement` abstract class - @ivanlanin #187\n- Media: Refactor media class to use one method for all docPart (section, header, footer, footnote) - @ivanlanin #187\n- General: Remove underscore prefix from all private properties name - @ivanlanin #187\n- General: Move Section `Settings` to `Style\\Section` - @ivanlanin #187\n- General: Give `Abstract` prefix and `Interface` suffix for all abstract classes and interfaces as per [PHP-FIG recommendation](https://github.com/php-fig/fig-standards/blob/master/bylaws/002-psr-naming-conventions.md) - @ivanlanin #187\n- Style: New `Style\\AbstractStyle` abstract class - @ivanlanin #187\n- Writer: New 'ODText\\Base` class - @ivanlanin #187\n- General: Rename `Footnote` to `Footnotes` to reflect the nature of collection - @ivanlanin\n- General: Add some unit tests for Shared & Element (100%!) - @Progi1984\n- Test: Add some samples and tests for image wrapping style - @brunocasado #59\n- Refactor: Remove Style\\Tabs - @ivanlanin\n- Refactor: Apply composite pattern for writers - @ivanlanin\n- Refactor: Split `AbstractContainer` from `AbstractElement` - @ivanlanin\n- Refactor: Apply composite pattern for Word2007 reader - @ivanlanin\n\n\n"
  },
  {
    "path": "docs/changes/0.x/0.10.1.md",
    "content": "\n\n# 0.10.1 (21 May 2014)\n\nThis is a bugfix release for `php-zip` requirement in Composer.\n\n- Change Composer requirements for php-zip from `require` to `suggest` - @bskrtich #246\n\n\n"
  },
  {
    "path": "docs/changes/0.x/0.11.0.md",
    "content": "# 0.11.0 (1 June 2014)\n\nThis release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Four new elements were added: TextBox, ListItemRun, Field, and Line. Relative and absolute positioning for images and textboxes were added. Writer classes were refactored into parts, elements, and styles. ODT and RTF features were enhanced. Ability to add elements to PHPWord object via HTML were implemented. RTF and HTML reader were initiated.\n\n### Features\n- Image: Ability to define relative and absolute positioning - @basjan #217\n- Footer: Conform footer with header by adding firstPage, evenPage and by inheritance - @basjan @ivanlanin #219\n- Element: New `TextBox` element - @basjan @ivanlanin #228, #229, #231\n- HTML: Ability to add elements to PHPWord object via html - @basjan #231\n- Element: New `ListItemRun` element that can add a list item with inline formatting like a textrun - @basjan #235\n- Table: Ability to add table inside a cell (nested table) - @ivanlanin #149\n- RTF Writer: UTF8 support for RTF: Internal UTF8 text is converted to Unicode before writing - @ivanlanin #158\n- Table: Ability to define table width (in percent and twip) and position - @ivanlanin #237\n- RTF Writer: Ability to add links and page breaks in RTF - @ivanlanin #196\n- ListItemRun: Remove fontStyle parameter because ListItemRun is inherited from TextRun and TextRun doesn't have fontStyle - @ivanlanin\n- Config: Ability to use a config file to store various common settings - @ivanlanin #200\n- ODT Writer: Enable inline font style in TextRun - @ivanlanin\n- ODT Writer: Enable underline, strike/doublestrike, smallcaps/allcaps, superscript/subscript font style - @ivanlanin\n- ODT Writer: Enable section and column - @ivanlanin\n- PDF Writer: Add TCPDF and mPDF as optional PDF renderer library - @ivanlanin\n- ODT Writer: Enable title element and custom document properties - @ivanlanin\n- ODT Reader: Ability to read standard and custom document properties - @ivanlanin\n- Word2007 Writer: Enable the missing custom document properties writer - @ivanlanin\n- Image: Enable \"image float left\" - @ivanlanin #244\n- RTF Writer: Ability to write document properties - @ivanlanin\n- RTF Writer: Ability to write image - @ivanlanin\n- Element: New `Field` element - @basjan #251\n- RTF Reader: Basic RTF reader - @ivanlanin #72, #252\n- Element: New `Line` element - @basjan #253\n- Title: Ability to apply numbering in heading - @ivanlanin #193\n- HTML Reader: Basic HTML reader - @ivanlanin #80, #254\n- RTF Writer: Basic table writing - @ivanlanin #245\n\n### Bugfixes\n- Header: All images added to the second header were assigned to the first header - @basjan #222\n- Conversion: Fix conversion from cm to pixel, pixel to cm, and pixel to point - @basjan #233, #234\n- PageBreak: Page break adds new line in the beginning of the new page - @ivanlanin #150\n- Image: `marginLeft` and `marginTop` cannot accept float value - @ivanlanin #248\n- Title: Orphan `w:fldChar` caused OpenOffice to crash when opening DOCX - @ivanlanin #236\n\n### Deprecated\n- Static classes `Footnotes`, `Endnotes`, and `TOC`\n- `Writer\\Word2007\\Part`: `Numbering::writeNumbering()`, `Settings::writeSettings()`, `WebSettings::writeWebSettings()`, `ContentTypes::writeContentTypes()`, `Styles::writeStyles()`, `Document::writeDocument()` all changed into `write()`\n- `Writer\\Word2007\\Part\\DocProps`: Split into `Writer\\Word2007\\Part\\DocPropsCore` and `Writer\\Word2007\\Part\\DocPropsApp`\n- `Element\\Title::getBookmarkId()` replaced by `Element\\Title::getRelationId()`\n- `Writer\\HTML::writeDocument`: Replaced by `Writer\\HTML::getContent`\n\n### Miscellaneous\n- License: Change the project license from LGPL 2.1 into LGPL 3.0 - #211\n- Word2007 Writer: New `Style\\Image` class - @ivanlanin\n- Refactor: Replace static classes `Footnotes`, `Endnotes`, and `TOC` with `Collections` - @ivanlanin #206\n- QA: Reactivate `phpcpd` and `phpmd` on Travis - @ivanlanin\n- Refactor: PHPMD recommendation: Change all `get...` method that returns `boolean` into `is...` or `has...` - @ivanlanin\n- Docs: Create gh-pages branch for API documentation - @Progi1984 #154\n- QA: Add `.scrutinizer.yml` and include `composer.lock` for preparation to Scrutinizer - @ivanlanin #186\n- Writer: Refactor writer parts using composite pattern - @ivanlanin\n- Docs: Show code quality and test code coverage badge on README\n- Style: Change behaviour of `set...` function of boolean properties; when none is defined, assumed true - @ivanlanin\n- Shared: Unify PHP ZipArchive and PCLZip features into PhpWord ZipArchive - @ivanlanin\n- Docs: Create VERSION file - @ivanlanin\n- QA: Improve dan update requirement check in `samples` folder - @ivanlanin\n\n"
  },
  {
    "path": "docs/changes/0.x/0.11.1.md",
    "content": "# 0.11.1 (2 June 2014)\n\nThis is an immediate bugfix release for HTML reader.\n\n- HTML Reader: `<p>` and header tags puts no output - @canyildiz @ivanlanin #257\n"
  },
  {
    "path": "docs/changes/0.x/0.12.0.md",
    "content": "# 0.12.0 (3 January 2015)\n\nThis release added form fields (textinput, checkbox, and dropdown), drawing shapes (arc, curve, line, polyline, rect, oval), and basic 2D chart (pie, doughnut, bar, line, area, scatter, radar) elements along with some new styles. Basic MsDoc reader is introduced.\n\n### Features\n- Element: Ability to add drawing shapes (arc, curve, line, polyline, rect, oval) using new `Shape` element - @ivanlanin #123\n- Font: New `scale`, `spacing`, and `kerning` property of font style - @ivanlanin\n- Paragraph:  Added shading to the paragraph style for full width shading - @lrobert #264\n- RTF Writer: Support for sections, margins, and borders - @ivanlanin #249\n- Section: Ability to set paper size, e.g. A4, A3, and Legal - @ivanlanin #249\n- General: New `PhpWord::save()` method to encapsulate `IOFactory` - @ivanlanin\n- General: New `Shared\\Converter` static class - @ivanlanin\n- Chart: Basic 2D chart (pie, doughnut, bar, line, area, scatter, radar) - @ivanlanin #278\n- Chart: 3D charts and ability to set width and height - @ivanlanin\n- FormField: Ability to add textinput, checkbox, and dropdown form elements - @ivanlanin #266\n- Setting: Ability to define document protection (readOnly, comments, trackedChanges, forms) - @ivanlanin\n- Setting: Ability to remove [Compatibility Mode] text in the MS Word title bar - @ivanlanin\n- SDT: Ability to add structured document tag elements (comboBox, dropDownList, date) - @ivanlanin\n- Paragraph: Support for paragraph with borders - @ivanlanin #294\n- Word2007 Writer : Support for RTL - @Progi1984 #331\n- MsDOC Reader: Basic MsDOC Reader - @Progi1984 #23, #287\n- \"absolute\" horizontal and vertical positioning of Frame - @basjan #302\n- Add new-page function for PDF generation. For multiple PDF-backends - @chc88 #426\n- Report style options enumerated when style unknown - @h6w\n\n### Bugfixes\n- Fix rare PclZip/realpath/PHP version problem - @andrew-kzoo #261\n- `addHTML` encoding and ampersand fixes for PHP 5.3 - @bskrtich #270\n- Page breaks on titles and tables - @ivanlanin #274\n- Table inside vertical border does not rendered properly - @ivanlanin #280\n- `add<elementName>` of container should be case insensitive, e.g. `addToc` should be accepted, not only `addTOC` - @ivanlanin #294\n- Fix specific borders (and margins) were not written correctly in word2007 writer - @pscheit #327\n- \"HTML is not a valid writer\" exception while running \"Sample_36_RTL.php\" - @RomanSyroeshko #340\n- \"addShape()\" magic method in AbstractContainer is mistakenly named as \"addObject()\" - @GMTA #356\n- `Element\\Section::setPageSizeW()` and `Element\\Section::setPageSizeH()` were mentioned in the docs but not implemented.\n- Special Characters (ampersand) in Title break docx output - @RomanSyroeshko #401\n- `<th>` tag is closed with `</td>` tag: - @franzholz #438\n\n### Deprecated\n- `Element\\Link::getTarget()` replaced by `Element\\Link::getSource()`\n- `Element\\Section::getSettings()` and `Element\\Section::setSettings()` replaced by `Element\\Section::getStyle()` and `Element\\Section::setStyle()`\n- `Shared\\Drawing` and `Shared\\Font` merged into `Shared\\Converter`\n- `DocumentProperties` replaced by `Metadata\\DocInfo`\n- `Template` replaced by `TemplateProcessor`\n- `PhpWord->loadTemplate($filename)`\n\n### Miscellaneous\n- Docs: Add known issue on `README` about requirement for temporary folder to be writable and update `samples/index.php` for this requirement check - @ivanlanin #238\n- Docs: Correct elements.rst about Line - @chrissharkman #292\n- PclZip: Remove temporary file after used - @andrew-kzoo #265\n- Autoloader: Add the ability to set the autoloader options - @bskrtich #267\n- Element: Refactor elements to move set relation Id from container to element - @ivanlanin\n- Introduced CreateTemporaryFileException, CopyFileException - @RomanSyroeshko\n- Settings: added method to set user defined temporary directory - @RomanSyroeshko #310\n- Renamed `Template` into `TemplateProcessor` - @RomanSyroeshko #216\n- Reverted #51. All text escaping must be performed out of the library - @RomanSyroeshko #51\n\n\n\nv"
  },
  {
    "path": "docs/changes/0.x/0.12.1.md",
    "content": "# 0.12.1 (30 August 2015)\n\nMaintenance release. This release is focused primarily on `TemplateProcessor`.\n\n### Changes\n- Changed visibility of all private properties and methods of `TemplateProcessor` to `protected`. - @RomanSyroeshko #498\n- Improved performance of `TemplateProcessor::setValue()`. - @RomanSyroeshko @nicoSWD #513\n\n### Bugfixes\n- Fixed issue with \"Access denied\" message while opening `Sample_07_TemplateCloneRow.docx` and `Sample_23_TemplateBlock.docx` result files on Windows platform. - @RomanSyroeshko @AshSat #532\n- Fixed `PreserveText` element alignment in footer (see `Sample_12_HeaderFooter.php`). - @RomanSyroeshko @SSchwaiger #495\n"
  },
  {
    "path": "docs/changes/0.x/0.13.0.md",
    "content": "# 0.13.0 (31 July 2016)\n\nThis release brings several improvements in `TemplateProcessor`, automatic output escaping feature for OOXML, ODF, HTML, and RTF (turned off, by default).\nIt also introduces constants for horizontal alignment options, and resolves some issues with PHP 7.\nManual installation feature has been dropped since the release. Please, use [Composer](https://getcomposer.org/) to install PHPWord.\n\n### Added\n- Introduced the `\\PhpOffice\\PhpWord\\SimpleType\\Jc` simple type. - @RomanSyroeshko\n- Introduced the `\\PhpOffice\\PhpWord\\SimpleType\\JcTable` simple type. - @RomanSyroeshko\n- Introduced writer for the \"Paragraph Alignment\" element (see `\\PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\ParagraphAlignment`). - @RomanSyroeshko\n- Introduced writer for the \"Table Alignment\" element (see `\\PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\TableAlignment`). - @RomanSyroeshko\n- Supported indexed arrays in arguments of `TemplateProcessor::setValue()`. - @RomanSyroeshko #618\n- Introduced automatic output escaping for OOXML, ODF, HTML, and RTF. To turn the feature on use `phpword.ini` or `\\PhpOffice\\PhpWord\\Settings`. - @RomanSyroeshko #483\n- Supported processing of headers and footers in `TemplateProcessor::applyXslStyleSheet()`. - @RomanSyroeshko #335\n\n### Changed\n- Improved error message for the case when `autoload.php` is not found. - @RomanSyroeshko #371\n- Renamed the `align` option of `NumberingLevel`, `Frame`, `Table`, and `Paragraph` styles into `alignment`. - @RomanSyroeshko\n- Improved performance of `TemplateProcessor::setValue()`. - @kazitanvirahsan #614, #617\n- Fixed some HTML tags not rendering any output (p, header & table) - #257, #324 - @twmobius and @garethellis\n\n### Deprecated\n- `getAlign` and `setAlign` methods of `NumberingLevel`, `Frame`, `Table`, and `Paragraph` styles.\nUse the correspondent `getAlignment` and `setAlignment` methods instead. - @RomanSyroeshko\n- `left`, `right`, and `justify` alignment options for paragraphs (now are mapped to `Jc::START`, `Jc::END`, and `Jc::BOTH`). - @RomanSyroeshko\n- `left`, `right`, and `justify` alignment options for tables (now are mapped to `Jc::START`, `Jc::END`, and `Jc::CENTER`). - @RomanSyroeshko\n- `TCPDF` due to its limited HTML support. Use `DomPDF` or `MPDF` writer instead. - @RomanSyroeshko #399\n\n### Removed\n- `\\PhpOffice\\PhpWord\\Style\\Alignment`. Style properties, which previously stored instances of this class, now deal with strings.\nIn each case set of available string values is defined by the correspondent simple type. - @RomanSyroeshko\n- Manual installation support. Since the release we have dependencies on third party libraries,\nso installation via ZIP-archive download is not an option anymore. To install PHPWord use [Composer](https://getcomposer.org/).\n We also removed `\\PhpOffice\\PhpWord\\Autoloader`, because the latter change made it completely useless.\n Autoloaders provided by Composer are in use now (see `bootstrap.php`). - @RomanSyroeshko\n- `\\PhpOffice\\PhpWord\\Shared\\Drawing` replaced by `\\PhpOffice\\Common\\Drawing`. - @Progi1984 #658\n- `\\PhpOffice\\PhpWord\\Shared\\Font`. - @Progi1984 #658\n- `\\PhpOffice\\PhpWord\\Shared\\String` replaced by `\\PhpOffice\\Common\\Text`. - @Progi1984 @RomanSyroeshko #658\n- `\\PhpOffice\\PhpWord\\Shared\\XMLReader` replaced by `\\PhpOffice\\Common\\XMLReader`. - @Progi1984 #658\n- `\\PhpOffice\\PhpWord\\Shared\\XMLWriter` replaced by `\\PhpOffice\\Common\\XMLWriter`. - @Progi1984 @RomanSyroeshko #658\n- `AbstractContainer::addMemoryImage()`. Use `AbstractContainer::addImage()` instead.\n\n### Fixed\n- `Undefined property` error while reading MS-DOC documents. - @jaberu #610\n- Corrupted OOXML template issue in case when its names is broken immediately after `$` sign.\nThat case wasn't taken into account in implementation of `TemplateProcessor::fixBrokenMacros()`. - @RomanSyroeshko @d-damien #548\n\n"
  },
  {
    "path": "docs/changes/0.x/0.14.0.md",
    "content": "# 0.14.0 (29 Dec 2017)\n\nThis release fixes several bugs and adds some new features.\nThis version brings compatibility with PHP 7.0 & 7.1\n\n### Added\n- Possibility to control the footnote numbering -by [@troosan](https://github.com/troosan) in [#1068](https://github.com/PHPOffice/PHPWord/pull/1068)\n- Image creation from string -by [@troosan](https://github.com/troosan) in [#937](https://github.com/PHPOffice/PHPWord/pull/937)\n- Introduced the `\\PhpOffice\\PhpWord\\SimpleType\\NumberFormat` simple type. - @troosan\n- Support for ContextualSpacing -by [@postHawk](https://github.com/postHawk) in [#1088](https://github.com/PHPOffice/PHPWord/pull/1088)\n- Possiblity to hide spelling and/or grammatical errors -by [@troosan](https://github.com/troosan) in [#542](https://github.com/PHPOffice/PHPWord/pull/542)\n- Possiblity to set default document language as well as changing the language for each text element -by [@troosan](https://github.com/troosan) in [#1108](https://github.com/PHPOffice/PHPWord/pull/1108)\n- Support for Comments -by [@troosan](https://github.com/troosan) in [#1067](https://github.com/PHPOffice/PHPWord/pull/1067)\n- Support for paragraph textAlignment -by [@troosan](https://github.com/troosan) in [#1165](https://github.com/PHPOffice/PHPWord/pull/1165)\n- Add support for HTML underline tag `<u>` in addHtml -by [@zNightFalLz](https://github.com/zNightFalLz) in [#1186](https://github.com/PHPOffice/PHPWord/pull/1186)\n- Add support for HTML `<br>` in addHtml - @anrikunby [@troosan](https://github.com/troosan) in [#659](https://github.com/PHPOffice/PHPWord/pull/659)\n- Allow to change cell width unit - guillaume-ro-fr #986\n- Allow to change the line height rule @troosan\n- Implement PageBreak for odt writerby [@cookiekiller](https://github.com/cookiekiller) in [#863](https://github.com/PHPOffice/PHPWord/pull/863) #824\n- Allow to force an update of all fields on opening a document -by [@troosan](https://github.com/troosan) in [#951](https://github.com/PHPOffice/PHPWord/pull/951)\n- Allow adding a CheckBox in a TextRun -by [@irond](https://github.com/irond) in [#727](https://github.com/PHPOffice/PHPWord/pull/727)\n- Add support for HTML img tag -by [@srggroup](https://github.com/srggroup) in [#934](https://github.com/PHPOffice/PHPWord/pull/934)\n- Add support for password protection for docx -by [@mariahaubner](https://github.com/mariahaubner) in [#1019](https://github.com/PHPOffice/PHPWord/pull/1019)\n\n### Fixed\n- Loosen dependency to Zend\n- Images are not being printed when generating PDF -by [@hubertinio](https://github.com/hubertinio) in [#1074](https://github.com/PHPOffice/PHPWord/pull/1074) #431\n- Fixed some PHP 7 warnings - @\tlikeuntomurphy #927\n- Fixed PHP 7.2 compatibility (renamed `Object` class names to `ObjectElement`) -by [@SailorMax](https://github.com/SailorMax) in [#1185](https://github.com/PHPOffice/PHPWord/pull/1185)\n- Fixed Word 97 reader - @alsofronie @Benpxpxby [@mario-rivera](https://github.com/mario-rivera) in [#912](https://github.com/PHPOffice/PHPWord/pull/912) #920 #892\n- Fixed image loading over https -by [@troosan](https://github.com/troosan) in [#988](https://github.com/PHPOffice/PHPWord/pull/988)\n- Impossibility to set different even and odd page headers -by [@troosan](https://github.com/troosan) in [#981](https://github.com/PHPOffice/PHPWord/pull/981)\n- Fixed Word2007 reader where unnecessary paragraphs were being created -by [@donghaobo](https://github.com/donghaobo) in [#1043](https://github.com/PHPOffice/PHPWord/pull/1043) #620\n- Fixed Word2007 reader where margins were not being read correctly -by [@slowprog](https://github.com/slowprog) in [#885](https://github.com/PHPOffice/PHPWord/pull/885) #1008\n- Impossible to add element PreserveText in Section -by [@rvanlaak](https://github.com/rvanlaak) in [#452](https://github.com/PHPOffice/PHPWord/pull/452)\n- Added missing options for numbering format -by [@troosan](https://github.com/troosan) in [#1041](https://github.com/PHPOffice/PHPWord/pull/1041)\n- Fixed impossibility to set a different footer for first page -by [@ctrlaltca](https://github.com/ctrlaltca) in [#1116](https://github.com/PHPOffice/PHPWord/pull/1116),by [@aoloe](https://github.com/aoloe) in [#875](https://github.com/PHPOffice/PHPWord/pull/875)\n- Fixed styles not being applied by HTML writer, better pdf output -by [@sarke](https://github.com/sarke) in [#1047](https://github.com/PHPOffice/PHPWord/pull/1047) #500 #1139\n- Fixed read docx error when document contains image from remote url -by [@FBnil](https://github.com/FBnil) in [#1173](https://github.com/PHPOffice/PHPWord/pull/1173) #1176\n- Padded the $args array to remove error -by [@kaigoh](https://github.com/kaigoh) in [#1150](https://github.com/PHPOffice/PHPWord/pull/1150),by [@reformed](https://github.com/reformed) in [#870](https://github.com/PHPOffice/PHPWord/pull/870)\n- Fix incorrect image size between windows and mac -by [@bskrtich](https://github.com/bskrtich) in [#874](https://github.com/PHPOffice/PHPWord/pull/874)\n- Fix adding HTML table to document - @mogilvieby [@arivanbastos](https://github.com/arivanbastos) in [#324](https://github.com/PHPOffice/PHPWord/pull/324)\n- Fix parsing on/off values (w:val=\"true|false|1|0|on|off\") -by [@troosan](https://github.com/troosan) in [#1221](https://github.com/PHPOffice/PHPWord/pull/1221) #1219\n- Fix error on Empty Dropdown Entry -by [@ComputerTinker](https://github.com/ComputerTinker) in [#592](https://github.com/PHPOffice/PHPWord/pull/592)\n\n### Deprecated\n- PhpWord->getProtection(), get it from the settings instead PhpWord->getSettings()->getDocumentProtection();\n"
  },
  {
    "path": "docs/changes/0.x/0.15.0.md",
    "content": "# 0.15.0 (14 Jul 2018)\n\n### Added\n- Parsing of `align` HTML attribute -by [@troosan](https://github.com/troosan) in [#1231](https://github.com/PHPOffice/PHPWord/pull/1231)\n- Parse formatting inside HTML lists - @troosanby [@samimussbach](https://github.com/samimussbach) in [#1239](https://github.com/PHPOffice/PHPWord/pull/1239) / [#945](https://github.com/PHPOffice/PHPWord/pull/945) / [#1215](https://github.com/PHPOffice/PHPWord/pull/1215) / [#508](https://github.com/PHPOffice/PHPWord/pull/508)\n- Parsing of CSS `direction` instruction, HTML `lang` attribute, formatting inside table cell -by [@troosan](https://github.com/troosan) in [#1273](https://github.com/PHPOffice/PHPWord/pull/1273) / [#1252](https://github.com/PHPOffice/PHPWord/pull/1252) / [#1254](https://github.com/PHPOffice/PHPWord/pull/1254)\n- Add support for Track changes @Cipby [@troosan](https://github.com/troosan) in [#354](https://github.com/PHPOffice/PHPWord/pull/354) / [#1262](https://github.com/PHPOffice/PHPWord/pull/1262)\n- Add support for fixed Table Layout @aoloe @ekopachby [@troosan](https://github.com/troosan) in [#841](https://github.com/PHPOffice/PHPWord/pull/841) / [#1276](https://github.com/PHPOffice/PHPWord/pull/1276)\n- Add support for Cell Spacing @dox07by [@troosan](https://github.com/troosan) in [#1040](https://github.com/PHPOffice/PHPWord/pull/1040)\n- Add parsing of formatting inside lists @atomicalnetby [@troosan](https://github.com/troosan) in [#594](https://github.com/PHPOffice/PHPWord/pull/594)\n- Added support for Vertically Raised or Lowered Text (w:position) @anrikunby [@troosan](https://github.com/troosan) in [#640](https://github.com/PHPOffice/PHPWord/pull/640)\n- Add support for MACROBUTTON field @phryneasby [@troosan](https://github.com/troosan) in [#1021](https://github.com/PHPOffice/PHPWord/pull/1021)\n- Add support for Hyphenationby [@Trainmaster](https://github.com/Trainmaster) in [#1282](https://github.com/PHPOffice/PHPWord/pull/1282) (Document: `autoHyphenation`, `consecutiveHyphenLimit`, `hyphenationZone`, `doNotHyphenateCaps`, Paragraph: `suppressAutoHyphens`)\n- Added support for Floating Table Positioning (tblpPr)by [@anrikun](https://github.com/anrikun) in [#639](https://github.com/PHPOffice/PHPWord/pull/639)\n- Added support for Image text wrapping distanceby [@troosan](https://github.com/troosan) in [#1310](https://github.com/PHPOffice/PHPWord/pull/1310)\n- Added parsing of CSS line-height and text-indent in HTML readerby [@troosan](https://github.com/troosan) in [#1316](https://github.com/PHPOffice/PHPWord/pull/1316)\n- Added the ability to enable gridlines and axislabels on chartsby [@FrankMeyer](https://github.com/FrankMeyer) in [#576](https://github.com/PHPOffice/PHPWord/pull/576)\n- Add support for table indent (tblInd)by [@Trainmaster](https://github.com/Trainmaster) in [#1343](https://github.com/PHPOffice/PHPWord/pull/1343)\n- Added parsing of internal links in HTML readerby [@lalop](https://github.com/lalop) in [#1336](https://github.com/PHPOffice/PHPWord/pull/1336)\n- Several improvements to chartsby [@JAEK-S](https://github.com/JAEK-S) in [#1332](https://github.com/PHPOffice/PHPWord/pull/1332)\n- Add parsing of html image in base64 formatby [@jgpATs2w](https://github.com/jgpATs2w) in [#1382](https://github.com/PHPOffice/PHPWord/pull/1382)\n- Added Support for Indentation & Tabs on RTF Writer.by [@smaug1985](https://github.com/smaug1985) in [#1405](https://github.com/PHPOffice/PHPWord/pull/1405)\n- Allows decimal numbers in HTML line-height styleby [@jgpATs2w](https://github.com/jgpATs2w) in [#1413](https://github.com/PHPOffice/PHPWord/pull/1413)\n\n### Fixed\n- Fix reading of docx default style -by [@troosan](https://github.com/troosan) in [#1238](https://github.com/PHPOffice/PHPWord/pull/1238)\n- Fix the size unit of when parsing html images -by [@troosan](https://github.com/troosan) in [#1254](https://github.com/PHPOffice/PHPWord/pull/1254)\n- Fixed HTML parsing of nested lists -by [@troosan](https://github.com/troosan) in [#1265](https://github.com/PHPOffice/PHPWord/pull/1265)\n- Save PNG alpha information when using remote images.by [@samsullivan](https://github.com/samsullivan) in [#779](https://github.com/PHPOffice/PHPWord/pull/779)\n- Fix parsing of `<w:br/>` tag.by [@troosan](https://github.com/troosan) in [#1274](https://github.com/PHPOffice/PHPWord/pull/1274)\n- Bookmark are not writton as internal link in html writerby [@troosan](https://github.com/troosan) in [#1263](https://github.com/PHPOffice/PHPWord/pull/1263)\n- It should be possible to add a Footnote in a ListItemRunby [@troosan](https://github.com/troosan) in [#1287](https://github.com/PHPOffice/PHPWord/pull/1287) #1287\n- Fix colspan and rowspan for tables in HTML Writerby [@mattbolt](https://github.com/mattbolt) in [#1292](https://github.com/PHPOffice/PHPWord/pull/1292)\n- Fix parsing of Heading and Title formating @troosanby [@gthomas2](https://github.com/gthomas2) in [#465](https://github.com/PHPOffice/PHPWord/pull/465)\n- Fix Dateformat typo, fix hours casing, add Month-Day-Year formatsby [@ComputerTinker](https://github.com/ComputerTinker) in [#591](https://github.com/PHPOffice/PHPWord/pull/591)\n- Support reading of w:drawing for documents produced by word 2011+by [@gthomas2](https://github.com/gthomas2) in [#464](https://github.com/PHPOffice/PHPWord/pull/464) #1324\n- Fix missing column width in ODText writerby [@potofcoffee](https://github.com/potofcoffee) in [#413](https://github.com/PHPOffice/PHPWord/pull/413)\n- Disable entity loader before parsing XML to avoid XXE injectionby [@Tom4t0](https://github.com/Tom4t0) in [#1427](https://github.com/PHPOffice/PHPWord/pull/1427)\n\n### Changed\n- Remove zend-stdlib dependencyby [@Trainmaster](https://github.com/Trainmaster) in [#1284](https://github.com/PHPOffice/PHPWord/pull/1284)\n- The default unit for `\\PhpOffice\\PhpWord\\Style\\Image` changed from `px` to `pt`.\n\n### Miscellaneous\n- Drop GitHub pages, switch to coveralls for code coverage analysisby [@czosel](https://github.com/czosel) in [#1360](https://github.com/PHPOffice/PHPWord/pull/1360)\n"
  },
  {
    "path": "docs/changes/0.x/0.16.0.md",
    "content": "# 0.16.0 (30 dec 2018)\n\n### Added\n- Add getVariableCount method in TemplateProcessor.by [@nicoder](https://github.com/nicoder) in [#1272](https://github.com/PHPOffice/PHPWord/pull/1272)\n- Add setting Chart Title and Legend visibilityby [@Tom-Magill](https://github.com/Tom-Magill) in [#1433](https://github.com/PHPOffice/PHPWord/pull/1433)\n- Add ability to pass a Style object in Section constructorby [@ndench](https://github.com/ndench) in [#1416](https://github.com/PHPOffice/PHPWord/pull/1416)\n- Add support for hidden textby [@Alexmg86](https://github.com/Alexmg86) in [#1527](https://github.com/PHPOffice/PHPWord/pull/1527)\n- Add support for setting images in TemplateProcessorby [@SailorMax](https://github.com/SailorMax) in [#1170](https://github.com/PHPOffice/PHPWord/pull/1170)\n- Add \"Plain Text\" type to SDT (Structured Document Tags)by [@morrisdj](https://github.com/morrisdj) in [#1541](https://github.com/PHPOffice/PHPWord/pull/1541)\n- Added possibility to index variables inside cloned block in TemplateProcessorby [@JPBetley](https://github.com/JPBetley) in [#817](https://github.com/PHPOffice/PHPWord/pull/817)\n- Added possibility to replace variables inside cloned block with values in TemplateProcessorby [@DIDoS](https://github.com/DIDoS) in [#1392](https://github.com/PHPOffice/PHPWord/pull/1392)\n\n### Fixed\n- Fix regex in `cloneBlock` functionby [@nicoder](https://github.com/nicoder) in [#1269](https://github.com/PHPOffice/PHPWord/pull/1269)\n- HTML Title Writer loses text when Title contains a TextRun instead a string.by [@begnini](https://github.com/begnini) in [#1436](https://github.com/PHPOffice/PHPWord/pull/1436)\n- Fix regex in fixBrokenMacros, make it less greedy @MuriloSo @brainwoodby [@yurii-sio2](https://github.com/yurii-sio2) in [#1502](https://github.com/PHPOffice/PHPWord/pull/1502) / [#1345](https://github.com/PHPOffice/PHPWord/pull/1345)\n- 240 twips are being added to line spacing, should not happen when using lineRule fixedby [@troosan](https://github.com/troosan) in [#1509](https://github.com/PHPOffice/PHPWord/pull/1509) / [#1505](https://github.com/PHPOffice/PHPWord/pull/1505)\n- Adding table layout to the generated HTMLby [@aarangara](https://github.com/aarangara) in [#1441](https://github.com/PHPOffice/PHPWord/pull/1441)\n- Fix loading of Sharepoint documentby [@Garrcomm](https://github.com/Garrcomm) in [#1498](https://github.com/PHPOffice/PHPWord/pull/1498)\n- RTF writer: Round getPageSizeW and getPageSizeH to avoid decimalsby [@Patrick64](https://github.com/Patrick64) in [#1493](https://github.com/PHPOffice/PHPWord/pull/1493)\n- Fix parsing of Office 365 documentsby [@Timanx](https://github.com/Timanx) in [#1485](https://github.com/PHPOffice/PHPWord/pull/1485)\n- For RTF writers, sizes should should never have decimalsby [@Samuel-BF](https://github.com/Samuel-BF) in [#1536](https://github.com/PHPOffice/PHPWord/pull/1536)\n- Style Name Parsing fails if document generated by a non-english word versionby [@begnini](https://github.com/begnini) in [#1434](https://github.com/PHPOffice/PHPWord/pull/1434)\n\n### Miscellaneous\n- Get rid of duplicated code in TemplateProcessorby [@abcdmitry](https://github.com/abcdmitry) in [#1161](https://github.com/PHPOffice/PHPWord/pull/1161)\n\n"
  },
  {
    "path": "docs/changes/0.x/0.17.0.md",
    "content": "# 0.17.0 (01 oct 2019)\n\n### Added\n- Add methods setValuesFromArray and cloneRowFromArray to the TemplateProcessor [@geraldb-nicat](https://github.com/geraldb-nicat) GH-670\n- Set complex type in template [@troosan](https://github.com/troosan) GH-1565\n- implement support for section vAlign [@troosan](https://github.com/troosan) GH-1569\n- ParseStyle for border-color [@Gllrm0](https://github.com/Gllrm0) GH-1551\n- Html writer auto invert text color [@SailorMax](https://github.com/SailorMax) GH-1387\n- Add RightToLeft table presentation. [@troosan](https://github.com/troosan) GH-1550\n- Add support for page vertical alignment. [@troosan](https://github.com/troosan) GH-672 GH-1569\n- Adding setNumId method for ListItem style [@eweso](https://github.com/eweso) GH-1329\n- Add support for basic fields in RTF writer. [@Samuel-BF](https://github.com/Samuel-BF) GH-1717\n\n### Fixed\n- Fix HTML border-color parsing. [@troosan](https://github.com/troosan) GH-1551 / GH-1570\n- Language::validateLocale should pass with locale 'zxx'. [@efpapado](https://github.com/efpapado) GH-1558\n- can't align center vertically with the text [@ter987](https://github.com/ter987) GH-672\n- fix parsing of border-color and add test [@troosan](https://github.com/troosan) GH-1570\n- TrackChange doesn't handle all return types of \\DateTime::createFromFormat(...) [@superhaggis](https://github.com/superhaggis) GH-1584\n- To support PreserveText inside sub container [@bhattnishant](https://github.com/bhattnishant) GH-1637\n- No nested w:pPr elements in ListItemRun. [@waltertamboer](https://github.com/waltertamboer) GH-1628\n- Ensure that entity_loader disable variable is re-set back to the original setting [@seamuslee001](https://github.com/seamuslee001) GH-1585\n\n### Miscellaneous\n- Use embedded http server to test loading of remote images [@troosan](https://github.com/troosan) GH-1544\n- Change private to protected to be able extending class Html [@SpinyMan](https://github.com/SpinyMan) GH-1646\n- Fix apt-get crash in Travis CI for PHP 5.3 [@mdupont](https://github.com/mdupont) GH-1707"
  },
  {
    "path": "docs/changes/0.x/0.18.0.md",
    "content": "# [0.18.0](https://github.com/PHPOffice/PHPWord/tree/0.18.0) (2021-02-12)\n\n[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/0.17.0...0.18.0)\n\n### Enhancements\n- Add support for charts in template processor [#2012](https://github.com/PHPOffice/PHPWord/pull/2012) ([@dbarzin](https://github.com/dbarzin))\n- add/setting page element border style. [#1986](https://github.com/PHPOffice/PHPWord/pull/1986) ([@emnabs](https://github.com/emnabs))\n- allow to use customized pdf library [#1983](https://github.com/PHPOffice/PHPWord/pull/1983) ([@SailorMax](https://github.com/SailorMax))\n- feat: Update addHtml to handle style inheritance [#1965](https://github.com/PHPOffice/PHPWord/pull/1965) ([@Julien1138](https://github.com/Julien1138))\n- Add parsing of Shape node values [#1924](https://github.com/PHPOffice/PHPWord/pull/1924) ([@sven-ahrens](https://github.com/sven-ahrens))\n- Allow to redefine TCPDF object [#1907](https://github.com/PHPOffice/PHPWord/pull/1907) ([@SailorMax](https://github.com/SailorMax))\n- Enhancements to addHTML parser [#1902](https://github.com/PHPOffice/PHPWord/pull/1902) ([@lubosdz](https://github.com/lubosdz))\n- Make Default Paper Configurable [#1851](https://github.com/PHPOffice/PHPWord/pull/1851) ([@oleibman](https://github.com/oleibman))\n- Implement various missing features for the ODT writer [#1796](https://github.com/PHPOffice/PHPWord/pull/1796) ([@oleibman](https://github.com/oleibman))\n- Added support for \"cloudConvert\" images [#1794](https://github.com/PHPOffice/PHPWord/pull/1794) ([@ErnestStaug](https://github.com/ErnestStaug))\n- Add support for several features for the RTF writer [#1775](https://github.com/PHPOffice/PHPWord/pull/1775) ([@oleibman](https://github.com/oleibman))\n- Add font style for Field elements [#1774](https://github.com/PHPOffice/PHPWord/pull/1774) ([@oleibman](https://github.com/oleibman))\n- Add support for ListItemRun in HTML writer [#1766](https://github.com/PHPOffice/PHPWord/pull/1766) ([@stefan-91](https://github.com/stefan-91))\n- Improvements in RTF writer [#1755](https://github.com/PHPOffice/PHPWord/pull/1755) ([@oleibman](https://github.com/oleibman))\n- Allow a closure to be passed with image replacement tags [#1716](https://github.com/PHPOffice/PHPWord/pull/1716) ([@mbardelmeijer](https://github.com/mbardelmeijer))\n- Add Option for Dynamic Chart Legend Position [#1699](https://github.com/PHPOffice/PHPWord/pull/1699) ([@Stephan212](https://github.com/Stephan212))\n- Add parsing of HTML checkbox input field [#1832](https://github.com/PHPOffice/PHPWord/pull/1832) ([@Matze2010](https://github.com/Matze2010))\n\n### Bug fixes\n- Fix image stroke in libreoffice 7.x [#1992](https://github.com/PHPOffice/PHPWord/pull/1992) ([@Adizbek](https://github.com/Adizbek))\n- Fix deprecated warning for non-hexadecimal number [#1988](https://github.com/PHPOffice/PHPWord/pull/1988) ([@Ciki](https://github.com/Ciki))\n- Fix limit not taken into account when adding image in template [#1967](https://github.com/PHPOffice/PHPWord/pull/1967) ([@jsochor](https://github.com/jsochor))\n- Add null check when setComplexValue is not found [#1936](https://github.com/PHPOffice/PHPWord/pull/1936) ([@YannikFirre](https://github.com/YannikFirre))\n- Some document have non-standard locale code [#1824](https://github.com/PHPOffice/PHPWord/pull/1824) ([@ErnestStaug](https://github.com/ErnestStaug))\n- Fixes PHPDoc @param and @return types for several Converter methods [#1818](https://github.com/PHPOffice/PHPWord/pull/1818) ([@caugner](https://github.com/caugner))\n- Update the regexp to avoid catastrophic backtracking [#1809](https://github.com/PHPOffice/PHPWord/pull/1809) ([@juzser](https://github.com/juzser))\n- Fix PHPUnit tests on develop branch [#1771](https://github.com/PHPOffice/PHPWord/pull/1771) ([@mdupont](https://github.com/mdupont))\n- TemplateProcessor cloneBlock wrongly clones images [#1763](https://github.com/PHPOffice/PHPWord/pull/1763) ([@alarai](https://github.com/alarai))\n\n### Miscellaneous\n- Compatibility with PHP 7.4, PHP 8.0 and migrate to Laminas Escaper [#1946](https://github.com/PHPOffice/PHPWord/pull/1946) ([@liborm85](https://github.com/liborm85))\n- Remove legacy PHPOffice/Common package, fix PHP 8.0 compatibility [#1996](https://github.com/PHPOffice/PHPWord/pull/1996) ([@liborm85](https://github.com/liborm85))\n- Improve Word2007 Test Coverage [#1858](https://github.com/PHPOffice/PHPWord/pull/1858) ([@oleibman](https://github.com/oleibman))\n- Fix typo in docs. Update templates-processing.rst [#1952](https://github.com/PHPOffice/PHPWord/pull/1952) ([@mnvx](https://github.com/mnvx))\n- Fix documentation and method name for FootnoteProperties [#1776](https://github.com/PHPOffice/PHPWord/pull/1776) ([@mdupont](https://github.com/mdupont))\n- fix: documentation about paragraph indentation [#1764](https://github.com/PHPOffice/PHPWord/pull/1764) ([@mdupont](https://github.com/mdupont))\n- Update templates-processing.rst [#1745](https://github.com/PHPOffice/PHPWord/pull/1745) ([@igronus](https://github.com/igronus))\n- Unused variables $rows, $cols in sample [#1877](https://github.com/PHPOffice/PHPWord/pull/1877) ([@ThanasisMpalatsoukas](https://github.com/ThanasisMpalatsoukas))\n- Add unit test for NumberingStyle [#1744](https://github.com/PHPOffice/PHPWord/pull/1744) ([@Manunchik](https://github.com/Manunchik))\n- Add unit test for PhpWord Settings [#1743](https://github.com/PHPOffice/PHPWord/pull/1743) (@[Manunchik](https://github.com/Manunchik))\n- Add unit test for Media elements [#1742](https://github.com/PHPOffice/PHPWord/pull/1742) ([@Manunchik](https://github.com/Manunchik))\n- Update templates processing docs [#1729](https://github.com/PHPOffice/PHPWord/pull/1729) ([@hcdias](https://github.com/hcdias))\n"
  },
  {
    "path": "docs/changes/0.x/0.18.1.md",
    "content": "# [0.18.1](https://github.com/PHPOffice/PHPWord/tree/0.18.1) (2021-03-08)\n\n[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/0.18.0...0.18.1)\n\n### Bug fixes\n- Fix BC break in GH-1946. \n    This package does not replace laminas/laminas-zendframework-bridge by [@mussbach](https://github.com/mussbach) in [#2032](https://github.com/PHPOffice/PHPWord/pull/2032)"
  },
  {
    "path": "docs/changes/0.x/0.18.2.md",
    "content": "# [0.18.2](https://github.com/PHPOffice/PHPWord/tree/0.18.2) (2021-06-04)\n\n[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/0.18.1...0.18.2)\n\n### Bug fixes\n- when adding image to relationship first check that the generated RID is actually unique by [@tpv-ebben](https://github.com/tpv-ebben) in [#2063](https://github.com/PHPOffice/PHPWord/pull/2063)\n- Update chart, don't write 'c:overlap' if grouping is 'clustered' by [@dfsd534](https://github.com/dfsd534) in [#2052](https://github.com/PHPOffice/PHPWord/pull/2052)\n- Update Html parser to accept line-height:normal by [@joelgo](https://github.com/joelgo) in [#2041](https://github.com/PHPOffice/PHPWord/pull/2041)\n- Fix image border in Word2007 Writer for LibreOffice 7 by [k@amilmmach](https://github.com/kamilmmach) in [#2021](https://github.com/PHPOffice/PHPWord/pull/2021)\n\n### Miscellaneous\n- Corrected namespace for Language class in docs by [@MegaChriz](https://github.com/MegaChriz) in [#2087](https://github.com/PHPOffice/PHPWord/pull/2087)\n- Added support for Garamond font by [@artemkolotilkin](https://github.com/artemkolotilkin) in [#2078](https://github.com/PHPOffice/PHPWord/pull/2078)\n- Add BorderStyle for Cell Style to documentation by [@DShkrabak](https://github.com/DShkrabak) in [#2090](https://github.com/PHPOffice/PHPWord/pull/2090)\n"
  },
  {
    "path": "docs/changes/0.x/0.18.3.md",
    "content": "# [0.18.3](https://github.com/PHPOffice/PHPWord/tree/0.18.3) (2022-02-17)\n\n[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/0.18.2...0.18.3)\n\n### Bug fixes\n- PHP 8.1 compatibility\n"
  },
  {
    "path": "docs/changes/0.x/0.7.0.md",
    "content": "# 0.7.0 (28 Jan 2014)\n\nThis is the first release after a long development hiatus in [CodePlex](https://phpword.codeplex.com/). This release initialized ODT and RTF Writer, along with some other new features for the existing Word2007 Writer, e.g. tab, multiple header, rowspan and colspan. [Composer](https://packagist.org/packages/phpoffice/phpword) and [Travis](https://travis-ci.org/PHPOffice/PHPWord) were added.\n\n### Features\n- Implement RTF Writer - @Progi1984 #1\n- Implement ODT Writer - @Progi1984 #2\n- Word2007: Add rowspan and colspan to cells - @kaystrobach\n- Word2007: Support for tab stops - @RLovelett\n- Word2007: Support Multiple headers - @RLovelett\n- Word2007: Wrapping Styles to Images - @gabrielbull\n- Added support for image wrapping style - @gabrielbull\n\n### Bugfixes\n- \"Warning: Invalid error type specified in ...\\PHPWord.php on line 226\" is thrown when the specified template file is not found - @RomanSyroeshko #32\n- PHPWord_Shared_String.IsUTF8 returns FALSE for Cyrillic UTF-8 input - @RomanSyroeshko #34\n- Temporary files naming logic in PHPWord_Template can lead to a collision - @RomanSyroeshko #38\n\n### Miscellaneous\n- Add superscript/subscript styling in Excel2007 Writer - @MarkBaker\n- add indentation support to paragraphs - @deds\n- Support for Composer - @Progi1984 #27\n- Basic CI with Travis - @Progi1984\n- Added PHPWord_Exception and exception when could not copy the template - @Progi1984\n- IMPROVED: Moved examples out of Classes directory - @Progi1984\n- IMPROVED: Advanced string replace in setValue for Template - @Esmeraldo [#49](http://phpword.codeplex.com/workitem/49)"
  },
  {
    "path": "docs/changes/0.x/0.8.0.md",
    "content": "# 0.8.0 (15 Mar 2014)\n\nThis release merged a lot of improvements from the community. Unit tests introduced in this release and has reached 90% code coverage.\n\n### Features\n- Template: Permit to save a template generated as a file (PHPWord_Template::saveAs()) - @RomanSyroeshko #56, #57\n- Word2007: Support sections page numbering - @gabrielbull\n- Word2007: Added line height methods to mirror the line height settings in Word in the paragraph styling - @gabrielbull\n- Word2007: Added support for page header & page footer height - @JillElaine #5\n- General: Add ability to manage line breaks after image insertion - @bskrtich #6, #66, #84\n- Template: Ability to limit number of replacements performed by setValue() method of Template class - @RomanSyroeshko #52, #53, #85\n- Table row: Repeat as header row & allow row to break across pages - @ivanlanin #48, #86\n- Table: Table width in percentage - @ivanlanin #48, #86\n- Font: Superscript and subscript - @ivanlanin #48, #86\n- Paragraph: Hanging paragraph - @ivanlanin #48, #86\n- Section: Multicolumn and section break - @ivanlanin #48, #86\n- Template: Ability to apply XSL style sheet to Template - @RomanSyroeshko #46, #47, #83\n- General: PHPWord_Shared_Font::pointSizeToTwips() converter - @ivanlanin #87\n- Paragraph: Ability to define normal paragraph style with PHPWord::setNormalStyle() - @ivanlanin #87\n- Paragraph: Ability to define parent style (basedOn) and style for following paragraph (next) - @ivanlanin #87\n- Clone table rows on the fly when using a template document - @jeroenmoors #44, #88\n- Initial addition of basic footnote support - @deds #16\n- Paragraph: Ability to define paragraph pagination: widow control, keep next, keep lines, and page break before - @ivanlanin #92\n- General: PHPWord_Style_Font refactoring - @ivanlanin #93\n- Font: Use points instead of halfpoints internally. Conversion to halfpoints done during XML Writing. - @ivanlanin #93\n- Paragraph: setTabs() function - @ivanlanin #92\n- General: Basic support for TextRun on ODT and RTF - @ivanlanin #99\n- Reader: Basic Reader for Word2007 - @ivanlanin #104\n- TextRun: Allow Text Break in Text Run - @bskrtich  #109\n- General: Support for East Asian fontstyle - @jhfangying #111, #118\n- Image: Use exif_imagetype to check image format instead of extension name - @gabrielbull #114\n- General: Setting for XMLWriter Compatibility option - @bskrtich  #103\n- MemoryImage: Allow remote image when allow_url_open = on - @ivanlanin #122\n- TextBreak: Allow font and paragraph style for text break - @ivanlanin #18\n\n### Bugfixes\n- Fixed bug with cell styling - @gabrielbull\n- Fixed bug list items inside of cells - @gabrielbull\n- Adding a value that contains \"&\" in a template breaks it - @SiebelsTim #51\n- Example in README.md is broken - @Progi1984 #89\n- General: PHPWord_Shared_Drawing::centimetersToPixels() conversion - @ivanlanin #94\n- Footnote: Corrupt DOCX reported by MS Word when sections > 1 and not every sections have footnote - @ivanlanin #125\n\n### Miscellaneous\n- UnitTests - @Progi1984"
  },
  {
    "path": "docs/changes/0.x/0.8.1.md",
    "content": "\n# 0.8.1 (17 Mar 2014)\n\nThis is a bugfix release for image detection functionality.\n\n- Added fallback for computers that do not have exif_imagetype - @bskrtich, @gabrielbull\n\n\n\n"
  },
  {
    "path": "docs/changes/0.x/0.9.0.md",
    "content": "# 0.9.0 (26 Mar 2014)\n\nThis release marked the transformation to namespaces (PHP 5.3+).\n\n### Features\n- Image: Ability to use remote or GD images using `addImage()` on sections, headers, footer, cells, and textruns - @ivanlanin\n- Header: Ability to use remote or GD images using `addWatermark()` - @ivanlanin\n\n### Bugfixes\n- Preserve text doesn't render correctly when the text is not the first word, e.g. 'Page {PAGE}' - @ivanlanin\n\n### Miscellaneous\n- Move documentation to [Read The Docs](http://phpword.readthedocs.org/en/develop/) - by [@Progi1984](https://github.com/Progi1984) & [@ivanlanin](https://github.com/ivanlanin) in [#82](https://github.com/PHPOffice/PHPWord/pull/82)\n- Reorganize and redesign samples folder - @ivanlanin #137\n- Use `PhpOffice\\PhpWord` namespace for PSR compliance - @RomanSyroeshko @gabrielbull #159, #58\n- Restructure folders and change folder name `Classes` to `src` and `Tests` to `test` for PSR compliance - @RomanSyroeshko @gabrielbull\n- Compliance to phpDocumentor - @ivanlanin\n- Merge Style\\TableFull into Style\\Table. Style\\TableFull is deprecated - @ivanlanin #160\n- Merge Section\\MemoryImage into Section\\Image. Section\\Image is deprecated - @ivanlanin #160\n"
  },
  {
    "path": "docs/changes/0.x/0.9.1.md",
    "content": "\n# 0.9.1 (27 Mar 2014)\n\nThis is a bugfix release for PSR-4 compatibility.\n\n- Fixed PSR-4 composer autoloader - @AntonTyutin\n\n\n"
  },
  {
    "path": "docs/changes/1.x/1.0.0.md",
    "content": "# [1.0.0](https://github.com/PHPOffice/PHPWord/tree/1.0.0) (2022-11-15)\n\n[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/0.18.3...1.0.0)\n\n### BREAKING CHANGE\n\nMost deprecated things were dropped. See details in \nhttps://github.com/PHPOffice/PHPWord/commit/b9f1151bc6f90c276153c3c9dca10a5fc7f355fb.\n\n#### Dropped classes:\n\n- `PhpOffice\\PhpWord\\Template`\n\n#### Dropped constants:\n\n- `PhpOffice\\PhpWord\\Style\\Font::UNDERLINE_DOTHASH`\n- `PhpOffice\\PhpWord\\Style\\Font::UNDERLINE_DOTHASHHEAVY`\n- `PhpOffice\\PhpWord\\Style\\Cell::VALIGN_TOP`\n- `PhpOffice\\PhpWord\\Style\\Cell::VALIGN_CENTER`\n- `PhpOffice\\PhpWord\\Style\\Cell::VALIGN_BOTTOM`\n- `PhpOffice\\PhpWord\\Style\\Cell::VALIGN_BOTH`\n- `PhpOffice\\PhpWord\\Style\\TOC::TABLEADER_DOT`\n- `PhpOffice\\PhpWord\\Style\\TOC::TABLEADER_UNDERSCORE`\n- `PhpOffice\\PhpWord\\Style\\TOC::TABLEADER_LINE`\n- `PhpOffice\\PhpWord\\Style\\TOC::TABLEADER_NONE`\n- `PhpOffice\\PhpWord\\Style\\Table::WIDTH_AUTO`\n- `PhpOffice\\PhpWord\\Style\\Table::WIDTH_PERCENT`\n- `PhpOffice\\PhpWord\\Style\\Table::WIDTH_TWIP`\n- `PhpOffice\\PhpWord\\PhpWord::DEFAULT_FONT_NAME`\n- `PhpOffice\\PhpWord\\PhpWord::DEFAULT_FONT_SIZE`\n- `PhpOffice\\PhpWord\\PhpWord::DEFAULT_FONT_COLOR`\n- `PhpOffice\\PhpWord\\PhpWord::DEFAULT_FONT_CONTENT_TYPE`\n- \n#### Dropped methods:\n\n- `PhpOffice\\PhpWord\\Ekement\\AbstractContainer::createTextRun()`\n- `PhpOffice\\PhpWord\\Ekement\\AbstractContainer::createFootnote()`\n- `PhpOffice\\PhpWord\\Ekement\\Footnote::getReferenceId()`\n- `PhpOffice\\PhpWord\\Ekement\\Footnote::setReferenceId()`\n- `PhpOffice\\PhpWord\\Ekement\\Image::getIsWatermark()`\n- `PhpOffice\\PhpWord\\Ekement\\Image::getIsMemImage()`\n- `PhpOffice\\PhpWord\\Ekement\\Link::getTarget()`\n- `PhpOffice\\PhpWord\\Ekement\\Link::getLinkSrc()`\n- `PhpOffice\\PhpWord\\Ekement\\Link::getLinkName()`\n- `PhpOffice\\PhpWord\\Ekement\\OLEObject::getObjectId()`\n- `PhpOffice\\PhpWord\\Ekement\\OLEObject::setObjectId()`\n- `PhpOffice\\PhpWord\\Ekement\\Section::getFootnotePropoperties()`\n- `PhpOffice\\PhpWord\\Ekement\\Section::setSettings()`\n- `PhpOffice\\PhpWord\\Ekement\\Section::getSettings()`\n- `PhpOffice\\PhpWord\\Ekement\\Section::createHeader()`\n- `PhpOffice\\PhpWord\\Ekement\\Section::createFooter()`\n- `PhpOffice\\PhpWord\\Ekement\\Section::getFooter()`\n- `PhpOffice\\PhpWord\\Media::addSectionMediaElement()`\n- `PhpOffice\\PhpWord\\Media::addSectionLinkElement()`\n- `PhpOffice\\PhpWord\\Media::getSectionMediaElements()`\n- `PhpOffice\\PhpWord\\Media::countSectionMediaElements()`\n- `PhpOffice\\PhpWord\\Media::addHeaderMediaElement()`\n- `PhpOffice\\PhpWord\\Media::countHeaderMediaElements()`\n- `PhpOffice\\PhpWord\\Media::getHeaderMediaElements()`\n- `PhpOffice\\PhpWord\\Media::addFooterMediaElement()`\n- `PhpOffice\\PhpWord\\Media::countFooterMediaElements()`\n- `PhpOffice\\PhpWord\\Media::getFooterMediaElements()`\n- `PhpOffice\\PhpWord\\PhpWord::getProtection()`\n- `PhpOffice\\PhpWord\\PhpWord::loadTemplate()`\n- `PhpOffice\\PhpWord\\PhpWord::createSection()`\n- `PhpOffice\\PhpWord\\PhpWord::getDocumentProperties()`\n- `PhpOffice\\PhpWord\\PhpWord::setDocumentProperties()`\n- `PhpOffice\\PhpWord\\Reader\\AbstractReader::getReadDataOnly()`\n- `PhpOffice\\PhpWord\\Settings::getCompatibility()`\n- `PhpOffice\\PhpWord\\Style\\AbstractStyle::setArrayStyle()`\n- `PhpOffice\\PhpWord\\Style\\Cell::getDefaultBorderColor()`\n- `PhpOffice\\PhpWord\\Style\\Font::getBold()`\n- `PhpOffice\\PhpWord\\Style\\Font::getItalic()`\n- `PhpOffice\\PhpWord\\Style\\Font::getSuperScript()`\n- `PhpOffice\\PhpWord\\Style\\Font::getSubScript()`\n- `PhpOffice\\PhpWord\\Style\\Font::getStrikethrough()`\n- `PhpOffice\\PhpWord\\Style\\Font::getParagraphStyle()`\n- `PhpOffice\\PhpWord\\Style\\Frame::getAlign()`\n- `PhpOffice\\PhpWord\\Style\\Frame::setAlign()`\n- `PhpOffice\\PhpWord\\Style\\NumberingLevel::getAlign()`\n- `PhpOffice\\PhpWord\\Style\\NumberingLevel::setAlign()`\n- `PhpOffice\\PhpWord\\Style\\Paragraph::getAlign()`\n- `PhpOffice\\PhpWord\\Style\\Paragraph::setAlign()`\n- `PhpOffice\\PhpWord\\Style\\Paragraph::getWidowControl()`\n- `PhpOffice\\PhpWord\\Style\\Paragraph::getKeepNext()`\n- `PhpOffice\\PhpWord\\Style\\Paragraph::getKeepLines()`\n- `PhpOffice\\PhpWord\\Style\\Paragraph::getPageBreakBefore()`\n- `PhpOffice\\PhpWord\\Style\\Row::getTblHeader()`\n- `PhpOffice\\PhpWord\\Style\\Row::isTblHeader()`\n- `PhpOffice\\PhpWord\\Style\\Row::getCantSplit()`\n- `PhpOffice\\PhpWord\\Style\\Row::getExactHeight()`\n- `PhpOffice\\PhpWord\\Style\\Spacing::getRule()`\n- `PhpOffice\\PhpWord\\Style\\Spacing::setRule()`\n- `PhpOffice\\PhpWord\\Style\\Table::getAlign()`\n- `PhpOffice\\PhpWord\\Style\\Table::setAlign()`\n- `PhpOffice\\PhpWord\\Writer\\AbstractWriter::getUseDiskCaching()`\n- `PhpOffice\\PhpWord\\Writer\\HTML::writeDocument()`\n\n### Bug fixes\n\n- Multiple PHP 8.1 fixes\n- `loadConfig` returns config that was actually applied\n- HTML Reader : Override inline style on HTML attribute for table\n- HTML Reader : Use `border` attribute for tables\n- HTML Reader : Style page-break-after in paragraph\n- HTML Reader : Heading in Text Run is not allowed\n\n### Miscellaneous\n\n- Drop support for PHP 7.0 and older"
  },
  {
    "path": "docs/changes/1.x/1.1.0.md",
    "content": "# [1.1.0](https://github.com/PHPOffice/PHPWord/tree/1.1.0) (2023-05-30)\n\n[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.0.0...1.1.0)\n\n### Enhancements\n\n- Introduce deleteRow() method for TemplateProcessor\n- HTML Reader: Add basic support for CSS Style Tag\n- Allow customizing macro syntax in TemplateProcessor\n- Add background color support for textboxes\n- Add softhyphen support to word reader\n- Add support table row height when importing HTML\n- Add support for fractional font sizes\n- Added image quality support, with the maximum quality as default\n- Support for reading nested tables\n\n### Bug fixes\n\n- DOCX reader: Read empty vmerge\n- Fixed setting width of Cell Style\n\n### Miscellaneous\n\n- `master` is the new default branch"
  },
  {
    "path": "docs/changes/1.x/1.2.0.md",
    "content": "# [1.2.0](https://github.com/PHPOffice/PHPWord/tree/1.2.0)\n\n[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.1.0...1.2.0)\n\n## Enhancements\n\n- Word2007 Reader/Writer : Added noWrap table cell property by [@kernusr](https://github.com/kernusr) in GH-2359\n- HTML Reader : Support for `font-variant: small-caps` by [@cambraca](https://github.com/cambraca) in GH-2117\n- Improved TextDirection for styling a cell by [@terryzwt](https://github.com/terryzwt) in GH-2429\n- Word2007 Reader : Added option to disable loading images by [@aelliott1485](https://github.com/aelliott1485) in GH-2450\n- HTML Writer : Added border-spacing to default styles for table by [@kernusr](https://github.com/kernusr) in GH-2451\n- Word2007 Reader : Support for table cell borders and margins by [@kernusr](https://github.com/kernusr) in GH-2454\n- PDF Writer : Add config for defining the default font by [@MikeMaldini](https://github.com/MikeMaldini) in [#2262](https://github.com/PHPOffice/PHPWord/pull/2262) & [#2468](https://github.com/PHPOffice/PHPWord/pull/2468)\n- Word2007 Reader : Added support for Comments by [@shaedrich](https://github.com/shaedrich) in [#2161](https://github.com/PHPOffice/PHPWord/pull/2161) & [#2469](https://github.com/PHPOffice/PHPWord/pull/2469)\n- Word2007 Reader/Writer: Permit book-fold printing by [@potofcoffee](https://github.com/potofcoffee) in [#2225](https://github.com/PHPOffice/PHPWord/pull/2225) & [#2470](https://github.com/PHPOffice/PHPWord/pull/2470)\n- Word2007 Writer : Add PageNumber to TOC by [@jet-desk](https://github.com/jet-desk) in [#1652](https://github.com/PHPOffice/PHPWord/pull/1652) & [#2471](https://github.com/PHPOffice/PHPWord/pull/2471)\n- Word2007 Reader/Writer + ODText Reader/Writer : Add Element Formula in  by [@Progi1984](https://github.com/Progi1984) in [#2477](https://github.com/PHPOffice/PHPWord/pull/2477)\n- Add Support for Various Missing Features in HTML Writer by [@oleibman](https://github.com/oleibman) in [#2475](https://github.com/PHPOffice/PHPWord/pull/2475)\n  - Fixed addHTML (text-align:right in html is not handled correctly) in [#2467](https://github.com/PHPOffice/PHPWord/pull/2467)\n  - HTML Writer : Added ability to specify generic fallback font \n  - HTML Writer : Added ability to specify handling of whitespace\n  - HTML Writer : Added support for Table Border style, color, and size\n  - HTML Writer : Added support for empty paragraphs (Word writer permits, browsers generally suppress)\n  - HTML Writer : Paragraph style should support indentation, line-height, page-break-before\n  - HTML Writer : Removed margin-top/bottom when spacing is null in Paragraph style\n  - HTML Writer : Added default paragraph style to all paragraphs, as well as class Normal\n  - HTML Writer : Use css @page and page declarations for sections\n  - HTML Writer : Wrap sections in div, with page break before each (except first)\n  - PDF Writer : Added support for PageBreak\n  - PDF Writer : Added callback for modifying the HTML\n  - Added Support for Language, both for document overall and individual text elements\n- Template : Set a checkbox by [@nxtpge](https://github.com/nxtpge) in [#2509](https://github.com/PHPOffice/PHPWord/pull/2509)\n- ODText / RTF / Word2007 Writer : Add field FILENAME by [@milkyway-git](https://github.com/milkyway-git) in [#2510](https://github.com/PHPOffice/PHPWord/pull/2510)\n- ODText Reader : Improve Section Reader by [@oleibman](https://github.com/oleibman) in [#2507](https://github.com/PHPOffice/PHPWord/pull/2507)\n\n### Bug fixes\n\n- Fixed wrong mimetype for docx files by [@gamerlv](https://github.com/gamerlv) in GH-2416\n- Word2007 Reader : Read hyperlingks in headings by [@hannesdorn](https://github.com/hannesdorn) in GH-2433\n- PclZip : strtr using empty string by [@spl1nes](https://github.com/spl1nes) in GH-2432\n- Fixed PHP 8.2 deprecated about Allow access to an undefined property by [@DAdq26](https://github.com/DAdq26) in GH-2440\n- Template Processor : Fixed choose dimention for Float Value by [@gdevilbat](https://github.com/gdevilbat) in GH-2449\n- HTML Parser : Fix image parsing from url without extension by [@JokubasR](https://github.com/JokubasR) in GH-2459\n- Word2007 Reader : Fixed reading of Office365 DocX file by [@filippotoso](https://github.com/filippotoso) & [@lfglopes](https://github.com/lfglopes) in [#2506](https://github.com/PHPOffice/PHPWord/pull/2506)\n- Word2007 Reader : Check for null on $fontDefaultStyle by [@spatialfree](https://github.com/spatialfree) in [#2513](https://github.com/PHPOffice/PHPWord/pull/2513)\n\n### Miscellaneous\n\n- Added PHPStan by [@PowerKiKi](https://github.com/PowerKiKi) in GH-2405\n- Bump symfony/process from 4.4.44 to 5.4.26 by [@dependabot](https://github.com/dependabot) in GH-2431\n- Bump phpunit/phpunit from 9.6.8 to 9.6.10 by [@dependabot](https://github.com/dependabot) in GH-2430\n- Added Coveralls.io by [@Progi1984](https://github.com/Progi1984) in GH-2452\n- Added support for PHP 8.2 & PHP 8.3 by [@Progi1984](https://github.com/Progi1984) in GH-2453\n- Moved documention from ReadTheDocs to MkDocs & Github Pages by [@Progi1984](https://github.com/Progi1984) in GH-2465\n- Bump phpstan/phpstan-phpunit from 1.3.13 to 1.3.14 by [@dependabot](https://github.com/dependabot) in [#2457](https://github.com/PHPOffice/PHPWord/pull/2457)\n- Bump symfony/process from 5.4.26 to 5.4.28 by [@dependabot](https://github.com/dependabot) in [#2456](https://github.com/PHPOffice/PHPWord/pull/2456)\n- Bump phpunit/phpunit from 9.6.10 to 9.6.11 by [@dependabot](https://github.com/dependabot) in [#2455](https://github.com/PHPOffice/PHPWord/pull/2455)\n- Remove deprecated utf8_encode in PHP 8.2 by [@mhcwebdesign](https://github.com/mhcwebdesign) in [#2447](https://github.com/PHPOffice/PHPWord/pull/2447) & [#2472](https://github.com/PHPOffice/PHPWord/pull/2472)\n- Bump mpdf/mpdf from 8.1.6 to 8.2.0 by [@dependabot](https://github.com/dependabot) in [#2480](https://github.com/PHPOffice/PHPWord/pull/2480)\n- Bump phpunit/phpunit from 9.6.11 to 9.6.13 by [@dependabot](https://github.com/dependabot) in [#2481](https://github.com/PHPOffice/PHPWord/pull/2481)\n- Bump tecnickcom/tcpdf from 6.6.2 to 6.6.5 by [@dependabot](https://github.com/dependabot) in [#2482](https://github.com/PHPOffice/PHPWord/pull/2482)\n- Bump phpmd/phpmd from 2.13.0 to 2.14.1 by [@dependabot](https://github.com/dependabot) in [#2483](https://github.com/PHPOffice/PHPWord/pull/2483)\n- Bump phpstan/phpstan-phpunit from 1.3.14 to 1.3.15 by [@dependabot](https://github.com/dependabot) in [#2494](https://github.com/PHPOffice/PHPWord/pull/2494)\n\n\n### BC Breaks\n- Removed dependency `laminas/laminas-escaper`\n- *Unintended Break* TemplateProcessor Does Not Persist File After Destruct. [#2539](https://github.com/PHPOffice/PHPWord/issues/2539) To be fixed by [#2545](https://github.com/PHPOffice/PHPWord/pull/2545\n"
  },
  {
    "path": "docs/changes/1.x/1.3.0.md",
    "content": "# [1.3.0](https://github.com/PHPOffice/PHPWord/tree/1.3.0)\n\n[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.2.0...1.3.0)\n\n## Enhancements\n\n- IOFactory : Added extractVariables method to extract variables from a document [@sibalonat](https://github.com/sibalonat) in [#2515](https://github.com/PHPOffice/PHPWord/pull/2515)\n- PDF Writer : Documented how to specify a PDF renderer, when working with the PDF writer, as well as the three available choices by [@settermjd](https://github.com/settermjd) in [#2642](https://github.com/PHPOffice/PHPWord/pull/2642)\n- Word2007 Reader: Support for Paragraph Border Style by [@damienfa](https://github.com/damienfa) in [#2651](https://github.com/PHPOffice/PHPWord/pull/2651)\n- Word2007 Writer: Support for field REF by [@crystoline](https://github.com/crystoline) in [#2652](https://github.com/PHPOffice/PHPWord/pull/2652)\n- Word2007 Reader : Support for FormFields by [@vincentKool](https://github.com/vincentKool) in [#2653](https://github.com/PHPOffice/PHPWord/pull/2653)\n- RTF Writer : Support for Table Border Style fixing [#345](https://github.com/PHPOffice/PHPWord/issues/345) by [@Progi1984](https://github.com/Progi1984) in [#2656](https://github.com/PHPOffice/PHPWord/pull/2656)\n- Word2007 Reader: Support the page break (<w:lastRenderedPageBreak/>) by [@stanolacko](https://github.com/stanolacko) in [#2662](https://github.com/PHPOffice/PHPWord/pull/2662)\n- MsDoc Reader: Support for UTF-8 characters by [@Progi1984] fixing [#881](https://github.com/PHPOffice/PHPWord/issues/881), [#1454](https://github.com/PHPOffice/PHPWord/issues/1454), [#1817](https://github.com/PHPOffice/PHPWord/issues/1817), [#1927](https://github.com/PHPOffice/PHPWord/issues/1927), [#2383](https://github.com/PHPOffice/PHPWord/issues/2383), [#2565](https://github.com/PHPOffice/PHPWord/issues/2565) in [#2664](https://github.com/PHPOffice/PHPWord/pull/2664)\n- Word2007 Writer: Added support for multiples comment for the same text by [@rodrigoq](https://github.com/rodrigoq) fixing [#2109](https://github.com/PHPOffice/PHPWord/issues/2109) in [#2665](https://github.com/PHPOffice/PHPWord/pull/2665)\n\n### Bug fixes\n\n- MsDoc Reader : Correct Font Size Calculation by [@oleibman](https://github.com/oleibman) fixing [#2526](https://github.com/PHPOffice/PHPWord/issues/2526) in [#2531](https://github.com/PHPOffice/PHPWord/pull/2531)\n- Html Reader : Process Titles as Headings not Paragraphs [@0b10011](https://github.com/0b10011) and [@oleibman](https://github.com/oleibman) Issue [#1692](https://github.com/PHPOffice/PHPWord/issues/1692) PR [#2533](https://github.com/PHPOffice/PHPWord/pull/2533)\n- Generate Table Cell if Row Doesn't Have Any [@oleibman](https://github.com/oleibman) fixing [#2505](https://github.com/PHPOffice/PHPWord/issues/2505) in [#2516](https://github.com/PHPOffice/PHPWord/pull/2516)\n- TemplateProcessor Persist File After Destruct [@oleibman](https://github.com/oleibman) fixing [#2539](https://github.com/PHPOffice/PHPWord/issues/2539) in [#2545](https://github.com/PHPOffice/PHPWord/pull/2545)\n- TemplateProcessor Destructor Problem with Php7 [@oleibman](https://github.com/oleibman) fixing [#2548](https://github.com/PHPOffice/PHPWord/issues/2548) in [#2554](https://github.com/PHPOffice/PHPWord/pull/2554)\n- bug: TemplateProcessor fix multiline values [@gimler](https://github.com/gimler) fixing [#268](https://github.com/PHPOffice/PHPWord/issues/268), [#2323](https://github.com/PHPOffice/PHPWord/issues/2323) and [#2486](https://github.com/PHPOffice/PHPWord/issues/2486) in [#2522](https://github.com/PHPOffice/PHPWord/pull/2522)\n- 32-bit Problem in PasswordEncoder [@oleibman](https://github.com/oleibman) fixing [#2550](https://github.com/PHPOffice/PHPWord/issues/2550) in [#2551](https://github.com/PHPOffice/PHPWord/pull/2551)\n- Typo : Fix hardcoded macro chars in TemplateProcessor method [@glafarge](https://github.com/glafarge) in [#2618](https://github.com/PHPOffice/PHPWord/pull/2618)\n- XML Reader : Prevent fatal errors when opening corrupt files or \"doc\" files [@mmcev106](https://github.com/mmcev106) in [#2626](https://github.com/PHPOffice/PHPWord/pull/2626)\n- Documentation : Updated Comment element by [@laminga](https://github.com/laminga) in [#2650](https://github.com/PHPOffice/PHPWord/pull/2650)\n- HTML Reader : Read width & height attributes in points fixing [#2589](https://github.com/PHPOffice/PHPWord/issues/2589) by [@Progi1984](https://github.com/Progi1984) in [#2654](https://github.com/PHPOffice/PHPWord/pull/2654)\n- Template Processor : Fixed bad naming of variables fixing [#2586](https://github.com/PHPOffice/PHPWord/issues/2586) by [@Progi1984](https://github.com/Progi1984) in [#2655](https://github.com/PHPOffice/PHPWord/pull/2655)\n- Word2007 Writer : Fix first footnote appearing as separator [#2634](https://github.com/PHPOffice/PHPWord/issues/2634) by [@jacksleight](https://github.com/jacksleight) in [#2635](https://github.com/PHPOffice/PHPWord/pull/2635)\n- Template Processor : Fixed images with transparent backgrounds displaying a white background by [@ElwynVdb](https://github.com/ElwynVdb) in [#2638](https://github.com/PHPOffice/PHPWord/pull/2638)\n- HTML Writer : Fixed rowspan for tables by [@andomiell](https://github.com/andomiell) in [#2659](https://github.com/PHPOffice/PHPWord/pull/2659)\n- Word2007 Writer : Fixed StrikeThrough property by [@noec764](https://github.com/noec764) fixing [#1722](https://github.com/PHPOffice/PHPWord/issues/1722) & [#1693](https://github.com/PHPOffice/PHPWord/issues/1693) in [#2661](https://github.com/PHPOffice/PHPWord/pull/2661)\n- HTML Reader : Fixed link without href by [@asmundstavdahl](https://github.com/asmundstavdahl) fixing [#1562](https://github.com/PHPOffice/PHPWord/issues/1562) in [#2663](https://github.com/PHPOffice/PHPWord/pull/2663)\n\n### Miscellaneous\n\n- Bump dompdf/dompdf from 2.0.3 to 2.0.4 by [@dependabot](https://github.com/dependabot) in [#2530](https://github.com/PHPOffice/PHPWord/pull/2530)\n- Bump phpunit/phpunit from 9.6.13 to 9.6.14 by [@dependabot](https://github.com/dependabot) in [#2519](https://github.com/PHPOffice/PHPWord/pull/2519)\n- Bump mpdf/mpdf from 8.2.0 to 8.2.2 by [@dependabot](https://github.com/dependabot) in [#2518](https://github.com/PHPOffice/PHPWord/pull/2518)\n- Bump phpmd/phpmd from 2.14.1 to 2.15.0 by [@dependabot](https://github.com/dependabot) in [#2538](https://github.com/PHPOffice/PHPWord/pull/2538)\n- Bump phpunit/phpunit from 9.6.14 to 9.6.15 by [@dependabot](https://github.com/dependabot) in [#2537](https://github.com/PHPOffice/PHPWord/pull/2537)\n- Bump symfony/process from 5.4.28 to 5.4.34 by [@dependabot](https://github.com/dependabot) in [#2536](https://github.com/PHPOffice/PHPWord/pull/2536)\n- Allow rgb() when converting Html by [@oleibman](https://github.com/oleibman) fixing [#2508](https://github.com/PHPOffice/PHPWord/issues/2508) in [#2512](https://github.com/PHPOffice/PHPWord/pull/2512)\n- Improved Issue Template by [@Progi1984](https://github.com/Progi1984) in [#2609](https://github.com/PHPOffice/PHPWord/pull/2609)\n- Bump phpoffice/math from 0.1.0 to 0.2.0 by [@Progi1984](https://github.com/Progi1984) fixing [#2559](https://github.com/PHPOffice/PHPWord/issues/2559) in [#2645](https://github.com/PHPOffice/PHPWord/pull/2645)\n- Bump tecnickcom/tcpdf from 6.6.5 to 6.7.5 by [@dependabot](https://github.com/dependabot) in [#2646](https://github.com/PHPOffice/PHPWord/pull/2646)\n- Bump mpdf/mpdf from 8.2.2 to 8.2.4 by [@dependabot](https://github.com/dependabot) in [#2647](https://github.com/PHPOffice/PHPWord/pull/2647)\n- Bump phenx/php-svg-lib from 0.5.1 to 0.5.4 by [@dependabot](https://github.com/dependabot) in [#2649](https://github.com/PHPOffice/PHPWord/pull/2649)\n- Bump phpstan/phpstan-phpunit from 1.3.15 to 1.4.0 by [@dependabot](https://github.com/dependabot) in [#2648](https://github.com/PHPOffice/PHPWord/pull/2648)\n\n### BC Breaks\n"
  },
  {
    "path": "docs/changes/1.x/1.4.0.md",
    "content": "# [1.4.0](https://github.com/PHPOffice/PHPWord/tree/1.4.0)\n\n[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.3.0...1.4.0)\n\n## Enhancements\n\n- Default Font: Allow specify Asisn font and Latin font separately\n\n- Writer ODText: Support for ListItemRun by [@Progi1984](https://github.com/Progi1984) fixing [#2159](https://github.com/PHPOffice/PHPWord/issues/2159), [#2620](https://github.com/PHPOffice/PHPWord/issues/2620) in [#2669](https://github.com/PHPOffice/PHPWord/pull/2669)\n- Writer HTML: Support for vAlign in Tables by [@SpraxDev](https://github.com/SpraxDev) in [#2675](https://github.com/PHPOffice/PHPWord/pull/2675)\n- Writer Word2007: Support for padding in Table Cell by [@Azamat8405](https://github.com/Azamat8405) in [#2697](https://github.com/PHPOffice/PHPWord/pull/2697)\n- Added support for PHP 8.4 by [@Progi1984](https://github.com/Progi1984) in [#2660](https://github.com/PHPOffice/PHPWord/pull/2660)\n- Autoload : Allow to use PHPWord without Composer fixing [#2543](https://github.com/PHPOffice/PHPWord/issues/2543), [#2552](https://github.com/PHPOffice/PHPWord/issues/2552), [#2716](https://github.com/PHPOffice/PHPWord/issues/2716), [#2717](https://github.com/PHPOffice/PHPWord/issues/2717) in [#2722](https://github.com/PHPOffice/PHPWord/pull/2722)\n- Add Default font color for Word by [@Collie-IT](https://github.com/Collie-IT) in [#2700](https://github.com/PHPOffice/PHPWord/pull/2700)\n- Writer HTML: Support Default font color by [@MichaelPFrey](https://github.com/MichaelPFrey) in [#2731](https://github.com/PHPOffice/PHPWord/pull/2731)\n- Writer ODText: Support Default font color by [@MichaelPFrey](https://github.com/MichaelPFrey) in [#2735](https://github.com/PHPOffice/PHPWord/pull/2735)\n- Add basic ruby text (phonetic guide) support for Word2007 and HTML Reader/Writer, RTF Writer, basic support for ODT writing by [@Deadpikle](https://github.com/Deadpikle) in [#2727](https://github.com/PHPOffice/PHPWord/pull/2727)\n- Reader HTML: Support font styles for h1/h6 by [@Progi1984](https://github.com/Progi1984) fixing [#2619](https://github.com/PHPOffice/PHPWord/issues/2619) in [#2737](https://github.com/PHPOffice/PHPWord/pull/2737)\n- Writer EPub3: Basic support by [@Sambit003](https://github.com/Sambit003) fixing [#55](https://github.com/PHPOffice/PHPWord/issues/55) in [#2724](https://github.com/PHPOffice/PHPWord/pull/2724)\n- Writer Word2007: Added support for background and border color transparency in Text Box element by [@chudy20007](https://github.com/Chudy20007) in [#2555](https://github.com/PHPOffice/PHPWord/pull/2555)\n- Writer/Reader Word2007: Added support for the firstLineChars for Indentation by [@liuzhilinux](https://github.com/liuzhilinux) & [@Progi1984](https://github.com/Progi1984) in [#2753](https://github.com/PHPOffice/PHPWord/pull/2753)\n\n### Bug fixes\n\n- Writer ODText: Support for images inside a textRun by [@Progi1984](https://github.com/Progi1984) fixing [#2240](https://github.com/PHPOffice/PHPWord/issues/2240) in [#2668](https://github.com/PHPOffice/PHPWord/pull/2668)\n- Allow vAlign and vMerge on Style\\Cell to be set to null by [@SpraxDev](https://github.com/SpraxDev) fixing [#2673](https://github.com/PHPOffice/PHPWord/issues/2673) in [#2676](https://github.com/PHPOffice/PHPWord/pull/2676)\n- Reader HTML: Support for differents size units for table by [@Progi1984](https://github.com/Progi1984) fixing [#2384](https://github.com/PHPOffice/PHPWord/issues/2384), [#2701](https://github.com/PHPOffice/PHPWord/issues/2701) in [#2725](https://github.com/PHPOffice/PHPWord/pull/2725)\n- Reader Word2007: Respect paragraph indent units by [@tugmaks](https://github.com/tugmaks) & [@Progi1984](https://github.com/Progi1984) fixing [#507](https://github.com/PHPOffice/PHPWord/issues/507) in [#2726](https://github.com/PHPOffice/PHPWord/pull/2726)\n- Reader Word2007: Support Header elements within Title elements by [@SpraxDev](https://github.com/SpraxDev) fixing [#2616](https://github.com/PHPOffice/PHPWord/issues/2616), [#2426](https://github.com/PHPOffice/PHPWord/issues/2426) in [#2674](https://github.com/PHPOffice/PHPWord/pull/2674)\n- Reader HTML: Support for inherit value for property line-height by [@Progi1984](https://github.com/Progi1984) fixing [#2683](https://github.com/PHPOffice/PHPWord/issues/2683) in [#2733](https://github.com/PHPOffice/PHPWord/pull/2733)\n- Writer HTML: Fixed null string for Text Elements by [@armagedon007](https://github.com/armagedon007) and [@Progi1984](https://github.com/Progi1984) in [#2738](https://github.com/PHPOffice/PHPWord/pull/2738)\n- Template Processor: Fix 0 considered as empty string by [@cavasinf](https://github.com/cavasinf), [@SnipsMine](https://github.com/SnipsMine) and [@Progi1984](https://github.com/Progi1984) fixing [#2572](https://github.com/PHPOffice/PHPWord/issues/2572), [#2703](https://github.com/PHPOffice/PHPWord/issues/2703) in [#2748](https://github.com/PHPOffice/PHPWord/pull/2748)\n- Word2007 Writer : Corrected generating TOC to fix page number missing issues [@jgiacomello](https://github.com/jgiacomello) in [#2556](https://github.com/PHPOffice/PHPWord/pull/2556)\n- Enhanced error handling in encoding functions [@michalschroeder](https://github.com/michalschroeder) in [#2784](https://github.com/PHPOffice/PHPWord/pull/2784)\n\n### Miscellaneous\n\n- Bump dompdf/dompdf from 2.0.4 to 3.0.0 by [@dependabot](https://github.com/dependabot) fixing [#2621](https://github.com/PHPOffice/PHPWord/issues/2621) in [#2666](https://github.com/PHPOffice/PHPWord/pull/2666)\n- Add test case to make sure vMerge defaults to 'continue' by [@SpraxDev](https://github.com/SpraxDev) in [#2677](https://github.com/PHPOffice/PHPWord/pull/2677)\n- Adding the possibility to use iterate search and replace with setValues by [@moghwan](https://github.com/moghwan) in [#2632](https://github.com/PHPOffice/PHPWord/pull/2640)\n- Add test cases that test the ODTText and Word2007 reader using the corresponding writer, increasing test coverage by [@MichaelPFrey](https://github.com/MichaelPFrey) in [#2745](https://github.com/PHPOffice/PHPWord/pull/2745)\n- Updated TOCTest to use static HTML content instead of external resource [@michalschroeder](https://github.com/michalschroeder) in [#2784](https://github.com/PHPOffice/PHPWord/pull/2784)\n- Bump PHPOffice/math from 0.2.0 to 0.3.0 by [@eileenmcnaughton](https://github.com/eileenmcnaughton) in [#2785](https://github.com/PHPOffice/PHPWord/pull/2785)\n\n### Deprecations\n- Deprecate `PhpOffice\\PhpWord\\Style\\Paragraph::getIndent()` : Use `PhpOffice\\PhpWord\\Style\\Paragraph::getIndentLeft()`\n- Deprecate `PhpOffice\\PhpWord\\Style\\Paragraph::setHanging()` : Use `PhpOffice\\PhpWord\\Style\\Paragraph::setIndentHanging()`\n- Deprecate `PhpOffice\\PhpWord\\Style\\Paragraph::setIndent()` : Use `PhpOffice\\PhpWord\\Style\\Paragraph::setIndentLeft()`\n\n### BC Breaks\n\n### Notes\n- Writer ODText previously used to set 'style:use-window-font-color' to 'true', now it is set to 'false'. (see [#2735](https://github.com/PHPOffice/PHPWord/pull/2735))\n  The effect of this attribute is \"implementation dependent\" (if implemented at all).\n  Setting it to false allows setting a default font color and improves interoperabilt,\n  but may break certain specific use cases.\n"
  },
  {
    "path": "docs/changes/1.x/1.5.0.md",
    "content": "# [1.5.0](https://github.com/PHPOffice/PHPWord/tree/1.5.0) (WIP)\n\n[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.4.0...1.5.0)\n\n## Enhancements\n\n### Bug fixes\n\n- Set writeAttribute return type by [@radarhere](https://github.com/radarhere) fixing [#2204](https://github.com/PHPOffice/PHPWord/issues/2204) in [#2776](https://github.com/PHPOffice/PHPWord/pull/2776)\n\n### Miscellaneous\n\n- Update phpstan/phpstan requirement from ^0.12.88 || ^1.0.0 to ^0.12.88 || ^1.0.0 || ^2.0.0 by [@dependabot](https://github.com/dependabot) & [@Progi1984](https://github.com/Progi1984) in [#2736](https://github.com/PHPOffice/PHPWord/pull/2736)\n\n### Deprecations\n\n### BC Breaks\n\n### Notes"
  },
  {
    "path": "docs/credits.md",
    "content": "# Credits\n\nImages from chart page come from the [LibreOffice Core](https://github.com/LibreOffice/core/tree/master/icon-themes/galaxy/chart2/res).\n\nSome definitions come from the [Office Open XML](http://officeopenxml.com).\n\n## References\n\n### OpenXML\n\nKnown as \"ISO/IEC 29500, Third edition, 2012-09-01\"\n\nISO :\n\n- [Part 1: Fundamentals and Markup Language Reference](http://standards.iso.org/ittf/PubliclyAvailableStandards/c061750_ISO_IEC_29500-1_2012.zip)\n- [Part 2: Open Packaging Conventions](http://standards.iso.org/ittf/PubliclyAvailableStandards/c061796_ISO_IEC_29500-2_2012.zip)\n- [Part 3: Markup Compatibility and Extensibility](http://standards.iso.org/ittf/PubliclyAvailableStandards/c061797_ISO_IEC_29500-3_2012.zip)\n- [Part 4: Transitional Migration Features](http://standards.iso.org/ittf/PubliclyAvailableStandards/c061798_ISO_IEC_29500-4_2012.zip)\n\nMSDN :\n\n- [Open XML SDK 2.5 with Validator](http://www.microsoft.com/en-gb/download/details.aspx?id=30425)\n- [DocumentFormat.OpenXml.Wordprocessing Namespace on MSDN](http://msdn.microsoft.com/en-us/library/documentformat.openxml.wordprocessing%28v=office.14%29.aspx)\n\nLibrary of Congress :\n\n- [OOXML Format Family -- ISO/IEC 29500 and ECMA 376](https://www.loc.gov/preservation/digital/formats/fdd/fdd000395.shtml)\n- [Schemas in W3C XML Schema language and in RELAX NG for the Strict variant of PPTX, etc.](http://standards.iso.org/ittf/PubliclyAvailableStandards/c071691_ISO_IEC_29500-1_2016_Electronic_inserts.zip)\n\n\n### OpenDocument\n\n- [Oasis OpenDocument Standard Version 1.2](http://docs.oasis-open.org/office/v1.2/os/OpenDocument-v1.2-os.html)\n- [Schema Central Open Document 1.1](http://www.datypic.com/sc/odf/ss.html)\n\n### Rich Text Format\n\n- [Rich Text Format (RTF) Specification, version 1.9.1](http://www.microsoft.com/en-us/download/details.aspx?id=10725)\n\n### Word 97"
  },
  {
    "path": "docs/faq.md",
    "content": "# Frequently asked questions\n\n## How contribute to PHPWord?\n- Improve the documentation\n\n"
  },
  {
    "path": "docs/howto.md",
    "content": "# How to\n\n## Create float left image\n\nUse absolute positioning relative to margin horizontally and to line vertically.\n\n``` php\n<?php\n\n$imageStyle = array(\n    'width' => 40,\n    'height' => 40,\n    'wrappingStyle' => 'square',\n    'positioning' => 'absolute',\n    'posHorizontalRel' => 'margin',\n    'posVerticalRel' => 'line',\n);\n$textrun->addImage(__DIR__ . '/resources/_earth.jpg', $imageStyle);\n```\n\n## Download the produced file automatically\n\nUse ``php://output`` as the filename.\n\n``` php\n<?php\n\n$phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n$section = $phpWord->addSection();\n$section->addText('Hello World!');\n$file = 'HelloWorld.docx';\nheader(\"Content-Description: File Transfer\");\nheader('Content-Disposition: attachment; filename=\"' . $file . '\"');\nheader('Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document');\nheader('Content-Transfer-Encoding: binary');\nheader('Cache-Control: must-revalidate, post-check=0, pre-check=0');\nheader('Expires: 0');\n$xmlWriter = \\PhpOffice\\PhpWord\\IOFactory::createWriter($phpWord, 'Word2007');\n$xmlWriter->save(\"php://output\");\n```\n\n## Create numbered headings\n\nDefine a numbering style and title styles, and match the two styles (with ``pStyle`` and ``numStyle``) like below.\n\n``` php\n<?php\n\n$phpWord->addNumberingStyle(\n    'hNum',\n    array('type' => 'multilevel', 'levels' => array(\n        array('pStyle' => 'Heading1', 'format' => 'decimal', 'text' => '%1'),\n        array('pStyle' => 'Heading2', 'format' => 'decimal', 'text' => '%1.%2'),\n        array('pStyle' => 'Heading3', 'format' => 'decimal', 'text' => '%1.%2.%3'),\n        )\n    )\n);\n$phpWord->addTitleStyle(1, array('size' => 16), array('numStyle' => 'hNum', 'numLevel' => 0));\n$phpWord->addTitleStyle(2, array('size' => 14), array('numStyle' => 'hNum', 'numLevel' => 1));\n$phpWord->addTitleStyle(3, array('size' => 12), array('numStyle' => 'hNum', 'numLevel' => 2));\n\n$section->addTitle('Heading 1', 1);\n$section->addTitle('Heading 2', 2);\n$section->addTitle('Heading 3', 3);\n```\n\n## Add a link within a title\n\nApply 'HeadingN' paragraph style to TextRun or Link. Sample code:\n\n``` php\n<?php\n\n$phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n$phpWord->addTitleStyle(1, array('size' => 16, 'bold' => true));\n$phpWord->addTitleStyle(2, array('size' => 14, 'bold' => true));\n$phpWord->addFontStyle('Link', array('color' => '0000FF', 'underline' => 'single'));\n\n$section = $phpWord->addSection();\n\n// Textrun\n$textrun = $section->addTextRun('Heading1');\n$textrun->addText('The ');\n$textrun->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord', 'Link');\n\n// Link\n$section->addLink('https://github.com/', 'GitHub', 'Link', 'Heading2');\n```\n\n## Remove [Compatibility Mode] text in the MS Word title bar\n\nUse the ``Metadata\\Compatibility\\setOoxmlVersion(n)`` method with ``n`` is the version of Office:\n\n* 14 = Office 2010\n* 15 = Office 2013\n\n``` php\n<?php\n\n$phpWord->getCompatibility()->setOoxmlVersion(15);\n```\n"
  },
  {
    "path": "docs/index.md",
    "content": "#\n\n![PHPWord](images/phpword.svg)\n\nPHPWord is a library written in pure PHP that provides a set ofclasses to write to different document file formats, i.e. [Microsoft Office Open XML](http://en.wikipedia.org/wiki/Office_Open_XML)(`.docx`), OASIS [Open Document Format for Office Applications](http://en.wikipedia.org/wiki/OpenDocument) (`.odt`), [Rich Text Format](http://en.wikipedia.org/wiki/Rich_Text_Format) (`.rtf`), [Microsoft Word Binary File](https://en.wikipedia.org/wiki/Doc_(computing)) (`.doc`), HTML (`.html`), and PDF (`.pdf`).\n\nPHPWord is an open source project licensed under the terms of [LGPL version 3](https://github.com/PHPOffice/PHPWord/blob/master/COPYING.LESSER). PHPWord is aimed to be a high quality software product by incorporating [continuous integration and unit testing](https://github.com/PHPOffice/PHPWord/actions/workflows/php.yml). You can learn more about PHPWord by reading this Developers'Documentation.\n<!---\n-  and the `API Documentation <http://phpoffice.github.io/PHPWord/docs/develop/>`__\n-->\n\n## Features\n\n- Set document properties, e.g. title, subject, and creator.\n- Create document sections with different settings, e.g. portrait/landscape, page size, and page numbering\n- Create header and footer for each sections\n- Set default font type, font size, and paragraph style\n- Use UTF-8 and East Asia fonts/characters\n- Define custom font styles (e.g. bold, italic, color) and paragraph styles (e.g. centered, multicolumns, spacing) either as named style or inline in text\n- Insert paragraphs, either as a simple text or complex one (a text run) that contains other elements\n- Insert titles (headers) and table of contents\n- Insert text breaks and page breaks\n- Insert and format images, either local, remote, or as page watermarks\n- Insert binary OLE Objects such as Excel or Visio\n- Insert and format table with customized properties for each rows (e.g. repeat as header row) and cells (e.g. background color, rowspan, colspan)\n- Insert list items as bulleted, numbered, or multilevel\n- Insert hyperlinks\n- Insert footnotes and endnotes\n- Insert drawing shapes (arc, curve, line, polyline, rect, oval)\n- Insert charts (pie, doughnut, bar, line, area, scatter, radar)\n- Insert form fields (textinput, checkbox, and dropdown)\n- Create document from templates\n- Use XSL 1.0 style sheets to transform headers, main document part, and footers of an OOXML template\n- ... and many more features on progress\n\n## File formats\n\nBelow are the supported features for each file formats.\n\n\n### Writers\n\n\n| Features                  |                      | OOXML  | ODF   | RTF   | HTML   | PDF   |\n|---------------------------|----------------------|--------|-------|-------|--------|--------|\n| **Document Properties**   | Standard             | :material-check: | :material-check: | :material-check: | :material-check: | :material-check: |\n|                           | Custom               | :material-check: | :material-check: |       |        |       |\n| **Element Type**          | Text                 | :material-check: | :material-check: | :material-check: | :material-check: | :material-check: |\n|                           | Text Run             | :material-check: | :material-check: | :material-check: | :material-check: | :material-check: |\n|                           | Title                | :material-check: | :material-check: |       | :material-check: | :material-check: |\n|                           | Link                 | :material-check: | :material-check: | :material-check: | :material-check: | :material-check: |\n|                           | Preserve Text        | :material-check: |       |       |        |       |\n|                           | Text Break           | :material-check: | :material-check: | :material-check: | :material-check: | :material-check: |\n|                           | Page Break           | :material-check: |       |  :material-check:    |        |       |\n|                           | List                 | :material-check: | :material-check: |       |        |       |\n|                           | Table                | :material-check: | :material-check: | :material-check: | :material-check: | :material-check: |\n|                           | Image                | :material-check: | :material-check: | :material-check: | :material-check: |       |\n|                           | Object               | :material-check: |       |       |        |       |\n|                           | Watermark            | :material-check: |       |       |        |       |\n|                           | Table of Contents    | :material-check: |       |       |        |       |\n|                           | Header               | :material-check: |       |       |        |       |\n|                           | Footer               | :material-check: |       |       |        |       |\n|                           | Footnote             | :material-check: |       |       | :material-check: |       |\n|                           | Endnote              | :material-check: |       |       | :material-check: |       |\n|                           | Comments             | :material-check: |       |       |        |       |\n| **Graphs**                | 2D basic graphs      | :material-check: |       |       |        |       |\n|                           | 2D advanced graphs   |        |       |       |        |       |\n|                           | 3D graphs            | :material-check: |       |       |        |       |\n| **Math**                  | OMML support         | :material-check: |       |       |        |       |\n|                           | MathML support       |        | :material-check: |       |        |       |\n| **Bonus**                 | Encryption           |        |       |       |        |       |\n|                           | Protection           |        |       |       |        |       |\n\n### Readers\n\n\n| Features                  |                      | OOXML  | DOC   | ODF   | RTF   | HTML  |\n|---------------------------|----------------------|--------|-------|-------|-------|-------|\n| **Document Properties**   | Standard             | :material-check: |       |       |       |       |\n|                           | Custom               | :material-check: |       |       |       |       |\n| **Element Type**          | Text                 | :material-check: | :material-check: | :material-check: | :material-check: | :material-check: |\n|                           | Text Run             | :material-check: |       |       |       |       |\n|                           | Title                | :material-check: |       | :material-check: |       |       |\n|                           | Link                 | :material-check: | :material-check: |       |       |       |\n|                           | Preserve Text        | :material-check: |       |       |       |       |\n|                           | Text Break           | :material-check: | :material-check: |       |       |       |\n|                           | Page Break           | :material-check: |       |       |       |       |\n|                           | List                 | :material-check: |       | :material-check: |       | :material-check: |\n|                           | Table                | :material-check: |       |       |       | :material-check: |\n|                           | Image                | :material-check: | :material-check: |       |       |       |\n|                           | Object               |        |       |       |       |       |\n|                           | Watermark            |        |       |       |       |       |\n|                           | Table of Contents    |        |       |       |       |       |\n|                           | Header               | :material-check: |       |       |       |       |\n|                           | Footer               | :material-check: |       |       |       |       |\n|                           | Footnote             | :material-check: |       |       |       |       |\n|                           | Endnote              | :material-check: |       |       |       |       |\n|                           | Comments             | :material-check: |       |       |       |       |\n| **Graphs**                | 2D basic graphs      |        |       |       |       |       |\n|                           | 2D advanced graphs   |        |       |       |       |       |\n|                           | 3D graphs            |        |       |       |       |       |\n| **Math**                  | OMML support         | :material-check: |       |       |       |       |\n|                           | MathML support       |        | :material-check: |       |       |       |\n| **Bonus**                 | Encryption           |        |       |       |       |       |\n|                           | Protection           |        |       |       |       |       |\n\n\n## Contributing\n\nWe welcome everyone to contribute to PHPWord. Below are some of the things that you can do to contribute:\n\n-  Read [our contributing guide](https://github.com/PHPOffice/PHPWord/blob/master/CONTRIBUTING.md)\n-  [Fork us](https://github.com/PHPOffice/PHPWord/fork) and [request a pull](https://github.com/PHPOffice/PHPWord/pulls) to the [master](https://github.com/PHPOffice/PHPWord/tree/master) branch\n-  Submit [bug reports or feature requests](https://github.com/PHPOffice/PHPWord/issues) to GitHub\n-  Follow [@PHPOffice](https://twitter.com/PHPOffice) on Twitter\n"
  },
  {
    "path": "docs/install.md",
    "content": "# Installation\n\n## Requirements\n\nMandatory:\n\n-  PHP 7.1+\n-  PHP [DOM extension](http://php.net/manual/en/book.dom.php)\n-  PHP [JSON extension](http://php.net/manual/en/book.json.php)\n-  PHP [XML Parser extension](http://www.php.net/manual/en/xml.installation.php)\n-  PHP [XMLWriter extension](http://php.net/manual/en/book.xmlwriter.php)\n\n\n## Installation\n\nThere are two ways to install PHPWord, i.e. via [Composer](http://getcomposer.org) or manually by downloading the library.\n\n### Using Composer\n\nTo install via Composer, add the following lines to your `composer.json`:\n\n``` json\n{\n    \"require\": {\n        \"phpoffice/phpword\": \"dev-master\"\n    }\n}\n```\n\n\n### Using manual install\nTo install manually:\n\n* [download PHPOffice\\PHPWord package from GitHub](https://github.com/PHPOffice/PHPWord/archive/master.zip)\n* extract the package and put the contents to your machine.\n\n\n``` php\n<?php\n\nrequire_once 'path/to/PHPWord/src/PhpWord/Autoloader.php';\n\\PhpOffice\\PhpWord\\Autoloader::register();\n\n```\n\nThe preferred method is the Composer one.\n\n### Configuration\n\nIn order to configure you can create phpword.ini file and load configuration by calling Settings::loadConfig\n\n``` php\n<?php\n\nSettings::loadConfig();\n\n```\n\nYou can also specify the config file location. (Do not use phpword.ini file in vendor folder)\n\n``` php\n<?php\n\nSettings::loadConfig(__DIR__ . '/../../phpword.ini');\n\n```\n\n## Samples\n\nAfter installation, you can browse and use the samples that we've provided, either by command line or using browser. If you can access your PhpWord library folder using browser, point your browser to the `samples` folder, e.g. `http://localhost/PhpWord/samples/`.\n"
  },
  {
    "path": "docs/usage/containers.md",
    "content": "# Containers\n\nContainers are objects where you can put elements (texts, lists, tables, etc). There are 3 main containers, i.e. sections, headers, and footers.There are 3 elements that can also act as containers, i.e. textruns, table cells, and footnotes.\n\n## Sections\n\nEvery visible element in word is placed inside of a section. To create a section, use the following code:\n\n``` php\n<?php\n\n$section = $phpWord->addSection($sectionStyle);\n```\n\nThe ``$sectionStyle`` is an optional associative array that sets the section. Example:\n\n``` php\n<?php\n\n$sectionStyle = array(\n    'orientation' => 'landscape',\n    'marginTop' => 600,\n    'colsNum' => 2,\n);\n```\n\n### Page number\n\nYou can change a section page number by using the ``pageNumberingStart``\nstyle of the section.\n\n``` php\n<?php\n\n// Method 1\n$section = $phpWord->addSection(array('pageNumberingStart' => 1));\n\n// Method 2\n$section = $phpWord->addSection();\n$section->getStyle()->setPageNumberingStart(1);\n```\n\n### Multicolumn\n\nYou can change a section layout to multicolumn (like in a newspaper) by\nusing the ``breakType`` and ``colsNum`` style of the section.\n\n``` php\n<?php\n\n// Method 1\n$section = $phpWord->addSection(array('breakType' => 'continuous', 'colsNum' => 2));\n\n// Method 2\n$section = $phpWord->addSection();\n$section->getStyle()->setBreakType('continuous');\n$section->getStyle()->setColsNum(2);\n```\n\n### Line numbering\n\nYou can apply line numbering to a section by using the ``lineNumbering``\nstyle of the section.\n\n``` php\n<?php\n\n// Method 1\n$section = $phpWord->addSection(array('lineNumbering' => array()));\n\n// Method 2\n$section = $phpWord->addSection();\n$section->getStyle()->setLineNumbering(array());\n```\n\nBelow are the properties of the line numbering style.\n\n-  ``start`` Line numbering starting value\n-  ``increment`` Line number increments\n-  ``distance`` Distance between text and line numbering in *twip*\n-  ``restart`` Line numbering restart setting\n   continuous\\|newPage\\|newSection\n\n## Headers\n\nEach section can have its own header reference. To create a header use\nthe ``addHeader`` method:\n\n``` php\n<?php\n\n$header = $section->addHeader();\n```\n\nBe sure to save the result in a local object. You can use all elements\nthat are available for the footer. See \"Footer\" section for detail.\nAdditionally, only inside of the header reference you can add watermarks\nor background pictures. See \"Watermarks\" section.\n\nYou can pass an optional parameter to specify where the header/footer should be applied, it can be\n\n-  ``Footer::AUTO`` default, all pages except if overridden by first or even\n-  ``Footer::FIRST`` each first page of the section\n-  ``Footer::EVEN`` each even page of the section. Will only be applied if the evenAndOddHeaders is set to true in phpWord->settings\n\nTo change the evenAndOddHeaders use the ``getSettings`` method to return the Settings object, and then call the ``setEvenAndOddHeaders`` method:\n\n``` php\n<?php\n\n$phpWord->getSettings()->setEvenAndOddHeaders(true);\n```\n\n## Footers\n\nEach section can have its own footer reference. To create a footer, use\nthe ``addFooter`` method:\n\n``` php\n<?php\n\n$footer = $section->addFooter();\n```\n\nBe sure to save the result in a local object to add elements to a\nfooter. You can add the following elements to footers:\n\n-  Texts ``addText`` and ``createTextrun``\n-  Text breaks\n-  Images\n-  Tables\n-  Preserve text\n\nSee the \"Elements\" section for the detail of each elements.\n\n### Other containers\n\nTextruns, table cells, and footnotes are elements that can also act as\ncontainers. See the corresponding \"Elements\" section for the detail of\neach elements.\n"
  },
  {
    "path": "docs/usage/elements/chart.md",
    "content": "# Chart\n\nCharts can be added using\n\n``` php\n<?php\n\n$categories = array('A', 'B', 'C', 'D', 'E');\n$series = array(1, 3, 2, 5, 4);\n$chart = $section->addChart('line', $categories, $series, $style);\n```\n\nFor available styling options, see [`Styles > Chart`](../styles/chart.md).\n\nCheck out the Sample_32_Chart.php for more options and styling."
  },
  {
    "path": "docs/usage/elements/checkbox.md",
    "content": "# Checkbox\n\nCheckbox elements can be added to sections or table cells by using ``addCheckBox``.\n\n``` php\n<?php\n\n$section->addCheckBox($name, $text, [$fontStyle], [$paragraphStyle]);\n```\n\n- ``$name``. Name of the check box.\n- ``$text``. Text to be displayed in the document.\n- ``$fontStyle``. See [`Styles > Font`](../styles/font.md).\n- ``$paragraphStyle``. See [`Styles > Paragraph`](../styles/paragraph.md)."
  },
  {
    "path": "docs/usage/elements/comment.md",
    "content": "# Comment\n\nComments can be added to a document by using ``addComment``.\nThe comment can contain formatted text. Once the comment has been added, it can be linked to any element with ``setCommentRangeStart``.\n\n``` php\n<?php\n\n// first create a comment\n$comment= new \\PhpOffice\\PhpWord\\Element\\Comment('Authors name', new \\DateTime(), 'my_initials');\n$comment->addText('Test', array('bold' => true));\n\n// add it to the document\n$phpWord->addComment($comment);\n\n$textrun = $section->addTextRun();\n$textrun->addText('This ');\n$text = $textrun->addText('is');\n// link the comment to the text you just created\n$text->setCommentRangeStart($comment);\n$textrun->addText(' a test');\n```\n\nIf no end is set for a comment using the ``setCommentRangeEnd``, the comment will be ended automatically at the end of the element it is started on."
  },
  {
    "path": "docs/usage/elements/field.md",
    "content": "# Field\n\nCurrently the following fields are supported:\n\n- PAGE\n- NUMPAGES\n- DATE\n- XE\n- INDEX\n- FILENAME\n- REF\n\n``` php\n<?php\n\n$section->addField($fieldType, [$properties], [$options], [$fieldText], [$fontStyle])\n```\n\n- ``$fontStyle``. See [`Styles > Font`](../styles/font.md).\n\nSee ``\\PhpOffice\\PhpWord\\Element\\Field`` for list of properties and options available for each field type.\nOptions which are not specifically defined can be added. Those must start with a ``\\``.\n\nFor instance for the INDEX field, you can do the following (See `Index Field for list of available options <https://support.office.com/en-us/article/Field-codes-Index-field-adafcf4a-cb30-43f6-85c7-743da1635d9e?ui=en-US&rs=en-US&ad=US>`_ ):\n\n``` php\n<?php\n\n// the $fieldText can be either a simple string\n$fieldText = 'The index value';\n\n// or a 'TextRun', to be able to format the text you want in the index\n$fieldText = new TextRun();\n$fieldText->addText('My ');\n$fieldText->addText('bold index', ['bold' => true]);\n$fieldText->addText(' entry');\n$section->addField('XE', array(), array(), $fieldText);\n\n// this actually adds the index\n$section->addField('INDEX', array(), array('\\\\e \"\t\" \\\\h \"A\" \\\\c \"3\"'), 'right click to update index');\n\n// Adding reference to a bookmark\n$fieldText->addField('REF', [\n    'name' => 'bookmark'\n], [\n    'InsertParagraphNumberRelativeContext',\n    'CreateHyperLink',\n]);\n```\n"
  },
  {
    "path": "docs/usage/elements/formula.md",
    "content": "# Formula\n\nFormula can be added using\n\n``` php\n<?php\n\nuse PhpOffice\\Math\\Element;\nuse PhpOffice\\Math\\Math;\n\n$fraction = new Element\\Fraction();\n$fraction\n    ->setDenominator(new Element\\Numeric(2))\n    ->setNumerator(new Element\\Identifier('π'))\n;\n\n$math = new Math();\n$math->add($fraction);\n\n$formula = $section->addFormula($math);\n```"
  },
  {
    "path": "docs/usage/elements/image.md",
    "content": "# Image\n\nTo add an image, use the ``addImage`` method to sections, headers, footers, textruns, or table cells.\n\n``` php\n<?php\n\n$section->addImage($src, [$style]);\n```\n\n- ``$src``. String path to a local image, URL of a remote image or the image data, as a string. Warning: Do not pass user-generated strings here, as that would allow an attacker to read arbitrary files or perform server-side request forgery by passing file paths or URLs instead of image data.\n- ``$style``. See [`Styles > Image`](../styles/image.md).\n\nExamples:\n\n``` php\n<?php\n\n$section = $phpWord->addSection();\n$section->addImage(\n    'mars.jpg',\n    array(\n        'width'         => 100,\n        'height'        => 100,\n        'marginTop'     => -1,\n        'marginLeft'    => -1,\n        'wrappingStyle' => 'behind'\n    )\n);\n$footer = $section->addFooter();\n$footer->addImage('http://example.com/image.php');\n$textrun = $section->addTextRun();\n$textrun->addImage('http://php.net/logo.jpg');\n$source = file_get_contents('/path/to/my/images/earth.jpg');\n$textrun->addImage($source);\n```"
  },
  {
    "path": "docs/usage/elements/index.md",
    "content": "# Elements\n\nBelow are the matrix of element availability in each container. The column shows the containers while the rows lists the elements.\n\n| Num   | Element        | Section    | Header   | Footer   | Cell    | Text Run   | Footnote   |\n|-------|-----------------|-----------|----------|----------|---------|------------|------------|\n| 1     | [Text](text.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| 2     | Text Run | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :red_circle: | :red_circle: |\n| 3     | [Link](link.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| 4     | [Title](title.md) | :white_check_mark: | :question: | :question: | :question: | :question: | :question: |\n| 5     | [Preserve Text](preservetext.md) | :question: | :white_check_mark: | :white_check_mark: | :material-check-decagram-outline: | :red_circle: | :red_circle: |\n| 6     | [Text Break](textbreak.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| 7     | [Page Break](pagebreak.md) | :white_check_mark: | :red_circle: | :red_circle: | :red_circle: | :red_circle: | :red_circle: |\n| 8     | [List](list.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :red_circle: | :red_circle: |\n| 9     | [Table](table.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :red_circle: | :red_circle: |\n| 10    | [Image](image.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| 11    | [Watermark](watermark.md) | :red_circle: | :white_check_mark: | :red_circle: | :red_circle: | :red_circle: | :red_circle: |\n| 12    | [OLEObject](oleobject.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| 13    | [TOC](toc.md) | :white_check_mark: | :red_circle: | :red_circle: | :red_circle: | :red_circle: | :red_circle: |\n| 14    | [Footnote](note.md) | :white_check_mark: | :red_circle: | :red_circle: | :material-check-decagram: | :material-check-decagram: | :red_circle: |\n| 15    | [Endnote](note.md) | :white_check_mark: | :red_circle: | :red_circle: | :material-check-decagram: | :material-check-decagram: | :red_circle: |\n| 16    | [CheckBox](checkbox.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :red_circle: |\n| 17    | [TextBox](textbox.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :red_circle: | :red_circle: |\n| 18    | [Field](field.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| 19    | [Line](line.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| 20    | [Chart](chart.md) | :white_check_mark: | | | :white_check_mark: | | |\n\nLegend:\n\n- :white_check_mark: : Available.\n- :material-check-decagram-outline: : Available only when inside header/footer.\n- :material-check-decagram: : Available only when inside section.\n- :red_circle: : Not available.\n- :question: : Should be available."
  },
  {
    "path": "docs/usage/elements/line.md",
    "content": "# Line\n\nLine elements can be added to sections by using ``addLine``.\n\n``` php\n<?php\n\n$lineStyle = array('weight' => 1, 'width' => 100, 'height' => 0, 'color' => 635552);\n$section->addLine($lineStyle);\n```\n\nAvailable line style attributes:\n\n- ``weight``. Line width in *twip*.\n- ``color``. Defines the color of stroke.\n- ``dash``. Line types: dash, rounddot, squaredot, dashdot, longdash, longdashdot, longdashdotdot.\n- ``beginArrow``. Start type of arrow: block, open, classic, diamond, oval.\n- ``endArrow``. End type of arrow: block, open, classic, diamond, oval.\n- ``width``. Line-object width in *pt*.\n- ``height``. Line-object height in *pt*.\n- ``flip``. Flip the line element: true, false."
  },
  {
    "path": "docs/usage/elements/link.md",
    "content": "# Link\n\nYou can add Hyperlinks to the document by using the function addLink:\n\n``` php\n<?php\n\n$section->addLink($linkSrc, [$linkName], [$fontStyle], [$paragraphStyle]);\n```\n\n- ``$linkSrc``. The URL of the link.\n- ``$linkName``. Placeholder of the URL that appears in the document.\n- ``$fontStyle``. See [`Styles > Font`](../styles/font.md).\n- ``$paragraphStyle``. See [`Styles > Paragraph`](../styles/paragraph.md)."
  },
  {
    "path": "docs/usage/elements/list.md",
    "content": "# List\n\nLists can be added by using ``addListItem`` and ``addListItemRun`` methods. ``addListItem`` is used for creating lists that only contain plain text. ``addListItemRun`` is used for creating complex list items that contains texts with different style (some bold, other italics, etc) or other elements, e.g. images or links. The syntaxes are as follow:\n\nBasic usage:\n\n``` php\n<?php\n\n$section->addListItem($text, [$depth], [$fontStyle], [$listStyle], [$paragraphStyle]);\n$listItemRun = $section->addListItemRun([$depth], [$listStyle], [$paragraphStyle])\n``` \n\nParameters:\n\n- ``$text``. Text that appears in the document.\n- ``$depth``. Depth of list item.\n- ``$fontStyle``. See [`Styles > Font`](../styles/font.md)..\n- ``$listStyle``. List style of the current element TYPE\\_NUMBER,\n  TYPE\\_ALPHANUM, TYPE\\_BULLET\\_FILLED, etc. See list of constants in PHPWord\\\\Style\\\\ListItem.\n- ``$paragraphStyle``. See [`Styles > Paragraph`](../styles/paragraph.md)..\n\nSee ``Sample_14_ListItem.php`` for more code sample.\n\nAdvanced usage:\n\nYou can also create your own numbering style by changing the ``$listStyle`` parameter with the name of your numbering style.\n\n``` php\n<?php\n\n$phpWord->addNumberingStyle(\n    'multilevel',\n    array(\n        'type' => 'multilevel',\n        'levels' => array(\n            array('format' => 'decimal', 'text' => '%1.', 'left' => 360, 'hanging' => 360, 'tabPos' => 360),\n            array('format' => 'upperLetter', 'text' => '%2.', 'left' => 720, 'hanging' => 360, 'tabPos' => 720),\n        )\n    )\n);\n$section->addListItem('List Item I', 0, null, 'multilevel');\n$section->addListItem('List Item I.a', 1, null, 'multilevel');\n$section->addListItem('List Item I.b', 1, null, 'multilevel');\n$section->addListItem('List Item II', 0, null, 'multilevel');\n``` \n\nFor available styling options see [`Styles > Numbering Level`](../styles/numberinglevel.md)."
  },
  {
    "path": "docs/usage/elements/note.md",
    "content": "# Footnote & Endnote\n\nYou can create footnotes with ``addFootnote`` and endnotes with``addEndnote`` in texts or textruns, but it's recommended to use textrun to have better layout. You can use ``addText``, ``addLink``,``addTextBreak``, ``addImage``, ``addOLEObject`` on footnotes and endnotes.\n\nOn textrun:\n\n``` php\n<?php\n\n$textrun = $section->addTextRun();\n$textrun->addText('Lead text.');\n$footnote = $textrun->addFootnote();\n$footnote->addText('Footnote text can have ');\n$footnote->addLink('http://test.com', 'links');\n$footnote->addText('.');\n$footnote->addTextBreak();\n$footnote->addText('And text break.');\n$textrun->addText('Trailing text.');\n$endnote = $textrun->addEndnote();\n$endnote->addText('Endnote put at the end');\n```\n\nOn text:\n\n``` php\n<?php\n\n$section->addText('Lead text.');\n$footnote = $section->addFootnote();\n$footnote->addText('Footnote text.');\n```\n\nBy default the footnote reference number will be displayed with decimal number\nstarting from 1. This number uses the ``FooterReference`` style which you can\nredefine with the ``addFontStyle`` method. Default value for this style is\n``array('superScript' => true)``;\n\nThe footnote numbering can be controlled by setting the FootnoteProperties on the Section.\n\n``` php\n<?php\n\n$fp = new \\PhpOffice\\PhpWord\\ComplexType\\FootnoteProperties();\n//sets the position of the footnote (pageBottom (default), beneathText, sectEnd, docEnd)\n$fp->setPos(\\PhpOffice\\PhpWord\\ComplexType\\FootnoteProperties::POSITION_BENEATH_TEXT);\n//set the number format to use (decimal (default), upperRoman, upperLetter, ...)\n$fp->setNumFmt(\\PhpOffice\\PhpWord\\SimpleType\\NumberFormat::LOWER_ROMAN);\n//force starting at other than 1\n$fp->setNumStart(2);\n//when to restart counting (continuous (default), eachSect, eachPage)\n$fp->setNumRestart(\\PhpOffice\\PhpWord\\ComplexType\\FootnoteProperties::RESTART_NUMBER_EACH_PAGE);\n//And finaly, set it on the Section\n$section->setFootnoteProperties($fp);\n```"
  },
  {
    "path": "docs/usage/elements/oleobject.md",
    "content": "# Object\n\nYou can add OLE embeddings, such as Excel spreadsheets or PowerPoint presentations to the document by using ``addOLEObject`` method.\n\n``` php\n<?php\n\n$section->addOLEObject($src, [$style]);\n```"
  },
  {
    "path": "docs/usage/elements/pagebreak.md",
    "content": "# Page breaks\n\nThere are two ways to insert a page break, using the ``addPageBreak`` method or using the ``pageBreakBefore`` style of paragraph.\n\n``` php\n<?php\n\n$section->addPageBreak();\n```"
  },
  {
    "path": "docs/usage/elements/preservetext.md",
    "content": "# Preserve text\n\nThe ``addPreserveText`` method is used to add a page number or page count to headers or footers.\n\n``` php\n<?php\n\n$footer->addPreserveText('Page {PAGE} of {NUMPAGES}.');\n```"
  },
  {
    "path": "docs/usage/elements/ruby.md",
    "content": "# Ruby\n\nRuby (phonetic guide) text can be added by using the ``addRuby`` method. Ruby elements require a ``RubyProperties`` object, a ``TextRun`` for the base text, and a ``TextRun`` for the actual ruby (phonetic guide) text.\n\nHere is one example for a complete ruby element setup:\n\n``` php\n<?php\n$phpWord = new PhpWord();\n\n$section = $phpWord->addSection();\n$properties = new RubyProperties();\n$properties->setAlignment(RubyProperties::ALIGNMENT_RIGHT_VERTICAL);\n$properties->setFontFaceSize(10);\n$properties->setFontPointsAboveBaseText(4);\n$properties->setFontSizeForBaseText(18);\n$properties->setLanguageId('ja-JP');\n\n$baseTextRun = new TextRun(null);\n$baseTextRun->addText('私');\n$rubyTextRun = new TextRun(null);\n$rubyTextRun->addText('わたし');\n\n$section->addRuby($baseTextRun, $rubyTextRun, $properties);\n```\n\n- ``$baseTextRun``. ``TextRun`` to be used for the base text.\n- ``$rubyTextRun``. ``TextRun`` to be used for the ruby text.\n- ``$properties``. ``RubyProperties`` properties object for the ruby text.\n\nA title with a phonetic guide is a little more complex, but still possible. Make sure you add the appropraite title style to your document.\n\n```php\n$phpWord = new PhpWord();\n$fontStyle = new Font();\n$fontStyle->setAllCaps(true);\n$fontStyle->setBold(true);\n$fontStyle->setSize(24);\n$phpWord->addTitleStyle(1, ['name' => 'Arial', 'size' => 24, 'bold' => true, 'color' => '990000']);\n\n$section = $phpWord->addSection();\n$properties = new RubyProperties();\n$properties->setAlignment(RubyProperties::ALIGNMENT_RIGHT_VERTICAL);\n$properties->setFontFaceSize(10);\n$properties->setFontPointsAboveBaseText(4);\n$properties->setFontSizeForBaseText(18);\n$properties->setLanguageId('ja-JP');\n\n$baseTextRun = new TextRun(null);\n$baseTextRun->addText('私');\n$rubyTextRun = new TextRun(null);\n$rubyTextRun->addText('わたし');\n\n$textRun = new TextRun();\n$textRun->addRuby($baseTextRun, $rubyTextRun, $properties);\n$section->addTitle($textRun, 1);\n```"
  },
  {
    "path": "docs/usage/elements/table.md",
    "content": "# Table\n\nTo add tables, rows, and cells, use the ``addTable``, ``addRow``, and ``addCell`` methods:\n\n``` php\n<?php\n\n$table = $section->addTable([$tableStyle]);\n$table->addRow([$height], [$rowStyle]);\n$cell = $table->addCell($width, [$cellStyle]);\n```\n\nTable style can be defined with ``addTableStyle``:\n\n``` php\n<?php\n\n$tableStyle = array(\n    'borderColor' => '006699',\n    'borderSize'  => 6,\n    'cellMargin'  => 50\n);\n$firstRowStyle = array('bgColor' => '66BBFF');\n$phpWord->addTableStyle('myTable', $tableStyle, $firstRowStyle);\n$table = $section->addTable('myTable');\n```\n\nFor available styling options see [`Styles > Table`](../styles/table.md).\n\n## Cell span\n\nYou can span a cell on multiple columns by using ``gridSpan`` or multiple rows by using ``vMerge``.\n\n``` php\n<?php\n\n$cell = $table->addCell(200);\n$cell->getStyle()->setGridSpan(5);\n```\n\nSee ``Sample_09_Tables.php`` for more code sample."
  },
  {
    "path": "docs/usage/elements/text.md",
    "content": "# Text\n\n\nText can be added by using ``addText`` and ``addTextRun`` methods. ``addText`` is used for creating simple paragraphs that only contain texts with the same style. ``addTextRun`` is used for creating complex paragraphs that contain text with different style (some bold, other italics, etc) or other elements, e.g. images or links. The syntaxes are as follow:\n\n``` php\n<?php\n\n$section->addText($text, [$fontStyle], [$paragraphStyle]);\n$textrun = $section->addTextRun([$paragraphStyle]);\n```\n\n- ``$text``. Text to be displayed in the document.\n- ``$fontStyle``. See [`Styles > Font`](../styles/font.md).\n- ``$paragraphStyle``. See [`Styles > Paragraph`](../styles/paragraph.md).\n\nFor available styling options, see [`Styles > Font`](../styles/font.md) and [`Styles > Paragraph`](../styles/paragraph.md).\n\nIf you want to enable track changes on added text you can mark it as INSERTED or DELETED by a specific user at a given time:\n\n``` php\n<?php\n\n$text = $section->addText('Hello World!');\n$text->setChanged(\\PhpOffice\\PhpWord\\Element\\ChangedElement::TYPE_INSERTED, 'Fred', (new \\DateTime()));\n```"
  },
  {
    "path": "docs/usage/elements/textbox.md",
    "content": "# TextBox\n\nTo Be Completed... "
  },
  {
    "path": "docs/usage/elements/textbreak.md",
    "content": "# Text breaks\n\nText breaks are empty new lines. To add text breaks, use the following syntax. All parameters are optional.\n\n``` php\n<?php\n\n$section->addTextBreak([$breakCount], [$fontStyle], [$paragraphStyle]);\n```\n\n- ``$breakCount``. How many lines.\n- ``$fontStyle``. See [`Styles > Font`](../styles/font.md).\n- ``$paragraphStyle``. See [`Styles > Paragraph`](../styles/paragraph.md)."
  },
  {
    "path": "docs/usage/elements/title.md",
    "content": "# Title\n\nIf you want to structure your document or build table of contents, you need titles or headings.\nTo add a title to the document, use the ``addTitleStyle`` and ``addTitle`` method.\nIf `depth` is 0, a Title will be inserted, otherwise a Heading1, Heading2, ...\n\n``` php\n<?php\n\n$phpWord->addTitleStyle($depth, [$fontStyle], [$paragraphStyle]);\n$section->addTitle($text, $depth, $pageNumber);\n```\n\n`addTitleStyle` :\n- ``$depth``\n- ``$fontStyle``: See [`Styles > Font`](../styles/font.md).\n- ``$paragraphStyle``: See [`Styles > Paragraph`](../styles/paragraph.md).\n\n`addTitle` :\n- ``$text``. Text to be displayed in the document. This can be `string` or a `\\PhpOffice\\PhpWord\\Element\\TextRun`\n- ``$depth``\n- ``$pageNumber`` : Number of the page\n\nIt's necessary to add a title style to your document because otherwise the title won't be detected as a real title."
  },
  {
    "path": "docs/usage/elements/toc.md",
    "content": "# Table of contents\n\nTo add a table of contents (TOC), you can use the ``addTOC`` method.\nYour TOC can only be generated if you have add at least one title (See \"[Title](title.md)\").\n\n``` php\n<?php\n\n$section->addTOC([$fontStyle], [$tocStyle], [$minDepth], [$maxDepth]);\n```\n\n- ``$fontStyle``. See font style section.\n- ``$tocStyle``. See available options below.\n- ``$minDepth``. Minimum depth of header to be shown. Default 1.\n- ``$maxDepth``. Maximum depth of header to be shown. Default 9.\n\nOptions for ``$tocStyle``:\n\n- ``tabLeader``. Fill type between the title text and the page number. Use the defined constants in ``\\PhpOffice\\PhpWord\\Style\\TOC``.\n- ``tabPos``. The position of the tab where the page number appears in *twip*.\n- ``indent``. The indent factor of the titles in *twip*."
  },
  {
    "path": "docs/usage/elements/trackchanges.md",
    "content": "# Track Changes\n\nTrack changes can be set on text elements. There are 2 ways to set the change information on an element.\nEither by calling the `setChangeInfo()`, or by setting the `TrackChange` instance on the element with `setTrackChange()`.\n\n``` php\n<?php\n\n$phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n\n// New portrait section\n$section = $phpWord->addSection();\n$textRun = $section->addTextRun();\n\n$text = $textRun->addText('Hello World! Time to ');\n\n$text = $textRun->addText('wake ', array('bold' => true));\n$text->setChangeInfo(TrackChange::INSERTED, 'Fred', time() - 1800);\n\n$text = $textRun->addText('up');\n$text->setTrackChange(new TrackChange(TrackChange::INSERTED, 'Fred'));\n\n$text = $textRun->addText('go to sleep');\n$text->setChangeInfo(TrackChange::DELETED, 'Barney', new \\DateTime('@' . (time() - 3600)));\n```"
  },
  {
    "path": "docs/usage/elements/watermark.md",
    "content": "# Watermark\n\nTo add a watermark (or page background image), your section needs a\nheader reference. After creating a header, you can use the\n``addWatermark`` method to add a watermark.\n\n``` php\n<?php\n\n$section = $phpWord->addSection();\n$header = $section->addHeader();\n$header->addWatermark('resources/_earth.jpg', array('marginTop' => 200, 'marginLeft' => 55));\n```"
  },
  {
    "path": "docs/usage/introduction.md",
    "content": "# Introduction\n\n## Basic example\n\nThe following is a basic example of the PHPWord library. More examples\nare provided in the [samples folder](https://github.com/PHPOffice/PHPWord/tree/master/samples/).\n\n``` php\n<?php\n\n// Creating the new document...\n$phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n\n/* Note: any element you append to a document must reside inside of a Section. */\n\n// Adding an empty Section to the document...\n$section = $phpWord->addSection();\n// Adding Text element to the Section having font styled by default...\n$section->addText(\n    '\"Learn from yesterday, live for today, hope for tomorrow. '\n        . 'The important thing is not to stop questioning.\" '\n        . '(Albert Einstein)'\n);\n\n/*\n * Note: it's possible to customize font style of the Text element you add in three ways:\n * - inline;\n * - using named font style (new font style object will be implicitly created);\n * - using explicitly created font style object.\n */\n\n// Adding Text element with font customized inline...\n$section->addText(\n    '\"Great achievement is usually born of great sacrifice, '\n        . 'and is never the result of selfishness.\" '\n        . '(Napoleon Hill)',\n    array('name' => 'Tahoma', 'size' => 10)\n);\n\n// Adding Text element with font customized using named font style...\n$fontStyleName = 'oneUserDefinedStyle';\n$phpWord->addFontStyle(\n    $fontStyleName,\n    array('name' => 'Tahoma', 'size' => 10, 'color' => '1B2232', 'bold' => true)\n);\n$section->addText(\n    '\"The greatest accomplishment is not in never falling, '\n        . 'but in rising again after you fall.\" '\n        . '(Vince Lombardi)',\n    $fontStyleName\n);\n\n// Adding Text element with font customized using explicitly created font style object...\n$fontStyle = new \\PhpOffice\\PhpWord\\Style\\Font();\n$fontStyle->setBold(true);\n$fontStyle->setName('Tahoma');\n$fontStyle->setSize(13);\n$myTextElement = $section->addText('\"Believe you can and you\\'re halfway there.\" (Theodor Roosevelt)');\n$myTextElement->setFontStyle($fontStyle);\n\n// Saving the document as OOXML file...\n$objWriter = \\PhpOffice\\PhpWord\\IOFactory::createWriter($phpWord, 'Word2007');\n$objWriter->save('helloWorld.docx');\n\n// Saving the document as ODF file...\n$objWriter = \\PhpOffice\\PhpWord\\IOFactory::createWriter($phpWord, 'ODText');\n$objWriter->save('helloWorld.odt');\n\n// Saving the document as HTML file...\n$objWriter = \\PhpOffice\\PhpWord\\IOFactory::createWriter($phpWord, 'HTML');\n$objWriter->save('helloWorld.html');\n\n/* Note: we skip RTF, because it's not XML-based and requires a different example. */\n/* Note: we skip PDF, because \"HTML-to-PDF\" approach is used to create PDF documents. */\n```\n\n## PHPWord Settings\n\nThe ``PhpOffice\\PhpWord\\Settings`` class provides some options that will\naffect the behavior of PHPWord. Below are the options.\n\n### XML Writer compatibility\n\nThis option sets [XMLWriter::setIndent](http://www.php.net/manual/en/function.xmlwriter-set-indent.php) and [XMLWriter::setIndentString](http://www.php.net/manual/en/function.xmlwriter-set-indent-string.php>). The default value of this option is ``true`` (compatible), which is [required for OpenOffice](https://github.com/PHPOffice/PHPWord/issues/103) to render OOXML document correctly. You can set this option to ``false`` during development to make the resulting XML file easier to read.\n\n``` php\n<?php\n\n\\PhpOffice\\PhpWord\\Settings::setCompatibility(false);\n```\n\n### Zip class\n\nBy default, PHPWord uses [Zip extension](http://php.net/manual/en/book.zip.php) to deal with ZIP compressed archives and files inside them. If you can't have Zip extension installed on your server, you can use pure PHP library alternative, `[PclZip](http://www.phpconcept.net/pclzip/)``, which is included in PHPWord.\n\n``` php\n<?php\n\n\\PhpOffice\\PhpWord\\Settings::setZipClass(\\PhpOffice\\PhpWord\\Settings::PCLZIP);\n```\n\n### Output escaping\n\nWriting documents of some formats, especially XML-based, requires correct output escaping.\nWithout it your document may become broken when you put special characters like ampersand, quotes, and others in it.\n\nEscaping can be performed in two ways: outside of the library by a software developer and inside of the library by built-in mechanism.\nBy default, the built-in mechanism is disabled for backward compatibility with versions prior to v0.13.0.\nTo turn it on set ``outputEscapingEnabled`` option to ``true`` in your PHPWord configuration file or use the following instruction at runtime:\n\n``` php\n<?php\n\n\\PhpOffice\\PhpWord\\Settings::setOutputEscapingEnabled(true);\n```\n\n### Default Paper\n\nBy default, all sections of the document will print on A4 paper.\nYou can alter the default paper by using the following function:\n\n``` php\n<?php\n\n\\PhpOffice\\PhpWord\\Settings::setDefaultPaper('Letter');\n```\n\n### Default font\n\nBy default, every text appears in Arial 10 point in the color black (000000).\nYou can alter the default font by using the following functions:\n\n``` php\n<?php\n\n$phpWord->setDefaultFontName('Times New Roman');\n$phpWord->setDefaultFontColor('FF0000');\n$phpWord->setDefaultFontSize(12);\n```\n\nOr you can specify Asian Font\n\n``` php\n<?php\n\n$phpWord->setDefaultAsianFontName('標楷體');\n```\n\n## Document settings\n\nSettings for the generated document can be set using ``$phpWord->getSettings()``\n\n### Magnification Setting\n\nThe default zoom value is 100 percent. This can be changed either to another percentage\n\n``` php\n<?php\n\n$phpWord->getSettings()->setZoom(75);\n```\n\nOr to predefined values ``fullPage``, ``bestFit``, ``textFit``\n\n``` php\n<?php\n\n$phpWord->getSettings()->setZoom(Zoom::BEST_FIT);\n```\n\n### Mirroring the Page Margins\n\nUse mirror margins to set up facing pages for double-sided documents, such as books or magazines.\n\n``` php\n<?php\n\n$phpWord->getSettings()->setMirrorMargins(true);\n```\n\n!!! note annotate \"Don't forget to set both paper size and page size\"\n\n    For example, to print a document on A4 paper (landscape) and fold it into A5 pages (portrait), use this section style:\n\n    ``` php\n    <?php\n\n    use PhpOffice\\PhpWord\\Shared\\Converter;\n\n    $phpWord->getSettings()->setMirrorMargins(true);\n    $phpWord->addSection([\n        'paperSize' => 'A4',\n        'orientation' => 'landscape',\n        'pageSizeW' => Converter::cmToTwip(14.85),\n        'pageSizeH' => Converter::cmToTwip(21),\n    ]);\n    ```\n\n### Printing as folded booklet\n\nUse book-fold printing to set up documents to be printed as foldable pages.\n\n``` php\n<?php\n\n$phpWord->getSettings()->setBookFoldPrinting(true);\n```\n\n### Spelling and grammatical checks\n\nBy default spelling and grammatical errors are shown as soon as you open a word document.\nFor big documents this can slow down the opening of the document. You can hide the spelling and/or grammatical errors with:\n\n``` php\n<?php\n\n$phpWord->getSettings()->setHideGrammaticalErrors(true);\n$phpWord->getSettings()->setHideSpellingErrors(true);\n```\n\nYou can also specify the status of the spell and grammar checks, marking spelling or grammar as dirty will force a re-check when opening the document.\n\n``` php\n<?php\n\n$proofState = new \\PhpOffice\\PhpWord\\ComplexType\\ProofState();\n$proofState->setGrammar(\\PhpOffice\\PhpWord\\ComplexType\\ProofState::CLEAN);\n$proofState->setSpelling(\\PhpOffice\\PhpWord\\ComplexType\\ProofState::DIRTY);\n\n$phpWord->getSettings()->setProofState($proofState);\n```\n\n### Track Revisions\n\nTrack changes can be activated using ``setTrackRevisions``, you can furture specify\n\n-  Not to use move syntax, instead moved items will be seen as deleted in one place and added in another\n-  Not track formatting revisions\n\n``` php\n<?php\n\n$phpWord->getSettings()->setTrackRevisions(true);\n$phpWord->getSettings()->setDoNotTrackMoves(true);\n$phpWord->getSettings()->setDoNotTrackFormatting(true);\n```\n\n### Decimal Symbol\n\nThe default symbol to represent a decimal figure is the ``.`` in english. In french you might want to change it to ``,`` for instance.\n\n``` php\n<?php\n\n$phpWord->getSettings()->setDecimalSymbol(',');\n```\n\n### Document Language\n\nThe default language of the document can be change with the following.\n\n``` php\n<?php\n\n$phpWord->getSettings()->setThemeFontLang(new Language(Language::FR_BE));\n```\n\n``Language`` has 3 parameters, one for Latin languages, one for East Asian languages and one for Complex (Bi-Directional) languages.\nA couple of language codes are provided in the ``PhpOffice\\PhpWord\\Style\\Language`` class but any valid code/ID can be used.\n\nIn case you are generating an RTF document the language need to be set differently.\n\n``` php\n<?php\n\n$lang = new Language();\n$lang->setLangId(Language::EN_GB_ID);\n$phpWord->getSettings()->setThemeFontLang($lang);\n```\n\n## Document information\n\nYou can set the document information such as title, creator, and company\nname. Use the following functions:\n\n``` php\n<?php\n\n$properties = $phpWord->getDocInfo();\n$properties->setCreator('My name');\n$properties->setCompany('My factory');\n$properties->setTitle('My title');\n$properties->setDescription('My description');\n$properties->setCategory('My category');\n$properties->setLastModifiedBy('My name');\n$properties->setCreated(mktime(0, 0, 0, 3, 12, 2014));\n$properties->setModified(mktime(0, 0, 0, 3, 14, 2014));\n$properties->setSubject('My subject');\n$properties->setKeywords('my, key, word');\n```\n\n## Measurement units\n\nThe base length unit in Open Office XML is twip. Twip means \"TWentieth\nof an Inch Point\", i.e. 1 twip = 1/1440 inch.\n\nYou can use PHPWord helper functions to convert inches, centimeters, or\npoints to twip.\n\n``` php\n<?php\n\n// Paragraph with 6 points space after\n$phpWord->addParagraphStyle('My Style', array(\n    'spaceAfter' => \\PhpOffice\\PhpWord\\Shared\\Converter::pointToTwip(6))\n);\n\n$section = $phpWord->addSection();\n$sectionStyle = $section->getStyle();\n// half inch left margin\n$sectionStyle->setMarginLeft(\\PhpOffice\\PhpWord\\Shared\\Converter::inchToTwip(.5));\n// 2 cm right margin\n$sectionStyle->setMarginRight(\\PhpOffice\\PhpWord\\Shared\\Converter::cmToTwip(2));\n```\n\n## Document protection\n\nThe document (or parts of it) can be password protected.\n\n``` php\n<?php\n\n$documentProtection = $phpWord->getSettings()->getDocumentProtection();\n$documentProtection->setEditing(DocProtect::READ_ONLY);\n$documentProtection->setPassword('myPassword');\n```\n\n## Automatically Recalculate Fields on Open\n\nTo force an update of the fields present in the document, set updateFields to true\n\n``` php\n<?php\n\n$phpWord->getSettings()->setUpdateFields(true);\n```\n\n## Hyphenation\n\nHyphenation describes the process of breaking words with hyphens. There are several options to control hyphenation.\n\n### Auto hyphenation\n\nTo automatically hyphenate text set ``autoHyphenation`` to ``true``.\n\n``` php\n<?php\n\n$phpWord->getSettings()->setAutoHyphenation(true);\n```\n\n### Consecutive Hyphen Limit\n\nThe maximum number of consecutive lines of text ending with a hyphen can be controlled by the ``consecutiveHyphenLimit`` option.\nThere is no limit if the option is not set or the provided value is ``0``.\n\n``` php\n<?php\n\n$phpWord->getSettings()->setConsecutiveHyphenLimit(2);\n```\n\n### Hyphenation Zone\n\nThe hyphenation zone (in *twip*) is the allowed amount of whitespace before hyphenation is applied.\nThe smaller the hyphenation zone the more words are hyphenated. Or in other words, the wider the hyphenation zone the less words are hyphenated.\n\n``` php\n<?php\n\n$phpWord->getSettings()->setHyphenationZone(\\PhpOffice\\PhpWord\\Shared\\Converter::cmToTwip(1));\n```\n\n### Hyphenate Caps\n\nTo control whether or not words in all capital letters shall be hyphenated use the `doNotHyphenateCaps` option.\n\n``` php\n<?php\n\n$phpWord->getSettings()->setDoNotHyphenateCaps(true);\n```\n"
  },
  {
    "path": "docs/usage/readers.md",
    "content": "# Readers\n\n## HTML\nThe name of the reader is `HTML`.\n\n``` php\n<?php\n\n$reader = IOFactory::createReader('HTML');\n$reader->load(__DIR__ . '/sample.html');\n```\n\n## MsDoc\nThe name of the reader is `MsDoc`.\n\n``` php\n<?php\n\n$reader = IOFactory::createReader('MsDoc');\n$reader->load(__DIR__ . '/sample.doc');\n```\n\n## ODText\nThe name of the reader is `ODText`.\n\n``` php\n<?php\n\n$reader = IOFactory::createReader('ODText');\n$reader->load(__DIR__ . '/sample.odt');\n```\n\n## RTF\nThe name of the reader is `RTF`.\n\n``` php\n<?php\n\n$reader = IOFactory::createReader('RTF');\n$reader->load(__DIR__ . '/sample.rtf');\n```\n\n## Word2007\nThe name of the reader is `Word2007`.\n\n``` php\n<?php\n\n$reader = IOFactory::createReader('Word2007');\n$reader->load(__DIR__ . '/sample.docx');\n```"
  },
  {
    "path": "docs/usage/styles/chart.md",
    "content": "# Chart\n\nAvailable Chart style options:\n\n- ``width``. Width (in EMU).\n- ``height``. Height (in EMU).\n- ``3d``. Is 3D; applies to pie, bar, line, area, *true* or *false*.\n- ``colors``. A list of colors to use in the chart.\n- ``title``. The title for the chart.\n- ``showLegend``. Show legend, *true* or *false*.\n- ``LegendPosition``. Legend position, *r* (default), *b*, *t*, *l* or *tr*.\n- ``categoryLabelPosition``. Label position for categories, *nextTo* (default), *low* or *high*.\n- ``valueLabelPosition``. Label position for values, *nextTo* (default), *low* or *high*.\n- ``categoryAxisTitle``. The title for the category axis.\n- ``valueAxisTitle``. The title for the values axis.\n- ``majorTickMarkPos``. The position for major tick marks, *in*, *out*, *cross*, *none* (default).\n- ``showAxisLabels``. Show labels for axis, *true* or *false*.\n- ``gridX``. Show Gridlines for X-Axis, *true* or *false*.\n- ``gridY``. Show Gridlines for Y-Axis, *true* or *false*."
  },
  {
    "path": "docs/usage/styles/font.md",
    "content": "# Font\n\nAvailable Font style options:\n\n- ``allCaps``. All caps, *true* or *false*.\n- ``bgColor``. Font background color, e.g. *FF0000*.\n- ``bold``. Bold, *true* or *false*.\n- ``color``. Font color, e.g. *FF0000*.\n- ``doubleStrikethrough``. Double strikethrough, *true* or *false*.\n- ``fgColor``. Font highlight color, e.g. *yellow*, *green*, *blue*.\n   See ``\\PhpOffice\\PhpWord\\Style\\Font::FGCOLOR_...`` class constants for possible values\n- ``hint``. Font content type, *default*, *eastAsia*, or *cs*.\n- ``italic``. Italic, *true* or *false*.\n- ``name``. Font name, e.g. *Arial*.\n- ``rtl``. Right to Left language, *true* or *false*.\n- ``size``. Font size, e.g. *20*, *22*.\n- ``smallCaps``. Small caps, *true* or *false*.\n- ``strikethrough``. Strikethrough, *true* or *false*.\n- ``subScript``. Subscript, *true* or *false*.\n- ``superScript``. Superscript, *true* or *false*.\n- ``underline``. Underline, *single*, *dash*, *dotted*, etc.\n   See ``\\PhpOffice\\PhpWord\\Style\\Font::UNDERLINE_...`` class constants for possible values\n- ``lang``. Language, either a language code like *en-US*, *fr-BE*, etc. or an object (or as an array) if you need to set eastAsian or bidirectional languages\n   See ``\\PhpOffice\\PhpWord\\Style\\Language`` class for some language codes.\n- ``position``. The text position, raised or lowered, in half points\n- ``hidden``. Hidden text, *true* or *false*.\n- ``whiteSpace``. How white space is handled when generating html/pdf. Possible values are *pre-wrap* and *normal* (other css values for white space are accepted, but are not expected to be useful).\n- ``fallbackFont``. Fallback generic font for html/pdf. Possible values are *sans-serif*, *serif*, and *monospace* (other css values for generic fonts are accepted).\n"
  },
  {
    "path": "docs/usage/styles/image.md",
    "content": "# Image\n\nAvailable Image style options:\n\n- ``alignment``. See ``\\PhpOffice\\PhpWord\\SimpleType\\Jc`` class for the details.\n- ``height``. Height in *pt*.\n- ``marginLeft``. Left margin in inches, can be negative.\n- ``marginTop``. Top margin in inches, can be negative.\n- ``width``. Width in *pt*.\n- ``wrappingStyle``. Wrapping style, *inline*, *square*, *tight*, *behind*, or *infront*.\n- ``wrapDistanceTop``. Top text wrapping in pixels.\n- ``wrapDistanceBottom``. Bottom text wrapping in pixels.\n- ``wrapDistanceLeft``. Left text wrapping in pixels.\n- ``wrapDistanceRight``. Right text wrapping in pixels."
  },
  {
    "path": "docs/usage/styles/numberinglevel.md",
    "content": "# Numbering level\n\nAvailable NumberingLevel style options:\n\n- ``alignment``. Supports all alignment modes since 1st Edition of ECMA-376 standard up till ISO/IEC 29500:2012.\n   See ``\\PhpOffice\\PhpWord\\SimpleType\\Jc`` class constants for possible values.\n- ``font``. Font name.\n- ``format``. Numbering format bullet\\|decimal\\|upperRoman\\|lowerRoman\\|upperLetter\\|lowerLetter.\n- ``hanging``. See paragraph style.\n- ``hint``. See font style.\n- ``left``. See paragraph style.\n- ``restart``. Restart numbering level symbol.\n- ``start``. Starting value.\n- ``suffix``. Content between numbering symbol and paragraph text tab\\|space\\|nothing.\n- ``tabPos``. See paragraph style.\n- ``text``. Numbering level text e.g. %1 for nonbullet or bullet character."
  },
  {
    "path": "docs/usage/styles/paragraph.md",
    "content": "# Paragraph\n\nAvailable Paragraph style options:\n\n- ``alignment``. Supports all alignment modes since 1st Edition of ECMA-376 standard up till ISO/IEC 29500:2012.\n   See ``\\PhpOffice\\PhpWord\\SimpleType\\Jc`` class constants for possible values.\n- ``basedOn``. Parent style.\n- ``hanging``. Hanging indentation in *half inches*.\n- ``indent``. Indent (left indentation) in *half inches*.\n- ``indentation``. An array of indentation key => value pairs in *twip*. Supports *left*, *right*, *firstLine*, *firstLineChars* and *hanging* indentation.\n   See ``\\PhpOffice\\PhpWord\\Style\\Indentation`` for possible identation types.\n- ``keepLines``. Keep all lines on one page, *true* or *false*.\n- ``keepNext``. Keep paragraph with next paragraph, *true* or *false*.\n- ``lineHeight``. Text line height, e.g. *1.0*, *1.5*, etc.\n- ``next``. Style for next paragraph.\n- ``pageBreakBefore``. Start paragraph on next page, *true* or *false*.\n- ``spaceBefore``. Space before paragraph in *twip*.\n- ``spaceAfter``. Space after paragraph in *twip*.\n- ``spacing``. Space between lines in *twip*. If spacingLineRule is auto, 240 (height of 1 line) will be added, so if you want a double line height, set this to 240.\n- ``spacingLineRule``. Line Spacing Rule. *auto*, *exact*, *atLeast*\n   See ``\\PhpOffice\\PhpWord\\SimpleType\\LineSpacingRule`` class constants for possible values.\n- ``suppressAutoHyphens``. Hyphenation for paragraph, *true* or *false*.\n- ``tabs``. Set of custom tab stops.\n- ``widowControl``. Allow first/last line to display on a separate page, *true* or *false*.\n- ``contextualSpacing``. Ignore Spacing Above and Below When Using Identical Styles, *true* or *false*.\n- ``bidi``. Right to Left Paragraph Layout, *true* or *false*.\n- ``shading``. Paragraph Shading.\n- ``textAlignment``. Vertical Character Alignment on Line.\n   See ``\\PhpOffice\\PhpWord\\SimpleType\\TextAlignment`` class constants for possible values."
  },
  {
    "path": "docs/usage/styles/section.md",
    "content": "# Section\n\nAvailable Section style options:\n\n- ``borderBottomColor``. Border bottom color.\n- ``borderBottomSize``. Border bottom size in *twip*.\n- ``borderLeftColor``. Border left color.\n- ``borderLeftSize``. Border left size in *twip*.\n- ``borderRightColor``. Border right color.\n- ``borderRightSize``. Border right size in *twip*.\n- ``borderTopColor``. Border top color.\n- ``borderTopSize``. Border top size in *twip*.\n- ``breakType``. Section break type (nextPage, nextColumn, continuous, evenPage, oddPage).\n- ``colsNum``. Number of columns.\n- ``colsSpace``. Spacing between columns.\n- ``footerHeight``. Spacing to bottom of footer.\n- ``gutter``. Page gutter spacing.\n- ``headerHeight``. Spacing to top of header.\n- ``marginTop``. Page margin top in *twip*.\n- ``marginLeft``. Page margin left in *twip*.\n- ``marginRight``. Page margin right in *twip*.\n- ``marginBottom``. Page margin bottom in *twip*.\n- ``orientation``. Page orientation (``portrait``, which is default, or ``landscape``).\n   See ``\\PhpOffice\\PhpWord\\Style\\Section::ORIENTATION_...`` class constants for possible values\n- ``pageSizeH``. Page height in *twip*. Implicitly defined by ``orientation`` option. Any changes are discouraged.\n- ``pageSizeW``. Page width in *twip*. Implicitly defined by ``orientation`` option. Any changes are discouraged.\n- ``vAlign``. Vertical Page Alignment\n   See ``\\PhpOffice\\PhpWord\\SimpleType\\VerticalJc`` for possible values"
  },
  {
    "path": "docs/usage/styles/table.md",
    "content": "# Table\n\nAvailable Table style options:\n\n- ``alignment``. Supports all alignment modes since 1st Edition of ECMA-376 standard up till ISO/IEC 29500:2012.\n   See ``\\PhpOffice\\PhpWord\\SimpleType\\JcTable`` and ``\\PhpOffice\\PhpWord\\SimpleType\\Jc`` class constants for possible values.\n- ``bgColor``. Background color, e.g. '9966CC'.\n- ``border(Top|Right|Bottom|Left)Color``. Border color, e.g. '9966CC'.\n- ``border(Top|Right|Bottom|Left)Size``. Border size in *twip*.\n- ``cellMargin(Top|Right|Bottom|Left)``. Cell margin in *twip*.\n- ``indent``. Table indent from leading margin. Must be an instance of ``\\PhpOffice\\PhpWord\\ComplexType\\TblWidth``.\n- ``width``. Table width in Fiftieths of a Percent or Twentieths of a Point.\n- ``unit``. The unit to use for the width. One of ``\\PhpOffice\\PhpWord\\SimpleType\\TblWidth``. Defaults to *auto*.\n- ``layout``. Table layout, either *fixed* or *autofit*  See ``\\PhpOffice\\PhpWord\\Style\\Table`` for constants.\n- ``cellSpacing`` Cell spacing in *twip*\n- ``position`` Floating Table Positioning, see below for options\n- ``bidiVisual`` Present table as Right-To-Left\n\nFloating Table Positioning options:\n\n- ``leftFromText`` Distance From Left of Table to Text in *twip*\n- ``rightFromText`` Distance From Right of Table to Text in *twip*\n- ``topFromText`` Distance From Top of Table to Text in *twip*\n- ``bottomFromText`` Distance From Top of Table to Text in *twip*\n- ``vertAnchor`` Table Vertical Anchor, one of ``\\PhpOffice\\PhpWord\\Style\\TablePosition::VANCHOR_*``\n- ``horzAnchor`` Table Horizontal Anchor, one of ``\\PhpOffice\\PhpWord\\Style\\TablePosition::HANCHOR_*``\n- ``tblpXSpec`` Relative Horizontal Alignment From Anchor, one of ``\\PhpOffice\\PhpWord\\Style\\TablePosition::XALIGN_*``\n- ``tblpX`` Absolute Horizontal Distance From Anchorin *twip*\n- ``tblpYSpec`` Relative Vertical Alignment From Anchor, one of ``\\PhpOffice\\PhpWord\\Style\\TablePosition::YALIGN_*``\n- ``tblpY`` Absolute Vertical Distance From Anchorin *twip*\n\nAvailable Row style options:\n\n- ``cantSplit``. Table row cannot break across pages, *true* or *false*.\n- ``exactHeight``. Row height is exact or at least.\n- ``tblHeader``. Repeat table row on every new page, *true* or *false*.\n\nAvailable Cell style options:\n\n- ``bgColor``. Background color, e.g. '9966CC'.\n- ``border(Top|Right|Bottom|Left)Color``. Border color, e.g. '9966CC'.\n- ``border(Top|Right|Bottom|Left)Size``. Border size in *twip*.\n- ``border(Top|Right|Bottom|Left)Style``. Border style. You can use constants from ``\\PhpOffice\\PhpWord\\SimpleType\\Border``\n- ``gridSpan``. Number of columns spanned.\n- ``textDirection(btLr|tbRl)``. Direction of text.\n   You can use constants ``\\PhpOffice\\PhpWord\\Style\\Cell::TEXT_DIR_BTLR`` and ``\\PhpOffice\\PhpWord\\Style\\Cell::TEXT_DIR_TBRL``\n- ``valign``. Vertical alignment, *top*, *center*, *both*, *bottom*.\n- ``vMerge``. *restart* or *continue*.\n- ``width``. Cell width in *twip*."
  },
  {
    "path": "docs/usage/template.md",
    "content": "# Template processing\n\nYou can create an OOXML document template with included search-patterns (macros) which can be replaced by any value you wish. Only single-line values can be replaced.\nBy default Macros are defined like this: ``${search-pattern}`` but you can define custom macros.\nTo load a template file, create a new instance of the TemplateProcessor.\n\n``` php\n<?php\n\n$templateProcessor = new TemplateProcessor('Template.docx');\n```\n\n## setValue\n\nGiven a template containing\n\n``` clean\nHello ${firstname} ${lastname}!\n```\n\nThe following will replace ``${firstname}`` with ``John``, and ``${lastname}`` with ``Doe`` .\nThe resulting document will now contain ``Hello John Doe!``\n\n``` php\n<?php\n\n$templateProcessor->setValue('firstname', 'John');\n$templateProcessor->setValue('lastname', 'Doe');\n```\n\n## setValues\n\nYou can also set multiple values by passing all of them in an array.\n\n``` php\n<?php\n\n$templateProcessor->setValues(array('firstname' => 'John', 'lastname' => 'Doe'));\n```\n\n## setCheckbox\n\nGiven a template containing a checkbox control with the title or tag named:\n\n``` clean\n${checkbox}\n```\nThe following will check the checkbox:\n\n``` php\n<?php\n\n$templateProcessor->setCheckbox('checkbox', true);\n```\n\n!!! note annotate \"To add a checkbox and set its title or tag in a template\"\n\n    1. Go to **Developer** tab > **Controls** group\n    2. Select the **Check Box Content Control**\n    3. Right-click on your checkbox\n    4. Click on **Properties**\n    5. Set the title or the tag\n\n    These steps may change regarding the version of Microsoft Word used.\n\n## setMacroOpeningChars\n\nYou can define a custom opening macro. The following will set ``{#`` as the opening search pattern.\n\n``` php\n<?php\n\n$templateProcessor->setMacroOpeningChars('{#');\n```\n\n## setMacroClosingChars\n\nYou can define a custom closing macro. The following will set ``#}`` as the closing search pattern.\n\n``` php\n<?php\n\n$templateProcessor->setMacroClosingChars('#}');\n```\n\n## setMacroChars\n\nYou can define a custom opening and closing macro at the same time . The following will set the search-pattern like this: ``{#search-pattern#}`` .\n\n``` php\n<?php\n\n$templateProcessor->setMacroChars('{#', '#}');\n```\n\n## setImageValue\n\nThe search-pattern model for images can be like:\n    - ``${search-image-pattern}``\n    - ``${search-image-pattern:[width]:[height]:[ratio]}``\n    - ``${search-image-pattern:[width]x[height]}``\n    - ``${search-image-pattern:size=[width]x[height]}``\n    - ``${search-image-pattern:width=[width]:height=[height]:ratio=false}``\n\nWhere:\n    - [width] and [height] can be just numbers or numbers with measure, which supported by Word (cm, mm, in, pt, pc, px, %, em, ex)\n    - [ratio] uses only for ``false``, ``-`` or ``f`` to turn off respect aspect ration of image. By default template image size uses as 'container' size.\n\nExample:\n\n``` clean\n\n${CompanyLogo}\n${UserLogo:50:50} ${Name} - ${City} - ${Street}\n```\n\n``` php\n<?php\n\n$templateProcessor = new TemplateProcessor('Template.docx');\n$templateProcessor->setValue('Name', 'John Doe');\n$templateProcessor->setValue(array('City', 'Street'), array('Detroit', '12th Street'));\n\n$templateProcessor->setImageValue('CompanyLogo', 'path/to/company/logo.png');\n$templateProcessor->setImageValue('UserLogo', array('path' => 'path/to/logo.png', 'width' => 100, 'height' => 100, 'ratio' => false));\n$templateProcessor->setImageValue('FeatureImage', function () {\n    // Closure will only be executed if the replacement tag is found in the template\n\n    return array('path' => SlowFeatureImageGenerator::make(), 'width' => 100, 'height' => 100, 'ratio' => false);\n});\n```\n\n## cloneBlock\n\nGiven a template containing\nSee ``Sample_23_TemplateBlock.php`` for an example.\n\n``` clean\n\n${block_name}\nCustomer: ${customer_name}\nAddress: ${customer_address}\n${/block_name}\n```\n\nThe following will duplicate everything between ``${block_name}`` and ``${/block_name}`` 3 times.\n\n``` php\n<?php\n\n$templateProcessor->cloneBlock('block_name', 3, true, true);\n```\n\nThe last parameter will rename any macro defined inside the block and add #1, #2, #3 ... to the macro name.\nThe result will be\n\n``` clean\n\nCustomer: ${customer_name#1}\nAddress: ${customer_address#1}\n\nCustomer: ${customer_name#2}\nAddress: ${customer_address#2}\n\nCustomer: ${customer_name#3}\nAddress: ${customer_address#3}\n```\n\nIt is also possible to pass an array with the values to replace the marcros with.\nIf an array with replacements is passed, the ``count`` argument is ignored, it is the size of the array that counts.\n\n``` php\n<?php\n\n$replacements = array(\n    array('customer_name' => 'Batman', 'customer_address' => 'Gotham City'),\n    array('customer_name' => 'Superman', 'customer_address' => 'Metropolis'),\n);\n$templateProcessor->cloneBlock('block_name', 0, true, false, $replacements);\n```\n\nThe result will then be\n\n``` clean\n\nCustomer: Batman\nAddress: Gotham City\n\nCustomer: Superman\nAddress: Metropolis\n```\n\n## replaceBlock\n\nGiven a template containing\n\n``` clean\n\n${block_name}\nThis block content will be replaced\n${/block_name}\n```\n\nThe following will replace everything between ``${block_name}`` and ``${/block_name}`` with the value passed.\n\n``` php\n<?php\n\n$templateProcessor->replaceBlock('block_name', 'This is the replacement text.');\n```\n\n## deleteBlock\n\nSame as previous, but it deletes the block\n\n``` php\n<?php\n\n$templateProcessor->deleteBlock('block_name');\n```\n\n## cloneRow\n\nClones a table row in a template document.\nSee ``Sample_07_TemplateCloneRow.php`` for an example.\n\n``` clean\n\n+-----------+----------------+\n| ${userId} | ${userName}    |\n|           |----------------+\n|           | ${userAddress} |\n+-----------+----------------+\n```\n\n``` php\n<?php\n\n$templateProcessor->cloneRow('userId', 2);\n```\n\nWill result in\n\n``` clean\n\n +-------------+------------------+\n| ${userId#1} | ${userName#1}    |\n|             |------------------+\n|             | ${userAddress#1} |\n+-------------+------------------+\n| ${userId#2} | ${userName#2}    |\n|             |------------------+\n|             | ${userAddress#2} |\n+-------------+------------------+\n```\n\n## cloneRowAndSetValues\n\nFinds a row in a table row identified by `$search` param and clones it as many times as there are entries in `$values`.\n\n``` clean\n\n+-----------+----------------+\n| ${userId} | ${userName}    |\n|           |----------------+\n|           | ${userAddress} |\n+-----------+----------------+\n```\n\n``` php\n<?php\n\n$values = [\n    ['userId' => 1, 'userName' => 'Batman', 'userAddress' => 'Gotham City'],\n    ['userId' => 2, 'userName' => 'Superman', 'userAddress' => 'Metropolis'],\n];\n$templateProcessor->cloneRowAndSetValues('userId', $values);\n```\n\nWill result in\n\n``` clean\n\n+---+-------------+\n| 1 | Batman      |\n|   |-------------+\n|   | Gotham City |\n+---+-------------+\n| 2 | Superman    |\n|   |-------------+\n|   | Metropolis  |\n+---+-------------+\n```\n\n## applyXslStyleSheet\n\nApplies the XSL stylesheet passed to header part, footer part and main part\n\n``` php\n<?php\n\n$xslDomDocument = new \\DOMDocument();\n$xslDomDocument->load('/path/to/my/stylesheet.xsl');\n$templateProcessor->applyXslStyleSheet($xslDomDocument);\n```\n\n## setComplexValue\n\nReplaces a ${macro} with the ComplexType passed.\nSee ``Sample_40_TemplateSetComplexValue.php`` for examples.\n\n``` php\n<?php\n\n$inline = new TextRun();\n$inline->addText('by a red italic text', array('italic' => true, 'color' => 'red'));\n$templateProcessor->setComplexValue('inline', $inline);\n```\n\n## setComplexBlock\n\nReplaces a ${macro} with the ComplexType passed.\nSee ``Sample_40_TemplateSetComplexValue.php`` for examples.\n\n``` php\n<?php\n\n$table = new Table(array('borderSize' => 12, 'borderColor' => 'green', 'width' => 6000, 'unit' => TblWidth::TWIP));\n$table->addRow();\n$table->addCell(150)->addText('Cell A1');\n$table->addCell(150)->addText('Cell A2');\n$table->addCell(150)->addText('Cell A3');\n$table->addRow();\n$table->addCell(150)->addText('Cell B1');\n$table->addCell(150)->addText('Cell B2');\n$table->addCell(150)->addText('Cell B3');\n$templateProcessor->setComplexBlock('table', $table);\n```\n\n## setChartValue\n\nReplace a variable by a chart.\n\n``` php\n<?php\n\n$categories = array('A', 'B', 'C', 'D', 'E');\n$series1 = array(1, 3, 2, 5, 4);\n$chart = new Chart('doughnut', $categories, $series1);\n$templateProcessor->setChartValue('myChart', $chart);\n```\n\n## save\n\nSaves the loaded template within the current directory. Returns the file path.\n\n``` php\n<?php\n\n$filepath = $templateProcessor->save();\n```\n    \n## saveAs\n\nSaves a copy of the loaded template in the indicated path.\n\n``` php\n<?php\n\n$pathToSave = 'path/to/save/file.ext';\n$templateProcessor->saveAs($pathToSave);\n```\n"
  },
  {
    "path": "docs/usage/writers.md",
    "content": "# Writers\n\n## HTML\nThe name of the writer is `HTML`.\n\n``` php\n<?php\n\n$writer = IOFactory::createWriter($oPhpWord, 'HTML');\n$writer->save(__DIR__ . '/sample.html');\n```\n\n\nWhen generating html/pdf, you can alter the default handling of white space (normal), and/or supply a fallback generic font as follows:\n\n```php\n$writer = IOFactory::createWriter($oPhpWord, 'HTML');\n$writer->setDefaultGenericFont('serif');\n$writer->setDefaultWhiteSpace('pre-wrap');\n$writer->save(__DIR__ . '/sample.html');\n```\n\n## ODText\nThe name of the writer is `ODText`.\n\n``` php\n<?php\n\n$writer = IOFactory::createWriter($oPhpWord, 'ODText');\n$writer->save(__DIR__ . '/sample.docx');\n```\n\n## PDF\nThe name of the writer is `PDF`.\n\n``` php\n<?php\n\n$writer = IOFactory::createWriter($oPhpWord, 'PDF');\n$writer->save(__DIR__ . '/sample.pdf');\n```\n\nTo generate a PDF, the PhpWord object passes through HTML before generating the PDF.\nThis HTML can be modified using a callback.\n\n``` php\n<?php\n\n$writer = IOFactory::createWriter($oPhpWord, 'PDF');\n$writer->setEditCallback('cbEditHTML');\n$writer->save(__DIR__ . '/sample.pdf');\n\n/**\n * Add a meta tag generator\n */\nfunction cbEditHTML(string $inputHTML): string\n{\n    $beforeBody = '<meta name=\"generator\" content=\"PHPWord\" />';\n    $needle = '</head>';\n\n    $pos = strpos($inputHTML, $needle);\n    if ($pos !== false) {\n        $inputHTML = (string) substr_replace($inputHTML, \"$beforeBody\\n$needle\", $pos, strlen($needle));\n    }\n\n    return $inputHTML;\n}\n```\n\n### Options\n\nYou can define options like :\n* `font`: default font\n\nOptions must be defined before creating the writer.\n\n``` php\n<?php\n\nuse PhpOffice\\PhpWord\\Settings;\n\nSettings::setPdfRendererOptions([\n    'font' => 'Arial'\n]);\n\n$writer = IOFactory::createWriter($oPhpWord, 'PDF');\n$writer->save(__DIR__ . '/sample.pdf');\n```\n\n#### Specify the PDF Renderer\n\nBefore PHPWord can write a PDF, you **must** specify the renderer to use and the path to it.\nCurrently, three renderers are supported: \n\n- [DomPDF](https://github.com/dompdf/dompdf)\n- [MPDF](https://mpdf.github.io/)\n- [TCPDF](https://tcpdf.org/)\n\nTo specify the renderer you use two static `Settings` functions:\n\n- `setPdfRendererName`: This sets the name of the renderer library to use.\n  Provide one of [`Settings`' three `PDF_` constants](https://github.com/PHPOffice/PHPWord/blob/master/src/PhpWord/Settings.php#L39-L41) to the function call.\n- `setPdfRendererPath`: This sets the path to the renderer library. \n  This directory is the renderer's package directory within Composer's _vendor_ directory.\n\nIn the code below, you can see an example of setting MPDF as the desired PDF renderer.\n\n```php\nSettings::setPdfRendererName(Settings::PDF_RENDERER_MPDF);\nSettings::setPdfRendererPath(__DIR__ . '/../vendor/mpdf/mpdf');\n```\n\nor you can edit settings in phpword.ini ( or phpword.ini.dist) file.\n\n``` ini\npdfRendererName       = MPDF    ;DomPDF, TCPDF, MPDF\npdfRendererPath       = /path/to/your/renderer/folder\n```\n\n## RTF\nThe name of the writer is `RTF`.\n\n``` php\n<?php\n\n$writer = IOFactory::createWriter($oPhpWord, 'RTF');\n$writer->save(__DIR__ . '/sample.rtf');\n```\n\n## Word2007\nThe name of the writer is `Word2007`.\n\n``` php\n<?php\n\n$writer = IOFactory::createWriter($oPhpWord, 'Word2007');\n$writer->save(__DIR__ . '/sample.docx');\n```\n\n### ZIP Adapter\nYou can change the ZIP Adapter for the writer. By default, the ZIP Adapter is `ZipArchiveAdapter`.\n\n``` php\n<?php\n\nuse PhpOffice\\Common\\Adapter\\Zip\\PclZipAdapter;\nuse PhpOffice\\Common\\Adapter\\Zip\\ZipArchiveAdapter;\n\n$writer = IOFactory::createWriter($oPhpWord, 'Word2007');\n$writer->setZipAdapter(new PclZipAdapter());\n$writer->save(__DIR__ . '/sample.docx');\n```\n"
  },
  {
    "path": "mkdocs.yml",
    "content": "site_name: PHPWord\nsite_url: https://phpoffice.github.io/PHPWord\nrepo_url: https://github.com/PHPOffice/PHPWord\nrepo_name: PHPOffice/PHPWord\nedit_uri: edit/develop/docs/\n\n## Theme\ntheme:\n  name: material\n  palette:\n    primary: indigo\n  features:\n    - search.highlight\n    - search.suggest\n\n## Plugins\nplugins:\n  - search\n  - autolink_references:\n      autolinks:\n        - reference_prefix: GP-\n          target_url: https://github.com/<num>\n        - reference_prefix: GH-\n          target_url: https://github.com/PHPOffice/PHPWord/issues/<num>\n        - reference_prefix: CP-\n          target_url: https://archive.codeplex.com/?p=phpword&<num>\n\n## Config\nextra:\n  generator: false\nmarkdown_extensions:\n  ## Syntax highlighting\n  - pymdownx.highlight\n  - pymdownx.superfences\n  ## Support for emojis\n  - pymdownx.emoji:\n      emoji_index: !!python/name:materialx.emoji.twemoji\n      emoji_generator: !!python/name:materialx.emoji.to_svg\n  ## Support for call-outs\n  - admonition\n  - pymdownx.details\nuse_directory_urls: false\n\n## Navigation\nnav:\n  - Introduction: 'index.md'\n  - Install: 'install.md'\n  - Usage:\n    - Introduction: 'usage/introduction.md'\n    - Containers: 'usage/containers.md'\n    - Elements: \n      - Introduction: 'usage/elements/index.md'\n      - Chart: 'usage/elements/chart.md'\n      - Checkbox: 'usage/elements/checkbox.md'\n      - Comment: 'usage/elements/comment.md'\n      - Field: 'usage/elements/field.md'\n      - Footnote & Endnote: 'usage/elements/note.md'\n      - Formula: 'usage/elements/formula.md'\n      - Image: 'usage/elements/image.md'\n      - Line: 'usage/elements/line.md'\n      - Link: 'usage/elements/link.md'\n      - List: 'usage/elements/list.md'\n      - OLE Object: 'usage/elements/oleobject.md'\n      - Page Break: 'usage/elements/pagebreak.md'\n      - Preserve Text: 'usage/elements/preservetext.md'\n      - Ruby: 'usage/elements/ruby.md'\n      - Text: 'usage/elements/text.md'\n      - TextBox: 'usage/elements/textbox.md'\n      - Text Break: 'usage/elements/textbreak.md'\n      - Table: 'usage/elements/table.md'\n      - Table of contents: 'usage/elements/toc.md'\n      - Title: 'usage/elements/title.md'\n      - Track Changes: 'usage/elements/trackchanges.md'\n      - Watermark: 'usage/elements/watermark.md'\n    - Styles: \n      - Chart: 'usage/styles/chart.md'\n      - Font: 'usage/styles/font.md'\n      - Image: 'usage/styles/image.md'\n      - Numbering Level: 'usage/styles/numberinglevel.md'\n      - Paragraph: 'usage/styles/paragraph.md'\n      - Section: 'usage/styles/section.md'\n      - Table: 'usage/styles/table.md'\n    - Template Processing: 'usage/template.md'\n    - Readers: 'usage/readers.md'\n    - Writers: 'usage/writers.md'\n  - FAQ: 'faq.md'\n  - How to: 'howto.md'\n  - Credits: 'credits.md'\n  - Releases:\n    - '1.x':\n      - '1.5.0 (WIP)': 'changes/1.x/1.5.0.md'\n      - '1.4.0': 'changes/1.x/1.4.0.md'\n      - '1.3.0': 'changes/1.x/1.3.0.md'\n      - '1.2.0': 'changes/1.x/1.2.0.md'\n      - '1.1.0': 'changes/1.x/1.1.0.md'\n      - '1.0.0': 'changes/1.x/1.0.0.md'\n    - '0.x':\n      - '0.18.3': 'changes/0.x/0.18.3.md'\n      - '0.18.2': 'changes/0.x/0.18.2.md'\n      - '0.18.1': 'changes/0.x/0.18.1.md'\n      - '0.18.0': 'changes/0.x/0.18.0.md'\n      - '0.17.0': 'changes/0.x/0.17.0.md'\n      - '0.16.0': 'changes/0.x/0.16.0.md'\n      - '0.15.0': 'changes/0.x/0.15.0.md'\n      - '0.14.0': 'changes/0.x/0.14.0.md'\n      - '0.13.0': 'changes/0.x/0.13.0.md'\n      - '0.12.1': 'changes/0.x/0.12.1.md'\n      - '0.12.0': 'changes/0.x/0.12.0.md'\n      - '0.11.1': 'changes/0.x/0.11.1.md'\n      - '0.11.0': 'changes/0.x/0.11.0.md'\n      - '0.10.1': 'changes/0.x/0.10.1.md'\n      - '0.10.0': 'changes/0.x/0.10.0.md'\n      - '0.9.1': 'changes/0.x/0.9.1.md'\n      - '0.9.0': 'changes/0.x/0.9.0.md'\n      - '0.8.1': 'changes/0.x/0.8.1.md'\n      - '0.8.0': 'changes/0.x/0.8.0.md'\n      - '0.7.0': 'changes/0.x/0.7.0.md'\n  - Developers:\n    - 'Coveralls': 'https://coveralls.io/github/PHPOffice/PHPWord'\n    - 'Code Coverage': 'coverage/index.html'\n    - 'PHPDoc': 'docs/index.html'\n"
  },
  {
    "path": "phpmd.xml.dist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<ruleset name=\"PHPWord PHP Mess Detector Rule Set\"\n    xmlns=\"http://pmd.sf.net/ruleset/1.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd\"\n    xsi:noNamespaceSchemaLocation=\"http://pmd.sf.net/ruleset_xml_schema.xsd\">\n    <rule ref=\"rulesets/naming.xml\">\n        <exclude name=\"ShortVariable\" />\n        <exclude name=\"ShortClassName\" />\n        <exclude name=\"LongVariable\" />\n    </rule>\n    <rule ref=\"rulesets/naming.xml/LongVariable\">\n        <properties>\n            <property name=\"maximum\" value=\"32\" />\n        </properties>\n    </rule>\n    <rule ref=\"rulesets/design.xml/ExitExpression\" />\n    <rule ref=\"rulesets/design.xml/EvalExpression\" />\n    <rule ref=\"rulesets/design.xml/GotoStatement\" />\n    <rule ref=\"rulesets/design.xml/DepthOfInheritance\" />\n    <rule ref=\"rulesets/design.xml/CouplingBetweenObjects\">\n        <!-- AbstractContainer and Html need more coupling (default: 13) -->\n        <properties>\n            <property name=\"maximum\" value=\"25\" />\n        </properties>\n    </rule>\n    <rule ref=\"rulesets/design.xml/NumberOfChildren\">\n        <!-- AbstractStyle needs more children (default: 15) -->\n        <properties>\n            <property name=\"minimum\" value=\"30\" />\n        </properties>\n    </rule>\n    <rule ref=\"rulesets/controversial.xml\" />\n</ruleset>"
  },
  {
    "path": "phpstan-baseline.neon",
    "content": "parameters:\n\tignoreErrors:\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\AbstractContainer\\\\:\\\\:__call\\\\(\\\\) should return PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\AbstractElement but returns null\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Element/AbstractContainer.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$objectOrClass of class ReflectionClass constructor expects class\\\\-string\\\\<T of object\\\\>\\\\|T of object, string given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Element/AbstractContainer.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$string of function md5 expects string, int\\\\<0, max\\\\> given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Element/AbstractElement.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#2 \\\\$styleValue of method PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\AbstractElement\\\\:\\\\:setNewStyle\\\\(\\\\) expects array\\\\|PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\|string\\\\|null, array\\\\|PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Cell\\\\|null given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Element/Cell.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\Field\\\\:\\\\:setOptions\\\\(\\\\) should return PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\Field but returns array\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Element/Field.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\Field\\\\:\\\\:setProperties\\\\(\\\\) should return PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\Field but returns array\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Element/Field.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\Field\\\\:\\\\:\\\\$fontStyle \\\\(PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Font\\\\|string\\\\) does not accept null\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Element/Field.php\n\n\t\t-\n\t\t\tmessage: \"#^Result of \\\\|\\\\| is always true\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Element/Field.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#2 \\\\$styleValue of method PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\AbstractElement\\\\:\\\\:setNewStyle\\\\(\\\\) expects array\\\\|PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\|string\\\\|null, array\\\\|PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Paragraph\\\\|string\\\\|null given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Element/Footnote.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\Image\\\\:\\\\:getArchiveImageSize\\\\(\\\\) should return array\\\\|null but returns array<int\\\\|string, int\\\\|string>\\\\|false\\\\|null\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Element/Image.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\Image\\\\:\\\\:getImageString\\\\(\\\\) should return string\\\\|null but returns string\\\\|false\\\\|null\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Element/Image.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$callback of function call_user_func expects callable\\\\(\\\\)\\\\: mixed, string given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Element/Image.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\Image\\\\:\\\\:\\\\$source \\\\(string\\\\) does not accept string\\\\|false\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Element/Image.php\n\n\t\t-\n\t\t\tmessage: \"#^Offset 'extension' does not exist on array\\\\{dirname\\\\?\\\\: string, basename\\\\: string, extension\\\\?\\\\: string, filename\\\\: string\\\\}\\\\.$#\"\n\t\t\tcount: 2\n\t\t\tpath: src/PhpWord/Element/OLEObject.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\OLEObject\\\\:\\\\:\\\\$icon \\\\(string\\\\) does not accept string\\\\|false\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Element/OLEObject.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\Section\\\\:\\\\:addHeader\\\\(\\\\) should return PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\Header but returns PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\Footer\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Element/Section.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\Section\\\\:\\\\:addHeaderFooter\\\\(\\\\) should return PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\Footer but returns PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\AbstractContainer\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Element/Section.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#2 \\\\$styleValue of method PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\AbstractElement\\\\:\\\\:setNewStyle\\\\(\\\\) expects array\\\\|PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\|string\\\\|null, array\\\\|PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\|PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Section\\\\|string given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Element/Section.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#3 \\\\$length of function substr expects int\\\\|null, int\\\\|false given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Element/Section.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Escaper\\\\\\\\Rtf\\\\:\\\\:escapeAsciiCharacter\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Escaper/Rtf.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Escaper\\\\\\\\Rtf\\\\:\\\\:escapeAsciiCharacter\\\\(\\\\) has parameter \\\\$code with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Escaper/Rtf.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Escaper\\\\\\\\Rtf\\\\:\\\\:escapeMultibyteCharacter\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Escaper/Rtf.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Escaper\\\\\\\\Rtf\\\\:\\\\:escapeMultibyteCharacter\\\\(\\\\) has parameter \\\\$code with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Escaper/Rtf.php\n\n\t\t-\n\t\t\tmessage: \"#^Cannot instantiate interface PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\WriterInterface\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/IOFactory.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\IOFactory\\\\:\\\\:createObject\\\\(\\\\) should return PhpOffice\\\\\\\\PhpWord\\\\\\\\Reader\\\\\\\\ReaderInterface\\\\|PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\WriterInterface but returns object\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/IOFactory.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\IOFactory\\\\:\\\\:createReader\\\\(\\\\) should return PhpOffice\\\\\\\\PhpWord\\\\\\\\Reader\\\\\\\\ReaderInterface but returns PhpOffice\\\\\\\\PhpWord\\\\\\\\Reader\\\\\\\\ReaderInterface\\\\|PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\WriterInterface\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/IOFactory.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\IOFactory\\\\:\\\\:createWriter\\\\(\\\\) should return PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\WriterInterface but returns PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\PDF\\\\|PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\WriterInterface\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/IOFactory.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$objectOrClass of class ReflectionClass constructor expects class\\\\-string\\\\<T of object\\\\>\\\\|T of object, string given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/IOFactory.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\PhpWord\\\\:\\\\:getDefaultFontSize\\\\(\\\\) should return int but returns float\\\\|int\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/PhpWord.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$callback of function forward_static_call_array expects callable\\\\(\\\\)\\\\: mixed, array\\\\{'PhpOffice\\\\\\\\\\\\\\\\PhpWord…', string\\\\} given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/PhpWord.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Reader\\\\\\\\AbstractReader\\\\:\\\\:openFile\\\\(\\\\) should return resource but return statement is missing\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Reader/AbstractReader.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#2 \\\\$html of static method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Html\\\\:\\\\:addHtml\\\\(\\\\) expects string, string\\\\|false given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Reader/HTML.php\n\n\t\t-\n\t\t\tmessage: \"#^Offset 'textNodes' on array\\\\{changed\\\\: PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\TrackChange, textNodes\\\\: DOMNodeList\\\\<DOMElement\\\\>\\\\} in isset\\\\(\\\\) always exists and is not nullable\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Reader/ODText/Content.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#2 \\\\$contextNode of method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\XMLReader\\\\:\\\\:getElements\\\\(\\\\) expects DOMElement\\\\|null, DOMNode\\\\|null given\\\\.$#\"\n\t\t\tcount: 2\n\t\t\tpath: src/PhpWord/Reader/ODText/Content.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#2 \\\\$depth of method PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\AbstractContainer\\\\:\\\\:addTitle\\\\(\\\\) expects int, string\\\\|null given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Reader/ODText/Content.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Reader\\\\\\\\RTF\\\\\\\\Document\\\\:\\\\:\\\\$rtf \\\\(string\\\\) does not accept string\\\\|false\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Reader/RTF.php\n\n\t\t-\n\t\t\tmessage: \"#^Cannot call method setStyleByArray\\\\(\\\\) on PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Font\\\\|string\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Reader/RTF/Document.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Reader\\\\\\\\RTF\\\\\\\\Document\\\\:\\\\:\\\\$phpWord is never read, only written\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Reader/RTF/Document.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Reader\\\\\\\\ReaderInterface\\\\:\\\\:load\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Reader/ReaderInterface.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$string of function substr expects string, string\\\\|false given\\\\.$#\"\n\t\t\tcount: 2\n\t\t\tpath: src/PhpWord/Reader/Word2007.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#2 \\\\$xmlFile of method PhpOffice\\\\\\\\PhpWord\\\\\\\\Reader\\\\\\\\Word2007\\\\:\\\\:getRels\\\\(\\\\) expects string, string\\\\|false given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Reader/Word2007.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#3 \\\\$subject of function str_replace expects array\\\\|string, string\\\\|false given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Reader/Word2007.php\n\n\t\t-\n\t\t\tmessage: \"#^Binary operation \\\"/\\\" between string\\\\|null and 2 results in an error\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Reader/Word2007/AbstractPart.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method DOMNode\\\\:\\\\:getAttribute\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 2\n\t\t\tpath: src/PhpWord/Reader/Word2007/AbstractPart.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Reader\\\\\\\\Word2007\\\\\\\\AbstractPart\\\\:\\\\:getHeadingDepth\\\\(\\\\) never returns float so it can be removed from the return type\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Reader/Word2007/AbstractPart.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Reader\\\\\\\\Word2007\\\\\\\\AbstractPart\\\\:\\\\:getHeadingDepth\\\\(\\\\) should return float\\\\|int\\\\|null but returns string\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Reader/Word2007/AbstractPart.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Reader\\\\\\\\Word2007\\\\\\\\AbstractPart\\\\:\\\\:read\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Reader/Word2007/AbstractPart.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$depth of method PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\AbstractContainer\\\\:\\\\:addListItemRun\\\\(\\\\) expects int, string\\\\|null given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Reader/Word2007/AbstractPart.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$height of method PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\Table\\\\:\\\\:addRow\\\\(\\\\) expects int\\\\|null, string\\\\|null given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Reader/Word2007/AbstractPart.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$value of method PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\AbstractElement\\\\:\\\\:setRelationId\\\\(\\\\) expects int, string\\\\|null given\\\\.$#\"\n\t\t\tcount: 2\n\t\t\tpath: src/PhpWord/Reader/Word2007/AbstractPart.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$width of method PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\Row\\\\:\\\\:addCell\\\\(\\\\) expects int\\\\|null, string\\\\|null given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Reader/Word2007/AbstractPart.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#2 \\\\$contextNode of method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\XMLReader\\\\:\\\\:getAttribute\\\\(\\\\) expects DOMElement\\\\|null, DOMNode\\\\|null given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Reader/Word2007/AbstractPart.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#2 \\\\$depth of method PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\AbstractContainer\\\\:\\\\:addTitle\\\\(\\\\) expects int, float\\\\|int given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Reader/Word2007/AbstractPart.php\n\n\t\t-\n\t\t\tmessage: \"#^Strict comparison using \\\\=\\\\=\\\\= between null and DOMElement will always evaluate to false\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Reader/Word2007/AbstractPart.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#2 \\\\$relationId of method PhpOffice\\\\\\\\PhpWord\\\\\\\\Reader\\\\\\\\Word2007\\\\\\\\Footnotes\\\\:\\\\:getElement\\\\(\\\\) expects int, string\\\\|null given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Reader/Word2007/Footnotes.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#3 \\\\$levelId of method PhpOffice\\\\\\\\PhpWord\\\\\\\\Reader\\\\\\\\Word2007\\\\\\\\Numbering\\\\:\\\\:readLevel\\\\(\\\\) expects int, string\\\\|null given\\\\.$#\"\n\t\t\tcount: 2\n\t\t\tpath: src/PhpWord/Reader/Word2007/Numbering.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$comments of method PhpOffice\\\\\\\\PhpWord\\\\\\\\ComplexType\\\\\\\\TrackChangesView\\\\:\\\\:setComments\\\\(\\\\) expects bool\\\\|null, string\\\\|null given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Reader/Word2007/Settings.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$consecutiveHyphenLimit of method PhpOffice\\\\\\\\PhpWord\\\\\\\\Metadata\\\\\\\\Settings\\\\:\\\\:setConsecutiveHyphenLimit\\\\(\\\\) expects int, string given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Reader/Word2007/Settings.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$hyphenationZone of method PhpOffice\\\\\\\\PhpWord\\\\\\\\Metadata\\\\\\\\Settings\\\\:\\\\:setHyphenationZone\\\\(\\\\) expects float\\\\|int\\\\|null, string given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Reader/Word2007/Settings.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$filename of function parse_ini_file expects string, string\\\\|false given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Settings.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\AbstractEnum\\\\:\\\\:getConstants\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/AbstractEnum.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\AbstractEnum\\\\:\\\\:\\\\$constCacheArray has no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/AbstractEnum.php\n\n\t\t-\n\t\t\tmessage: \"#^Binary operation \\\"/\\\" between string and 10 results in an error\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Converter.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Converter\\\\:\\\\:angleToDegree\\\\(\\\\) should return int but returns float\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Converter.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Converter\\\\:\\\\:cssToPoint\\\\(\\\\) should return float\\\\|null but returns string\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Converter.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Converter\\\\:\\\\:htmlToRgb\\\\(\\\\) should return array but returns false\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Converter.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Converter\\\\:\\\\:inchToEmu\\\\(\\\\) should return int but returns float\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Converter.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Converter\\\\:\\\\:pixelToEmu\\\\(\\\\) should return int but returns float\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Converter.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$centimeter of static method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Converter\\\\:\\\\:cmToPoint\\\\(\\\\) expects float, string given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Converter.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$inch of static method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Converter\\\\:\\\\:inchToPoint\\\\(\\\\) expects float, string given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Converter.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$pica of static method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Converter\\\\:\\\\:picaToPoint\\\\(\\\\) expects float, string given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Converter.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$pixel of static method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Converter\\\\:\\\\:pixelToPoint\\\\(\\\\) expects float, string given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Converter.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Drawing\\\\:\\\\:angleToDegrees\\\\(\\\\) should return int but returns float\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Drawing.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Drawing\\\\:\\\\:emuToPixels\\\\(\\\\) should return int but returns float\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Drawing.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Drawing\\\\:\\\\:pixelsToEmu\\\\(\\\\) should return int but returns float\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Drawing.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method DOMNode\\\\:\\\\:getAttribute\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Html.php\n\n\t\t-\n\t\t\tmessage: \"#^Cannot call method setBorderSize\\\\(\\\\) on PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Table\\\\|string\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Html.php\n\n\t\t-\n\t\t\tmessage: \"#^Cannot call method setStyleName\\\\(\\\\) on PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Table\\\\|string\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Html.php\n\n\t\t-\n\t\t\tmessage: \"#^If condition is always true\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Html.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Html\\\\:\\\\:addHtml\\\\(\\\\) has parameter \\\\$options with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Html.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Html\\\\:\\\\:filterOutNonInheritedStyles\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Html.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Html\\\\:\\\\:mapBorderColor\\\\(\\\\) has parameter \\\\$cssBorderColor with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Html.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Html\\\\:\\\\:mapBorderColor\\\\(\\\\) has parameter \\\\$styles with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Html.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Html\\\\:\\\\:mapListType\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Html.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Html\\\\:\\\\:parseLink\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Html.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Html\\\\:\\\\:parseList\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Html.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Html\\\\:\\\\:parseRuby\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Html.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Html\\\\:\\\\:parseStyleDeclarations\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Html.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Html\\\\:\\\\:recursiveParseStylesInHierarchy\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Html.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$attribute of static method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Html\\\\:\\\\:parseStyle\\\\(\\\\) expects DOMAttr, DOMNode given\\\\.$#\"\n\t\t\tcount: 3\n\t\t\tpath: src/PhpWord/Shared/Html.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#2 \\\\$element of static method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Html\\\\:\\\\:parseNode\\\\(\\\\) expects PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\AbstractContainer, PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\AbstractContainer\\\\|PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\Row\\\\|PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\Table given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Html.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Html\\\\:\\\\:\\\\$listIndex has no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Html.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Html\\\\:\\\\:\\\\$options has no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Html.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Html\\\\:\\\\:\\\\$xpath has no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Html.php\n\n\t\t-\n\t\t\tmessage: \"#^Result of \\\\|\\\\| is always true\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Html.php\n\n\t\t-\n\t\t\tmessage: \"#^Right side of && is always true\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Html.php\n\n\t\t-\n\t\t\tmessage: \"#^Variable \\\\$cNodes in empty\\\\(\\\\) always exists and is not falsy\\\\.$#\"\n\t\t\tcount: 2\n\t\t\tpath: src/PhpWord/Shared/Html.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Microsoft\\\\\\\\PasswordEncoder\\\\:\\\\:\\\\$encryptionMatrix has no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Microsoft/PasswordEncoder.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Microsoft\\\\\\\\PasswordEncoder\\\\:\\\\:\\\\$initialCodeArray has no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Microsoft/PasswordEncoder.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Microsoft\\\\\\\\PasswordEncoder\\\\:\\\\:\\\\$passwordMaxLength has no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/Microsoft/PasswordEncoder.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\XMLWriter\\\\:\\\\:getData\\\\(\\\\) should return string but returns string\\\\|false\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/XMLWriter.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to method add\\\\(\\\\) on an unknown class PclZip\\\\.$#\"\n\t\t\tcount: 2\n\t\t\tpath: src/PhpWord/Shared/ZipArchive.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to method addFromString\\\\(\\\\) on an unknown class PclZip\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/ZipArchive.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to method close\\\\(\\\\) on an unknown class PclZip\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/ZipArchive.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to method extract\\\\(\\\\) on an unknown class PclZip\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/ZipArchive.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to method extractByIndex\\\\(\\\\) on an unknown class PclZip\\\\.$#\"\n\t\t\tcount: 3\n\t\t\tpath: src/PhpWord/Shared/ZipArchive.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to method extractTo\\\\(\\\\) on an unknown class PclZip\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/ZipArchive.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to method getFromName\\\\(\\\\) on an unknown class PclZip\\\\.$#\"\n\t\t\tcount: 2\n\t\t\tpath: src/PhpWord/Shared/ZipArchive.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to method listContent\\\\(\\\\) on an unknown class PclZip\\\\.$#\"\n\t\t\tcount: 3\n\t\t\tpath: src/PhpWord/Shared/ZipArchive.php\n\n\t\t-\n\t\t\tmessage: \"#^Comparison operation \\\"\\\\!\\\\=\\\" between array and 0 results in an error\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/ZipArchive.php\n\n\t\t-\n\t\t\tmessage: \"#^Constant PCLZIP_OPT_ADD_PATH not found\\\\.$#\"\n\t\t\tcount: 2\n\t\t\tpath: src/PhpWord/Shared/ZipArchive.php\n\n\t\t-\n\t\t\tmessage: \"#^Constant PCLZIP_OPT_EXTRACT_AS_STRING not found\\\\.$#\"\n\t\t\tcount: 2\n\t\t\tpath: src/PhpWord/Shared/ZipArchive.php\n\n\t\t-\n\t\t\tmessage: \"#^Constant PCLZIP_OPT_PATH not found\\\\.$#\"\n\t\t\tcount: 2\n\t\t\tpath: src/PhpWord/Shared/ZipArchive.php\n\n\t\t-\n\t\t\tmessage: \"#^Constant PCLZIP_OPT_REMOVE_PATH not found\\\\.$#\"\n\t\t\tcount: 2\n\t\t\tpath: src/PhpWord/Shared/ZipArchive.php\n\n\t\t-\n\t\t\tmessage: \"#^Instantiated class PclZip not found\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/ZipArchive.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\ZipArchive\\\\:\\\\:getFromName\\\\(\\\\) should return string but returns string\\\\|false\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/ZipArchive.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\ZipArchive\\\\:\\\\:open\\\\(\\\\) should return bool but returns int\\\\|true\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/ZipArchive.php\n\n\t\t-\n\t\t\tmessage: \"#^Offset 'dirname' does not exist on array\\\\{dirname\\\\?\\\\: string, basename\\\\: string, extension\\\\?\\\\: string, filename\\\\: string\\\\}\\\\.$#\"\n\t\t\tcount: 3\n\t\t\tpath: src/PhpWord/Shared/ZipArchive.php\n\n\t\t-\n\t\t\tmessage: \"#^PHPDoc tag @var for variable \\\\$zip contains unknown class PclZip\\\\.$#\"\n\t\t\tcount: 6\n\t\t\tpath: src/PhpWord/Shared/ZipArchive.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$callback of function call_user_func_array expects callable\\\\(\\\\)\\\\: mixed, array\\\\{\\\\$this\\\\(PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\ZipArchive\\\\)\\\\|PclZip\\\\|ZipArchive, mixed\\\\} given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/ZipArchive.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$stream of function fclose expects resource, resource\\\\|false given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/ZipArchive.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$stream of function fwrite expects resource, resource\\\\|false given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/ZipArchive.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\ZipArchive\\\\:\\\\:\\\\$zip has unknown class PclZip as its type\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Shared/ZipArchive.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\:\\\\:addFontStyle\\\\(\\\\) should return PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Font but returns PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\AbstractStyle\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\:\\\\:addLinkStyle\\\\(\\\\) should return PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Font but returns PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\AbstractStyle\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\:\\\\:addNumberingStyle\\\\(\\\\) should return PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Numbering but returns PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\AbstractStyle\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\:\\\\:addParagraphStyle\\\\(\\\\) should return PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Paragraph but returns PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\AbstractStyle\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\:\\\\:addTableStyle\\\\(\\\\) should return PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Table but returns PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\AbstractStyle\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\:\\\\:addTitleStyle\\\\(\\\\) should return PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Font but returns PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\AbstractStyle\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method object\\\\:\\\\:setStyleByArray\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/AbstractStyle.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\AbstractStyle\\\\:\\\\:setFloatVal\\\\(\\\\) should return float\\\\|null but returns float\\\\|int\\\\|string\\\\|null\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/AbstractStyle.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\AbstractStyle\\\\:\\\\:setNumericVal\\\\(\\\\) should return float\\\\|int\\\\|null but returns float\\\\|int\\\\|string\\\\|null\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/AbstractStyle.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#3 \\\\$length of function substr expects int\\\\|null, int\\\\|false given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/AbstractStyle.php\n\n\t\t-\n\t\t\tmessage: \"#^Unreachable statement \\\\- code above always terminates\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/AbstractStyle.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Border\\\\:\\\\:getBorderSize\\\\(\\\\) should return array\\\\<int\\\\> but returns array\\\\<int, float\\\\|int\\\\>\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/Border.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Cell\\\\:\\\\:getBgColor\\\\(\\\\) should return string but returns null\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/Cell.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Cell\\\\:\\\\:setUnit\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/Cell.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Chart\\\\:\\\\:getMajorTickPosition\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/Chart.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Chart\\\\:\\\\:setCategoryAxisTitle\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/Chart.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Chart\\\\:\\\\:setValueAxisTitle\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/Chart.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Chart\\\\:\\\\:setValueLabelPosition\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/Chart.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Chart\\\\:\\\\:showAxisLabels\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/Chart.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Chart\\\\:\\\\:showGridY\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/Chart.php\n\n\t\t-\n\t\t\tmessage: \"#^PHPDoc tag @param has invalid value \\\\(string\\\\)\\\\: Unexpected token \\\"\\\\\\\\n     \\\\* \\\", expected variable at offset 250$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/Chart.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Font\\\\:\\\\:setAllCaps\\\\(\\\\) should return PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Font but returns PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\AbstractStyle\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/Font.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Font\\\\:\\\\:setBgColor\\\\(\\\\) should return PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Table but return statement is missing\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/Font.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Font\\\\:\\\\:setDoubleStrikethrough\\\\(\\\\) should return PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Font but returns PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\AbstractStyle\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/Font.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Font\\\\:\\\\:setSmallCaps\\\\(\\\\) should return PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Font but returns PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\AbstractStyle\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/Font.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Font\\\\:\\\\:setStrikethrough\\\\(\\\\) should return PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Font but returns PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\AbstractStyle\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/Font.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Font\\\\:\\\\:setSubScript\\\\(\\\\) should return PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Font but returns PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\AbstractStyle\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/Font.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Font\\\\:\\\\:setSuperScript\\\\(\\\\) should return PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Font but returns PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\AbstractStyle\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/Font.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Line\\\\:\\\\:\\\\$weight \\\\(int\\\\) does not accept float\\\\|int\\\\|null\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/Line.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\ListItem\\\\:\\\\:getListTypeStyle\\\\(\\\\) should return array but empty return statement found\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/ListItem.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\ListItem\\\\:\\\\:getListTypeStyle\\\\(\\\\) should return array but return statement is missing\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/ListItem.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Paragraph\\\\:\\\\:setStyleValue\\\\(\\\\) should return PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Paragraph but returns PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\AbstractStyle\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/Paragraph.php\n\n\t\t-\n\t\t\tmessage: \"#^Result of && is always false\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/Paragraph.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Section\\\\:\\\\:setSettingValue\\\\(\\\\) should return PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Section but returns PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\AbstractStyle\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/Section.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\TOC\\\\:\\\\:setTabLeader\\\\(\\\\) should return PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\TOC but returns PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Tab\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/TOC.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\TOC\\\\:\\\\:setTabPos\\\\(\\\\) should return PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\TOC but returns PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Tab\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/TOC.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Table\\\\:\\\\:getBorderInsideHColor\\\\(\\\\) should return string but returns int\\\\|string\\\\|null\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/Table.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Table\\\\:\\\\:getBorderInsideHSize\\\\(\\\\) should return int but returns int\\\\|string\\\\|null\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/Table.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Table\\\\:\\\\:getBorderInsideVColor\\\\(\\\\) should return string but returns int\\\\|string\\\\|null\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/Table.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Table\\\\:\\\\:getBorderInsideVSize\\\\(\\\\) should return int but returns int\\\\|string\\\\|null\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/Table.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Table\\\\:\\\\:getBorderSize\\\\(\\\\) should return array\\\\<int\\\\> but returns array\\\\<int, float\\\\|int\\\\>\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/Table.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Table\\\\:\\\\:getCellMarginBottom\\\\(\\\\) should return int but returns int\\\\|string\\\\|null\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/Table.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Table\\\\:\\\\:getCellMarginLeft\\\\(\\\\) should return int but returns int\\\\|string\\\\|null\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/Table.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Table\\\\:\\\\:getCellMarginRight\\\\(\\\\) should return int but returns int\\\\|string\\\\|null\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/Table.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Table\\\\:\\\\:getCellMarginTop\\\\(\\\\) should return int but returns int\\\\|string\\\\|null\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/Table.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\TablePosition\\\\:\\\\:\\\\$bottomFromText \\\\(int\\\\) does not accept float\\\\|int\\\\|null\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/TablePosition.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\TablePosition\\\\:\\\\:\\\\$leftFromText \\\\(int\\\\) does not accept float\\\\|int\\\\|null\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/TablePosition.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\TablePosition\\\\:\\\\:\\\\$rightFromText \\\\(int\\\\) does not accept float\\\\|int\\\\|null\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/TablePosition.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\TablePosition\\\\:\\\\:\\\\$tblpX \\\\(int\\\\) does not accept float\\\\|int\\\\|null\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/TablePosition.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\TablePosition\\\\:\\\\:\\\\$tblpY \\\\(int\\\\) does not accept float\\\\|int\\\\|null\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/TablePosition.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\TablePosition\\\\:\\\\:\\\\$topFromText \\\\(int\\\\) does not accept float\\\\|int\\\\|null\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Style/TablePosition.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method object\\\\:\\\\:write\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Cannot access offset 'end' on array\\\\<int\\\\>\\\\|true\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Cannot access offset 'start' on array\\\\<int\\\\>\\\\|true\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\TemplateProcessor\\\\:\\\\:addImageToRelations\\\\(\\\\) has parameter \\\\$imageMimeType with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\TemplateProcessor\\\\:\\\\:addImageToRelations\\\\(\\\\) has parameter \\\\$imgPath with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\TemplateProcessor\\\\:\\\\:addImageToRelations\\\\(\\\\) has parameter \\\\$partFileName with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\TemplateProcessor\\\\:\\\\:addImageToRelations\\\\(\\\\) has parameter \\\\$rid with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\TemplateProcessor\\\\:\\\\:chooseImageDimension\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\TemplateProcessor\\\\:\\\\:chooseImageDimension\\\\(\\\\) has parameter \\\\$baseValue with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\TemplateProcessor\\\\:\\\\:chooseImageDimension\\\\(\\\\) has parameter \\\\$defaultValue with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\TemplateProcessor\\\\:\\\\:chooseImageDimension\\\\(\\\\) has parameter \\\\$inlineValue with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\TemplateProcessor\\\\:\\\\:fixImageWidthHeightRatio\\\\(\\\\) has parameter \\\\$actualHeight with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\TemplateProcessor\\\\:\\\\:fixImageWidthHeightRatio\\\\(\\\\) has parameter \\\\$actualWidth with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\TemplateProcessor\\\\:\\\\:fixImageWidthHeightRatio\\\\(\\\\) has parameter \\\\$height with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\TemplateProcessor\\\\:\\\\:fixImageWidthHeightRatio\\\\(\\\\) has parameter \\\\$width with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\TemplateProcessor\\\\:\\\\:getImageArgs\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\TemplateProcessor\\\\:\\\\:getImageArgs\\\\(\\\\) has parameter \\\\$varNameWithArgs with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\TemplateProcessor\\\\:\\\\:getNextRelationsIndex\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\TemplateProcessor\\\\:\\\\:getNextRelationsIndex\\\\(\\\\) has parameter \\\\$documentPartName with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\TemplateProcessor\\\\:\\\\:indexClonedVariables\\\\(\\\\) should return string but returns array\\\\<int\\\\<0, max\\\\>, string\\\\|null\\\\>\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\TemplateProcessor\\\\:\\\\:prepareImageAttrs\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\TemplateProcessor\\\\:\\\\:prepareImageAttrs\\\\(\\\\) has parameter \\\\$replaceImage with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\TemplateProcessor\\\\:\\\\:prepareImageAttrs\\\\(\\\\) has parameter \\\\$varInlineArgs with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\TemplateProcessor\\\\:\\\\:setValueForPart\\\\(\\\\) should return string but returns array\\\\<int, string\\\\>\\\\|string\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\TemplateProcessor\\\\:\\\\:setValueForPart\\\\(\\\\) should return string but returns array\\\\<int, string\\\\>\\\\|string\\\\|null\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$element of method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\Word2007\\\\\\\\Part\\\\\\\\Chart\\\\:\\\\:setElement\\\\(\\\\) expects PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\Chart, PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\AbstractElement given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#2 \\\\$array of function implode expects array\\\\|null, array\\\\<string\\\\>\\\\|string given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#2 \\\\$array of function implode expects array\\\\|null, string given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\TemplateProcessor\\\\:\\\\:\\\\$macroClosingChars has no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\TemplateProcessor\\\\:\\\\:\\\\$macroOpeningChars has no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\TemplateProcessor\\\\:\\\\:\\\\$tempDocumentFooters \\\\(array\\\\<string\\\\>\\\\) does not accept string\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\TemplateProcessor\\\\:\\\\:\\\\$tempDocumentHeaders \\\\(array\\\\<string\\\\>\\\\) does not accept string\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/TemplateProcessor.php\n\n\t\t-\n\t\t\tmessage: \"#^Argument of an invalid type array\\\\<int, string\\\\>\\\\|false supplied for foreach, only iterables are supported\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/AbstractWriter.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\HTML\\\\\\\\Element\\\\\\\\AbstractElement\\\\:\\\\:write\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/HTML/Element/AbstractElement.php\n\n\t\t-\n\t\t\tmessage: \"#^Variable \\\\$row in PHPDoc tag @var does not match assigned variable \\\\$rowStyle\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/HTML/Element/Table.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\ODText\\\\\\\\Element\\\\\\\\Field\\\\:\\\\:writeDefault\\\\(\\\\) has parameter \\\\$type with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/ODText/Element/Field.php\n\n\t\t-\n\t\t\tmessage: \"#^Variable \\\\$row in PHPDoc tag @var does not match any variable in the foreach loop\\\\: \\\\$cell$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/ODText/Element/Table.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\ODText\\\\\\\\Element\\\\\\\\AbstractElement\\\\:\\\\:replaceTabs\\\\(\\\\) has parameter \\\\$text with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/ODText/Element/AbstractElement.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\ODText\\\\\\\\Element\\\\\\\\AbstractElement\\\\:\\\\:replaceTabs\\\\(\\\\) has parameter \\\\$xmlWriter with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/ODText/Element/AbstractElement.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\ODText\\\\\\\\Element\\\\\\\\Text\\\\:\\\\:writeChangeInsertion\\\\(\\\\) has parameter \\\\$start with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/ODText/Element/Text.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\AbstractElement\\\\:\\\\:getParagraphStyle\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/ODText/Element/TextRun.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\AbstractStyle\\\\:\\\\:setColumnWidths\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/ODText/Part/Content.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$container of method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\ODText\\\\\\\\Part\\\\\\\\Content\\\\:\\\\:collectTrackedChanges\\\\(\\\\) expects PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\AbstractContainer, PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\AbstractElement given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/ODText/Part/Content.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\ODText\\\\\\\\Part\\\\\\\\Content\\\\:\\\\:\\\\$imageParagraphStyles has no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/ODText/Part/Content.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method object\\\\:\\\\:write\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 2\n\t\t\tpath: src/PhpWord/Writer/ODText/Part/Styles.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\ODText\\\\\\\\Part\\\\\\\\Styles\\\\:\\\\:cvttwiptostr\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/ODText/Part/Styles.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$callback of function call_user_func_array expects callable\\\\(\\\\)\\\\: mixed, array\\\\{PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\PDF\\\\\\\\AbstractRenderer, string\\\\} given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/PDF.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\PDF\\\\:\\\\:\\\\$renderer \\\\(PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\PDF\\\\\\\\AbstractRenderer\\\\) does not accept object\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/PDF.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\PDF\\\\\\\\DomPDF\\\\:\\\\:loadHtml\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/PDF/DomPDF.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\PDF\\\\\\\\DomPDF\\\\:\\\\:output\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/PDF/DomPDF.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\PDF\\\\\\\\DomPDF\\\\:\\\\:render\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/PDF/DomPDF.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\PDF\\\\\\\\DomPDF\\\\:\\\\:setPaper\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/PDF/DomPDF.php\n\n\t\t-\n\t\t\tmessage: \"#^Class PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\PDF\\\\\\\\DomPDF referenced with incorrect case\\\\: PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\PDF\\\\\\\\Dompdf\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/PDF/DomPDF.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\PDF\\\\\\\\DomPDF\\\\:\\\\:createExternalWriterInstance\\\\(\\\\) should return PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\PDF\\\\\\\\DomPDF but returns Dompdf\\\\\\\\Dompdf\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/PDF/DomPDF.php\n\n\t\t-\n\t\t\tmessage: \"#^Binary operation \\\"\\\\+\\\" between int\\\\|string and 1 results in an error\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/RTF/Element/AbstractElement.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$value of method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\RTF\\\\\\\\Style\\\\\\\\Font\\\\:\\\\:setNameIndex\\\\(\\\\) expects int, int\\\\|string given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/RTF/Element/AbstractElement.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\RTF\\\\\\\\Element\\\\\\\\AbstractElement\\\\:\\\\:\\\\$fontStyle \\\\(PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Font\\\\) does not accept PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\AbstractStyle\\\\|null\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/RTF/Element/AbstractElement.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\RTF\\\\\\\\Element\\\\\\\\AbstractElement\\\\:\\\\:\\\\$fontStyle \\\\(PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Font\\\\) does not accept PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Font\\\\|string\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/RTF/Element/AbstractElement.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\RTF\\\\\\\\Element\\\\\\\\AbstractElement\\\\:\\\\:\\\\$paragraphStyle \\\\(PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Paragraph\\\\) does not accept PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\AbstractStyle\\\\|null\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/RTF/Element/AbstractElement.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\RTF\\\\\\\\Element\\\\\\\\AbstractElement\\\\:\\\\:\\\\$paragraphStyle \\\\(PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Paragraph\\\\) does not accept PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Paragraph\\\\|string\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/RTF/Element/AbstractElement.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\RTF\\\\\\\\Element\\\\\\\\AbstractElement\\\\:\\\\:\\\\$paragraphStyle \\\\(PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Paragraph\\\\) does not accept null\\\\.$#\"\n\t\t\tcount: 2\n\t\t\tpath: src/PhpWord/Writer/RTF/Element/AbstractElement.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\RTF\\\\\\\\Element\\\\\\\\Field\\\\:\\\\:write\\\\(\\\\) should return string but empty return statement found\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/RTF/Element/Field.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\RTF\\\\\\\\Element\\\\\\\\Field\\\\:\\\\:writeDate\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/RTF/Element/Field.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\RTF\\\\\\\\Element\\\\\\\\Field\\\\:\\\\:writeNumpages\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/RTF/Element/Field.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\RTF\\\\\\\\Element\\\\\\\\Field\\\\:\\\\:writePage\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/RTF/Element/Field.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\AbstractElement\\\\:\\\\:getImageStringData\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/RTF/Element/Image.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\AbstractElement\\\\:\\\\:getStyle\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/RTF/Element/Image.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\AbstractElement\\\\:\\\\:getSource\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/RTF/Element/Link.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\AbstractElement\\\\:\\\\:getText\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/RTF/Element/Link.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method object\\\\:\\\\:write\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 2\n\t\t\tpath: src/PhpWord/Writer/RTF/Part/Document.php\n\n\t\t-\n\t\t\tmessage: \"#^Binary operation \\\"\\\\+\\\" between int\\\\|string and 1 results in an error\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/RTF/Style/Border.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\Word2007\\\\\\\\Element\\\\\\\\AbstractElement\\\\:\\\\:write\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/Word2007/Element/AbstractElement.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\Word2007\\\\\\\\Element\\\\\\\\Field\\\\:\\\\:buildPropertiesAndOptions\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/Word2007/Element/Field.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$content of method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\Word2007\\\\\\\\Element\\\\\\\\AbstractElement\\\\:\\\\:writeText\\\\(\\\\) expects string, bool\\\\|int\\\\|string given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/Word2007/Element/FormField.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#3 \\\\$value of method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\XMLWriter\\\\:\\\\:writeElementBlock\\\\(\\\\) expects string\\\\|null, bool\\\\|int\\\\|string given\\\\.$#\"\n\t\t\tcount: 3\n\t\t\tpath: src/PhpWord/Writer/Word2007/Element/FormField.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#3 \\\\$value of method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\XMLWriter\\\\:\\\\:writeElementBlock\\\\(\\\\) expects string\\\\|null, int given\\\\.$#\"\n\t\t\tcount: 4\n\t\t\tpath: src/PhpWord/Writer/Word2007/Element/FormField.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\Word2007\\\\\\\\Element\\\\\\\\ParagraphAlignment\\\\:\\\\:\\\\$attributes has no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\Word2007\\\\\\\\Element\\\\\\\\ParagraphAlignment\\\\:\\\\:\\\\$name has no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#2 \\\\$content of method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\XMLWriter\\\\:\\\\:writeElement\\\\(\\\\) expects string\\\\|null, bool\\\\|int\\\\|string given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/Word2007/Element/SDT.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#3 \\\\$value of method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\XMLWriter\\\\:\\\\:writeElementBlock\\\\(\\\\) expects string\\\\|null, int\\\\<100000000, 999999999\\\\> given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/Word2007/Element/SDT.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\Word2007\\\\\\\\Element\\\\\\\\TableAlignment\\\\:\\\\:\\\\$attributes has no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/Word2007/Element/TableAlignment.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\Word2007\\\\\\\\Element\\\\\\\\TableAlignment\\\\:\\\\:\\\\$name has no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/Word2007/Element/TableAlignment.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\PhpWord\\\\:\\\\:addBookmark\\\\(\\\\) invoked with 0 parameters, 1 required\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/Word2007/Element/Title.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\Word2007\\\\\\\\Part\\\\\\\\Chart\\\\:\\\\:writeAxisTitle\\\\(\\\\) has parameter \\\\$title with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/Word2007/Part/Chart.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#3 \\\\$value of method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\XMLWriter\\\\:\\\\:writeElementBlock\\\\(\\\\) expects string\\\\|null, int given\\\\.$#\"\n\t\t\tcount: 9\n\t\t\tpath: src/PhpWord/Writer/Word2007/Part/Chart.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#3 \\\\$value of method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\XMLWriter\\\\:\\\\:writeElementBlock\\\\(\\\\) expects string\\\\|null, int\\\\<0, max\\\\> given\\\\.$#\"\n\t\t\tcount: 4\n\t\t\tpath: src/PhpWord/Writer/Word2007/Part/Chart.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$string of function md5 expects string, int\\\\<0, max\\\\> given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/Word2007/Part/Numbering.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$haystack of function strpos expects string, int given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/Word2007/Part/Rels.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\Word2007\\\\\\\\Style\\\\\\\\AbstractStyle\\\\:\\\\:write\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/Word2007/Style/AbstractStyle.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$styleName of static method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\:\\\\:getStyle\\\\(\\\\) expects string, PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\AbstractStyle\\\\|string given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/Word2007/Style/Font.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method object\\\\:\\\\:read\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/AbstractTestReader.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWordTests\\\\\\\\AbstractTestReader\\\\:\\\\:\\\\$parts has no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/AbstractTestReader.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWordTests\\\\\\\\AbstractWebServerEmbedded\\\\:\\\\:getBaseUrl\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/AbstractWebServerEmbedded.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWordTests\\\\\\\\AbstractWebServerEmbedded\\\\:\\\\:getRemoteBmpImageUrl\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/AbstractWebServerEmbedded.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWordTests\\\\\\\\AbstractWebServerEmbedded\\\\:\\\\:getRemoteGifImageUrl\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/AbstractWebServerEmbedded.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWordTests\\\\\\\\AbstractWebServerEmbedded\\\\:\\\\:getRemoteImageUrl\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/AbstractWebServerEmbedded.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWordTests\\\\\\\\AbstractWebServerEmbedded\\\\:\\\\:\\\\$httpServer has no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/AbstractWebServerEmbedded.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$width of class PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\Cell constructor expects int\\\\|null, string given\\\\.$#\"\n\t\t\tcount: 2\n\t\t\tpath: tests/PhpWordTests/Element/CellTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#2 \\\\$style of class PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\Cell constructor expects array\\\\|PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Cell\\\\|null, int given\\\\.$#\"\n\t\t\tcount: 2\n\t\t\tpath: tests/PhpWordTests/Element/CellTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$text of method PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\Field\\\\:\\\\:setText\\\\(\\\\) expects PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\TextRun\\\\|string\\\\|null, array given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Element/FieldTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWordTests\\\\\\\\Element\\\\\\\\ImageTest\\\\:\\\\:testImages\\\\(\\\\) has parameter \\\\$createFunction with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Element/ImageTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWordTests\\\\\\\\Element\\\\\\\\ImageTest\\\\:\\\\:testImages\\\\(\\\\) has parameter \\\\$extension with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Element/ImageTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWordTests\\\\\\\\Element\\\\\\\\ImageTest\\\\:\\\\:testImages\\\\(\\\\) has parameter \\\\$imageFunction with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Element/ImageTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWordTests\\\\\\\\Element\\\\\\\\ImageTest\\\\:\\\\:testImages\\\\(\\\\) has parameter \\\\$imageQuality with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Element/ImageTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWordTests\\\\\\\\Element\\\\\\\\ImageTest\\\\:\\\\:testImages\\\\(\\\\) has parameter \\\\$source with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Element/ImageTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWordTests\\\\\\\\Element\\\\\\\\ImageTest\\\\:\\\\:testImages\\\\(\\\\) has parameter \\\\$type with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Element/ImageTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$source of class PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\Image constructor expects string, string\\\\|false given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Element/ImageTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$string of function md5 expects string, string\\\\|false given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Element/ImageTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$string of function ucfirst expects string, string\\\\|false given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Element/ImageTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#3 \\\\$watermark of class PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\Image constructor expects bool, null given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Element/ImageTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#2 \\\\$style of class PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\Section constructor expects array\\\\|PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\|string\\\\|null, PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Section given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Element/SectionTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$text of class PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\Title constructor expects PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\TextRun\\\\|string, PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\PageBreak given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Element/TitleTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWordTests\\\\\\\\Escaper\\\\\\\\RtfEscaper2Test\\\\:\\\\:escapestring\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Escaper/RtfEscaper2Test.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWordTests\\\\\\\\Escaper\\\\\\\\RtfEscaper2Test\\\\:\\\\:escapestring\\\\(\\\\) has parameter \\\\$str with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Escaper/RtfEscaper2Test.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWordTests\\\\\\\\Escaper\\\\\\\\RtfEscaper2Test\\\\:\\\\:expect\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Escaper/RtfEscaper2Test.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWordTests\\\\\\\\Escaper\\\\\\\\RtfEscaper2Test\\\\:\\\\:expect\\\\(\\\\) has parameter \\\\$str with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Escaper/RtfEscaper2Test.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$expected of static method PHPUnit\\\\\\\\Framework\\\\\\\\Assert\\\\:\\\\:assertInstanceOf\\\\(\\\\) expects class\\\\-string\\\\<object\\\\>, string given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/IOFactoryTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#2 \\\\$libraryBaseDir of static method PhpOffice\\\\\\\\PhpWord\\\\\\\\Settings\\\\:\\\\:setPdfRenderer\\\\(\\\\) expects string, string\\\\|false given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/IOFactoryTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method PhpOffice\\\\\\\\PhpWord\\\\\\\\PhpWord\\\\:\\\\:undefinedMethod\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/PhpWordTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\AbstractElement\\\\:\\\\:getRows\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Reader/Word2007/ElementTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\AbstractElement\\\\:\\\\:getText\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Reader/Word2007/ElementTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Cannot access offset 0 on PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\TextRun\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Reader/Word2007/ElementTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\AbstractElement\\\\:\\\\:getElement\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 2\n\t\t\tpath: tests/PhpWordTests/Reader/Word2007/PartTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Cannot call method getElement\\\\(\\\\) on PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\TextRun\\\\|string\\\\.$#\"\n\t\t\tcount: 3\n\t\t\tpath: tests/PhpWordTests/Reader/Word2007/PartTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Cannot call method isBold\\\\(\\\\) on PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Font\\\\|string\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Reader/Word2007/PartTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Variable \\\\$endnote in PHPDoc tag @var does not match assigned variable \\\\$documentEndnote\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Reader/Word2007/PartTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Variable \\\\$footnote in PHPDoc tag @var does not match assigned variable \\\\$documentFootnote\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Reader/Word2007/PartTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Cannot access offset 0 on PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\TextRun\\\\.$#\"\n\t\t\tcount: 2\n\t\t\tpath: tests/PhpWordTests/Reader/Word2007/StyleTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Else branch is unreachable because ternary operator condition is always true\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/SettingsTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#2 \\\\$libraryBaseDir of static method PhpOffice\\\\\\\\PhpWord\\\\\\\\Settings\\\\:\\\\:setPdfRenderer\\\\(\\\\) expects string, string\\\\|false given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/SettingsTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWordTests\\\\\\\\SettingsTest\\\\:\\\\:\\\\$compatibility has no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/SettingsTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWordTests\\\\\\\\SettingsTest\\\\:\\\\:\\\\$defaultFontName has no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/SettingsTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWordTests\\\\\\\\SettingsTest\\\\:\\\\:\\\\$defaultFontSize has no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/SettingsTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWordTests\\\\\\\\SettingsTest\\\\:\\\\:\\\\$defaultPaper has no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/SettingsTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWordTests\\\\\\\\SettingsTest\\\\:\\\\:\\\\$measurementUnit has no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/SettingsTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWordTests\\\\\\\\SettingsTest\\\\:\\\\:\\\\$outputEscapingEnabled has no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/SettingsTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWordTests\\\\\\\\SettingsTest\\\\:\\\\:\\\\$pdfRendererName has no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/SettingsTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWordTests\\\\\\\\SettingsTest\\\\:\\\\:\\\\$pdfRendererPath has no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/SettingsTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWordTests\\\\\\\\SettingsTest\\\\:\\\\:\\\\$tempDir has no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/SettingsTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWordTests\\\\\\\\SettingsTest\\\\:\\\\:\\\\$zipClass has no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/SettingsTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Cannot call method getStyleName\\\\(\\\\) on PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Table\\\\|string\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Shared/HtmlTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$number of static method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\Text\\\\:\\\\:numberFormat\\\\(\\\\) expects float, string given\\\\.$#\"\n\t\t\tcount: 2\n\t\t\tpath: tests/PhpWordTests/Shared/TextTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#2 \\\\$locale of function setlocale expects array\\\\|string\\\\|null, int given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Shared/XMLWriterTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#2 \\\\$locale of function setlocale expects string\\\\|null, string\\\\|false given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Shared/XMLWriterTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Argument of an invalid type array\\\\<int, string\\\\>\\\\|false supplied for foreach, only iterables are supported\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Shared/ZipArchiveTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWordTests\\\\\\\\Style\\\\\\\\AbstractStyleTest\\\\:\\\\:callProtectedMethod\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Style/AbstractStyleTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$objectOrClass of class ReflectionClass constructor expects class\\\\-string\\\\<object\\\\>\\\\|object, class\\\\-string\\\\|false given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Style/AbstractStyleTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Cannot call method setLineHeight\\\\(\\\\) on PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Font\\\\|string\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Style/FontTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$type of class PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Font constructor expects string, null given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Style/FontTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#2 \\\\$value of method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\AbstractStyle\\\\:\\\\:setStyleValue\\\\(\\\\) expects array\\\\|int\\\\|string, null given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Style/FontTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Cannot call method setLineHeight\\\\(\\\\) on PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Paragraph\\\\|string\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Style/ParagraphTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#2 \\\\$value of method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\AbstractStyle\\\\:\\\\:setStyleValue\\\\(\\\\) expects array\\\\|int\\\\|string, bool given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Style/RowTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#2 \\\\$value of method PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\Section\\\\:\\\\:setSettingValue\\\\(\\\\) expects array\\\\|int\\\\|string, null given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Style/SectionTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\AbstractElement\\\\:\\\\:getText\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 2\n\t\t\tpath: tests/PhpWordTests/TemplateProcessorTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method PhpOffice\\\\\\\\PhpWord\\\\\\\\Shared\\\\\\\\ZipArchive\\\\:\\\\:AddFromString\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/TemplateProcessorTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Cannot access offset 'end' on array\\\\<int\\\\>\\\\|bool\\\\.$#\"\n\t\t\tcount: 2\n\t\t\tpath: tests/PhpWordTests/TemplateProcessorTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Cannot access offset 'start' on array\\\\<int\\\\>\\\\|bool\\\\.$#\"\n\t\t\tcount: 2\n\t\t\tpath: tests/PhpWordTests/TemplateProcessorTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#2 \\\\$haystack of static method PHPUnit\\\\\\\\Framework\\\\\\\\Assert\\\\:\\\\:assertStringContainsString\\\\(\\\\) expects string, string\\\\|false given\\\\.$#\"\n\t\t\tcount: 6\n\t\t\tpath: tests/PhpWordTests/TemplateProcessorTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#2 \\\\$haystack of static method PHPUnit\\\\\\\\Framework\\\\\\\\Assert\\\\:\\\\:assertStringNotContainsString\\\\(\\\\) expects string, string\\\\|false given\\\\.$#\"\n\t\t\tcount: 4\n\t\t\tpath: tests/PhpWordTests/TemplateProcessorTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Part \\\\$documentZip \\\\(ZipArchive\\\\) of encapsed string cannot be cast to string\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/TemplateProcessorTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Part \\\\$templateZip \\\\(ZipArchive\\\\) of encapsed string cannot be cast to string\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/TemplateProcessorTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Argument of an invalid type array\\\\<int, string\\\\>\\\\|false supplied for foreach, only iterables are supported\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/TestHelperDOCX.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWordTests\\\\\\\\TestableTemplateProcesor\\\\:\\\\:__construct\\\\(\\\\) has parameter \\\\$mainPart with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/TestableTemplateProcesor.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWordTests\\\\\\\\TestableTemplateProcesor\\\\:\\\\:__construct\\\\(\\\\) has parameter \\\\$settingsPart with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/TestableTemplateProcesor.php\n\n\t\t-\n\t\t\tmessage: \"#^Cannot access property \\\\$length on DOMNodeList\\\\<DOMNode\\\\>\\\\|false\\\\.$#\"\n\t\t\tcount: 9\n\t\t\tpath: tests/PhpWordTests/Writer/HTML/ElementTest.php\n\t\t\t\n\t\t-\n\t\t\tmessage: \"#^Cannot access property \\\\$length on DOMNodeList\\\\<DOMNode\\\\>\\\\|false\\\\.$#\"\n\t\t\tcount: 2\n\t\t\tpath: tests/PhpWordTests/Writer/HTML/Element/RubyTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Cannot call method item\\\\(\\\\) on DOMNodeList\\\\<DOMNode\\\\>\\\\|false\\\\.$#\"\n\t\t\tcount: 11\n\t\t\tpath: tests/PhpWordTests/Writer/HTML/ElementTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#2 \\\\$libraryBaseDir of static method PhpOffice\\\\\\\\PhpWord\\\\\\\\Settings\\\\:\\\\:setPdfRenderer\\\\(\\\\) expects string, string\\\\|false given\\\\.$#\"\n\t\t\tcount: 3\n\t\t\tpath: tests/PhpWordTests/Writer/HTML/Element/PageBreakTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWordTests\\\\\\\\Writer\\\\\\\\ODText\\\\\\\\Style\\\\\\\\FontTest\\\\:\\\\:providerAllNamedColors\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Writer/ODText/Style/FontTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\PDF\\\\:\\\\:getFont\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 2\n\t\t\tpath: tests/PhpWordTests/Writer/PDF/DomPDFTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\PDF\\\\:\\\\:getOrientation\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Writer/PDF/DomPDFTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\PDF\\\\:\\\\:getPaperSize\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Writer/PDF/DomPDFTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\PDF\\\\:\\\\:getTempDir\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Writer/PDF/DomPDFTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\PDF\\\\:\\\\:setFont\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Writer/PDF/DomPDFTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\PDF\\\\:\\\\:setOrientation\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Writer/PDF/DomPDFTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\PDF\\\\:\\\\:setPaperSize\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Writer/PDF/DomPDFTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\PDF\\\\:\\\\:setTempDir\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Writer/PDF/DomPDFTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#2 \\\\$libraryBaseDir of static method PhpOffice\\\\\\\\PhpWord\\\\\\\\Settings\\\\:\\\\:setPdfRenderer\\\\(\\\\) expects string, string\\\\|false given\\\\.$#\"\n\t\t\tcount: 3\n\t\t\tpath: tests/PhpWordTests/Writer/PDF/DomPDFTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\PDF\\\\:\\\\:getFont\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Writer/PDF/MPDFTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#2 \\\\$libraryBaseDir of static method PhpOffice\\\\\\\\PhpWord\\\\\\\\Settings\\\\:\\\\:setPdfRenderer\\\\(\\\\) expects string, string\\\\|false given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Writer/PDF/MPDFTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#2 \\\\$libraryBaseDir of static method PhpOffice\\\\\\\\PhpWord\\\\\\\\Settings\\\\:\\\\:setPdfRenderer\\\\(\\\\) expects string, string\\\\|false given\\\\.$#\"\n\t\t\tcount: 2\n\t\t\tpath: tests/PhpWordTests/Writer/PDF/TCPDFTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\PDF\\\\:\\\\:getFont\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Writer/PDF/TCPDFTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#2 \\\\$libraryBaseDir of static method PhpOffice\\\\\\\\PhpWord\\\\\\\\Settings\\\\:\\\\:setPdfRenderer\\\\(\\\\) expects string, string\\\\|false given\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Writer/PDFTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWordTests\\\\\\\\Writer\\\\\\\\RTF\\\\\\\\ElementTest\\\\:\\\\:removeCr\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Writer/RTF/ElementTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWordTests\\\\\\\\Writer\\\\\\\\RTF\\\\\\\\ElementTest\\\\:\\\\:removeCr\\\\(\\\\) has parameter \\\\$field with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Writer/RTF/ElementTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWordTests\\\\\\\\Writer\\\\\\\\RTF\\\\\\\\StyleTest\\\\:\\\\:removeCr\\\\(\\\\) has no return type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Writer/RTF/StyleTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWordTests\\\\\\\\Writer\\\\\\\\RTF\\\\\\\\StyleTest\\\\:\\\\:removeCr\\\\(\\\\) has parameter \\\\$field with no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Writer/RTF/StyleTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWordTests\\\\\\\\Writer\\\\\\\\Word2007\\\\\\\\Element\\\\\\\\ChartTest\\\\:\\\\:\\\\$outputEscapingEnabled has no type specified\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Writer/Word2007/Element/ChartTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method object\\\\:\\\\:write\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Writer/Word2007/ElementTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Call to an undefined method object\\\\:\\\\:write\\\\(\\\\)\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/Writer/Word2007/StyleTest.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWordTests\\\\\\\\XmlDocument\\\\:\\\\:getElement\\\\(\\\\) should return DOMElement\\\\|null but returns DOMNode\\\\|null\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/XmlDocument.php\n\n\t\t-\n\t\t\tmessage: \"#^Method PhpOffice\\\\\\\\PhpWordTests\\\\\\\\XmlDocument\\\\:\\\\:getNodeList\\\\(\\\\) should return DOMNodeList\\\\<DOMNode\\\\> but returns DOMNodeList\\\\<DOMNode\\\\>\\\\|false\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/XmlDocument.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWordTests\\\\\\\\XmlDocument\\\\:\\\\:\\\\$path \\\\(string\\\\) does not accept string\\\\|false\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/XmlDocument.php\n\n\t\t-\n\t\t\tmessage: \"#^Property PhpOffice\\\\\\\\PhpWordTests\\\\\\\\XmlDocument\\\\:\\\\:\\\\$xpath \\\\(DOMXPath\\\\) does not accept null\\\\.$#\"\n\t\t\tcount: 1\n\t\t\tpath: tests/PhpWordTests/XmlDocument.php\n\n\t\t# https://github.com/phpstan/phpstan/issues/8770\n\t\t-\n\t\t\tmessage: \"#^PHPDoc tag @var with type PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\HTML\\\\\\\\Part\\\\\\\\AbstractPart is not subtype of native type[\\\\sA-Za-z\\\\@\\\\\\\\\\\\/0-9\\\\.:|]+$#\"\n\t\t\tcount: 1\n\t\t\tpath: src/PhpWord/Writer/HTML.php\n\n\t\t# https://github.com/phpstan/phpstan/issues/8770\n\t\t-\n\t\t\tmessage: \"#^PHPDoc tag @var with type PhpOffice\\\\\\\\PhpWord\\\\\\\\Element\\\\\\\\AbstractElement is not subtype of native type[\\\\sA-Za-z\\\\@\\\\\\\\\\\\/0-9\\\\.:]+$#\"\n\t\t\tcount: 2\n\t\t\tpath: tests/PhpWordTests/Element/AbstractElementTest.php\n\n\t\t# https://github.com/phpstan/phpstan/issues/8770\n\t\t-\n\t\t\tmessage: \"#^PHPDoc tag @var with type PhpOffice\\\\\\\\PhpWord\\\\\\\\Style\\\\\\\\AbstractStyle is not subtype of native type[\\\\sA-Za-z\\\\@\\\\\\\\\\\\/0-9\\\\.:]+$#\"\n\t\t\tcount: 4\n\t\t\tpath: tests/PhpWordTests/Style/AbstractStyleTest.php\n\n\t\t# https://github.com/phpstan/phpstan/issues/8770\n\t\t-\n\t\t\tmessage: \"#^PHPDoc tag @var with type PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\EPub3\\\\\\\\Style\\\\\\\\AbstractStyle is not subtype of native type[\\\\sA-Za-z\\\\@\\\\\\\\\\\\/0-9\\\\.:]+$#\"\n\t\t\tcount: 2\n\t\t\tpath: tests/PhpWordTests/Writer/EPub3/Style/AbstractStyleTest.php\n\n\t\t# https://github.com/phpstan/phpstan/issues/8770\n\t\t-\n\t\t\tmessage: \"#^PHPDoc tag @var with type PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\ODText\\\\\\\\Part\\\\\\\\AbstractPart is not subtype of native type[\\\\sA-Za-z\\\\@\\\\\\\\\\\\/0-9\\\\.:]+$#\"\n\t\t\tcount: 2\n\t\t\tpath: tests/PhpWordTests/Writer/ODText/Part/AbstractPartTest.php\n\n\t\t# https://github.com/phpstan/phpstan/issues/8770\n\t\t-\n\t\t\tmessage: \"#^PHPDoc tag @var with type PhpOffice\\\\\\\\PhpWord\\\\\\\\Writer\\\\\\\\Word2007\\\\\\\\Part\\\\\\\\AbstractPart is not subtype of native type[\\\\sA-Za-z\\\\@\\\\\\\\\\\\/0-9\\\\.:]+$#\"\n\t\t\tcount: 2\n\t\t\tpath: tests/PhpWordTests/Writer/Word2007/Part/AbstractPartTest.php\n"
  },
  {
    "path": "phpstan.neon.dist",
    "content": "includes:\n    - phpstan-baseline.neon\n    - vendor/phpstan/phpstan-phpunit/extension.neon\n    - vendor/phpstan/phpstan-phpunit/rules.neon\nparameters:\n    level: 7\n    paths:\n        - src/\n        - tests/\n    excludePaths:\n        - */pclzip.lib.php\n        - src/PhpWord/Shared/OLERead.php\n        - src/PhpWord/Reader/MsDoc.php\n        - src/PhpWord/Writer/PDF/MPDF.php\n    bootstrapFiles:\n        - tests/bootstrap.php\n    ## <=PHP7.4\n    reportUnmatchedIgnoredErrors: false\n    treatPhpDocTypesAsCertain: false\n    ignoreErrors:\n        -\n            identifier: missingType.iterableValue\n        \n        ## <=PHP7.4\n        -\n            message: '#Parameter \\#1 \\$argument of class ReflectionClass constructor expects class-string<T of object>\\|T of object, string given.#'\n            path: src/PhpWord/Element/AbstractContainer.php\n        -\n            message: '#Parameter \\#1 \\$function of function call_user_func expects callable\\(\\): mixed, string given.#'\n            path: src/PhpWord/Element/Image.php\n        -\n            message: '#Parameter \\#1 \\$argument of class ReflectionClass constructor expects class-string<T of object>\\|T of object, string given.#'\n            path: src/PhpWord/IOFactory.php\n        -\n            message: '#Parameter \\#1 \\$function of function forward_static_call_array expects callable\\(\\): mixed, array{.+, string} given.#'\n            path: src/PhpWord/PhpWord.php\n        -\n            message: '#Parameter \\#1 \\$function of function call_user_func_array expects callable\\(\\): mixed, array{\\$this\\(PhpOffice\\\\PhpWord\\\\Shared\\\\ZipArchive\\)\\|PclZip\\|ZipArchive, mixed} given.#'\n            path: src/PhpWord/Shared/ZipArchive.php\n        -\n            message: '#Parameter \\#1 \\$function of function call_user_func_array expects callable\\(\\): mixed, array{PhpOffice\\\\PhpWord\\\\Writer\\\\PDF\\\\AbstractRenderer, string} given.#'\n            path: src/PhpWord/Writer/PDF.php\n        - \n            message: '#Parameter \\#1 \\$argument of class ReflectionClass constructor expects class-string<object>\\|object, class-string\\|false given.#'\n            path: tests/PhpWordTests/Style/AbstractStyleTest.php\n"
  },
  {
    "path": "phpunit.xml.dist",
    "content": "<?xml version=\"1.0\"?>\n<phpunit xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" backupGlobals=\"false\" backupStaticAttributes=\"false\" bootstrap=\"./tests/bootstrap.php\" colors=\"true\" convertErrorsToExceptions=\"true\" convertNoticesToExceptions=\"true\" convertWarningsToExceptions=\"true\" convertDeprecationsToExceptions=\"true\" processIsolation=\"false\" stopOnFailure=\"false\" xsi:noNamespaceSchemaLocation=\"https://schema.phpunit.de/9.3/phpunit.xsd\">\n  <coverage>\n    <include>\n      <directory suffix=\".php\">./src</directory>\n    </include>\n    <exclude>\n      <directory suffix=\".php\">./src/PhpWord/Shared/PCLZip</directory>\n    </exclude>\n    <report>\n      <clover outputFile=\"./build/logs/clover.xml\"/>\n      <html outputDirectory=\"./build/coverage\"/>\n    </report>\n  </coverage>\n  <php>\n    <ini name=\"error_reporting\" value=\"E_ALL\"/>\n  </php>\n  <testsuites>\n    <testsuite name=\"PhpWord Test Suite\">\n      <directory>./tests/PhpWordTests</directory>\n    </testsuite>\n  </testsuites>\n  <logging/>\n</phpunit>\n"
  },
  {
    "path": "phpword.ini.dist",
    "content": "; Default config file for PHPWord\n; Copy this file into phpword.ini and use Settings::loadConfig to load\n\n[General]\n\ncompatibility         = true\nzipClass              = ZipArchive\npdfRendererName       = DomPDF\npdfRendererPath       =\n; tempDir               = \"C:\\PhpWordTemp\"\noutputEscapingEnabled = false\n\n[Font]\n\ndefaultFontName = Arial\ndefaultFontSize = 10\ndefaultFontColor = 000000\n\n[Paper]\n\ndefaultPaper = \"A4\"\n"
  },
  {
    "path": "samples/Sample_01_SimpleText.php",
    "content": "<?php\n\nuse PhpOffice\\PhpWord\\Style\\Font;\n\ninclude_once 'Sample_Header.php';\n\n// New Word Document\necho date('H:i:s') , ' Create new PhpWord object' , EOL;\n\n$languageEnGb = new PhpOffice\\PhpWord\\Style\\Language(PhpOffice\\PhpWord\\Style\\Language::EN_GB);\n\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n$phpWord->getSettings()->setThemeFontLang($languageEnGb);\n\n$fontStyleName = 'rStyle';\n$phpWord->addFontStyle($fontStyleName, ['bold' => true, 'italic' => true, 'size' => 16, 'allCaps' => true, 'doubleStrikethrough' => true]);\n\n$paragraphStyleName = 'pStyle';\n$phpWord->addParagraphStyle($paragraphStyleName, ['alignment' => PhpOffice\\PhpWord\\SimpleType\\Jc::CENTER, 'spaceAfter' => 100]);\n\n$phpWord->addTitleStyle(1, ['bold' => true], ['spaceAfter' => 240]);\n\n// New portrait section\n$section = $phpWord->addSection();\n\n// Simple text\n$section->addTitle('Welcome to PhpWord', 1);\n$section->addText('Hello World!');\n\n// $pStyle = new Font();\n// $pStyle->setLang()\n$section->addText('Ce texte-ci est en français.', ['lang' => PhpOffice\\PhpWord\\Style\\Language::FR_BE]);\n\n// Two text break\n$section->addTextBreak(2);\n\n// Define styles\n$section->addText('I am styled by a font style definition.', $fontStyleName);\n$section->addText('I am styled by a paragraph style definition.', null, $paragraphStyleName);\n$section->addText('I am styled by both font and paragraph style.', $fontStyleName, $paragraphStyleName);\n\n$section->addTextBreak();\n\n// Inline font style\n$fontStyle['name'] = 'Times New Roman';\n$fontStyle['size'] = 20;\n\n$textrun = $section->addTextRun();\n$textrun->addText('I am inline styled ', $fontStyle);\n$textrun->addText('with ');\n$textrun->addText('color', ['color' => '996699']);\n$textrun->addText(', ');\n$textrun->addText('bold', ['bold' => true]);\n$textrun->addText(', ');\n$textrun->addText('italic', ['italic' => true]);\n$textrun->addText(', ');\n$textrun->addText('underline', ['underline' => 'dash']);\n$textrun->addText(', ');\n$textrun->addText('strikethrough', ['strikethrough' => true]);\n$textrun->addText(', ');\n$textrun->addText('doubleStrikethrough', ['doubleStrikethrough' => true]);\n$textrun->addText(', ');\n$textrun->addText('superScript', ['superScript' => true]);\n$textrun->addText(', ');\n$textrun->addText('subScript', ['subScript' => true]);\n$textrun->addText(', ');\n$textrun->addText('smallCaps', ['smallCaps' => true]);\n$textrun->addText(', ');\n$textrun->addText('allCaps', ['allCaps' => true]);\n$textrun->addText(', ');\n$textrun->addText('fgColor', ['fgColor' => 'yellow']);\n$textrun->addText(', ');\n$textrun->addText('scale', ['scale' => 200]);\n$textrun->addText(', ');\n$textrun->addText('spacing', ['spacing' => 120]);\n$textrun->addText(', ');\n$textrun->addText('kerning', ['kerning' => 10]);\n$textrun->addText('. ');\n\n// Link\n$section->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub');\n$section->addTextBreak();\n\n// Image\n$section->addImage(__DIR__ . '/resources/_earth.jpg', ['width' => 18, 'height' => 18]);\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_02_TabStops.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// New Word Document\necho date('H:i:s'), ' Create new PhpWord object', EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n\n// Define styles\n$multipleTabsStyleName = 'multipleTab';\n$phpWord->addParagraphStyle(\n    $multipleTabsStyleName,\n    [\n        'tabs' => [\n            new PhpOffice\\PhpWord\\Style\\Tab('left', 1550),\n            new PhpOffice\\PhpWord\\Style\\Tab('center', 3200),\n            new PhpOffice\\PhpWord\\Style\\Tab('right', 5300),\n        ],\n    ]\n);\n\n$rightTabStyleName = 'rightTab';\n$phpWord->addParagraphStyle($rightTabStyleName, ['tabs' => [new PhpOffice\\PhpWord\\Style\\Tab('right', 9090)]]);\n\n$leftTabStyleName = 'centerTab';\n$phpWord->addParagraphStyle($leftTabStyleName, ['tabs' => [new PhpOffice\\PhpWord\\Style\\Tab('center', 4680)]]);\n\n// New portrait section\n$section = $phpWord->addSection();\n\n// Add listitem elements\n$section->addText(\"Multiple Tabs:\\tOne\\tTwo\\tThree\", null, $multipleTabsStyleName);\n$section->addText(\"Left Aligned\\tRight Aligned\", null, $rightTabStyleName);\n$section->addText(\"\\tCenter Aligned\", null, $leftTabStyleName);\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_03_Sections.php",
    "content": "<?php\n\nuse PhpOffice\\PhpWord\\SimpleType\\VerticalJc;\n\ninclude_once 'Sample_Header.php';\n\n// New Word Document\necho date('H:i:s'), ' Create new PhpWord object', EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n\n// New portrait section\n$section = $phpWord->addSection(['borderColor' => '00FF00', 'borderSize' => 12]);\n$section->addText('I am placed on a default section.');\n\n// New landscape section\n$section = $phpWord->addSection(['orientation' => 'landscape']);\n$section->addText('I am placed on a landscape section. Every page starting from this section will be landscape style.');\n$section->addPageBreak();\n$section->addPageBreak();\n\n// New portrait section\n$section = $phpWord->addSection(\n    ['paperSize' => 'Folio', 'marginLeft' => 600, 'marginRight' => 600, 'marginTop' => 600, 'marginBottom' => 600]\n);\n$section->addText('This section uses other margins with folio papersize.');\n\n// The text of this section is vertically centered\n$section = $phpWord->addSection(\n    ['vAlign' => VerticalJc::CENTER]\n);\n$section->addText('This section is vertically centered.');\n\n// New portrait section with Header & Footer\n$section = $phpWord->addSection(\n    [\n        'marginLeft' => 200,\n        'marginRight' => 200,\n        'marginTop' => 200,\n        'marginBottom' => 200,\n        'headerHeight' => 50,\n        'footerHeight' => 50,\n    ]\n);\n$section->addText('This section and we play with header/footer height.');\n$section->addHeader()->addText('Header');\n$section->addFooter()->addText('Footer');\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_04_Textrun.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// New Word Document\necho date('H:i:s'), ' Create new PhpWord object', EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n\n// Define styles\n$paragraphStyleName = 'pStyle';\n$phpWord->addParagraphStyle($paragraphStyleName, ['spacing' => 100]);\n\n$boldFontStyleName = 'BoldText';\n$phpWord->addFontStyle($boldFontStyleName, ['bold' => true]);\n\n$coloredFontStyleName = 'ColoredText';\n$phpWord->addFontStyle($coloredFontStyleName, ['color' => 'FF8080', 'bgColor' => 'FFFFCC']);\n\n$linkFontStyleName = 'NLink';\n$phpWord->addLinkStyle($linkFontStyleName, ['color' => '0000FF', 'underline' => PhpOffice\\PhpWord\\Style\\Font::UNDERLINE_SINGLE]);\n\n// New portrait section\n$section = $phpWord->addSection();\n\n// Add text run\n$textrun = $section->addTextRun($paragraphStyleName);\n$textrun->addText('Each textrun can contain native text, link elements or an image.');\n$textrun->addText(' No break is placed after adding an element.', $boldFontStyleName);\n$textrun->addText(' Both ');\n$textrun->addText('superscript', ['superScript' => true]);\n$textrun->addText(' and ');\n$textrun->addText('subscript', ['subScript' => true]);\n$textrun->addText(' are also available.');\n$textrun->addText(' All elements are placed inside a paragraph with the optionally given paragraph style.', $coloredFontStyleName);\n$textrun->addText(' Sample Link: ');\n$textrun->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub', $linkFontStyleName);\n$textrun->addText(' Sample Image: ');\n$textrun->addImage(__DIR__ . '/resources/_earth.jpg', ['width' => 18, 'height' => 18]);\n$textrun->addText(' Sample Object: ');\n$textrun->addObject(__DIR__ . '/resources/_sheet.xls');\n$textrun->addText(' Here is some more text. ');\n\n$textrun = $section->addTextRun();\n$textrun->addText('This text is not visible.', ['hidden' => true]);\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_05_Multicolumn.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// New Word Document\necho date('H:i:s'), ' Create new PhpWord object', EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n$filler = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. '\n        . 'Nulla fermentum, tortor id adipiscing adipiscing, tortor turpis commodo. '\n        . 'Donec vulputate iaculis metus, vel luctus dolor hendrerit ac. '\n        . 'Suspendisse congue congue leo sed pellentesque.';\n\n// Normal\n$section = $phpWord->addSection();\n$section->addText(\"Normal paragraph. {$filler}\");\n\n// Two columns\n$section = $phpWord->addSection(\n    [\n        'colsNum' => 2,\n        'colsSpace' => 1440,\n        'breakType' => 'continuous',\n    ]\n);\n$section->addText(\"Two columns, one inch (1440 twips) spacing. {$filler}\");\n\n// Normal\n$section = $phpWord->addSection(['breakType' => 'continuous']);\n$section->addText(\"Normal paragraph again. {$filler}\");\n\n// Three columns\n$section = $phpWord->addSection(\n    [\n        'colsNum' => 3,\n        'colsSpace' => 720,\n        'breakType' => 'continuous',\n    ]\n);\n$section->addText(\"Three columns, half inch (720 twips) spacing. {$filler}\");\n\n// Normal\n$section = $phpWord->addSection(['breakType' => 'continuous']);\n$section->addText(\"Normal paragraph again. {$filler}\");\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_06_Footnote.php",
    "content": "<?php\n\nuse PhpOffice\\PhpWord\\ComplexType\\FootnoteProperties;\nuse PhpOffice\\PhpWord\\SimpleType\\NumberFormat;\n\ninclude_once 'Sample_Header.php';\n\n// New Word Document\necho date('H:i:s'), ' Create new PhpWord object', EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\nPhpOffice\\PhpWord\\Settings::setCompatibility(false);\n\n// Define styles\n$paragraphStyleName = 'pStyle';\n$phpWord->addParagraphStyle($paragraphStyleName, ['spacing' => 100]);\n\n$boldFontStyleName = 'BoldText';\n$phpWord->addFontStyle($boldFontStyleName, ['bold' => true]);\n\n$coloredFontStyleName = 'ColoredText';\n$phpWord->addFontStyle($coloredFontStyleName, ['color' => 'FF8080', 'bgColor' => 'FFFFCC']);\n\n$linkFontStyleName = 'NLink';\n$phpWord->addLinkStyle($linkFontStyleName, ['color' => '0000FF', 'underline' => PhpOffice\\PhpWord\\Style\\Font::UNDERLINE_SINGLE]);\n\n// New portrait section\n$section = $phpWord->addSection();\n\n// Add text elements\n$textrun = $section->addTextRun($paragraphStyleName);\n$textrun->addText('This is some lead text in a paragraph with a following footnote. ', $paragraphStyleName);\n\n$footnote = $textrun->addFootnote();\n$footnote->addText('Just like a textrun, a footnote can contain native texts. ');\n$footnote->addText('No break is placed after adding an element. ', $boldFontStyleName);\n$footnote->addText('All elements are placed inside a paragraph. ', $coloredFontStyleName);\n$footnote->addTextBreak();\n$footnote->addText('But you can insert a manual text break like above, ');\n$footnote->addText('links like ');\n$footnote->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub', $linkFontStyleName);\n$footnote->addText(', image like ');\n$footnote->addImage(__DIR__ . '/resources/_earth.jpg', ['width' => 18, 'height' => 18]);\n$footnote->addText(', or object like ');\n$footnote->addObject(__DIR__ . '/resources/_sheet.xls');\n$footnote->addText('But you can only put footnote in section, not in header or footer.');\n\n$section->addText(\n    'You can also create the footnote directly from the section making it wrap in a paragraph '\n        . 'like the footnote below this paragraph. But is best used from within a textrun.'\n);\n$footnote = $section->addFootnote();\n$footnote->addText('The reference for this is wrapped in its own line');\n\n$footnoteProperties = new FootnoteProperties();\n$footnoteProperties->setNumFmt(NumberFormat::DECIMAL_ENCLOSED_CIRCLE);\n$section->setFootnoteProperties($footnoteProperties);\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_07_TemplateCloneRow.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// Template processor instance creation\necho date('H:i:s'), ' Creating new TemplateProcessor instance...', EOL;\n$templateProcessor = new PhpOffice\\PhpWord\\TemplateProcessor(__DIR__ . '/resources/Sample_07_TemplateCloneRow.docx');\n\n// Variables on different parts of document\n$templateProcessor->setValue('weekday', date('l'));            // On section/content\n$templateProcessor->setValue('time', date('H:i'));             // On footer\n$templateProcessor->setValue('serverName', realpath(__DIR__)); // On header\n\n// Simple table\n$templateProcessor->cloneRow('rowValue', 10);\n\n$templateProcessor->setValue('rowValue#1', 'Sun');\n$templateProcessor->setValue('rowValue#2', 'Mercury');\n$templateProcessor->setValue('rowValue#3', 'Venus');\n$templateProcessor->setValue('rowValue#4', 'Earth');\n$templateProcessor->setValue('rowValue#5', 'Mars');\n$templateProcessor->setValue('rowValue#6', 'Jupiter');\n$templateProcessor->setValue('rowValue#7', 'Saturn');\n$templateProcessor->setValue('rowValue#8', 'Uranus');\n$templateProcessor->setValue('rowValue#9', 'Neptun');\n$templateProcessor->setValue('rowValue#10', 'Pluto');\n\n$templateProcessor->setValue('rowNumber#1', '1');\n$templateProcessor->setValue('rowNumber#2', '2');\n$templateProcessor->setValue('rowNumber#3', '3');\n$templateProcessor->setValue('rowNumber#4', '4');\n$templateProcessor->setValue('rowNumber#5', '5');\n$templateProcessor->setValue('rowNumber#6', '6');\n$templateProcessor->setValue('rowNumber#7', '7');\n$templateProcessor->setValue('rowNumber#8', '8');\n$templateProcessor->setValue('rowNumber#9', '9');\n$templateProcessor->setValue('rowNumber#10', '10');\n\n// Table with a spanned cell\n$values = [\n    [\n        'userId' => 1,\n        'userFirstName' => 'James',\n        'userName' => 'Taylor',\n        'userPhone' => '+1 428 889 773',\n    ],\n    [\n        'userId' => 2,\n        'userFirstName' => 'Robert',\n        'userName' => 'Bell',\n        'userPhone' => '+1 428 889 774',\n    ],\n    [\n        'userId' => 3,\n        'userFirstName' => 'Michael',\n        'userName' => 'Ray',\n        'userPhone' => '+1 428 889 775',\n    ],\n];\n\n$templateProcessor->cloneRowAndSetValues('userId', $values);\n\n//this is equivalent to cloning and settings values with cloneRowAndSetValues\n// $templateProcessor->cloneRow('userId', 3);\n\n// $templateProcessor->setValue('userId#1', '1');\n// $templateProcessor->setValue('userFirstName#1', 'James');\n// $templateProcessor->setValue('userName#1', 'Taylor');\n// $templateProcessor->setValue('userPhone#1', '+1 428 889 773');\n\n// $templateProcessor->setValue('userId#2', '2');\n// $templateProcessor->setValue('userFirstName#2', 'Robert');\n// $templateProcessor->setValue('userName#2', 'Bell');\n// $templateProcessor->setValue('userPhone#2', '+1 428 889 774');\n\n// $templateProcessor->setValue('userId#3', '3');\n// $templateProcessor->setValue('userFirstName#3', 'Michael');\n// $templateProcessor->setValue('userName#3', 'Ray');\n// $templateProcessor->setValue('userPhone#3', '+1 428 889 775');\n\necho date('H:i:s'), ' Saving the result document...', EOL;\n$templateProcessor->saveAs(__DIR__ . '/results/Sample_07_TemplateCloneRow.docx');\n\necho getEndingNotes(['Word2007' => 'docx'], __DIR__ . '/results/Sample_07_TemplateCloneRow.docx');\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_08_ParagraphPagination.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// New Word document\necho date('H:i:s'), ' Create new PhpWord object', EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n$phpWord->setDefaultParagraphStyle(\n    [\n        'alignment' => PhpOffice\\PhpWord\\SimpleType\\Jc::BOTH,\n        'spaceAfter' => PhpOffice\\PhpWord\\Shared\\Converter::pointToTwip(12),\n        'spacing' => 120,\n    ]\n);\n\n// New section\n$section = $phpWord->addSection();\n\n$section->addText(\n    'Below are the samples on how to control your paragraph '\n        . 'pagination. See \"Line and Page Break\" tab on paragraph properties '\n        . 'window to see the attribute set by these controls.',\n    ['bold' => true],\n    ['space' => ['before' => 360, 'after' => 480]]\n);\n\n$section->addText(\n    'Paragraph with widowControl = false (default: true). '\n        . 'A \"widow\" is the last line of a paragraph printed by itself at the top '\n        . 'of a page. An \"orphan\" is the first line of a paragraph printed by '\n        . 'itself at the bottom of a page. Set this option to \"false\" if you want '\n        . 'to disable this automatic control.',\n    null,\n    ['widowControl' => false, 'indentation' => ['left' => 240, 'right' => 120]]\n);\n\n$section->addText(\n    'Paragraph with keepNext = true (default: false). '\n        . '\"Keep with next\" is used to prevent Word from inserting automatic page '\n        . 'breaks between paragraphs. Set this option to \"true\" if you do not want '\n        . 'your paragraph to be separated with the next paragraph.',\n    null,\n    ['keepNext' => true, 'indentation' => ['firstLine' => 240]]\n);\n\n$section->addText(\n    'Paragraph with keepLines = true (default: false). '\n        . '\"Keep lines together\" will prevent Word from inserting an automatic page '\n        . 'break within a paragraph. Set this option to \"true\" if you do not want '\n        . 'all lines of your paragraph to be in the same page.',\n    null,\n    ['keepLines' => true, 'indentation' => ['left' => 240, 'hanging' => 240]]\n);\n\n$section->addText('Keep scrolling. More below.');\n\n$section->addText(\n    'Paragraph with pageBreakBefore = true (default: false). '\n        . 'Different with all other control above, \"page break before\" separates '\n        . 'your paragraph into the next page. This option is most useful for '\n        . 'heading styles.',\n    null,\n    ['pageBreakBefore' => true]\n);\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_09_Tables.php",
    "content": "<?php\n\nuse PhpOffice\\PhpWord\\Shared\\Converter;\nuse PhpOffice\\PhpWord\\Style\\TablePosition;\n\ninclude_once 'Sample_Header.php';\n\n// New Word Document\necho date('H:i:s'), ' Create new PhpWord object', EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n$section = $phpWord->addSection();\n$header = ['size' => 16, 'bold' => true];\n\n// 1. Basic table\n\n$rows = 10;\n$cols = 5;\n$section->addText('Basic table', $header);\n\n$table = $section->addTable();\nfor ($r = 1; $r <= $rows; ++$r) {\n    $table->addRow();\n    for ($c = 1; $c <= $cols; ++$c) {\n        $table->addCell(1750)->addText(\"Row {$r}, Cell {$c}\");\n    }\n}\n\n// 2. Advanced table\n\n$section->addTextBreak(1);\n$section->addText('Fancy table', $header);\n\n$fancyTableStyleName = 'Fancy Table';\n$fancyTableStyle = ['borderSize' => 6, 'borderColor' => '006699', 'cellMargin' => 80, 'alignment' => PhpOffice\\PhpWord\\SimpleType\\JcTable::CENTER, 'cellSpacing' => 50];\n$fancyTableFirstRowStyle = ['borderBottomSize' => 18, 'borderBottomColor' => '0000FF', 'bgColor' => '66BBFF'];\n$fancyTableCellStyle = ['valign' => 'center'];\n$fancyTableCellBtlrStyle = ['valign' => 'center', 'textDirection' => PhpOffice\\PhpWord\\Style\\Cell::TEXT_DIR_BTLR];\n$fancyTableFontStyle = ['bold' => true];\n$phpWord->addTableStyle($fancyTableStyleName, $fancyTableStyle, $fancyTableFirstRowStyle);\n$table = $section->addTable($fancyTableStyleName);\n$table->addRow(900);\n$table->addCell(2000, $fancyTableCellStyle)->addText('Row 1', $fancyTableFontStyle);\n$table->addCell(2000, $fancyTableCellStyle)->addText('Row 2', $fancyTableFontStyle);\n$table->addCell(2000, $fancyTableCellStyle)->addText('Row 3', $fancyTableFontStyle);\n$table->addCell(2000, $fancyTableCellStyle)->addText('Row 4', $fancyTableFontStyle);\n$table->addCell(500, $fancyTableCellBtlrStyle)->addText('Row 5', $fancyTableFontStyle);\nfor ($i = 1; $i <= 8; ++$i) {\n    $table->addRow();\n    $table->addCell(2000)->addText(\"Cell {$i}\");\n    $table->addCell(2000)->addText(\"Cell {$i}\");\n    $table->addCell(2000)->addText(\"Cell {$i}\");\n    $table->addCell(2000)->addText(\"Cell {$i}\");\n    $text = (0 == $i % 2) ? 'X' : '';\n    $table->addCell(500)->addText($text);\n}\n\n/*\n *  3. colspan (gridSpan) and rowspan (vMerge)\n *  -------------------------\n *  |  A  |     B     |  C  |\n *  |-----|-----------|     |\n *  |        D        |     |\n *  ------|-----------|     |\n *  |  E  |  F  |  G  |     |\n *  -------------------------\n */\n\n$section->addPageBreak();\n$section->addText('Table with colspan and rowspan', $header);\n\n$fancyTableStyle = ['borderSize' => 6, 'borderColor' => '999999'];\n$cellRowSpan = ['vMerge' => 'restart', 'valign' => 'center', 'bgColor' => 'FFFF00'];\n$cellRowContinue = ['vMerge' => 'continue'];\n$cellColSpan = ['gridSpan' => 2, 'valign' => 'center'];\n$cellHCentered = ['alignment' => PhpOffice\\PhpWord\\SimpleType\\Jc::CENTER];\n$cellVCentered = ['valign' => 'center'];\n\n$spanTableStyleName = 'Colspan Rowspan';\n$phpWord->addTableStyle($spanTableStyleName, $fancyTableStyle);\n$table = $section->addTable($spanTableStyleName);\n\n$row1 = $table->addRow();\n$row1->addCell(500)->addText('A');\n$row1->addCell(1000, ['gridSpan' => 2])->addText('B');\n$row1->addCell(500, ['vMerge' => 'restart'])->addText('C');\n\n$row2 = $table->addRow();\n$row2->addCell(1500, ['gridSpan' => 3])->addText('D');\n$row2->addCell(null, ['vMerge' => 'continue']);\n\n$row3 = $table->addRow();\n$row3->addCell(500)->addText('E');\n$row3->addCell(500)->addText('F');\n$row3->addCell(500)->addText('G');\n$row3->addCell(null, ['vMerge' => 'continue']);\n\n/*\n *  4. colspan (gridSpan) and rowspan (vMerge)\n *  ---------------------\n *  |     |   B    |  1 |\n *  |  A  |        |----|\n *  |     |        |  2 |\n *  |     |---|----|----|\n *  |     | C |  D |  3 |\n *  ---------------------\n * @see https://github.com/PHPOffice/PHPWord/issues/806\n */\n\n$section->addPageBreak();\n$section->addText('Table with colspan and rowspan', $header);\n\n$styleTable = ['borderSize' => 6, 'borderColor' => '999999'];\n$phpWord->addTableStyle('Colspan Rowspan', $styleTable);\n$table = $section->addTable('Colspan Rowspan');\n\n$row = $table->addRow();\n$row->addCell(1000, ['vMerge' => 'restart'])->addText('A');\n$row->addCell(1000, ['gridSpan' => 2, 'vMerge' => 'restart'])->addText('B');\n$row->addCell(1000)->addText('1');\n\n$row = $table->addRow();\n$row->addCell(1000, ['vMerge' => 'continue']);\n$row->addCell(1000, ['vMerge' => 'continue', 'gridSpan' => 2]);\n$row->addCell(1000)->addText('2');\n\n$row = $table->addRow();\n$row->addCell(1000, ['vMerge' => 'continue']);\n$row->addCell(1000)->addText('C');\n$row->addCell(1000)->addText('D');\n$row->addCell(1000)->addText('3');\n\n// 5. Nested table\n\n$section->addTextBreak(2);\n$section->addText('Nested table in a centered and 50% width table.', $header);\n\n$table = $section->addTable(['width' => 50 * 50, 'unit' => 'pct', 'alignment' => PhpOffice\\PhpWord\\SimpleType\\JcTable::CENTER]);\n$cell = $table->addRow()->addCell();\n$cell->addText('This cell contains nested table.');\n$innerCell = $cell->addTable(['alignment' => PhpOffice\\PhpWord\\SimpleType\\JcTable::CENTER])->addRow()->addCell();\n$innerCell->addText('Inside nested table');\n\n// 6. Table with floating position\n\n$section->addTextBreak(2);\n$section->addText('Table with floating positioning.', $header);\n\n$table = $section->addTable(['borderSize' => 6, 'borderColor' => '999999', 'position' => ['vertAnchor' => TablePosition::VANCHOR_TEXT, 'bottomFromText' => Converter::cmToTwip(1)]]);\n$cell = $table->addRow()->addCell();\n$cell->addText('This is a single cell.');\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_10_EastAsianFontStyle.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// New Word Document\necho date('H:i:s'), ' Create new PhpWord object', EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n$section = $phpWord->addSection();\n$header = ['size' => 16, 'bold' => true];\n//1.Use EastAisa FontStyle\n$section->addText('中文楷体样式测试', ['name' => '楷体', 'size' => 16, 'color' => '1B2232', 'lang' => ['latin' => 'en-US', 'eastAsia' => 'zh-CN']]);\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_11_ReadWord2007.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// Read contents\n$name = basename(__FILE__, '.php');\n$source = __DIR__ . \"/resources/{$name}.docx\";\n\necho date('H:i:s'), \" Reading contents from `{$source}`\", EOL;\n$phpWord = PhpOffice\\PhpWord\\IOFactory::load($source);\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_11_ReadWord97.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// Read contents\n$name = basename(__FILE__, '.php');\n$source = __DIR__ . \"/resources/{$name}.doc\";\necho date('H:i:s'), \" Reading contents from `{$source}`\", EOL;\n$phpWord = PhpOffice\\PhpWord\\IOFactory::load($source, 'MsDoc');\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_12_HeaderFooter.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// New Word document\necho date('H:i:s'), ' Create new PhpWord object', EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n\n// New portrait section\n$section = $phpWord->addSection();\n\n// Add first page header\n$header = $section->addHeader();\n$header->firstPage();\n$table = $header->addTable();\n$table->addRow();\n$cell = $table->addCell(4500);\n$textrun = $cell->addTextRun();\n$textrun->addText('This is the header with ');\n$textrun->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub');\n$table->addCell(4500)->addImage(__DIR__ . '/resources/PhpWord.png', ['width' => 80, 'height' => 80, 'alignment' => PhpOffice\\PhpWord\\SimpleType\\Jc::END]);\n\n// Add header for all other pages\n$subsequent = $section->addHeader();\n$subsequent->addText('Subsequent pages in Section 1 will Have this!');\n$subsequent->addImage(__DIR__ . '/resources/_mars.jpg', ['width' => 80, 'height' => 80]);\n\n// Add footer\n$footer = $section->addFooter();\n$footer->addPreserveText('Page {PAGE} of {NUMPAGES}.', null, ['alignment' => PhpOffice\\PhpWord\\SimpleType\\Jc::CENTER]);\n$footer->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub');\n\n// Write some text\n$section->addTextBreak();\n$section->addText('Some text...');\n\n// Create a second page\n$section->addPageBreak();\n\n// Write some text\n$section->addTextBreak();\n$section->addText('Some text...');\n\n// Create a third page\n$section->addPageBreak();\n\n// Write some text\n$section->addTextBreak();\n$section->addText('Some text...');\n\n// New portrait section\n$section2 = $phpWord->addSection();\n\n$sec2Header = $section2->addHeader();\n$sec2Header->addText('All pages in Section 2 will Have this!');\n\n// Write some text\n$section2->addTextBreak();\n$section2->addText('Some text...');\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_13_Images.php",
    "content": "<?php\n\nuse PhpOffice\\PhpWord\\Element\\Section;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Shared\\Converter;\n\ninclude_once 'Sample_Header.php';\n\n// New Word document\necho date('H:i:s'), ' Create new PhpWord object', EOL;\n$phpWord = new PhpWord();\n\n// Begin code\n$section = $phpWord->addSection();\n$section->addText('Local image without any styles:');\n$section->addImage(__DIR__ . '/resources/_mars.jpg');\n\nprintSeparator($section);\n$section->addText('Local image with styles:');\n$section->addImage(__DIR__ . '/resources/_earth.jpg', ['width' => 210, 'height' => 210, 'alignment' => PhpOffice\\PhpWord\\SimpleType\\Jc::CENTER]);\n\n// Remote image\nprintSeparator($section);\n$source = 'http://php.net/images/logos/php-med-trans-light.gif';\n$section->addText(\"Remote image from: {$source}\");\n$section->addImage($source);\n\n// Image from string\nprintSeparator($section);\n$source = __DIR__ . '/resources/_mars.jpg';\n$fileContent = file_get_contents($source);\n$section->addText('Image from string');\n$section->addImage($fileContent);\n\n//Wrapping style\nprintSeparator($section);\n$text = str_repeat('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. ', 2);\n$wrappingStyles = ['inline', 'behind', 'infront', 'square', 'tight'];\nforeach ($wrappingStyles as $wrappingStyle) {\n    $section->addText(\"Wrapping style {$wrappingStyle}\");\n    $section->addImage(\n        __DIR__ . '/resources/_earth.jpg',\n        [\n            'positioning' => 'relative',\n            'marginTop' => -1,\n            'marginLeft' => 1,\n            'width' => 80,\n            'height' => 80,\n            'wrappingStyle' => $wrappingStyle,\n            'wrapDistanceRight' => Converter::cmToPoint(1),\n            'wrapDistanceBottom' => Converter::cmToPoint(1),\n        ]\n    );\n    $section->addText($text);\n    printSeparator($section);\n}\n\n//Absolute positioning\n$section->addText('Absolute positioning: see top right corner of page');\n$section->addImage(\n    __DIR__ . '/resources/_mars.jpg',\n    [\n        'width' => Converter::cmToPixel(3),\n        'height' => Converter::cmToPixel(3),\n        'positioning' => PhpOffice\\PhpWord\\Style\\Image::POSITION_ABSOLUTE,\n        'posHorizontal' => PhpOffice\\PhpWord\\Style\\Image::POSITION_HORIZONTAL_RIGHT,\n        'posHorizontalRel' => PhpOffice\\PhpWord\\Style\\Image::POSITION_RELATIVE_TO_PAGE,\n        'posVerticalRel' => PhpOffice\\PhpWord\\Style\\Image::POSITION_RELATIVE_TO_PAGE,\n        'marginLeft' => Converter::cmToPixel(15.5),\n        'marginTop' => Converter::cmToPixel(1.55),\n    ]\n);\n\n//Relative positioning\nprintSeparator($section);\n$section->addText('Relative positioning: Horizontal position center relative to column,');\n$section->addText('Vertical position top relative to line');\n$section->addImage(\n    __DIR__ . '/resources/_mars.jpg',\n    [\n        'width' => Converter::cmToPixel(3),\n        'height' => Converter::cmToPixel(3),\n        'positioning' => PhpOffice\\PhpWord\\Style\\Image::POSITION_RELATIVE,\n        'posHorizontal' => PhpOffice\\PhpWord\\Style\\Image::POSITION_HORIZONTAL_CENTER,\n        'posHorizontalRel' => PhpOffice\\PhpWord\\Style\\Image::POSITION_RELATIVE_TO_COLUMN,\n        'posVertical' => PhpOffice\\PhpWord\\Style\\Image::POSITION_VERTICAL_TOP,\n        'posVerticalRel' => PhpOffice\\PhpWord\\Style\\Image::POSITION_RELATIVE_TO_LINE,\n    ]\n);\n\nfunction printSeparator(Section $section): void\n{\n    $section->addTextBreak();\n    $lineStyle = ['weight' => 0.2, 'width' => 150, 'height' => 0, 'align' => 'center'];\n    $section->addLine($lineStyle);\n    $section->addTextBreak(2);\n}\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_14_ListItem.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// New Word document\necho date('H:i:s'), ' Create new PhpWord object', EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n\n// Define styles\n$fontStyleName = 'myOwnStyle';\n$phpWord->addFontStyle($fontStyleName, ['color' => 'FF0000']);\n\n$paragraphStyleName = 'P-Style';\n$phpWord->addParagraphStyle($paragraphStyleName, ['spaceAfter' => 95]);\n\n$multilevelNumberingStyleName = 'multilevel';\n$phpWord->addNumberingStyle(\n    $multilevelNumberingStyleName,\n    [\n        'type' => 'multilevel',\n        'levels' => [\n            ['format' => 'decimal', 'text' => '%1.', 'left' => 360, 'hanging' => 360, 'tabPos' => 360],\n            ['format' => 'upperLetter', 'text' => '%2.', 'left' => 720, 'hanging' => 360, 'tabPos' => 720],\n        ],\n    ]\n);\n\n$predefinedMultilevelStyle = ['listType' => PhpOffice\\PhpWord\\Style\\ListItem::TYPE_NUMBER_NESTED];\n\n// New section\n$section = $phpWord->addSection();\n\n// Lists\n$section->addText('Multilevel list.');\n$section->addListItem('List Item I', 0, null, $multilevelNumberingStyleName);\n$section->addListItem('List Item I.a', 1, null, $multilevelNumberingStyleName);\n$section->addListItem('List Item I.b', 1, null, $multilevelNumberingStyleName);\n$section->addListItem('List Item II', 0, null, $multilevelNumberingStyleName);\n$section->addListItem('List Item II.a', 1, null, $multilevelNumberingStyleName);\n$section->addListItem('List Item III', 0, null, $multilevelNumberingStyleName);\n$section->addTextBreak(2);\n\n$section->addText('Basic simple bulleted list.');\n$section->addListItem('List Item 1');\n$section->addListItem('List Item 2');\n$section->addListItem('List Item 3');\n$section->addTextBreak(2);\n\n$section->addText('Continue from multilevel list above.');\n$section->addListItem('List Item IV', 0, null, $multilevelNumberingStyleName);\n$section->addListItem('List Item IV.a', 1, null, $multilevelNumberingStyleName);\n$section->addTextBreak(2);\n\n$section->addText('Multilevel predefined list.');\n$section->addListItem('List Item 1', 0, $fontStyleName, $predefinedMultilevelStyle, $paragraphStyleName);\n$section->addListItem('List Item 2', 0, $fontStyleName, $predefinedMultilevelStyle, $paragraphStyleName);\n$section->addListItem('List Item 3', 1, $fontStyleName, $predefinedMultilevelStyle, $paragraphStyleName);\n$section->addListItem('List Item 4', 1, $fontStyleName, $predefinedMultilevelStyle, $paragraphStyleName);\n$section->addListItem('List Item 5', 2, $fontStyleName, $predefinedMultilevelStyle, $paragraphStyleName);\n$section->addListItem('List Item 6', 1, $fontStyleName, $predefinedMultilevelStyle, $paragraphStyleName);\n$section->addListItem('List Item 7', 0, $fontStyleName, $predefinedMultilevelStyle, $paragraphStyleName);\n$section->addTextBreak(2);\n\n$section->addText('List with inline formatting.');\n$listItemRun = $section->addListItemRun();\n$listItemRun->addText('List item 1');\n$listItemRun->addText(' in bold', ['bold' => true]);\n$listItemRun = $section->addListItemRun(1, $predefinedMultilevelStyle, $paragraphStyleName);\n$listItemRun->addText('List item 2');\n$listItemRun->addText(' in italic', ['italic' => true]);\n$footnote = $listItemRun->addFootnote();\n$footnote->addText('this is a footnote on a list item');\n$listItemRun = $section->addListItemRun();\n$listItemRun->addText('List item 3');\n$listItemRun->addText(' underlined', ['underline' => 'dash']);\n$section->addTextBreak(2);\n\n// Numbered heading\n$headingNumberingStyleName = 'headingNumbering';\n$phpWord->addNumberingStyle(\n    $headingNumberingStyleName,\n    ['type' => 'multilevel',\n        'levels' => [\n            ['pStyle' => 'Heading1', 'format' => 'decimal', 'text' => '%1'],\n            ['pStyle' => 'Heading2', 'format' => 'decimal', 'text' => '%1.%2'],\n            ['pStyle' => 'Heading3', 'format' => 'decimal', 'text' => '%1.%2.%3'],\n        ],\n    ]\n);\n$phpWord->addTitleStyle(1, ['size' => 16], ['numStyle' => $headingNumberingStyleName, 'numLevel' => 0]);\n$phpWord->addTitleStyle(2, ['size' => 14], ['numStyle' => $headingNumberingStyleName, 'numLevel' => 1]);\n$phpWord->addTitleStyle(3, ['size' => 12], ['numStyle' => $headingNumberingStyleName, 'numLevel' => 2]);\n\n$section->addTitle('Heading 1', 1);\n$section->addTitle('Heading 2', 2);\n$section->addTitle('Heading 3', 3);\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_15_Link.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// New Word document\necho date('H:i:s'), ' Create new PhpWord object', EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n\n// Define styles\n$linkFontStyleName = 'myOwnLinStyle';\n$phpWord->addLinkStyle($linkFontStyleName, ['bold' => true, 'color' => '808000']);\n\n// New section\n$section = $phpWord->addSection();\n\n// Add hyperlink elements\n$section->addLink(\n    'https://github.com/PHPOffice/PHPWord',\n    'PHPWord on GitHub',\n    ['color' => '0000FF', 'underline' => PhpOffice\\PhpWord\\Style\\Font::UNDERLINE_SINGLE]\n);\n$section->addTextBreak(2);\n$section->addLink('http://www.bing.com', null, $linkFontStyleName);\n$section->addLink('http://www.yahoo.com', null, $linkFontStyleName);\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_16_Object.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// New Word document\necho date('H:i:s'), ' Create new PhpWord object', EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n\n// Begin code\n$section = $phpWord->addSection();\n$section->addText('You can open this OLE object by double clicking on the icon:');\n$section->addTextBreak(2);\n$section->addOLEObject(__DIR__ . '/resources/_sheet.xls');\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_17_TitleTOC.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// New Word document\necho date('H:i:s'), ' Create new PhpWord object', EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n$phpWord->getSettings()->setUpdateFields(true);\n\n// New section\n$section = $phpWord->addSection();\n\n// Define styles\n$fontStyle12 = ['spaceAfter' => 60, 'size' => 12];\n$fontStyle10 = ['size' => 10];\n$phpWord->addTitleStyle(null, ['size' => 22, 'bold' => true]);\n$phpWord->addTitleStyle(1, ['size' => 20, 'color' => '333333', 'bold' => true]);\n$phpWord->addTitleStyle(2, ['size' => 16, 'color' => '666666']);\n$phpWord->addTitleStyle(3, ['size' => 14, 'italic' => true]);\n$phpWord->addTitleStyle(4, ['size' => 12]);\n\n// Add text elements\n$section->addTitle('Table of contents 1', 0);\n$section->addTextBreak(2);\n\n// Add TOC #1\n$toc = $section->addTOC($fontStyle12);\n$section->addTextBreak(2);\n\n// Filler\n$section->addText('Text between TOC');\n$section->addTextBreak(2);\n\n// Add TOC #1\n$section->addText('Table of contents 2');\n$section->addTextBreak(2);\n$toc2 = $section->addTOC($fontStyle10);\n$toc2->setMinDepth(2);\n$toc2->setMaxDepth(3);\n\n// Add Titles\n$section->addPageBreak();\n$section->addTitle('Foo n Bar', 1);\n$section->addText('Some text...');\n$section->addTextBreak(2);\n\n$section->addTitle('I am a Subtitle of Title 1', 2);\n$section->addTextBreak(2);\n$section->addText('Some more text...');\n$section->addTextBreak(2);\n\n$section->addTitle('Another Title (Title 2)', 1);\n$section->addText('Some text...');\n$section->addPageBreak();\n$section->addTitle('I am Title 3', 1);\n$section->addText('And more text...');\n$section->addTextBreak(2);\n$section->addTitle('I am a Subtitle of Title 3', 2);\n$section->addText('Again and again, more text...');\n$section->addTitle('Subtitle 3.1.1', 3);\n$section->addText('Text');\n$section->addTitle('Subtitle 3.1.1.1', 4);\n$section->addText('Text');\n$section->addTitle('Subtitle 3.1.1.2', 4);\n$section->addText('Text');\n$section->addTitle('Subtitle 3.1.2', 3);\n$section->addText('Text');\n\necho date('H:i:s'), ' Note: Please refresh TOC manually.', EOL;\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_18_Watermark.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// New Word document\necho date('H:i:s'), ' Create new PhpWord object', EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n\n// Begin code\n$section = $phpWord->addSection();\n$header = $section->addHeader();\n$header->addWatermark(__DIR__ . '/resources/_earth.jpg', ['marginTop' => 200, 'marginLeft' => 55]);\n$section->addText('The header reference to the current section includes a watermark image.');\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_19_TextBreak.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// New Word document\necho date('H:i:s'), ' Create new PhpWord object', EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n\n// Define styles\n$fontStyle24 = ['size' => 24];\n\n$paragraphStyle24 = ['spacing' => 240, 'size' => 24];\n\n$fontStyleName = 'fontStyle';\n$phpWord->addFontStyle($fontStyleName, ['size' => 9]);\n\n$paragraphStyleName = 'paragraphStyle';\n$phpWord->addParagraphStyle($paragraphStyleName, ['spacing' => 480]);\n\n// New section\n$section = $phpWord->addSection();\n\n$section->addText('Text break with no style:');\n$section->addTextBreak();\n$section->addText('Text break with defined font style:');\n$section->addTextBreak(1, $fontStyleName);\n$section->addText('Text break with defined paragraph style:');\n$section->addTextBreak(1, null, $paragraphStyleName);\n$section->addText('Text break with inline font style:');\n$section->addTextBreak(1, $fontStyle24);\n$section->addText('Text break with inline paragraph style:');\n$section->addTextBreak(1, null, $paragraphStyle24);\n$section->addText('Done.');\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_20_BGColor.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// New Word document\necho date('H:i:s'), ' Create new PhpWord object', EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n\n// New section\n$section = $phpWord->addSection();\n\n$section->addText(\n    'This is some text highlighted using fgColor (limited to 15 colors)',\n    ['fgColor' => PhpOffice\\PhpWord\\Style\\Font::FGCOLOR_YELLOW]\n);\n$section->addText('This one uses bgColor and is using hex value (0xfbbb10)', ['bgColor' => 'fbbb10']);\n$section->addText('Compatible with font colors', ['color' => '0000ff', 'bgColor' => 'fbbb10']);\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_21_TableRowRules.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// New Word document\necho date('H:i:s'), ' Create new PhpWord object', EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n\n// New section\n$section = $phpWord->addSection();\n\n$section->addText('By default, when you insert an image, it adds a textbreak after its content.');\n$section->addText('If we want a simple border around an image, we wrap the image inside a table->row->cell');\n$section->addText(\n    'On the image with the red border, even if we set the row height to the height of the image, '\n        . 'the textbreak is still there:'\n);\n\n$table1 = $section->addTable(['cellMargin' => 0, 'cellMarginRight' => 0, 'cellMarginBottom' => 0, 'cellMarginLeft' => 0]);\n$table1->addRow(3750);\n$cell1 = $table1->addCell(null, ['valign' => 'top', 'borderSize' => 30, 'borderColor' => 'ff0000']);\n$cell1->addImage(__DIR__ . '/resources/_earth.jpg', ['width' => 250, 'height' => 250, 'alignment' => PhpOffice\\PhpWord\\SimpleType\\Jc::CENTER]);\n\n$section->addTextBreak();\n$section->addText(\"But if we set the rowStyle 'exactHeight' to true, the real row height is used, removing the textbreak:\");\n\n$table2 = $section->addTable(\n    [\n        'cellMargin' => 0,\n        'cellMarginRight' => 0,\n        'cellMarginBottom' => 0,\n        'cellMarginLeft' => 0,\n    ]\n);\n$table2->addRow(3750, ['exactHeight' => true]);\n$cell2 = $table2->addCell(null, ['valign' => 'top', 'borderSize' => 30, 'borderColor' => '00ff00']);\n$cell2->addImage(__DIR__ . '/resources/_earth.jpg', ['width' => 250, 'height' => 250, 'alignment' => PhpOffice\\PhpWord\\SimpleType\\Jc::CENTER]);\n\n$section->addTextBreak();\n$section->addText('In this example, image is 250px height. Rows are calculated in twips, and 1px = 15twips.');\n$section->addText('So: $' . \"table2->addRow(3750, array('exactHeight'=>true));\");\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_22_CheckBox.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// New Word document\necho date('H:i:s'), ' Create new PhpWord object', EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n\n// New section\n$section = $phpWord->addSection();\n\n$section->addText('Check box in section');\n$section->addCheckBox('chkBox1', 'Checkbox 1');\n$section->addText('Check box in table cell');\n$table = $section->addTable();\n$table->addRow();\n$cell = $table->addCell();\n$cell->addCheckBox('chkBox2', 'Checkbox 2');\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_23_TemplateBlock.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// Template processor instance creation\necho date('H:i:s') , ' Creating new TemplateProcessor instance...' , EOL;\n$templateProcessor = new PhpOffice\\PhpWord\\TemplateProcessor(__DIR__ . '/resources/Sample_23_TemplateBlock.docx');\n\n// Will clone everything between ${tag} and ${/tag}, the number of times. By default, 1.\n$templateProcessor->cloneBlock('CLONEME', 3);\n\n// Everything between ${tag} and ${/tag}, will be deleted/erased.\n$templateProcessor->deleteBlock('DELETEME');\n\necho date('H:i:s'), ' Saving the result document...', EOL;\n$templateProcessor->saveAs(__DIR__ . '/results/Sample_23_TemplateBlock.docx');\n\necho getEndingNotes(['Word2007' => 'docx'], __DIR__ . '/results/Sample_23_TemplateBlock.docx');\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_24_ReadODText.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// Read contents\n$name = basename(__FILE__, '.php');\n$source = __DIR__ . \"/resources/{$name}.odt\";\n\necho date('H:i:s'), \" Reading contents from `{$source}`\", EOL;\n$phpWord = PhpOffice\\PhpWord\\IOFactory::load($source, 'ODText');\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_25_TextBox.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// New Word Document\necho date('H:i:s'), ' Create new PhpWord object', EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n\n// New section\n$section = $phpWord->addSection();\n\n// In section\n$textbox = $section->addTextBox(\n    [\n        'alignment' => PhpOffice\\PhpWord\\SimpleType\\Jc::CENTER,\n        'width' => 400,\n        'height' => 150,\n        'borderSize' => 1,\n        'borderColor' => '#FF0000',\n    ]\n);\n$textbox->addText('Text box content in section.');\n$textbox->addText('Another line.');\n$cell = $textbox->addTable()->addRow()->addCell();\n$cell->addText('Table inside textbox');\n\n// Inside table\n$section->addTextBreak(2);\n$cell = $section->addTable()->addRow()->addCell(300);\n$textbox = $cell->addTextBox(['borderSize' => 1, 'borderColor' => '#0000FF', 'innerMargin' => 100]);\n$textbox->addText('Textbox inside table');\n\n// Inside header with textrun\n$header = $section->addHeader();\n$textbox = $header->addTextBox(['width' => 600, 'borderSize' => 1, 'borderColor' => '#00FF00']);\n$textrun = $textbox->addTextRun();\n$textrun->addText('TextBox in header. TextBox can contain a TextRun ');\n$textrun->addText('with bold text', ['bold' => true]);\n$textrun->addText(', ');\n$textrun->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub');\n$textrun->addText(', and image ');\n$textrun->addImage(__DIR__ . '/resources/_earth.jpg', ['width' => 18, 'height' => 18]);\n$textrun->addText('.');\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_26_Html.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// New Word Document\necho date('H:i:s') , ' Create new PhpWord object' , EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n$phpWord->addParagraphStyle('Heading2', ['alignment' => 'center']);\n\n$section = $phpWord->addSection();\n$html = '<h1>Adding element via HTML</h1>';\n$html .= '<p>Some well-formed HTML snippet needs to be used</p>';\n$html .= '<p>With for example <strong>some<sup>1</sup> <em>inline</em> formatting</strong><sub>1</sub></p>';\n\n$html .= '<p>A link to <a href=\"https://phpoffice.github.io/PHPWord/\" style=\"text-decoration: underline\">Read the docs</a></p>';\n\n$html .= '<p lang=\"he-IL\" style=\"text-align: right; direction: rtl\">היי, זה פסקה מימין לשמאל</p>';\n\n$html .= '<p style=\"margin-top: 240pt;\">Unordered (bulleted) list:</p>';\n$html .= '<ul><li>Item 1</li><li>Item 2</li><ul><li>Item 2.1</li><li>Item 2.1</li></ul></ul>';\n\n$html .= '<p style=\"margin-top: 240pt;\">1.5 line height with first line text indent:</p>';\n$html .= '<p style=\"text-align: justify; text-indent: 70.9pt; line-height: 150%;\">Lorem ipsum dolor sit amet, <strong>consectetur adipiscing elit</strong>, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>';\n\n$html .= '<h2 style=\"align: center\">centered title</h2>';\n\n$html .= '<p style=\"margin-top: 240pt;\">Ordered (numbered) list:</p>';\n$html .= '<ol>\n                <li><p style=\"font-weight: bold;\">List 1 item 1</p></li>\n                <li>List 1 item 2</li>\n                <ol>\n                    <li>sub list 1</li>\n                    <li>sub list 2</li>\n                </ol>\n                <li>List 1 item 3</li>\n            </ol>\n            <p style=\"margin-top: 15px;\">A second list, numbering should restart</p>\n            <ol>\n                <li>List 2 item 1</li>\n                <li>List 2 item 2</li>\n                <li>\n                    <ol>\n                        <li>sub list 1</li>\n                        <li>sub list 2</li>\n                    </ol>\n                </li>\n                <li>List 2 item 3</li>\n                <ol>\n                    <li>sub list 1, restarts with a</li>\n                    <li>sub list 2</li>\n                </ol>\n            </ol>';\n\n$html .= '<p style=\"margin-top: 240pt;\">List with formatted content:</p>';\n$html .= '<ul>\n                <li>\n                    <span style=\"font-family: arial,helvetica,sans-serif;\">\n                        <span style=\"font-size: 16px;\">big list item1</span>\n                    </span>\n                </li>\n                <li>\n                    <span style=\"font-family: arial,helvetica,sans-serif;\">\n                        <span style=\"font-size: 10px; font-weight: bold;\">list item2 in bold</span>\n                    </span>\n                </li>\n            </ul>';\n\n$html .= '<p style=\"margin-top: 240pt;\">A table with formatting:</p>';\n$html .= '<table align=\"center\" style=\"width: 50%; border: 6px #0000FF double;\">\n                <thead>\n                    <tr style=\"background-color: #FF0000; text-align: center; color: #FFFFFF; font-weight: bold; \">\n                        <th style=\"width: 50pt\">header a</th>\n                        <th style=\"width: 50\">header          b</th>\n                        <th style=\"background-color: #FFFF00; border-width: 12px\"><span style=\"background-color: #00FF00;\">header c</span></th>\n                    </tr>\n                </thead>\n                <tbody>\n                    <tr><td style=\"border-style: dotted; border-color: #FF0000\">1</td><td colspan=\"2\">2</td></tr>\n                    <tr><td>This is <b>bold</b> text</td><td></td><td>6</td></tr>\n                </tbody>\n            </table>';\n\n$html .= '<p style=\"margin-top: 240pt;\">Table inside another table:</p>';\n$html .= '<table align=\"center\" style=\"width: 80%; border: 6px #0000FF double;\">\n    <tr><td>\n        <table style=\"width: 100%; border: 4px #FF0000 dotted;\">\n            <tr><td>column 1</td><td>column 2</td></tr>\n        </table>\n    </td></tr>\n    <tr><td style=\"text-align: center;\">Cell in parent table</td></tr>\n</table>';\n\n$html .= '<p style=\"margin-top: 240pt;\">The text below is not visible, click on show/hide to reveil it:</p>';\n$html .= '<p style=\"display: none\">This is hidden text</p>';\n\nPhpOffice\\PhpWord\\Shared\\Html::addHtml($section, $html, false, false);\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_27_Field.php",
    "content": "<?php\n\nuse PhpOffice\\PhpWord\\Element\\TextRun;\n\ninclude_once 'Sample_Header.php';\n\n// New Word document\necho date('H:i:s'), ' Create new PhpWord object', EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\nPhpOffice\\PhpWord\\Style::addTitleStyle(1, ['size' => 14]);\n\n// New section\n$section = $phpWord->addSection();\n$section->addTitle('This page demos fields');\n\n// Add Field elements\n// See Element/Field.php for all options\n$section->addText('Date field:');\n$section->addField('DATE', ['dateformat' => 'dddd d MMMM yyyy H:mm:ss'], ['PreserveFormat']);\n\n$section->addText('Style Ref field:');\n$section->addField('STYLEREF', ['StyleIdentifier' => 'Heading 1']);\n\n$section->addText('Page field:');\n$section->addField('PAGE', ['format' => 'Arabic']);\n\n$section->addText('Number of pages field:');\n$section->addField('NUMPAGES', ['numformat' => '0,00', 'format' => 'Arabic'], ['PreserveFormat']);\n\n$section->addText('Filename field:');\n$section->addField('FILENAME', ['format' => 'Upper'], ['Path', 'PreserveFormat']);\n$section->addTextBreak();\n\n$textrun = $section->addTextRun();\n$textrun->addText('An index field is ');\n$textrun->addField('XE', [], ['Italic'], 'My first index');\n$textrun->addText('here:');\n\n$indexEntryText = new TextRun();\n$indexEntryText->addText('My ');\n$indexEntryText->addText('bold index', ['bold' => true]);\n$indexEntryText->addText(' entry');\n\n$textrun = $section->addTextRun();\n$textrun->addText('A complex index field is ');\n$textrun->addField('XE', [], ['Bold'], $indexEntryText);\n$textrun->addText('here:');\n\n$section->addText('The actual index:');\n$section->addField('INDEX', [], ['\\\\e \"\t\"'], 'right click to update the index');\n\n$textrun = $section->addTextRun(['alignment' => PhpOffice\\PhpWord\\SimpleType\\Jc::CENTER]);\n$textrun->addText('This is the date of lunar calendar ');\n$textrun->addField('DATE', ['dateformat' => 'd-M-yyyy H:mm:ss'], ['PreserveFormat', 'LunarCalendar']);\n$textrun->addText(' written in a textrun.');\n$section->addTextBreak();\n\n$macroText = new TextRun();\n$macroText->addText('Double click', ['bold' => true]);\n$macroText->addText(' to ');\n$macroText->addText('zoom to 100%', ['italic' => true]);\n\n$section->addText('A macro button with styled text:');\n$section->addField('MACROBUTTON', ['macroname' => 'Zoom100'], [], $macroText);\n$section->addTextBreak();\n\n$section->addText('A macro button with simple text:');\n$section->addField('MACROBUTTON', ['macroname' => 'Zoom100'], [], 'double click to zoom');\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_28_ReadRTF.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// Read contents\n$name = basename(__FILE__, '.php');\n$source = __DIR__ . \"/resources/{$name}.rtf\";\n\necho date('H:i:s'), \" Reading contents from `{$source}`\", EOL;\n$phpWord = PhpOffice\\PhpWord\\IOFactory::load($source, 'RTF');\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_29_Line.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// New Word document\necho date('H:i:s'), ' Create new PhpWord object', EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n\n// New section\n$section = $phpWord->addSection();\n\n// Add Line elements\n// See Element/Line.php for all options\n$section->addText('Horizontal Line (Inline style):');\n$section->addLine(\n    [\n        'width' => PhpOffice\\PhpWord\\Shared\\Converter::cmToPixel(4),\n        'height' => PhpOffice\\PhpWord\\Shared\\Converter::cmToPixel(0),\n        'positioning' => 'absolute',\n    ]\n);\n$section->addText('Vertical Line (Inline style):');\n$section->addLine(\n    [\n        'width' => PhpOffice\\PhpWord\\Shared\\Converter::cmToPixel(0),\n        'height' => PhpOffice\\PhpWord\\Shared\\Converter::cmToPixel(1),\n        'positioning' => 'absolute',\n    ]\n);\n// Two text break\n$section->addTextBreak(1);\n\n$section->addText('Positioned Line (red):');\n$section->addLine(\n    [\n        'width' => PhpOffice\\PhpWord\\Shared\\Converter::cmToPixel(4),\n        'height' => PhpOffice\\PhpWord\\Shared\\Converter::cmToPixel(1),\n        'positioning' => 'absolute',\n        'posHorizontalRel' => 'page',\n        'posVerticalRel' => 'page',\n        'marginLeft' => PhpOffice\\PhpWord\\Shared\\Converter::cmToPixel(10),\n        'marginTop' => PhpOffice\\PhpWord\\Shared\\Converter::cmToPixel(8),\n        'wrappingStyle' => PhpOffice\\PhpWord\\Style\\Image::WRAPPING_STYLE_SQUARE,\n        'color' => 'red',\n    ]\n);\n\n$section->addText('Horizontal Formatted Line');\n$section->addLine(\n    [\n        'width' => PhpOffice\\PhpWord\\Shared\\Converter::cmToPixel(15),\n        'height' => PhpOffice\\PhpWord\\Shared\\Converter::cmToPixel(0),\n        'positioning' => 'absolute',\n        'beginArrow' => PhpOffice\\PhpWord\\Style\\Line::ARROW_STYLE_BLOCK,\n        'endArrow' => PhpOffice\\PhpWord\\Style\\Line::ARROW_STYLE_OVAL,\n        'dash' => PhpOffice\\PhpWord\\Style\\Line::DASH_STYLE_LONG_DASH_DOT_DOT,\n        'weight' => 10,\n    ]\n);\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_30_ReadHTML.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// Read contents\n$name = basename(__FILE__, '.php');\n$source = realpath(__DIR__ . \"/resources/{$name}.html\");\n\necho date('H:i:s'), \" Reading contents from `{$source}`\", EOL;\n$phpWord = PhpOffice\\PhpWord\\IOFactory::load($source, 'HTML');\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_31_Shape.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// New Word document\necho date('H:i:s'), ' Create new PhpWord object', EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n\n// New section\n$section = $phpWord->addSection();\n\n// Define styles\n$phpWord->addTitleStyle(1, ['size' => 14, 'bold' => true]);\n\n// Arc\n$section->addTitle('Arc', 1);\n$section->addShape(\n    'arc',\n    [\n        'points' => '-90 20',\n        'frame' => ['width' => 120, 'height' => 120],\n        'outline' => ['color' => '#333333', 'weight' => 2, 'startArrow' => 'oval', 'endArrow' => 'open'],\n    ]\n);\n\n// Curve\n$section->addTitle('Curve', 1);\n$section->addShape(\n    'curve',\n    [\n        'points' => '1,100 200,1 1,50 200,50',\n        'connector' => 'elbow',\n        'outline' => [\n            'color' => '#66cc00',\n            'weight' => 2,\n            'dash' => 'dash',\n            'startArrow' => 'diamond',\n            'endArrow' => 'block',\n        ],\n    ]\n);\n\n// Line\n$section->addTitle('Line', 1);\n$section->addShape(\n    'line',\n    [\n        'points' => '1,1 150,30',\n        'outline' => [\n            'color' => '#cc00ff',\n            'line' => 'thickThin',\n            'weight' => 3,\n            'startArrow' => 'oval',\n            'endArrow' => 'classic',\n        ],\n    ]\n);\n\n// Polyline\n$section->addTitle('Polyline', 1);\n$section->addShape(\n    'polyline',\n    [\n        'points' => '1,30 20,10 55,20 75,10 100,40 115,50, 120,15 200,50',\n        'outline' => ['color' => '#cc6666', 'weight' => 2, 'startArrow' => 'none', 'endArrow' => 'classic'],\n    ]\n);\n\n// Rectangle\n$section->addTitle('Rectangle', 1);\n$section->addShape(\n    'rect',\n    [\n        'roundness' => 0.2,\n        'frame' => ['width' => 100, 'height' => 100, 'left' => 1, 'top' => 1],\n        'fill' => ['color' => '#FFCC33'],\n        'outline' => ['color' => '#990000', 'weight' => 1],\n        'shadow' => [],\n    ]\n);\n\n// Oval\n$section->addTitle('Oval', 1);\n$section->addShape(\n    'oval',\n    [\n        'frame' => ['width' => 100, 'height' => 70, 'left' => 1, 'top' => 1],\n        'fill' => ['color' => '#33CC99'],\n        'outline' => ['color' => '#333333', 'weight' => 2],\n        'extrusion' => [],\n    ]\n);\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_32_Chart.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\nuse PhpOffice\\PhpWord\\Shared\\Converter;\n\n// New Word document\necho date('H:i:s'), ' Create new PhpWord object', EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n\n// Define styles\n$phpWord->addTitleStyle(1, ['size' => 14, 'bold' => true], ['keepNext' => true, 'spaceBefore' => 240]);\n$phpWord->addTitleStyle(2, ['size' => 14, 'bold' => true], ['keepNext' => true, 'spaceBefore' => 240]);\n\n// 2D charts\n$section = $phpWord->addSection();\n$section->addTitle('2D charts', 1);\n$section = $phpWord->addSection(['colsNum' => 2, 'breakType' => 'continuous']);\n\n$chartTypes = ['pie', 'doughnut', 'bar', 'column', 'line', 'area', 'scatter', 'radar', 'stacked_bar', 'percent_stacked_bar', 'stacked_column', 'percent_stacked_column'];\n$twoSeries = ['bar', 'column', 'line', 'area', 'scatter', 'radar', 'stacked_bar', 'percent_stacked_bar', 'stacked_column', 'percent_stacked_column'];\n$threeSeries = ['bar', 'line'];\n$categories = ['A', 'B', 'C', 'D', 'E'];\n$series1 = [1, 3, 2, 5, 4];\n$series2 = [3, 1, 7, 2, 6];\n$series3 = [8, 3, 2, 5, 4];\n$showGridLines = false;\n$showAxisLabels = false;\n$showLegend = true;\n$legendPosition = 't';\n// r = right, l = left, t = top, b = bottom, tr = top right\n\nforeach ($chartTypes as $chartType) {\n    $section->addTitle(ucfirst($chartType), 2);\n    $chart = $section->addChart($chartType, $categories, $series1);\n    $chart->getStyle()->setWidth(Converter::inchToEmu(2.5))->setHeight(Converter::inchToEmu(2));\n    $chart->getStyle()->setShowGridX($showGridLines);\n    $chart->getStyle()->setShowGridY($showGridLines);\n    $chart->getStyle()->setShowAxisLabels($showAxisLabels);\n    $chart->getStyle()->setShowLegend($showLegend);\n    $chart->getStyle()->setLegendPosition($legendPosition);\n    if (in_array($chartType, $twoSeries)) {\n        $chart->addSeries($categories, $series2);\n    }\n    if (in_array($chartType, $threeSeries)) {\n        $chart->addSeries($categories, $series3);\n    }\n    $section->addTextBreak();\n}\n\n// 3D charts\n$section = $phpWord->addSection(['breakType' => 'continuous']);\n$section->addTitle('3D charts', 1);\n$section = $phpWord->addSection(['colsNum' => 2, 'breakType' => 'continuous']);\n\n$chartTypes = ['pie', 'bar', 'column', 'line', 'area'];\n$multiSeries = ['bar', 'column', 'line', 'area'];\n$style = [\n    'width' => Converter::cmToEmu(5),\n    'height' => Converter::cmToEmu(4),\n    '3d' => true,\n    'showAxisLabels' => $showAxisLabels,\n    'showGridX' => $showGridLines,\n    'showGridY' => $showGridLines,\n];\nforeach ($chartTypes as $chartType) {\n    $section->addTitle(ucfirst($chartType), 2);\n    $chart = $section->addChart($chartType, $categories, $series1, $style);\n    if (in_array($chartType, $multiSeries)) {\n        $chart->addSeries($categories, $series2);\n        $chart->addSeries($categories, $series3);\n    }\n    $section->addTextBreak();\n}\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_33_FormField.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// New Word document\necho date('H:i:s'), ' Create new PhpWord object', EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n$phpWord->getSettings()->getDocumentProtection()->setEditing('forms');\n\n// New section\n$section = $phpWord->addSection();\n\n$textrun = $section->addTextRun();\n$textrun->addText('Form fields can be added in a text run and can be in form of textinput ');\n$textrun->addFormField('textinput')->setName('MyTextBox');\n$textrun->addText(', checkbox ');\n$textrun->addFormField('checkbox')->setDefault(true);\n$textrun->addText(', or dropdown ');\n$textrun->addFormField('dropdown')->setEntries(['Choice 1', 'Choice 2', 'Choice 3']);\n$textrun->addText('. You have to set document protection to \"forms\" to enable dropdown.');\n\n$section->addText('They can also be added as a stand alone paragraph.');\n$section->addFormField('textinput')->setValue('Your name');\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_34_SDT.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// New Word document\necho date('H:i:s'), ' Create new PhpWord object', EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n\n// New section\n$section = $phpWord->addSection();\n\n$textrun = $section->addTextRun();\n$textrun->addText('Combobox: ');\n$textrun->addSDT('comboBox')->setListItems(['1' => 'Choice 1', '2' => 'Choice 2']);\n\n$textrun = $section->addTextRun();\n$textrun->addText('Date: ');\n$textrun->addSDT('date');\n$textrun->addTextBreak(1);\n$textrun->addText('Date with pre set value: ');\n$textrun->addSDT('date')->setValue('03/30/2017');\n$textrun->addTextBreak(1);\n$textrun->addText('Date with pre set value: ');\n$textrun->addSDT('date')->setValue('30.03.2017');\n\n$textrun = $section->addTextRun();\n$textrun->addText('Drop down list: ');\n$textrun->addSDT('dropDownList')->setListItems(['1' => 'Choice 1', '2' => 'Choice 2'])->setValue('Choice 1');\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_35_InternalLink.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// New Word document\necho date('H:i:s'), ' Create new PhpWord object', EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n\n$section = $phpWord->addSection();\n$section->addTitle('This is page 1', 1);\n$linkIsInternal = true;\n$section->addLink('MyBookmark', 'Take me to page 3', null, null, $linkIsInternal);\n$section->addPageBreak();\n$section->addTitle('This is page 2', 1);\n$section->addPageBreak();\n$section->addTitle('This is page 3', 1);\n$section->addBookmark('MyBookmark');\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_36_RTL.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\nuse PhpOffice\\PhpWord\\Settings;\n\n// New Word document\necho date('H:i:s'), ' Create new PhpWord object', EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n$phpWord->setDefaultFontName('DejaVu Sans'); // for good rendition of PDF\n$rendererName = Settings::PDF_RENDERER_MPDF;\n$rendererLibraryPath = $vendorDirPath . '/mpdf/mpdf';\nSettings::setPdfRenderer($rendererName, $rendererLibraryPath);\n\n// New section\n$section = $phpWord->addSection();\n\n$textrun = $section->addTextRun();\n$textrun->addText('This is a Left to Right paragraph.');\n\n$textrun = $section->addTextRun(['alignment' => PhpOffice\\PhpWord\\SimpleType\\Jc::END]);\n$textrun->addText('سلام این یک پاراگراف راست به چپ است', ['rtl' => true]);\n\n$section->addText('Table visually presented as RTL');\n$style = ['rtl' => true, 'size' => 12];\n$tableStyle = ['borderSize' => 6, 'borderColor' => '000000', 'width' => 5000, 'unit' => PhpOffice\\PhpWord\\SimpleType\\TblWidth::PERCENT, 'bidiVisual' => true];\n\n$table = $section->addTable($tableStyle);\n$cellHCentered = ['alignment' => PhpOffice\\PhpWord\\SimpleType\\Jc::CENTER];\n$cellHEnd = ['alignment' => PhpOffice\\PhpWord\\SimpleType\\Jc::END];\n$cellVCentered = ['valign' => PhpOffice\\PhpWord\\SimpleType\\VerticalJc::CENTER];\n\n//Vidually bidirectinal table\n$table->addRow();\n$cell = $table->addCell(1500, $cellVCentered);\n$textrun = $cell->addTextRun($cellHCentered);\n$textrun->addText('ردیف', $style);\n\n$cell = $table->addCell(2000);\n$textrun = $cell->addTextRun($cellHEnd);\n$textrun->addText('سوالات', $style);\n\n$cell = $table->addCell(1000, $cellVCentered);\n$textrun = $cell->addTextRun($cellHCentered);\n$textrun->addText('بارم', $style);\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_37_Comments.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// New Word Document\necho date('H:i:s') , ' Create new PhpWord object' , EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n\n// A comment\n$comment = new PhpOffice\\PhpWord\\Element\\Comment('Authors name', new DateTime(), 'my_initials');\n$comment->addText('Test', ['bold' => true]);\n$phpWord->addComment($comment);\n\n$section = $phpWord->addSection();\n\n$textrun = $section->addTextRun();\n$textrun->addText('This ');\n$text = $textrun->addText('is');\n$text->setCommentRangeStart($comment);\n$textrun->addText(' a test');\n\n$section->addTextBreak(2);\n\n// Let's create a comment that we will link to a start element and an end element\n$commentWithStartAndEnd = new PhpOffice\\PhpWord\\Element\\Comment('Foo Bar', new DateTime());\n$commentWithStartAndEnd->addText('A comment with a start and an end');\n$phpWord->addComment($commentWithStartAndEnd);\n\n$textrunWithEnd = $section->addTextRun();\n$textrunWithEnd->addText('This ');\n$textToStartOn = $textrunWithEnd->addText('is', ['bold' => true]);\n$textToStartOn->setCommentRangeStart($commentWithStartAndEnd);\n$textrunWithEnd->addText(' another', ['italic' => true]);\n$textToEndOn = $textrunWithEnd->addText(' test');\n$textToEndOn->setCommentRangeEnd($commentWithStartAndEnd);\n\n$section->addTextBreak(2);\n\n// Let's add a comment on an image\n$commentOnImage = new PhpOffice\\PhpWord\\Element\\Comment('Mr Smart', new DateTime());\n$imageComment = $commentOnImage->addTextRun();\n$imageComment->addText('Hey, Mars does look ');\n$imageComment->addText('red', ['color' => 'FF0000']);\n$phpWord->addComment($commentOnImage);\n$image = $section->addImage(__DIR__ . '/resources/_mars.jpg');\n$image->setCommentRangeStart($commentOnImage);\n\n$section->addTextBreak(2);\n\n// We can also do things the other way round, link the comment to the element\n$anotherText = $section->addText('another text');\n\n$comment1 = new PhpOffice\\PhpWord\\Element\\Comment('Authors name', new DateTime(), 'my_initials');\n$comment1->addText('Test', ['bold' => true]);\n$comment1->setStartElement($anotherText);\n$comment1->setEndElement($anotherText);\n$phpWord->addComment($comment1);\n\n// We can also do things the other way round, link the comment to the element\n$lastText = $section->addText('with a last text and two comments');\n\n$comment1 = new PhpOffice\\PhpWord\\Element\\Comment('Authors name', new DateTime(), 'my_initials');\n$comment1->addText('Comment 1', ['bold' => true]);\n$comment1->setStartElement($lastText);\n$comment1->setEndElement($lastText);\n$phpWord->addComment($comment1);\n\n$comment2 = new PhpOffice\\PhpWord\\Element\\Comment('Authors name', new DateTime(), 'my_initials');\n$comment2->addText('Comment 2', ['bold' => true]);\n$comment2->setStartElement($lastText);\n$comment2->setEndElement($lastText);\n$phpWord->addComment($comment2);\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_38_Protection.php",
    "content": "<?php\n\nuse PhpOffice\\PhpWord\\SimpleType\\DocProtect;\n\ninclude_once 'Sample_Header.php';\n\n// New Word Document\necho date('H:i:s') , ' Create new PhpWord object' , EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n\n$documentProtection = $phpWord->getSettings()->getDocumentProtection();\n$documentProtection->setEditing(DocProtect::READ_ONLY);\n$documentProtection->setPassword('myPassword');\n\n$section = $phpWord->addSection();\n$section->addText('this document is password protected');\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_39_TrackChanges.php",
    "content": "<?php\n\nuse PhpOffice\\PhpWord\\Element\\TrackChange;\n\ninclude_once 'Sample_Header.php';\n\n// New Word Document\necho date('H:i:s') , ' Create new PhpWord object' , EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n\n// New portrait section\n$section = $phpWord->addSection();\n$textRun = $section->addTextRun();\n\n$text = $textRun->addText('Hello World! Time to ');\n\n$text = $textRun->addText('wake ', ['bold' => true]);\n$text->setChangeInfo(TrackChange::INSERTED, 'Fred', time() - 1800);\n\n$text = $textRun->addText('up');\n$text->setTrackChange(new TrackChange(TrackChange::INSERTED, 'Fred'));\n\n$text = $textRun->addText('go to sleep');\n$text->setChangeInfo(TrackChange::DELETED, 'Barney', new DateTime('@' . (time() - 3600)));\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_40_TemplateSetComplexValue.php",
    "content": "<?php\n\nuse PhpOffice\\PhpWord\\Element\\Field;\nuse PhpOffice\\PhpWord\\Element\\Table;\nuse PhpOffice\\PhpWord\\Element\\TextRun;\nuse PhpOffice\\PhpWord\\SimpleType\\TblWidth;\n\ninclude_once 'Sample_Header.php';\n\n// Template processor instance creation\necho date('H:i:s'), ' Creating new TemplateProcessor instance...', EOL;\n$templateProcessor = new PhpOffice\\PhpWord\\TemplateProcessor(__DIR__ . '/resources/Sample_40_TemplateSetComplexValue.docx');\n\n$title = new TextRun();\n$title->addText('This title has been set ', ['bold' => true, 'italic' => true, 'color' => 'blue']);\n$title->addText('dynamically', ['bold' => true, 'italic' => true, 'color' => 'red', 'underline' => 'single']);\n$templateProcessor->setComplexBlock('title', $title);\n\n$inline = new TextRun();\n$inline->addText('by a red italic text', ['italic' => true, 'color' => 'red']);\n$templateProcessor->setComplexValue('inline', $inline);\n\n$table = new Table(['borderSize' => 12, 'borderColor' => 'green', 'width' => 6000, 'unit' => TblWidth::TWIP]);\n$table->addRow();\n$table->addCell(150)->addText('Cell A1');\n$table->addCell(150)->addText('Cell A2');\n$table->addCell(150)->addText('Cell A3');\n$table->addRow();\n$table->addCell(150)->addText('Cell B1');\n$table->addCell(150)->addText('Cell B2');\n$table->addCell(150)->addText('Cell B3');\n$templateProcessor->setComplexBlock('table', $table);\n\n$field = new Field('DATE', ['dateformat' => 'dddd d MMMM yyyy H:mm:ss'], ['PreserveFormat']);\n$templateProcessor->setComplexValue('field', $field);\n\n// $link = new Link('https://github.com/PHPOffice/PHPWord');\n// $templateProcessor->setComplexValue('link', $link);\n\necho date('H:i:s'), ' Saving the result document...', EOL;\n$templateProcessor->saveAs(__DIR__ . '/results/Sample_40_TemplateSetComplexValue.docx');\n\necho getEndingNotes(['Word2007' => 'docx'], __DIR__ . '/results/Sample_40_TemplateSetComplexValue.docx');\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_41_TemplateSetChart.php",
    "content": "<?php\n\nuse PhpOffice\\PhpWord\\Element\\Chart;\nuse PhpOffice\\PhpWord\\Shared\\Converter;\n\ninclude_once 'Sample_Header.php';\n\n// Template processor instance creation\necho date('H:i:s'), ' Creating new TemplateProcessor instance...', EOL;\n$templateProcessor = new PhpOffice\\PhpWord\\TemplateProcessor(__DIR__ . '/resources/Sample_41_TemplateSetChart.docx');\n\n$chartTypes = ['pie', 'doughnut', 'bar', 'column', 'line', 'area', 'scatter', 'radar', 'stacked_bar', 'percent_stacked_bar', 'stacked_column', 'percent_stacked_column'];\n$twoSeries = ['bar', 'column', 'line', 'area', 'scatter', 'radar', 'stacked_bar', 'percent_stacked_bar', 'stacked_column', 'percent_stacked_column'];\n$threeSeries = ['bar', 'line'];\n\n$categories = ['A', 'B', 'C', 'D', 'E'];\n$series1 = [1, 3, 2, 5, 4];\n$series2 = [3, 1, 7, 2, 6];\n$series3 = [8, 3, 2, 5, 4];\n\n$i = 0;\nforeach ($chartTypes as $chartType) {\n    $chart = new Chart($chartType, $categories, $series1);\n\n    if (in_array($chartType, $twoSeries)) {\n        $chart->addSeries($categories, $series2);\n    }\n    if (in_array($chartType, $threeSeries)) {\n        $chart->addSeries($categories, $series3);\n    }\n\n    $chart->getStyle()\n        ->setWidth(Converter::inchToEmu(3))\n        ->setHeight(Converter::inchToEmu(3));\n\n    $templateProcessor->setChart(\"chart{$i}\", $chart);\n    ++$i;\n}\n\necho date('H:i:s'), ' Saving the result document...', EOL;\n$templateProcessor->saveAs(__DIR__ . '/results/Sample_41_TemplateSetChart.docx');\n\necho getEndingNotes(['Word2007' => 'docx'], __DIR__ . '/results/Sample_41_TemplateSetChart.docx');\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_42_TemplateSetCheckbox.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\nuse PhpOffice\\PhpWord\\TemplateProcessor;\n\n// Template processor instance creation\necho date('H:i:s'), ' Creating new TemplateProcessor instance...', EOL;\n$filename = 'Sample_42_TemplateSetCheckbox.docx';\n$templateProcessor = new TemplateProcessor(__DIR__ . \"/resources/{$filename}\");\n\n$templateProcessor->setCheckbox('checkbox', true);\n$templateProcessor->setCheckbox('checkbox2', false);\n\necho date('H:i:s'), ' Saving the result document...', EOL;\n$templateProcessor->saveAs(__DIR__ . \"/results/{$filename}\");\n\necho getEndingNotes(['Word2007' => 'docx'], \"results/{$filename}\");\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_43_RTLDefault.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Shared\\Html as SharedHtml;\n\n// Suggested by issue 2427.\necho date('H:i:s'), ' Create new PhpWord object', EOL;\n$phpWord = new PhpWord();\nSettings::setDefaultRtl(true);\n$phpWord->setDefaultFontName('DejaVu Sans'); // for good rendition of PDF\n$rendererName = Settings::PDF_RENDERER_MPDF;\n$rendererLibraryPath = $vendorDirPath . '/mpdf/mpdf';\nSettings::setPdfRenderer($rendererName, $rendererLibraryPath);\n\n// New section\n$section = $phpWord->addSection();\n$arabic = '<p>  الألم الذي ربما تنجم عنه بعض ا.</p>';\n$english = '<p style=\"text-align: left; direction: ltr; font-family: DejaVu Sans, sans-serif;\">LTR in RTL document.</p>';\nSharedHtml::addHtml($section, $arabic, false, false);\nSharedHtml::addHtml($section, $english, false, false);\nSharedHtml::addHtml($section, $english, false, false);\nSharedHtml::addHtml($section, $arabic, false, false);\nSharedHtml::addHtml($section, $arabic, false, false);\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\nSettings::setDefaultRtl(false);\n"
  },
  {
    "path": "samples/Sample_44_ExtractVariablesFromReaderWord2007.php",
    "content": "<?php\n\ninclude_once 'Sample_Header.php';\n\n// Read contents\n$name = basename(__FILE__, '.php');\n\n$source = __DIR__ . \"/resources/{$name}.docx\";\n\necho date('H:i:s'), \" Reading contents from `{$source}`\", EOL;\n\n$variables = PhpOffice\\PhpWord\\IOFactory::extractVariables($source);\n\nvar_dump($variables);\n"
  },
  {
    "path": "samples/Sample_45_Autoloader.php",
    "content": "<?php\n\nuse PhpOffice\\PhpWord\\Style\\Font;\n\ndefine('USE_AUTOLOADER', true);\n\ninclude_once 'Sample_Header.php';\n\n// New Word Document\necho date('H:i:s') , ' Create new PhpWord object' , EOL;\n\n$languageEnGb = new PhpOffice\\PhpWord\\Style\\Language(PhpOffice\\PhpWord\\Style\\Language::EN_GB);\n\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n$phpWord->getSettings()->setThemeFontLang($languageEnGb);\n\n$fontStyleName = 'rStyle';\n$phpWord->addFontStyle($fontStyleName, ['bold' => true, 'italic' => true, 'size' => 16, 'allCaps' => true, 'doubleStrikethrough' => true]);\n\n$paragraphStyleName = 'pStyle';\n$phpWord->addParagraphStyle($paragraphStyleName, ['alignment' => PhpOffice\\PhpWord\\SimpleType\\Jc::CENTER, 'spaceAfter' => 100]);\n\n$phpWord->addTitleStyle(1, ['bold' => true], ['spaceAfter' => 240]);\n\n// New portrait section\n$section = $phpWord->addSection();\n\n// Simple text\n$section->addTitle('Welcome to PhpWord', 1);\n$section->addText('Hello World!');\n\n// $pStyle = new Font();\n// $pStyle->setLang()\n$section->addText('Ce texte-ci est en français.', ['lang' => PhpOffice\\PhpWord\\Style\\Language::FR_BE]);\n\n// Two text break\n$section->addTextBreak(2);\n\n// Define styles\n$section->addText('I am styled by a font style definition.', $fontStyleName);\n$section->addText('I am styled by a paragraph style definition.', null, $paragraphStyleName);\n$section->addText('I am styled by both font and paragraph style.', $fontStyleName, $paragraphStyleName);\n\n$section->addTextBreak();\n\n// Inline font style\n$fontStyle['name'] = 'Times New Roman';\n$fontStyle['size'] = 20;\n\n$textrun = $section->addTextRun();\n$textrun->addText('I am inline styled ', $fontStyle);\n$textrun->addText('with ');\n$textrun->addText('color', ['color' => '996699']);\n$textrun->addText(', ');\n$textrun->addText('bold', ['bold' => true]);\n$textrun->addText(', ');\n$textrun->addText('italic', ['italic' => true]);\n$textrun->addText(', ');\n$textrun->addText('underline', ['underline' => 'dash']);\n$textrun->addText(', ');\n$textrun->addText('strikethrough', ['strikethrough' => true]);\n$textrun->addText(', ');\n$textrun->addText('doubleStrikethrough', ['doubleStrikethrough' => true]);\n$textrun->addText(', ');\n$textrun->addText('superScript', ['superScript' => true]);\n$textrun->addText(', ');\n$textrun->addText('subScript', ['subScript' => true]);\n$textrun->addText(', ');\n$textrun->addText('smallCaps', ['smallCaps' => true]);\n$textrun->addText(', ');\n$textrun->addText('allCaps', ['allCaps' => true]);\n$textrun->addText(', ');\n$textrun->addText('fgColor', ['fgColor' => 'yellow']);\n$textrun->addText(', ');\n$textrun->addText('scale', ['scale' => 200]);\n$textrun->addText(', ');\n$textrun->addText('spacing', ['spacing' => 120]);\n$textrun->addText(', ');\n$textrun->addText('kerning', ['kerning' => 10]);\n$textrun->addText('. ');\n\n// Link\n$section->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub');\n$section->addTextBreak();\n\n// Image\n$section->addImage(__DIR__ . '/resources/_earth.jpg', ['width' => 18, 'height' => 18]);\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_46_RubyPhoneticGuide.php",
    "content": "<?php\n\nuse PhpOffice\\PhpWord\\ComplexType\\RubyProperties;\nuse PhpOffice\\PhpWord\\Element\\TextRun;\n\ninclude_once 'Sample_Header.php';\n\n// New Word Document\necho date('H:i:s'), ' Create sample for Ruby (Phonetic Guide) use', EOL;\n$phpWord = new PhpOffice\\PhpWord\\PhpWord();\n\n// Section for demonstrating ruby (phonetic guide) features\n$section = $phpWord->addSection();\n\n$section->addText('Here is some normal text with no ruby, also known as \"phonetic guide\", text.');\n\n$properties = new RubyProperties();\n$properties->setAlignment(RubyProperties::ALIGNMENT_CENTER);\n$properties->setFontFaceSize(10);\n$properties->setFontPointsAboveBaseText(20);\n$properties->setFontSizeForBaseText(18);\n$properties->setLanguageId('en-US');\n\n$textRun = $section->addTextRun();\n$textRun->addText('Here is a demonstration of ruby text for ');\n$baseTextRun = new TextRun(null);\n$baseTextRun->addText('this');\n$rubyTextRun = new TextRun(null);\n$rubyTextRun->addText('ruby-text');\n$textRun->addRuby($baseTextRun, $rubyTextRun, $properties);\n$textRun->addText(' word.');\n\n$textRun = $section->addTextRun();\n$properties = new RubyProperties();\n$properties->setAlignment(RubyProperties::ALIGNMENT_CENTER);\n$properties->setFontFaceSize(10);\n$properties->setFontPointsAboveBaseText(20);\n$properties->setFontSizeForBaseText(18);\n$properties->setLanguageId('ja-JP');\n$textRun->addText('Here is a demonstration of ruby text for Japanese text: ');\n$baseTextRun = new TextRun(null);\n$baseTextRun->addText('私');\n$rubyTextRun = new TextRun(null);\n$rubyTextRun->addText('わたし');\n$textRun->addRuby($baseTextRun, $rubyTextRun, $properties);\n\n$section->addText('You can also have ruby text for titles:');\n\n$phpWord->addTitleStyle(1, ['name' => 'Arial', 'size' => 24, 'bold' => true, 'color' => '000099']);\n\n$properties = new RubyProperties();\n$properties->setAlignment(RubyProperties::ALIGNMENT_CENTER);\n$properties->setFontFaceSize(10);\n$properties->setFontPointsAboveBaseText(50);\n$properties->setFontSizeForBaseText(18);\n$properties->setLanguageId('ja-JP');\n\n$baseTextRun = new TextRun(null);\n$baseTextRun->addText('私');\n$rubyTextRun = new TextRun(null);\n$rubyTextRun->addText('わたし');\n$textRun = new TextRun();\n$textRun->addRuby($baseTextRun, $rubyTextRun, $properties);\n$section->addTitle($textRun, 1);\n\n// Save file\necho write($phpWord, basename(__FILE__, '.php'), $writers);\nif (!CLI) {\n    include_once 'Sample_Footer.php';\n}\n"
  },
  {
    "path": "samples/Sample_Footer.php",
    "content": "<?php\nif (CLI) {\n    return;\n}\n?>\n</div>\n<script src=\"bootstrap/js/jquery.min.js\"></script>\n<script src=\"bootstrap/js/bootstrap.min.js\"></script>\n</body>\n</html>\n\n"
  },
  {
    "path": "samples/Sample_Header.php",
    "content": "<?php\n\n$vendorDirPath = realpath(__DIR__ . '/../vendor');\n\nif ((defined('USE_AUTOLOADER') && USE_AUTOLOADER == true)\n    || !file_exists($vendorDirPath . '/autoload.php')) {\n    // PhpWord\n    require_once __DIR__ . '/../src/PhpWord/Autoloader.php';\n    PhpOffice\\PhpWord\\Autoloader::register();\n} else {\n    require $vendorDirPath . '/autoload.php';\n    $dompdfPath = $vendorDirPath . '/dompdf/dompdf';\n    if (file_exists($dompdfPath)) {\n        define('DOMPDF_ENABLE_AUTOLOAD', false);\n    }\n}\n\nuse PhpOffice\\PhpWord\\Settings;\n\ndate_default_timezone_set('UTC');\nerror_reporting(E_ALL);\ndefine('CLI', (PHP_SAPI == 'cli') ? true : false);\ndefine('EOL', CLI ? PHP_EOL : '<br />');\ndefine('SCRIPT_FILENAME', basename($_SERVER['SCRIPT_FILENAME'], '.php'));\ndefine('IS_INDEX', SCRIPT_FILENAME == 'index');\n\nSettings::loadConfig();\n\nif (defined('DOMPDF_ENABLE_AUTOLOAD')) {\n    Settings::setPdfRenderer(Settings::PDF_RENDERER_DOMPDF, $vendorDirPath . '/dompdf/dompdf');\n}\n\n// Set writers\n$writers = ['Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf', 'HTML' => 'html', 'PDF' => 'pdf', 'EPub3' => 'epub'];\n\n// Set PDF renderer\nif (null === Settings::getPdfRendererPath()) {\n    $writers['PDF'] = null;\n}\n\n// Turn output escaping on\nSettings::setOutputEscapingEnabled(true);\n\n// Return to the caller script when runs by CLI\nif (CLI) {\n    return;\n}\n\n// Set titles and names\n$pageHeading = str_replace('_', ' ', SCRIPT_FILENAME);\n$pageTitle = IS_INDEX ? 'Welcome to ' : \"{$pageHeading} - \";\n$pageTitle .= 'PHPWord';\n$pageHeading = IS_INDEX ? '' : \"<h1>{$pageHeading}</h1>\";\n\n// Populate samples\n$files = '';\nif ($handle = opendir('.')) {\n    $sampleFiles = [];\n    while (false !== ($sampleFile = readdir($handle))) {\n        $sampleFiles[] = $sampleFile;\n    }\n    sort($sampleFiles);\n    closedir($handle);\n\n    foreach ($sampleFiles as $file) {\n        if (preg_match('/^Sample_\\d+_/', $file)) {\n            $name = str_replace('_', ' ', preg_replace('/(Sample_|\\.php)/', '', $file));\n            $files .= \"<li><a href='{$file}'>{$name}</a></li>\";\n        }\n    }\n}\n\n/**\n * Write documents.\n */\nfunction write(PhpOffice\\PhpWord\\PhpWord $phpWord, string $filename, array $writers): string\n{\n    $result = '';\n\n    // Write documents\n    foreach ($writers as $format => $extension) {\n        $result .= date('H:i:s') . \" Write to {$format} format\";\n        if (null !== $extension) {\n            $targetFile = __DIR__ . \"/results/{$filename}.{$extension}\";\n            $phpWord->save($targetFile, $format);\n        } else {\n            $result .= ' ... NOT DONE!';\n        }\n        $result .= EOL;\n    }\n\n    $result .= getEndingNotes($writers, $filename);\n\n    return $result;\n}\n\n/**\n * Get ending notes.\n */\nfunction getEndingNotes(array $writers, string $filename): string\n{\n    $result = '';\n\n    // Do not show execution time for index\n    if (!IS_INDEX) {\n        $result .= date('H:i:s') . ' Done writing file(s)' . EOL;\n        $result .= date('H:i:s') . ' Peak memory usage: ' . (memory_get_peak_usage(true) / 1024 / 1024) . ' MB' . EOL;\n    }\n\n    // Return\n    if (CLI) {\n        $result .= 'The results are stored in the \"results\" subdirectory.' . EOL;\n    } else {\n        if (!IS_INDEX) {\n            $types = array_values($writers);\n            $result .= '<p>&nbsp;</p>';\n            $result .= '<p>Results: ';\n            foreach ($types as $type) {\n                if (null !== $type) {\n                    $resultFile = 'results/' . SCRIPT_FILENAME . '.' . $type;\n                    if (file_exists($resultFile)) {\n                        $result .= \"<a href='{$resultFile}' class='btn btn-primary'>{$type}</a> \";\n                    }\n                }\n            }\n            $result .= '</p>';\n\n            $result .= '<pre>';\n            if (file_exists($filename . '.php')) {\n                $result .= highlight_file($filename . '.php', true);\n            }\n            $result .= '</pre>';\n        }\n    }\n\n    return $result;\n}\n?>\n<title><?php echo $pageTitle; ?></title>\n<meta charset=\"utf-8\">\n<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n<link rel=\"stylesheet\" href=\"bootstrap/css/bootstrap.min.css\" />\n<link rel=\"stylesheet\" href=\"bootstrap/css/font-awesome.min.css\" />\n<link rel=\"stylesheet\" href=\"bootstrap/css/phpword.css\" />\n</head>\n<body>\n<div class=\"container\">\n<div class=\"navbar navbar-default\" role=\"navigation\">\n    <div class=\"container-fluid\">\n        <div class=\"navbar-header\">\n            <button type=\"button\" class=\"navbar-toggle\" data-toggle=\"collapse\" data-target=\".navbar-collapse\">\n            <span class=\"sr-only\">Toggle navigation</span>\n            <span class=\"icon-bar\"></span>\n            <span class=\"icon-bar\"></span>\n            <span class=\"icon-bar\"></span>\n            </button>\n            <a class=\"navbar-brand\" href=\"./\">PHPWord</a>\n        </div>\n        <div class=\"navbar-collapse collapse\">\n            <ul class=\"nav navbar-nav\">\n                <li class=\"dropdown active\">\n                    <a href=\"#\" class=\"dropdown-toggle\" data-toggle=\"dropdown\"><i class=\"fa fa-code fa-lg\"></i>&nbsp;Samples<strong class=\"caret\"></strong></a>\n                    <ul class=\"dropdown-menu\"><?php echo $files; ?></ul>\n                </li>\n            </ul>\n            <ul class=\"nav navbar-nav navbar-right\">\n                <li><a href=\"https://github.com/PHPOffice/PHPWord\"><i class=\"fa fa-github fa-lg\" title=\"GitHub\"></i>&nbsp;</a></li>\n                <li><a href=\"https://phpoffice.github.io/PHPWord/\"><i class=\"fa fa-book fa-lg\" title=\"Docs\"></i>&nbsp;</a></li>\n                <li><a href=\"http://twitter.com/PHPOffice\"><i class=\"fa fa-twitter fa-lg\" title=\"Twitter\"></i>&nbsp;</a></li>\n            </ul>\n        </div>\n    </div>\n</div>\n<?php echo $pageHeading; ?>\n"
  },
  {
    "path": "samples/bootstrap/css/phpword.css",
    "content": "body {\n    padding-top: 20px;\n    padding-bottom: 20px;\n    min-height: 1000px;\n}\n.navbar {\n    margin-bottom: 20px;\n}\n.passed {\n    color: #339900;\n}\n.failed {\n    color: #ff0000;\n}\n"
  },
  {
    "path": "samples/index.php",
    "content": "<?php\ninclude_once 'Sample_Header.php';\n\nuse PhpOffice\\PhpWord\\Settings;\n\n$requirements = [\n    'php' => ['PHP 7.1', version_compare(PHP_VERSION, '7.1', '>=')],\n    'xml' => ['PHP extension XML', extension_loaded('xml')],\n    'temp' => ['Temp folder \"<code>' . Settings::getTempDir() . '</code>\" is writable', is_writable(Settings::getTempDir())],\n    'zip' => ['PHP extension ZipArchive (optional)', extension_loaded('zip')],\n    'gd' => ['PHP extension GD (optional)', extension_loaded('gd')],\n    'xmlw' => ['PHP extension XMLWriter (optional)', extension_loaded('xmlwriter')],\n    'xsl' => ['PHP extension XSL (optional)', extension_loaded('xsl')],\n];\nif (!CLI) {\n    ?>\n<div class=\"jumbotron\">\n<p>Welcome to PHPWord, a library written in pure PHP that provides a set of classes to write to and read from different document file formats, i.e. Office Open XML (.docx), Open Document Format (.odt), and Rich Text Format (.rtf).</p>\n<p>&nbsp;</p>\n<p>\n    <a class=\"btn btn-lg btn-primary\" href=\"https://github.com/PHPOffice/PHPWord\" role=\"button\"><i class=\"fa fa-github fa-lg\" title=\"GitHub\"></i>  Fork us on Github!</a>\n    <a class=\"btn btn-lg btn-primary\" href=\"https://phpoffice.github.io/PHPWord/\" role=\"button\"><i class=\"fa fa-book fa-lg\" title=\"Docs\"></i>  Read the Docs</a>\n</p>\n</div>\n    <?php\n}\nif (!CLI) {\n    echo '<h3>Requirement check:</h3>';\n    echo '<ul>';\n    foreach ($requirements as $key => $value) {\n        [$label, $result] = $value;\n        $status = $result ? 'passed' : 'failed';\n        echo \"<li>{$label} ... <span class='{$status}'>{$status}</span></li>\";\n    }\n    echo '</ul>';\n    include_once 'Sample_Footer.php';\n} else {\n    echo 'Requirement check:' . PHP_EOL;\n    foreach ($requirements as $key => $value) {\n        [$label, $result] = $value;\n        $label = strip_tags($label);\n        $status = $result ? '32m passed' : '31m failed';\n        echo \"{$label} ... \\033[{$status}\\033[0m\" . PHP_EOL;\n    }\n}\n"
  },
  {
    "path": "samples/resources/Sample_28_ReadRTF.rtf",
    "content": "{\\rtf1\n\\ansi\\ansicpg1252\n\\deff0\n{\\fonttbl{\\f0\\fnil\\fcharset0 Arial;}{\\f1\\fnil\\fcharset0 Times New Roman;}}\n{\\colortbl;\\red255\\green0\\blue0;\\red14\\green0\\blue0}\n{\\*\\generator PhpWord;}\n\n{\\info{\\title }{\\subject }{\\category }{\\keywords }{\\comment }{\\author }{\\operator }{\\creatim \\yr2014\\mo05\\dy27\\hr23\\min36\\sec45}{\\revtim \\yr2014\\mo05\\dy27\\hr23\\min36\\sec45}{\\company }{\\manager }}\n\\deftab720\\viewkind1\\uc1\\pard\\nowidctlpar\\lang1036\\kerning1\\fs20\n{Welcome to PhpWord}\\par\n\\pard\\nowidctlpar{\\cf0\\f0 Hello World!}\\par\n\\par\n\\par\n\\pard\\nowidctlpar{\\cf0\\f0\\fs32\\b\\i I am styled by a font style definition.}\\par\n\\pard\\nowidctlpar{\\cf0\\f0 I am styled by a paragraph style definition.}\\par\n\\pard\\nowidctlpar\\qc\\sa100{\\cf0\\f0\\fs32\\b\\i I am styled by both font and paragraph style.}\\par\n\\pard\\nowidctlpar{\\cf1\\f1\\fs40\\b\\i\\ul\\strike\\super I am inline styled.}\\par\n\\par\n{\\field {\\*\\fldinst {HYPERLINK \"https://github.com/PHPOffice/PHPWord\"}}{\\fldrslt {PHPWord on GitHub}}}\\par\n\\par\n}"
  },
  {
    "path": "samples/resources/Sample_30_ReadHTML.html",
    "content": "<html>\n<head>\n<meta charset=\"UTF-8\" />\n<title>PHPWord</title>\n</head>\n<body>\n<h1>Adding element via HTML</h1>\n<p>Some well formed HTML snippet needs to be used</p>\n<p>With for example <strong>some<sup>1</sup> <em>inline</em> formatting</strong><sub>1</sub></p>\n<p>Unordered (bulleted) list:</p>\n<ul><li>Item 1</li><li>Item 2</li><ul><li>Item 2.1</li><li>Item 2.1</li></ul></ul>\n<p>Ordered (numbered) list:</p>\n<ol><li>Item 1</li><li>Item 2</li></ol>\n\n<p style=\"line-height:2\">Double height</p>\n\n<h2>Includes images</h2>\n<img src=\"https://phpoffice.github.io/PHPWord/images/phpword.png\" alt=\"\"/>\n\n<img src=\"http://php.net/images/logos/php-med-trans-light.gif\" name=\"Imagen 12\" align=\"bottom\" width=\"208\" height=\"183\" border=\"0\"/>\n<img src=\"http://php.net/images/logos/php-icon.png\" name=\"Imagen 13\" align=\"bottom\" width=\"143\" height=\"202\" border=\"0\"/>\n<img src=\"http://php.net/images/logos/php-med-trans-light.gif\" name=\"Imagen 14\" align=\"bottom\" width=\"194\" height=\"188\" border=\"0\"/>\n\n</body>\n</html>\n"
  },
  {
    "path": "src/PhpWord/Autoloader.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\ndeclare(strict_types=1);\n\nnamespace PhpOffice\\PhpWord;\n\nclass Autoloader\n{\n    /** @const string */\n    const NAMESPACE_PREFIX = 'PhpOffice\\\\PhpWord\\\\';\n\n    public static function register(): void\n    {\n        spl_autoload_register([new self(), 'autoload']);\n    }\n\n    public static function autoload(string $class): void\n    {\n        $prefixLength = strlen(self::NAMESPACE_PREFIX);\n        if (0 === strncmp(self::NAMESPACE_PREFIX, $class, $prefixLength)) {\n            $file = str_replace('\\\\', DIRECTORY_SEPARATOR, substr($class, $prefixLength));\n            $file = realpath(__DIR__ . (empty($file) ? '' : DIRECTORY_SEPARATOR) . $file . '.php');\n            if (!$file) {\n                return;\n            }\n            if (file_exists($file)) {\n                /** @noinspection PhpIncludeInspection Dynamic includes */\n                require_once $file;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Collection/AbstractCollection.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Collection;\n\n/**\n * Collection abstract class.\n *\n * @since 0.10.0\n *\n * @template T\n */\nabstract class AbstractCollection\n{\n    /**\n     * Items.\n     *\n     * @var T[]\n     */\n    private $items = [];\n\n    /**\n     * Get items.\n     *\n     * @return T[]\n     */\n    public function getItems(): array\n    {\n        return $this->items;\n    }\n\n    /**\n     * Get item by index.\n     *\n     * @return ?T\n     */\n    public function getItem(int $index)\n    {\n        if (array_key_exists($index, $this->items)) {\n            return $this->items[$index];\n        }\n\n        return null;\n    }\n\n    /**\n     * Set item.\n     *\n     * @param ?T $item\n     */\n    public function setItem(int $index, $item): void\n    {\n        if (array_key_exists($index, $this->items)) {\n            $this->items[$index] = $item;\n        }\n    }\n\n    /**\n     * Add new item.\n     *\n     * @param T $item\n     */\n    public function addItem($item): int\n    {\n        $index = $this->countItems();\n        $this->items[$index] = $item;\n\n        return $index;\n    }\n\n    /**\n     * Get item count.\n     */\n    public function countItems(): int\n    {\n        return count($this->items);\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Collection/Bookmarks.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Collection;\n\nuse PhpOffice\\PhpWord\\Element\\Bookmark;\n\n/**\n * Bookmarks collection.\n *\n * @since 0.12.0\n *\n * @extends AbstractCollection<Bookmark>\n */\nclass Bookmarks extends AbstractCollection\n{\n}\n"
  },
  {
    "path": "src/PhpWord/Collection/Charts.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Collection;\n\nuse PhpOffice\\PhpWord\\Element\\Chart;\n\n/**\n * Charts collection.\n *\n * @since 0.12.0\n *\n * @extends AbstractCollection<Chart>\n */\nclass Charts extends AbstractCollection\n{\n}\n"
  },
  {
    "path": "src/PhpWord/Collection/Comments.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Collection;\n\nuse PhpOffice\\PhpWord\\Element\\Comment;\n\n/**\n * Comments collection.\n *\n * @since 0.12.0\n *\n * @extends AbstractCollection<Comment>\n */\nclass Comments extends AbstractCollection\n{\n}\n"
  },
  {
    "path": "src/PhpWord/Collection/Endnotes.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Collection;\n\nuse PhpOffice\\PhpWord\\Element\\Endnote;\n\n/**\n * Endnotes collection.\n *\n * @since 0.10.0\n *\n * @extends AbstractCollection<Endnote>\n */\nclass Endnotes extends AbstractCollection\n{\n}\n"
  },
  {
    "path": "src/PhpWord/Collection/Footnotes.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Collection;\n\nuse PhpOffice\\PhpWord\\Element\\Footnote;\n\n/**\n * Footnotes collection.\n *\n * @since 0.10.0\n *\n * @extends AbstractCollection<Footnote>\n */\nclass Footnotes extends AbstractCollection\n{\n}\n"
  },
  {
    "path": "src/PhpWord/Collection/Titles.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Collection;\n\nuse PhpOffice\\PhpWord\\Element\\Title;\n\n/**\n * Titles collection.\n *\n * @since 0.10.0\n *\n * @extends AbstractCollection<Title>\n */\nclass Titles extends AbstractCollection\n{\n}\n"
  },
  {
    "path": "src/PhpWord/ComplexType/FootnoteProperties.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\ComplexType;\n\nuse InvalidArgumentException;\nuse PhpOffice\\PhpWord\\SimpleType\\NumberFormat;\n\n/**\n * Footnote properties.\n *\n * @see http://www.datypic.com/sc/ooxml/e-w_footnotePr-1.html\n */\nfinal class FootnoteProperties\n{\n    const RESTART_NUMBER_CONTINUOUS = 'continuous';\n    const RESTART_NUMBER_EACH_SECTION = 'eachSect';\n    const RESTART_NUMBER_EACH_PAGE = 'eachPage';\n\n    const POSITION_PAGE_BOTTOM = 'pageBottom';\n    const POSITION_BENEATH_TEXT = 'beneathText';\n    const POSITION_SECTION_END = 'sectEnd';\n    const POSITION_DOC_END = 'docEnd';\n\n    /**\n     * Footnote Positioning Location.\n     *\n     * @var string\n     */\n    private $pos;\n\n    /**\n     * Footnote Numbering Format w:numFmt, one of PhpOffice\\PhpWord\\SimpleType\\NumberFormat.\n     *\n     * @var string\n     */\n    private $numFmt;\n\n    /**\n     * Footnote and Endnote Numbering Starting Value.\n     *\n     * @var float\n     */\n    private $numStart;\n\n    /**\n     * Footnote and Endnote Numbering Restart Location.\n     *\n     * @var string\n     */\n    private $numRestart;\n\n    /**\n     * Get the Footnote Positioning Location.\n     *\n     * @return string\n     */\n    public function getPos()\n    {\n        return $this->pos;\n    }\n\n    /**\n     * Set the Footnote Positioning Location (pageBottom, beneathText, sectEnd, docEnd).\n     *\n     * @param string $pos\n     *\n     * @return self\n     */\n    public function setPos($pos)\n    {\n        $position = [\n            self::POSITION_PAGE_BOTTOM,\n            self::POSITION_BENEATH_TEXT,\n            self::POSITION_SECTION_END,\n            self::POSITION_DOC_END,\n        ];\n\n        if (in_array($pos, $position)) {\n            $this->pos = $pos;\n        } else {\n            throw new InvalidArgumentException('Invalid value, on of ' . implode(', ', $position) . ' possible');\n        }\n\n        return $this;\n    }\n\n    /**\n     * Get the Footnote Numbering Format.\n     *\n     * @return string\n     */\n    public function getNumFmt()\n    {\n        return $this->numFmt;\n    }\n\n    /**\n     * Set the Footnote Numbering Format.\n     *\n     * @param string $numFmt One of NumberFormat\n     *\n     * @return self\n     */\n    public function setNumFmt($numFmt)\n    {\n        NumberFormat::validate($numFmt);\n        $this->numFmt = $numFmt;\n\n        return $this;\n    }\n\n    /**\n     * Get the Footnote Numbering Format.\n     *\n     * @return float\n     */\n    public function getNumStart()\n    {\n        return $this->numStart;\n    }\n\n    /**\n     * Set the Footnote Numbering Format.\n     *\n     * @param float $numStart\n     *\n     * @return self\n     */\n    public function setNumStart($numStart)\n    {\n        $this->numStart = $numStart;\n\n        return $this;\n    }\n\n    /**\n     * Get the Footnote and Endnote Numbering Starting Value.\n     *\n     * @return string\n     */\n    public function getNumRestart()\n    {\n        return $this->numRestart;\n    }\n\n    /**\n     * Set the Footnote and Endnote Numbering Starting Value (continuous, eachSect, eachPage).\n     *\n     * @param  string $numRestart\n     *\n     * @return self\n     */\n    public function setNumRestart($numRestart)\n    {\n        $restartNumbers = [\n            self::RESTART_NUMBER_CONTINUOUS,\n            self::RESTART_NUMBER_EACH_SECTION,\n            self::RESTART_NUMBER_EACH_PAGE,\n        ];\n\n        if (in_array($numRestart, $restartNumbers)) {\n            $this->numRestart = $numRestart;\n        } else {\n            throw new InvalidArgumentException('Invalid value, on of ' . implode(', ', $restartNumbers) . ' possible');\n        }\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/ComplexType/ProofState.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\ComplexType;\n\nuse InvalidArgumentException;\n\n/**\n * Spelling and Grammatical Checking State.\n *\n * @see http://www.datypic.com/sc/ooxml/e-w_proofState-1.html\n */\nfinal class ProofState\n{\n    /**\n     * Check Completed.\n     */\n    const CLEAN = 'clean';\n\n    /**\n     * Check Not Completed.\n     */\n    const DIRTY = 'dirty';\n\n    /**\n     * Spell Checking State.\n     *\n     * @var string\n     */\n    private $spelling;\n\n    /**\n     * Grammatical Checking State.\n     *\n     * @var string\n     */\n    private $grammar;\n\n    /**\n     * Set the Spell Checking State (dirty or clean).\n     *\n     * @param string $spelling\n     *\n     * @return self\n     */\n    public function setSpelling($spelling)\n    {\n        if ($spelling == self::CLEAN || $spelling == self::DIRTY) {\n            $this->spelling = $spelling;\n        } else {\n            throw new InvalidArgumentException('Invalid value, dirty or clean possible');\n        }\n\n        return $this;\n    }\n\n    /**\n     * Get the Spell Checking State.\n     *\n     * @return string\n     */\n    public function getSpelling()\n    {\n        return $this->spelling;\n    }\n\n    /**\n     * Set the Grammatical Checking State (dirty or clean).\n     *\n     * @param string $grammar\n     *\n     * @return self\n     */\n    public function setGrammar($grammar)\n    {\n        if ($grammar == self::CLEAN || $grammar == self::DIRTY) {\n            $this->grammar = $grammar;\n        } else {\n            throw new InvalidArgumentException('Invalid value, dirty or clean possible');\n        }\n\n        return $this;\n    }\n\n    /**\n     * Get the Grammatical Checking State.\n     *\n     * @return string\n     */\n    public function getGrammar()\n    {\n        return $this->grammar;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/ComplexType/RubyProperties.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\ComplexType;\n\nuse InvalidArgumentException;\n\n/**\n * Ruby properties.\n *\n * @see https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.wordprocessing.rubyproperties?view=openxml-3.0.1\n */\nclass RubyProperties\n{\n    const ALIGNMENT_CENTER = 'center';\n    const ALIGNMENT_DISTRIBUTE_LETTER = 'distributeLetter';\n    const ALIGNMENT_DISTRIBUTE_SPACE = 'distributeSpace';\n    const ALIGNMENT_LEFT = 'left';\n    const ALIGNMENT_RIGHT = 'right';\n    const ALIGNMENT_RIGHT_VERTICAL = 'rightVertical';\n\n    /**\n     * Ruby alignment (w:rubyAlign).\n     *\n     * @var string\n     */\n    private $alignment;\n\n    /**\n     * Ruby font face size (w:hps).\n     *\n     * @var float\n     */\n    private $fontFaceSize;\n\n    /**\n     * Ruby font points above base text (w:hpsRaise).\n     *\n     * @var float\n     */\n    private $fontPointsAboveText;\n\n    /**\n     * Ruby font size for base text (w:hpsBaseText).\n     *\n     * @var float\n     */\n    private $baseTextFontSize;\n\n    /**\n     * Ruby type/language id (w:lid).\n     *\n     * @var string\n     */\n    private $languageId;\n\n    /**\n     * Create a new RubyProperties object.\n     */\n    public function __construct()\n    {\n        // these defaults came from opening a new Word doc, adding some ruby text to some\n        // Japanese text, and copying out the defaults.\n        $this->alignment = self::ALIGNMENT_DISTRIBUTE_SPACE;\n        $this->fontFaceSize = 12;\n        $this->fontPointsAboveText = 22;\n        $this->languageId = 'ja-JP';\n        $this->baseTextFontSize = 24;\n    }\n\n    /**\n     * Get the ruby alignment.\n     */\n    public function getAlignment(): string\n    {\n        return $this->alignment;\n    }\n\n    /**\n     * Set the Ruby Alignment (center, distributeLetter, distributeSpace, left, right, rightVertical).\n     */\n    public function setAlignment(string $alignment): self\n    {\n        $alignmentTypes = [\n            self::ALIGNMENT_CENTER,\n            self::ALIGNMENT_DISTRIBUTE_LETTER,\n            self::ALIGNMENT_DISTRIBUTE_SPACE,\n            self::ALIGNMENT_LEFT,\n            self::ALIGNMENT_RIGHT,\n            self::ALIGNMENT_RIGHT_VERTICAL,\n        ];\n\n        if (in_array($alignment, $alignmentTypes)) {\n            $this->alignment = $alignment;\n        } else {\n            throw new InvalidArgumentException('Invalid value, alignments of ' . implode(', ', $alignmentTypes) . ' possible');\n        }\n\n        return $this;\n    }\n\n    /**\n     * Get the ruby font face size.\n     */\n    public function getFontFaceSize(): float\n    {\n        return $this->fontFaceSize;\n    }\n\n    /**\n     * Set the ruby font face size.\n     */\n    public function setFontFaceSize(float $size): self\n    {\n        $this->fontFaceSize = $size;\n\n        return $this;\n    }\n\n    /**\n     * Get the ruby font points above base text.\n     */\n    public function getFontPointsAboveBaseText(): float\n    {\n        return $this->fontPointsAboveText;\n    }\n\n    /**\n     * Set the ruby font points above base text.\n     */\n    public function setFontPointsAboveBaseText(float $size): self\n    {\n        $this->fontPointsAboveText = $size;\n\n        return $this;\n    }\n\n    /**\n     * Get the ruby font size for base text.\n     */\n    public function getFontSizeForBaseText(): float\n    {\n        return $this->baseTextFontSize;\n    }\n\n    /**\n     * Set the ruby font size for base text.\n     */\n    public function setFontSizeForBaseText(float $size): self\n    {\n        $this->baseTextFontSize = $size;\n\n        return $this;\n    }\n\n    /**\n     * Get the ruby language id.\n     */\n    public function getLanguageId(): string\n    {\n        return $this->languageId;\n    }\n\n    /**\n     * Set the ruby language id.\n     */\n    public function setLanguageId(string $langId): self\n    {\n        $this->languageId = $langId;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/ComplexType/TblWidth.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\ComplexType;\n\nuse PhpOffice\\PhpWord\\SimpleType\\TblWidth as TblWidthSimpleType;\n\n/**\n * @see http://www.datypic.com/sc/ooxml/t-w_CT_TblWidth.html\n */\nfinal class TblWidth\n{\n    /** @var string */\n    private $type;\n\n    /** @var int */\n    private $value;\n\n    /**\n     * @param int $value If omitted, then its value shall be assumed to be 0\n     * @param string $type If omitted, then its value shall be assumed to be dxa\n     */\n    public function __construct($value = 0, $type = TblWidthSimpleType::TWIP)\n    {\n        $this->value = $value;\n        TblWidthSimpleType::validate($type);\n        $this->type = $type;\n    }\n\n    /**\n     * @return string\n     */\n    public function getType()\n    {\n        return $this->type;\n    }\n\n    /**\n     * @return int\n     */\n    public function getValue()\n    {\n        return $this->value;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/ComplexType/TrackChangesView.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\ComplexType;\n\n/**\n * Visibility of Annotation Types.\n *\n * @see http://www.datypic.com/sc/ooxml/e-w_revisionView-1.html\n */\nfinal class TrackChangesView\n{\n    /**\n     * Display Visual Indicator Of Markup Area.\n     *\n     * @var bool\n     */\n    private $markup;\n\n    /**\n     * Display Comments.\n     *\n     * @var bool\n     */\n    private $comments;\n\n    /**\n     * Display Content Revisions.\n     *\n     * @var bool\n     */\n    private $insDel;\n\n    /**\n     * Display Formatting Revisions.\n     *\n     * @var bool\n     */\n    private $formatting;\n\n    /**\n     * Display Ink Annotations.\n     *\n     * @var bool\n     */\n    private $inkAnnotations;\n\n    /**\n     * Get Display Visual Indicator Of Markup Area.\n     *\n     * @return bool True if markup is shown\n     */\n    public function hasMarkup()\n    {\n        return $this->markup;\n    }\n\n    /**\n     * Set Display Visual Indicator Of Markup Area.\n     *\n     * @param ?bool $markup\n     *            Set to true to show markup\n     */\n    public function setMarkup($markup): void\n    {\n        $this->markup = $markup === null ? true : $markup;\n    }\n\n    /**\n     * Get Display Comments.\n     *\n     * @return bool True if comments are shown\n     */\n    public function hasComments()\n    {\n        return $this->comments;\n    }\n\n    /**\n     * Set Display Comments.\n     *\n     * @param ?bool $comments\n     *            Set to true to show comments\n     */\n    public function setComments($comments): void\n    {\n        $this->comments = $comments === null ? true : $comments;\n    }\n\n    /**\n     * Get Display Content Revisions.\n     *\n     * @return bool True if content revisions are shown\n     */\n    public function hasInsDel()\n    {\n        return $this->insDel;\n    }\n\n    /**\n     * Set Display Content Revisions.\n     *\n     * @param ?bool $insDel\n     *            Set to true to show content revisions\n     */\n    public function setInsDel($insDel): void\n    {\n        $this->insDel = $insDel === null ? true : $insDel;\n    }\n\n    /**\n     * Get Display Formatting Revisions.\n     *\n     * @return bool True if formatting revisions are shown\n     */\n    public function hasFormatting()\n    {\n        return $this->formatting;\n    }\n\n    /**\n     * Set Display Formatting Revisions.\n     *\n     * @param null|bool $formatting\n     *            Set to true to show formatting revisions\n     */\n    public function setFormatting($formatting = null): void\n    {\n        $this->formatting = $formatting === null ? true : $formatting;\n    }\n\n    /**\n     * Get Display Ink Annotations.\n     *\n     * @return bool True if ink annotations are shown\n     */\n    public function hasInkAnnotations()\n    {\n        return $this->inkAnnotations;\n    }\n\n    /**\n     * Set Display Ink Annotations.\n     *\n     * @param ?bool $inkAnnotations\n     *            Set to true to show ink annotations\n     */\n    public function setInkAnnotations($inkAnnotations): void\n    {\n        $this->inkAnnotations = $inkAnnotations === null ? true : $inkAnnotations;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/AbstractContainer.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\nuse BadMethodCallException;\nuse PhpOffice\\Math\\Math;\nuse ReflectionClass;\n\n/**\n * Container abstract class.\n *\n * @method Text addText(string $text, mixed $fStyle = null, mixed $pStyle = null)\n * @method TextRun addTextRun(mixed $pStyle = null)\n * @method Bookmark addBookmark(string $name)\n * @method Link addLink(string $target, string $text = null, mixed $fStyle = null, mixed $pStyle = null, boolean $internal = false)\n * @method PreserveText addPreserveText(string $text, mixed $fStyle = null, mixed $pStyle = null)\n * @method void addTextBreak(int $count = 1, mixed $fStyle = null, mixed $pStyle = null)\n * @method ListItem addListItem(string $txt, int $depth = 0, mixed $font = null, mixed $list = null, mixed $para = null)\n * @method ListItemRun addListItemRun(int $depth = 0, mixed $listStyle = null, mixed $pStyle = null)\n * @method Footnote addFootnote(mixed $pStyle = null)\n * @method Endnote addEndnote(mixed $pStyle = null)\n * @method CheckBox addCheckBox(string $name, $text, mixed $fStyle = null, mixed $pStyle = null)\n * @method Title addTitle(mixed $text, int $depth = 1, int $pageNumber = null)\n * @method TOC addTOC(mixed $fontStyle = null, mixed $tocStyle = null, int $minDepth = 1, int $maxDepth = 9)\n * @method PageBreak addPageBreak()\n * @method Table addTable(mixed $style = null)\n * @method Image addImage(string $source, mixed $style = null, bool $isWatermark = false, $name = null)\n * @method OLEObject addOLEObject(string $source, mixed $style = null)\n * @method TextBox addTextBox(mixed $style = null)\n * @method Field addField(string $type = null, array $properties = array(), array $options = array(), mixed $text = null)\n * @method Line addLine(mixed $lineStyle = null)\n * @method Shape addShape(string $type, mixed $style = null)\n * @method Chart addChart(string $type, array $categories, array $values, array $style = null, $seriesName = null)\n * @method FormField addFormField(string $type, mixed $fStyle = null, mixed $pStyle = null)\n * @method SDT addSDT(string $type)\n * @method Formula addFormula(Math $math)\n * @method Ruby addRuby(TextRun $baseText, TextRun $rubyText, \\PhpOffice\\PhpWord\\ComplexType\\RubyProperties $properties)\n * @method \\PhpOffice\\PhpWord\\Element\\OLEObject addObject(string $source, mixed $style = null) deprecated, use addOLEObject instead\n *\n * @since 0.10.0\n */\nabstract class AbstractContainer extends AbstractElement\n{\n    /**\n     * Elements collection.\n     *\n     * @var AbstractElement[]\n     */\n    protected $elements = [];\n\n    /**\n     * Container type Section|Header|Footer|Footnote|Endnote|Cell|TextRun|TextBox|ListItemRun|TrackChange.\n     *\n     * @var string\n     */\n    protected $container;\n\n    /**\n     * Magic method to catch all 'addElement' variation.\n     *\n     * This removes addText, addTextRun, etc. When adding new element, we have to\n     * add the model in the class docblock with `@method`.\n     *\n     * Warning: This makes capitalization matters, e.g. addCheckbox or addcheckbox won't work.\n     *\n     * @param mixed $function\n     * @param mixed $args\n     *\n     * @return AbstractElement\n     */\n    public function __call($function, $args)\n    {\n        $elements = [\n            'Text', 'TextRun', 'Bookmark', 'Link', 'PreserveText', 'TextBreak',\n            'ListItem', 'ListItemRun', 'Table', 'Image', 'Object', 'OLEObject',\n            'Footnote', 'Endnote', 'CheckBox', 'TextBox', 'Field',\n            'Line', 'Shape', 'Title', 'TOC', 'PageBreak',\n            'Chart', 'FormField', 'SDT', 'Comment',\n            'Formula', 'Ruby',\n        ];\n        $functions = [];\n        foreach ($elements as $element) {\n            $functions['add' . strtolower($element)] = $element == 'Object' ? 'OLEObject' : $element;\n        }\n\n        // Run valid `add` command\n        $function = strtolower($function);\n        if (isset($functions[$function])) {\n            $element = $functions[$function];\n\n            // Special case for TextBreak\n            // @todo Remove the `$count` parameter in 1.0.0 to make this element similiar to other elements?\n            if ($element == 'TextBreak') {\n                [$count, $fontStyle, $paragraphStyle] = array_pad($args, 3, null);\n                if ($count === null) {\n                    $count = 1;\n                }\n                for ($i = 1; $i <= $count; ++$i) {\n                    $this->addElement($element, $fontStyle, $paragraphStyle);\n                }\n            } else {\n                // All other elements\n                array_unshift($args, $element); // Prepend element name to the beginning of args array\n\n                return call_user_func_array([$this, 'addElement'], $args);\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * Add element.\n     *\n     * Each element has different number of parameters passed\n     *\n     * @param string $elementName\n     *\n     * @return AbstractElement\n     */\n    protected function addElement($elementName)\n    {\n        $elementClass = __NAMESPACE__ . '\\\\' . $elementName;\n        $this->checkValidity($elementName);\n\n        // Get arguments\n        $args = func_get_args();\n        $withoutP = in_array($this->container, ['TextRun', 'Footnote', 'Endnote', 'ListItemRun', 'Field']);\n        if ($withoutP && ($elementName == 'Text' || $elementName == 'PreserveText')) {\n            $args[3] = null; // Remove paragraph style for texts in textrun\n        }\n\n        // Create element using reflection\n        $reflection = new ReflectionClass($elementClass);\n        $elementArgs = $args;\n        array_shift($elementArgs); // Shift the $elementName off the beginning of array\n\n        /** @var AbstractElement $element Type hint */\n        $element = $reflection->newInstanceArgs($elementArgs);\n\n        // Set parent container\n        $element->setParentContainer($this);\n        $element->setElementIndex($this->countElements() + 1);\n        $element->setElementId();\n\n        $this->elements[] = $element;\n\n        return $element;\n    }\n\n    /**\n     * Get all elements.\n     *\n     * @return AbstractElement[]\n     */\n    public function getElements()\n    {\n        return $this->elements;\n    }\n\n    /**\n     * Returns the element at the requested position.\n     *\n     * @param int $index\n     *\n     * @return null|AbstractElement\n     */\n    public function getElement($index)\n    {\n        if (array_key_exists($index, $this->elements)) {\n            return $this->elements[$index];\n        }\n\n        return null;\n    }\n\n    /**\n     * Removes the element at requested index.\n     *\n     * @param AbstractElement|int $toRemove\n     */\n    public function removeElement($toRemove): void\n    {\n        if (is_int($toRemove) && array_key_exists($toRemove, $this->elements)) {\n            unset($this->elements[$toRemove]);\n        } elseif ($toRemove instanceof AbstractElement) {\n            foreach ($this->elements as $key => $element) {\n                if ($element->getElementId() === $toRemove->getElementId()) {\n                    unset($this->elements[$key]);\n\n                    return;\n                }\n            }\n        }\n    }\n\n    /**\n     * Count elements.\n     *\n     * @return int\n     */\n    public function countElements()\n    {\n        return count($this->elements);\n    }\n\n    /**\n     * Check if a method is allowed for the current container.\n     *\n     * @param string $method\n     *\n     * @return bool\n     */\n    private function checkValidity($method)\n    {\n        $generalContainers = [\n            'Section', 'Header', 'Footer', 'Footnote', 'Endnote', 'Cell', 'TextRun', 'TextBox', 'ListItemRun', 'TrackChange',\n        ];\n\n        $validContainers = [\n            'Text' => $generalContainers,\n            'Bookmark' => $generalContainers,\n            'Link' => $generalContainers,\n            'TextBreak' => $generalContainers,\n            'Image' => $generalContainers,\n            'OLEObject' => $generalContainers,\n            'Field' => $generalContainers,\n            'Line' => $generalContainers,\n            'Shape' => $generalContainers,\n            'FormField' => $generalContainers,\n            'SDT' => $generalContainers,\n            'TrackChange' => $generalContainers,\n            'TextRun' => ['Section', 'Header', 'Footer', 'Cell', 'TextBox', 'TrackChange', 'ListItemRun'],\n            'ListItem' => ['Section', 'Header', 'Footer', 'Cell', 'TextBox'],\n            'ListItemRun' => ['Section', 'Header', 'Footer', 'Cell', 'TextBox'],\n            'Table' => ['Section', 'Header', 'Footer', 'Cell', 'TextBox'],\n            'CheckBox' => ['Section', 'Header', 'Footer', 'Cell', 'TextRun'],\n            'TextBox' => ['Section', 'Header', 'Footer', 'Cell'],\n            'Footnote' => ['Section', 'TextRun', 'Cell', 'ListItemRun'],\n            'Endnote' => ['Section', 'TextRun', 'Cell'],\n            'PreserveText' => ['Section', 'Header', 'Footer', 'Cell'],\n            'Title' => ['Section', 'Cell', 'Header'],\n            'TOC' => ['Section'],\n            'PageBreak' => ['Section'],\n            'Chart' => ['Section', 'Cell'],\n        ];\n\n        // Special condition, e.g. preservetext can only exists in cell when\n        // the cell is located in header or footer\n        $validSubcontainers = [\n            'PreserveText' => [['Cell'], ['Header', 'Footer', 'Section']],\n            'Footnote' => [['Cell', 'TextRun'], ['Section']],\n            'Endnote' => [['Cell', 'TextRun'], ['Section']],\n        ];\n\n        // Check if a method is valid for current container\n        if (isset($validContainers[$method])) {\n            if (!in_array($this->container, $validContainers[$method])) {\n                throw new BadMethodCallException(\"Cannot add {$method} in {$this->container}.\");\n            }\n        }\n\n        // Check if a method is valid for current container, located in other container\n        if (isset($validSubcontainers[$method])) {\n            $rules = $validSubcontainers[$method];\n            $containers = $rules[0];\n            $allowedDocParts = $rules[1];\n            foreach ($containers as $container) {\n                if ($this->container == $container && !in_array($this->getDocPart(), $allowedDocParts)) {\n                    throw new BadMethodCallException(\"Cannot add {$method} in {$this->container}.\");\n                }\n            }\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/AbstractElement.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\nuse DateTime;\nuse InvalidArgumentException;\nuse PhpOffice\\PhpWord\\Collection\\Comments;\nuse PhpOffice\\PhpWord\\Media;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Style;\n\n/**\n * Element abstract class.\n *\n * @since 0.10.0\n */\nabstract class AbstractElement\n{\n    /**\n     * PhpWord object.\n     *\n     * @var ?PhpWord\n     */\n    protected $phpWord;\n\n    /**\n     * Section Id.\n     *\n     * @var int\n     */\n    protected $sectionId;\n\n    /**\n     * Document part type: Section|Header|Footer|Footnote|Endnote.\n     *\n     * Used by textrun and cell container to determine where the element is\n     * located because it will affect the availability of other element,\n     * e.g. footnote will not be available when $docPart is header or footer.\n     *\n     * @var string\n     */\n    protected $docPart = 'Section';\n\n    /**\n     * Document part Id.\n     *\n     * For header and footer, this will be = ($sectionId - 1) * 3 + $index\n     * because the max number of header/footer in every page is 3, i.e.\n     * AUTO, FIRST, and EVEN (AUTO = ODD)\n     *\n     * @var int\n     */\n    protected $docPartId = 1;\n\n    /**\n     * Index of element in the elements collection (start with 1).\n     *\n     * @var int\n     */\n    protected $elementIndex = 1;\n\n    /**\n     * Unique Id for element.\n     *\n     * @var string\n     */\n    protected $elementId;\n\n    /**\n     * Relation Id.\n     *\n     * @var int\n     */\n    protected $relationId;\n\n    /**\n     * Depth of table container nested level; Primarily used for RTF writer/reader.\n     *\n     * 0 = Not in a table; 1 = in a table; 2 = in a table inside another table, etc.\n     *\n     * @var int\n     */\n    private $nestedLevel = 0;\n\n    /**\n     * A reference to the parent.\n     *\n     * @var null|AbstractElement\n     */\n    private $parent;\n\n    /**\n     * changed element info.\n     *\n     * @var TrackChange\n     */\n    private $trackChange;\n\n    /**\n     * Parent container type.\n     *\n     * @var string\n     */\n    private $parentContainer;\n\n    /**\n     * Has media relation flag; true for Link, Image, and Object.\n     *\n     * @var bool\n     */\n    protected $mediaRelation = false;\n\n    /**\n     * Is part of collection; true for Title, Footnote, Endnote, Chart, and Comment.\n     *\n     * @var bool\n     */\n    protected $collectionRelation = false;\n\n    /**\n     * The start position for the linked comments.\n     *\n     * @var Comments\n     */\n    protected $commentsRangeStart;\n\n    /**\n     * The end position for the linked comments.\n     *\n     * @var Comments\n     */\n    protected $commentsRangeEnd;\n\n    /**\n     * Get PhpWord.\n     */\n    public function getPhpWord(): ?PhpWord\n    {\n        return $this->phpWord;\n    }\n\n    /**\n     * Set PhpWord as reference.\n     */\n    public function setPhpWord(?PhpWord $phpWord = null): void\n    {\n        $this->phpWord = $phpWord;\n    }\n\n    /**\n     * Get section number.\n     *\n     * @return int\n     */\n    public function getSectionId()\n    {\n        return $this->sectionId;\n    }\n\n    /**\n     * Set doc part.\n     *\n     * @param string $docPart\n     * @param int $docPartId\n     */\n    public function setDocPart($docPart, $docPartId = 1): void\n    {\n        $this->docPart = $docPart;\n        $this->docPartId = $docPartId;\n    }\n\n    /**\n     * Get doc part.\n     *\n     * @return string\n     */\n    public function getDocPart()\n    {\n        return $this->docPart;\n    }\n\n    /**\n     * Get doc part Id.\n     *\n     * @return int\n     */\n    public function getDocPartId()\n    {\n        return $this->docPartId;\n    }\n\n    /**\n     * Return media element (image, object, link) container name.\n     *\n     * @return string section|headerx|footerx|footnote|endnote\n     */\n    private function getMediaPart()\n    {\n        $mediaPart = $this->docPart;\n        if ($mediaPart == 'Header' || $mediaPart == 'Footer') {\n            $mediaPart .= $this->docPartId;\n        }\n\n        return strtolower($mediaPart);\n    }\n\n    /**\n     * Get element index.\n     *\n     * @return int\n     */\n    public function getElementIndex()\n    {\n        return $this->elementIndex;\n    }\n\n    /**\n     * Set element index.\n     *\n     * @param int $value\n     */\n    public function setElementIndex($value): void\n    {\n        $this->elementIndex = $value;\n    }\n\n    /**\n     * Get element unique ID.\n     *\n     * @return string\n     */\n    public function getElementId()\n    {\n        return $this->elementId;\n    }\n\n    /**\n     * Set element unique ID from 6 first digit of md5.\n     */\n    public function setElementId(): void\n    {\n        $this->elementId = substr(md5((string) mt_rand()), 0, 6);\n    }\n\n    /**\n     * Get relation Id.\n     *\n     * @return int\n     */\n    public function getRelationId()\n    {\n        return $this->relationId;\n    }\n\n    /**\n     * Set relation Id.\n     *\n     * @param int $value\n     */\n    public function setRelationId($value): void\n    {\n        $this->relationId = $value;\n    }\n\n    /**\n     * Get nested level.\n     *\n     * @return int\n     */\n    public function getNestedLevel()\n    {\n        return $this->nestedLevel;\n    }\n\n    /**\n     * Get comments start.\n     */\n    public function getCommentsRangeStart(): ?Comments\n    {\n        return $this->commentsRangeStart;\n    }\n\n    /**\n     * Get comment start.\n     */\n    public function getCommentRangeStart(): ?Comment\n    {\n        if ($this->commentsRangeStart != null) {\n            return $this->commentsRangeStart->getItem($this->commentsRangeStart->countItems());\n        }\n\n        return null;\n    }\n\n    /**\n     * Set comment start.\n     */\n    public function setCommentRangeStart(Comment $value): void\n    {\n        if ($this instanceof Comment) {\n            throw new InvalidArgumentException('Cannot set a Comment on a Comment');\n        }\n        if ($this->commentsRangeStart == null) {\n            $this->commentsRangeStart = new Comments();\n        }\n        // Set ID early to avoid duplicates.\n        if ($value->getElementId() == null) {\n            $value->setElementId();\n        }\n        foreach ($this->commentsRangeStart->getItems() as $comment) {\n            if ($value->getElementId() == $comment->getElementId()) {\n                return;\n            }\n        }\n        $idxItem = $this->commentsRangeStart->addItem($value);\n        $this->commentsRangeStart->getItem($idxItem)->setStartElement($this);\n    }\n\n    /**\n     * Get comments end.\n     */\n    public function getCommentsRangeEnd(): ?Comments\n    {\n        return $this->commentsRangeEnd;\n    }\n\n    /**\n     * Get comment end.\n     */\n    public function getCommentRangeEnd(): ?Comment\n    {\n        if ($this->commentsRangeEnd != null) {\n            return $this->commentsRangeEnd->getItem($this->commentsRangeEnd->countItems());\n        }\n\n        return null;\n    }\n\n    /**\n     * Set comment end.\n     */\n    public function setCommentRangeEnd(Comment $value): void\n    {\n        if ($this instanceof Comment) {\n            throw new InvalidArgumentException('Cannot set a Comment on a Comment');\n        }\n        if ($this->commentsRangeEnd == null) {\n            $this->commentsRangeEnd = new Comments();\n        }\n        // Set ID early to avoid duplicates.\n        if ($value->getElementId() == null) {\n            $value->setElementId();\n        }\n        foreach ($this->commentsRangeEnd->getItems() as $comment) {\n            if ($value->getElementId() == $comment->getElementId()) {\n                return;\n            }\n        }\n        $idxItem = $this->commentsRangeEnd->addItem($value);\n        $this->commentsRangeEnd->getItem($idxItem)->setEndElement($this);\n    }\n\n    /**\n     * Get parent element.\n     *\n     * @return null|AbstractElement\n     */\n    public function getParent()\n    {\n        return $this->parent;\n    }\n\n    /**\n     * Set parent container.\n     *\n     * Passed parameter should be a container, except for Table (contain Row) and Row (contain Cell)\n     */\n    public function setParentContainer(self $container): void\n    {\n        $this->parentContainer = substr(get_class($container), strrpos(get_class($container), '\\\\') + 1);\n        $this->parent = $container;\n\n        // Set nested level\n        $this->nestedLevel = $container->getNestedLevel();\n        if ($this->parentContainer == 'Cell') {\n            ++$this->nestedLevel;\n        }\n\n        // Set phpword\n        $this->setPhpWord($container->getPhpWord());\n\n        // Set doc part\n        if (!$this instanceof Footnote) {\n            $this->setDocPart($container->getDocPart(), $container->getDocPartId());\n        }\n\n        $this->setMediaRelation();\n        $this->setCollectionRelation();\n    }\n\n    /**\n     * Set relation Id for media elements (link, image, object; legacy of OOXML).\n     *\n     * - Image element needs to be passed to Media object\n     * - Icon needs to be set for Object element\n     */\n    private function setMediaRelation(): void\n    {\n        if (!$this instanceof Link && !$this instanceof Image && !$this instanceof OLEObject) {\n            return;\n        }\n\n        $elementName = substr(static::class, strrpos(static::class, '\\\\') + 1);\n        if ($elementName == 'OLEObject') {\n            $elementName = 'Object';\n        }\n        $mediaPart = $this->getMediaPart();\n        $source = $this->getSource();\n        $image = null;\n        if ($this instanceof Image) {\n            $image = $this;\n        }\n        $rId = Media::addElement($mediaPart, strtolower($elementName), $source, $image);\n        $this->setRelationId($rId);\n\n        if ($this instanceof OLEObject) {\n            $icon = $this->getIcon();\n            $rId = Media::addElement($mediaPart, 'image', $icon, new Image($icon));\n            $this->setImageRelationId($rId);\n        }\n    }\n\n    /**\n     * Set relation Id for elements that will be registered in the Collection subnamespaces.\n     */\n    private function setCollectionRelation(): void\n    {\n        if ($this->collectionRelation === true && $this->phpWord instanceof PhpWord) {\n            $elementName = substr(static::class, strrpos(static::class, '\\\\') + 1);\n            $addMethod = \"add{$elementName}\";\n            $rId = $this->phpWord->$addMethod($this);\n            $this->setRelationId($rId);\n        }\n    }\n\n    /**\n     * Check if element is located in Section doc part (as opposed to Header/Footer).\n     *\n     * @return bool\n     */\n    public function isInSection()\n    {\n        return $this->docPart == 'Section';\n    }\n\n    /**\n     * Set new style value.\n     *\n     * @param mixed $styleObject Style object\n     * @param null|array|string|Style $styleValue Style value\n     * @param bool $returnObject Always return object\n     *\n     * @return mixed\n     */\n    protected function setNewStyle($styleObject, $styleValue = null, $returnObject = false)\n    {\n        if (null !== $styleValue && is_array($styleValue)) {\n            $styleObject->setStyleByArray($styleValue);\n            $style = $styleObject;\n        } else {\n            $style = $returnObject ? $styleObject : $styleValue;\n        }\n\n        return $style;\n    }\n\n    /**\n     * Sets the trackChange information.\n     */\n    public function setTrackChange(TrackChange $trackChange): void\n    {\n        $this->trackChange = $trackChange;\n    }\n\n    /**\n     * Gets the trackChange information.\n     *\n     * @return TrackChange\n     */\n    public function getTrackChange()\n    {\n        return $this->trackChange;\n    }\n\n    /**\n     * Set changed.\n     *\n     * @param string $type INSERTED|DELETED\n     * @param string $author\n     * @param null|DateTime|int $date allways in UTC\n     */\n    public function setChangeInfo($type, $author, $date = null): void\n    {\n        $this->trackChange = new TrackChange($type, $author, $date);\n    }\n\n    /**\n     * Set enum value.\n     *\n     * @param null|string $value\n     * @param string[] $enum\n     * @param null|string $default\n     *\n     * @return null|string\n     *\n     * @todo Merge with the same method in AbstractStyle\n     */\n    protected function setEnumVal($value = null, $enum = [], $default = null)\n    {\n        if ($value !== null && trim($value) != '' && !empty($enum) && !in_array($value, $enum)) {\n            throw new InvalidArgumentException(\"Invalid style value: {$value}\");\n        } elseif ($value === null || trim($value) == '') {\n            $value = $default;\n        }\n\n        return $value;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/Bookmark.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\nuse PhpOffice\\PhpWord\\Shared\\Text as SharedText;\n\n/**\n * Bookmark element.\n */\nclass Bookmark extends AbstractElement\n{\n    /**\n     * Bookmark Name.\n     *\n     * @var string\n     */\n    private $name;\n\n    /**\n     * Is part of collection.\n     *\n     * @var bool\n     */\n    protected $collectionRelation = true;\n\n    /**\n     * Create a new Bookmark Element.\n     *\n     * @param string $name\n     */\n    public function __construct($name = '')\n    {\n        $this->name = SharedText::toUTF8($name);\n    }\n\n    /**\n     * Get Bookmark name.\n     *\n     * @return string\n     */\n    public function getName()\n    {\n        return $this->name;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/Cell.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\nuse PhpOffice\\PhpWord\\Style\\Cell as CellStyle;\n\n/**\n * Table cell element.\n */\nclass Cell extends AbstractContainer\n{\n    /**\n     * @var string Container type\n     */\n    protected $container = 'Cell';\n\n    /**\n     * Cell width.\n     *\n     * @var ?int\n     */\n    private $width;\n\n    /**\n     * Cell style.\n     *\n     * @var ?CellStyle\n     */\n    private $style;\n\n    /**\n     * Create new instance.\n     *\n     * @param null|int $width\n     * @param array|CellStyle $style\n     */\n    public function __construct($width = null, $style = null)\n    {\n        $this->width = $width;\n        $this->style = $this->setNewStyle(new CellStyle(), $style, true);\n    }\n\n    /**\n     * Get cell style.\n     *\n     * @return ?CellStyle\n     */\n    public function getStyle()\n    {\n        return $this->style;\n    }\n\n    /**\n     * Get cell width.\n     *\n     * @return ?int\n     */\n    public function getWidth()\n    {\n        return $this->width;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/Chart.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\nuse PhpOffice\\PhpWord\\Style\\Chart as ChartStyle;\n\n/**\n * Chart element.\n *\n * @since 0.12.0\n */\nclass Chart extends AbstractElement\n{\n    /**\n     * Is part of collection.\n     *\n     * @var bool\n     */\n    protected $collectionRelation = true;\n\n    /**\n     * Type.\n     *\n     * @var string\n     */\n    private $type = 'pie';\n\n    /**\n     * Series.\n     *\n     * @var array\n     */\n    private $series = [];\n\n    /**\n     * Chart style.\n     *\n     * @var ?ChartStyle\n     */\n    private $style;\n\n    /**\n     * Create new instance.\n     *\n     * @param string $type\n     * @param array $categories\n     * @param array $values\n     * @param array $style\n     * @param null|mixed $seriesName\n     */\n    public function __construct($type, $categories, $values, $style = null, $seriesName = null)\n    {\n        $this->setType($type);\n        $this->addSeries($categories, $values, $seriesName);\n        $this->style = $this->setNewStyle(new ChartStyle(), $style, true);\n    }\n\n    /**\n     * Get type.\n     *\n     * @return string\n     */\n    public function getType()\n    {\n        return $this->type;\n    }\n\n    /**\n     * Set type.\n     *\n     * @param string $value\n     */\n    public function setType($value): void\n    {\n        $enum = ['pie', 'doughnut', 'line', 'bar', 'stacked_bar', 'percent_stacked_bar', 'column', 'stacked_column', 'percent_stacked_column', 'area', 'radar', 'scatter'];\n        $this->type = $this->setEnumVal($value, $enum, 'pie');\n    }\n\n    /**\n     * Add series.\n     *\n     * @param array $categories\n     * @param array $values\n     * @param null|mixed $name\n     */\n    public function addSeries($categories, $values, $name = null): void\n    {\n        $this->series[] = [\n            'categories' => $categories,\n            'values' => $values,\n            'name' => $name,\n        ];\n    }\n\n    /**\n     * Get series.\n     *\n     * @return array\n     */\n    public function getSeries()\n    {\n        return $this->series;\n    }\n\n    /**\n     * Get chart style.\n     *\n     * @return ?ChartStyle\n     */\n    public function getStyle()\n    {\n        return $this->style;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/CheckBox.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\nuse PhpOffice\\PhpWord\\Shared\\Text as SharedText;\n\n/**\n * Check box element.\n *\n * @since 0.10.0\n */\nclass CheckBox extends Text\n{\n    /**\n     * Name content.\n     *\n     * @var string\n     */\n    private $name;\n\n    /**\n     * Create new instance.\n     *\n     * @param string $name\n     * @param string $text\n     * @param mixed $fontStyle\n     * @param mixed $paragraphStyle\n     */\n    public function __construct($name = null, $text = null, $fontStyle = null, $paragraphStyle = null)\n    {\n        $this->setName($name);\n        parent::__construct($text, $fontStyle, $paragraphStyle);\n    }\n\n    /**\n     * Set name content.\n     *\n     * @param string $name\n     *\n     * @return self\n     */\n    public function setName($name)\n    {\n        $this->name = SharedText::toUTF8($name);\n\n        return $this;\n    }\n\n    /**\n     * Get name content.\n     *\n     * @return string\n     */\n    public function getName()\n    {\n        return $this->name;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/Comment.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\nuse DateTime;\n\n/**\n * Comment element.\n *\n * @see http://datypic.com/sc/ooxml/t-w_CT_Comment.html\n */\nclass Comment extends TrackChange\n{\n    /**\n     * Initials.\n     *\n     * @var string\n     */\n    private $initials;\n\n    /**\n     * The Element where this comment starts.\n     *\n     * @var AbstractElement\n     */\n    private $startElement;\n\n    /**\n     * The Element where this comment ends.\n     *\n     * @var AbstractElement\n     */\n    private $endElement;\n\n    /**\n     * Is part of collection.\n     *\n     * @var bool\n     */\n    protected $collectionRelation = true;\n\n    /**\n     * Create a new Comment Element.\n     *\n     * @param string $author\n     * @param null|DateTime $date\n     * @param string $initials\n     */\n    public function __construct($author, $date = null, $initials = null)\n    {\n        parent::__construct(null, $author, $date);\n        $this->initials = $initials;\n    }\n\n    /**\n     * Get Initials.\n     *\n     * @return string\n     */\n    public function getInitials()\n    {\n        return $this->initials;\n    }\n\n    /**\n     * Sets the element where this comment starts.\n     */\n    public function setStartElement(AbstractElement $value): void\n    {\n        $this->startElement = $value;\n        $value->setCommentRangeStart($this);\n    }\n\n    /**\n     * Get the element where this comment starts.\n     *\n     * @return AbstractElement\n     */\n    public function getStartElement()\n    {\n        return $this->startElement;\n    }\n\n    /**\n     * Sets the element where this comment ends.\n     */\n    public function setEndElement(AbstractElement $value): void\n    {\n        $this->endElement = $value;\n        $value->setCommentRangeEnd($this);\n    }\n\n    /**\n     * Get the element where this comment ends.\n     *\n     * @return AbstractElement\n     */\n    public function getEndElement()\n    {\n        return $this->endElement;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/Endnote.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\n/**\n * Endnote element.\n *\n * @since 0.10.0\n */\nclass Endnote extends Footnote\n{\n    /**\n     * @var string Container type\n     */\n    protected $container = 'Endnote';\n\n    /**\n     * Create new instance.\n     *\n     * @param array|\\PhpOffice\\PhpWord\\Style\\Paragraph|string $paragraphStyle\n     */\n    public function __construct($paragraphStyle = null)\n    {\n        parent::__construct($paragraphStyle);\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/Field.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\nuse InvalidArgumentException;\nuse PhpOffice\\PhpWord\\Style\\Font;\n\n/**\n * Field element.\n *\n * @since 0.11.0\n * @see  http://www.schemacentral.com/sc/ooxml/t-w_CT_SimpleField.html\n */\nclass Field extends AbstractElement\n{\n    /**\n     * Field properties and options. Depending on type, a field can have different properties\n     * and options.\n     *\n     * @var array\n     */\n    protected $fieldsArray = [\n        'PAGE' => [\n            'properties' => [\n                'format' => ['Arabic', 'ArabicDash', 'alphabetic', 'ALPHABETIC', 'roman', 'ROMAN'],\n            ],\n            'options' => ['PreserveFormat'],\n        ],\n        'NUMPAGES' => [\n            'properties' => [\n                'format' => ['Arabic', 'ArabicDash', 'CardText', 'DollarText', 'Ordinal', 'OrdText',\n                    'alphabetic', 'ALPHABETIC', 'roman', 'ROMAN', 'Caps', 'FirstCap', 'Lower', 'Upper', ],\n                'numformat' => ['0', '0,00', '#.##0', '#.##0,00', '€ #.##0,00(€ #.##0,00)', '0%', '0,00%'],\n            ],\n            'options' => ['PreserveFormat'],\n        ],\n        'DATE' => [\n            'properties' => [\n                'dateformat' => [\n                    // Generic formats\n                    'yyyy-MM-dd', 'yyyy-MM', 'MMM-yy', 'MMM-yyyy', 'h:mm am/pm', 'h:mm:ss am/pm', 'HH:mm', 'HH:mm:ss',\n                    // Day-Month-Year formats\n                    'dddd d MMMM yyyy', 'd MMMM yyyy', 'd-MMM-yy', 'd MMM. yy',\n                    'd-M-yy', 'd-M-yy h:mm', 'd-M-yy h:mm:ss', 'd-M-yy h:mm am/pm', 'd-M-yy h:mm:ss am/pm', 'd-M-yy HH:mm', 'd-M-yy HH:mm:ss',\n                    'd/M/yy', 'd/M/yy h:mm', 'd/M/yy h:mm:ss', 'd/M/yy h:mm am/pm', 'd/M/yy h:mm:ss am/pm', 'd/M/yy HH:mm', 'd/M/yy HH:mm:ss',\n                    'd-M-yyyy', 'd-M-yyyy h:mm', 'd-M-yyyy h:mm:ss', 'd-M-yyyy h:mm am/pm', 'd-M-yyyy h:mm:ss am/pm', 'd-M-yyyy HH:mm', 'd-M-yyyy HH:mm:ss',\n                    'd/M/yyyy', 'd/M/yyyy h:mm', 'd/M/yyyy h:mm:ss', 'd/M/yyyy h:mm am/pm', 'd/M/yyyy h:mm:ss am/pm', 'd/M/yyyy HH:mm', 'd/M/yyyy HH:mm:ss',\n                    // Month-Day-Year formats\n                    'dddd, MMMM d yyyy', 'MMMM d yyyy', 'MMM-d-yy', 'MMM. d yy',\n                    'M-d-yy', 'M-d-yy h:mm', 'M-d-yy h:mm:ss', 'M-d-yy h:mm am/pm', 'M-d-yy h:mm:ss am/pm', 'M-d-yy HH:mm', 'M-d-yy HH:mm:ss',\n                    'M/d/yy', 'M/d/yy h:mm', 'M/d/yy h:mm:ss', 'M/d/yy h:mm am/pm', 'M/d/yy h:mm:ss am/pm', 'M/d/yy HH:mm', 'M/d/yy HH:mm:ss',\n                    'M-d-yyyy', 'M-d-yyyy h:mm', 'M-d-yyyy h:mm:ss', 'M-d-yyyy h:mm am/pm', 'M-d-yyyy h:mm:ss am/pm', 'M-d-yyyy HH:mm', 'M-d-yyyy HH:mm:ss',\n                    'M/d/yyyy', 'M/d/yyyy h:mm', 'M/d/yyyy h:mm:ss', 'M/d/yyyy h:mm am/pm', 'M/d/yyyy h:mm:ss am/pm', 'M/d/yyyy HH:mm', 'M/d/yyyy HH:mm:ss',\n                ],\n            ],\n            'options' => ['PreserveFormat', 'LunarCalendar', 'SakaEraCalendar', 'LastUsedFormat'],\n        ],\n        'MACROBUTTON' => [\n            'properties' => ['macroname' => ''],\n        ],\n        'XE' => [\n            'properties' => [],\n            'options' => ['Bold', 'Italic'],\n        ],\n        'INDEX' => [\n            'properties' => [],\n            'options' => ['PreserveFormat'],\n        ],\n        'STYLEREF' => [\n            'properties' => ['StyleIdentifier' => ''],\n            'options' => ['PreserveFormat'],\n        ],\n        'FILENAME' => [\n            'properties' => [\n                'format' => ['Upper', 'Lower', 'FirstCap', 'Caps'],\n            ],\n            'options' => ['Path', 'PreserveFormat'],\n        ],\n        'REF' => [\n            'properties' => ['name' => ''],\n            'options' => ['f', 'h', 'n', 'p', 'r', 't', 'w'],\n        ],\n    ];\n\n    /**\n     * Field type.\n     *\n     * @var string\n     */\n    protected $type;\n\n    /**\n     * Field text.\n     *\n     * @var null|string|TextRun\n     */\n    protected $text;\n\n    /**\n     * Field properties.\n     *\n     * @var array\n     */\n    protected $properties = [];\n\n    /**\n     * Field options.\n     *\n     * @var array\n     */\n    protected $options = [];\n\n    /**\n     * Font style.\n     *\n     * @var Font|string\n     */\n    protected $fontStyle;\n\n    /**\n     * Set Font style.\n     *\n     * @param array|Font|string $style\n     *\n     * @return Font|string\n     */\n    public function setFontStyle($style = null)\n    {\n        if ($style instanceof Font) {\n            $this->fontStyle = $style;\n        } elseif (is_array($style)) {\n            $this->fontStyle = new Font('text');\n            $this->fontStyle->setStyleByArray($style);\n        } elseif (null === $style) {\n            $this->fontStyle = null;\n        } else {\n            $this->fontStyle = $style;\n        }\n\n        return $this->fontStyle;\n    }\n\n    /**\n     * Get Font style.\n     *\n     * @return Font|string\n     */\n    public function getFontStyle()\n    {\n        return $this->fontStyle;\n    }\n\n    /**\n     * Create a new Field Element.\n     *\n     * @param string $type\n     * @param array $properties\n     * @param array $options\n     * @param null|string|TextRun $text\n     * @param array|Font|string $fontStyle\n     */\n    public function __construct($type = null, $properties = [], $options = [], $text = null, $fontStyle = null)\n    {\n        $this->setType($type);\n        $this->setProperties($properties);\n        $this->setOptions($options);\n        $this->setText($text);\n        $this->setFontStyle($fontStyle);\n    }\n\n    /**\n     * Set Field type.\n     *\n     * @param string $type\n     *\n     * @return string\n     */\n    public function setType($type = null)\n    {\n        if (isset($type)) {\n            if (isset($this->fieldsArray[$type])) {\n                $this->type = $type;\n            } else {\n                throw new InvalidArgumentException(\"Invalid type '$type'\");\n            }\n        }\n\n        return $this->type;\n    }\n\n    /**\n     * Get Field type.\n     *\n     * @return string\n     */\n    public function getType()\n    {\n        return $this->type;\n    }\n\n    /**\n     * Set Field properties.\n     *\n     * @return self\n     */\n    public function setProperties(array $properties = [])\n    {\n        foreach (array_keys($properties) as $propkey) {\n            if (!(isset($this->fieldsArray[$this->type]['properties'][$propkey]))) {\n                throw new InvalidArgumentException(\"Invalid property '$propkey'\");\n            }\n        }\n        $this->properties = array_merge($this->properties, $properties);\n\n        return $this;\n    }\n\n    /**\n     * Get Field properties.\n     *\n     * @return array\n     */\n    public function getProperties()\n    {\n        return $this->properties;\n    }\n\n    /**\n     * Set Field options.\n     *\n     * @return self\n     */\n    public function setOptions(array $options = [])\n    {\n        foreach (array_keys($options) as $optionkey) {\n            if (!(isset($this->fieldsArray[$this->type]['options'][$optionkey])) && substr($optionkey, 0, 1) !== '\\\\') {\n                throw new InvalidArgumentException(\"Invalid option '$optionkey', possible values are \" . implode(', ', $this->fieldsArray[$this->type]['options']));\n            }\n        }\n        $this->options = array_merge($this->options, $options);\n\n        return $this;\n    }\n\n    /**\n     * Get Field properties.\n     *\n     * @return array\n     */\n    public function getOptions()\n    {\n        return $this->options;\n    }\n\n    /**\n     * Set Field text.\n     *\n     * @param null|mixed|string|TextRun $text\n     *\n     * @return null|string|TextRun\n     */\n    public function setText($text = null)\n    {\n        if (null !== $text) {\n            if (is_string($text) || $text instanceof TextRun) {\n                $this->text = $text;\n            } else {\n                throw new InvalidArgumentException('Invalid text');\n            }\n        }\n\n        return $this->text;\n    }\n\n    /**\n     * Get Field text.\n     *\n     * @return string|TextRun\n     */\n    public function getText()\n    {\n        return $this->text;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/Footer.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\n/**\n * Footer element.\n */\nclass Footer extends AbstractContainer\n{\n    /**\n     * Header/footer types constants.\n     *\n     * @var string\n     *\n     * @see  http://www.datypic.com/sc/ooxml/t-w_ST_HdrFtr.html Header or Footer Type\n     */\n    const AUTO = 'default';  // default and odd pages\n    const FIRST = 'first';\n    const EVEN = 'even';\n\n    /**\n     * @var string Container type\n     */\n    protected $container = 'Footer';\n\n    /**\n     * Header type.\n     *\n     * @var string\n     */\n    protected $type = self::AUTO;\n\n    /**\n     * Create new instance.\n     *\n     * @param int $sectionId\n     * @param int $containerId\n     * @param string $type\n     */\n    public function __construct($sectionId, $containerId = 1, $type = self::AUTO)\n    {\n        $this->sectionId = $sectionId;\n        $this->setType($type);\n        $this->setDocPart($this->container, ($sectionId - 1) * 3 + $containerId);\n    }\n\n    /**\n     * Set type.\n     *\n     * @since 0.10.0\n     *\n     * @param string $value\n     */\n    public function setType($value = self::AUTO): void\n    {\n        if (!in_array($value, [self::AUTO, self::FIRST, self::EVEN])) {\n            $value = self::AUTO;\n        }\n        $this->type = $value;\n    }\n\n    /**\n     * Get type.\n     *\n     * @return string\n     *\n     * @since 0.10.0\n     */\n    public function getType()\n    {\n        return $this->type;\n    }\n\n    /**\n     * Reset type to default.\n     *\n     * @return string\n     */\n    public function resetType()\n    {\n        return $this->type = self::AUTO;\n    }\n\n    /**\n     * First page only header.\n     *\n     * @return string\n     */\n    public function firstPage()\n    {\n        return $this->type = self::FIRST;\n    }\n\n    /**\n     * Even numbered pages only.\n     *\n     * @return string\n     */\n    public function evenPage()\n    {\n        return $this->type = self::EVEN;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/Footnote.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\nuse PhpOffice\\PhpWord\\Style\\Paragraph;\n\nclass Footnote extends AbstractContainer\n{\n    /**\n     * @var string Container type\n     */\n    protected $container = 'Footnote';\n\n    /**\n     * Paragraph style.\n     *\n     * @var null|Paragraph|string\n     */\n    protected $paragraphStyle;\n\n    /**\n     * Is part of collection.\n     *\n     * @var bool\n     */\n    protected $collectionRelation = true;\n\n    /**\n     * Create new instance.\n     *\n     * @param array|Paragraph|string $paragraphStyle\n     */\n    public function __construct($paragraphStyle = null)\n    {\n        $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle);\n        $this->setDocPart($this->container);\n    }\n\n    /**\n     * Get paragraph style.\n     *\n     * @return null|Paragraph|string\n     */\n    public function getParagraphStyle()\n    {\n        return $this->paragraphStyle;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/FormField.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\n/**\n * Form field element.\n *\n * @since 0.12.0\n * @see  http://www.datypic.com/sc/ooxml/t-w_CT_FFData.html\n */\nclass FormField extends Text\n{\n    /**\n     * Form field type: textinput|checkbox|dropdown.\n     *\n     * @var string\n     */\n    private $type = 'textinput';\n\n    /**\n     * Form field name.\n     *\n     * @var ?string\n     */\n    private $name;\n\n    /**\n     * Default value.\n     *\n     * - TextInput: string\n     * - CheckBox: bool\n     * - DropDown: int Index of entries (zero based)\n     *\n     * @var bool|int|string\n     */\n    private $default;\n\n    /**\n     * Value.\n     *\n     * @var null|bool|int|string\n     */\n    private $value;\n\n    /**\n     * Dropdown entries.\n     *\n     * @var array\n     */\n    private $entries = [];\n\n    /**\n     * Create new instance.\n     *\n     * @param string $type\n     * @param mixed $fontStyle\n     * @param mixed $paragraphStyle\n     */\n    public function __construct($type, $fontStyle = null, $paragraphStyle = null)\n    {\n        parent::__construct(null, $fontStyle, $paragraphStyle);\n        $this->setType($type);\n    }\n\n    /**\n     * Get type.\n     *\n     * @return string\n     */\n    public function getType()\n    {\n        return $this->type;\n    }\n\n    /**\n     * Set type.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setType($value)\n    {\n        $enum = ['textinput', 'checkbox', 'dropdown'];\n        $this->type = $this->setEnumVal($value, $enum, $this->type);\n\n        return $this;\n    }\n\n    /**\n     * Get name.\n     *\n     * @return ?string\n     */\n    public function getName()\n    {\n        return $this->name;\n    }\n\n    /**\n     * Set name.\n     *\n     * @param ?string $value\n     *\n     * @return self\n     */\n    public function setName($value)\n    {\n        $this->name = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get default.\n     *\n     * @return bool|int|string\n     */\n    public function getDefault()\n    {\n        return $this->default;\n    }\n\n    /**\n     * Set default.\n     *\n     * @param bool|int|string $value\n     *\n     * @return self\n     */\n    public function setDefault($value)\n    {\n        $this->default = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get value.\n     *\n     * @return null|bool|int|string\n     */\n    public function getValue()\n    {\n        return $this->value;\n    }\n\n    /**\n     * Set value.\n     *\n     * @param null|bool|int|string $value\n     *\n     * @return self\n     */\n    public function setValue($value)\n    {\n        $this->value = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get entries.\n     *\n     * @return array\n     */\n    public function getEntries()\n    {\n        return $this->entries;\n    }\n\n    /**\n     * Set entries.\n     *\n     * @param array $value\n     *\n     * @return self\n     */\n    public function setEntries($value)\n    {\n        $this->entries = $value;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/Formula.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\ndeclare(strict_types=1);\n\nnamespace PhpOffice\\PhpWord\\Element;\n\nuse PhpOffice\\Math\\Math;\n\n/**\n * Formula element.\n */\nclass Formula extends AbstractElement\n{\n    /**\n     * @var Math\n     */\n    protected $math;\n\n    /**\n     * Create a new Formula Element.\n     */\n    public function __construct(Math $math)\n    {\n        $this->setMath($math);\n    }\n\n    public function setMath(Math $math): self\n    {\n        $this->math = $math;\n\n        return $this;\n    }\n\n    public function getMath(): Math\n    {\n        return $this->math;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/Header.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\n/**\n * Header element.\n */\nclass Header extends Footer\n{\n    /**\n     * @var string Container type\n     */\n    protected $container = 'Header';\n\n    /**\n     * Add a Watermark Element.\n     *\n     * @param string $src\n     * @param mixed $style\n     *\n     * @return Image\n     */\n    public function addWatermark($src, $style = null)\n    {\n        return $this->addImage($src, $style, true);\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/Image.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\nuse PhpOffice\\PhpWord\\Exception\\CreateTemporaryFileException;\nuse PhpOffice\\PhpWord\\Exception\\InvalidImageException;\nuse PhpOffice\\PhpWord\\Exception\\UnsupportedImageTypeException;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Shared\\ZipArchive;\nuse PhpOffice\\PhpWord\\Style\\Image as ImageStyle;\n\n/**\n * Image element.\n */\nclass Image extends AbstractElement\n{\n    /**\n     * Image source type constants.\n     */\n    const SOURCE_LOCAL = 'local'; // Local images\n    const SOURCE_GD = 'gd'; // Generated using GD\n    const SOURCE_ARCHIVE = 'archive'; // Image in archives zip://$archive#$image\n    const SOURCE_STRING = 'string'; // Image from string\n\n    /**\n     * Image source.\n     *\n     * @var string\n     */\n    private $source;\n\n    /**\n     * Source type: local|gd|archive.\n     *\n     * @var string\n     */\n    private $sourceType;\n\n    /**\n     * Image style.\n     *\n     * @var ?ImageStyle\n     */\n    private $style;\n\n    /**\n     * Is watermark.\n     *\n     * @var bool\n     */\n    private $watermark;\n\n    /**\n     * Name of image.\n     *\n     * @var string\n     */\n    private $name;\n\n    /**\n     * Image type.\n     *\n     * @var string\n     */\n    private $imageType;\n\n    /**\n     * Image create function.\n     *\n     * @var string\n     */\n    private $imageCreateFunc;\n\n    /**\n     * Image function.\n     *\n     * @var null|callable(resource): void\n     */\n    private $imageFunc;\n\n    /**\n     * Image extension.\n     *\n     * @var string\n     */\n    private $imageExtension;\n\n    /**\n     * Image quality.\n     *\n     * Functions imagepng() and imagejpeg() have an optional parameter for\n     * quality.\n     *\n     * @var null|int\n     */\n    private $imageQuality;\n\n    /**\n     * Is memory image.\n     *\n     * @var bool\n     */\n    private $memoryImage;\n\n    /**\n     * Image target file name.\n     *\n     * @var string\n     */\n    private $target;\n\n    /**\n     * Image media index.\n     *\n     * @var int\n     */\n    private $mediaIndex;\n\n    /**\n     * Has media relation flag; true for Link, Image, and Object.\n     *\n     * @var bool\n     */\n    protected $mediaRelation = true;\n\n    /**\n     * Create new image element.\n     *\n     * @param string $source\n     * @param mixed $style\n     * @param bool $watermark\n     * @param string $name\n     */\n    public function __construct($source, $style = null, $watermark = false, $name = null)\n    {\n        $this->source = $source;\n        $this->style = $this->setNewStyle(new ImageStyle(), $style, true);\n        $this->setIsWatermark($watermark);\n        $this->setName($name);\n\n        $this->checkImage();\n    }\n\n    /**\n     * Get Image style.\n     *\n     * @return ?ImageStyle\n     */\n    public function getStyle()\n    {\n        return $this->style;\n    }\n\n    /**\n     * Get image source.\n     *\n     * @return string\n     */\n    public function getSource()\n    {\n        return $this->source;\n    }\n\n    /**\n     * Get image source type.\n     *\n     * @return string\n     */\n    public function getSourceType()\n    {\n        return $this->sourceType;\n    }\n\n    /**\n     * Sets the image name.\n     *\n     * @param string $value\n     */\n    public function setName($value): void\n    {\n        $this->name = $value;\n    }\n\n    /**\n     * Get image name.\n     *\n     * @return null|string\n     */\n    public function getName()\n    {\n        return $this->name;\n    }\n\n    /**\n     * Get image media ID.\n     *\n     * @return string\n     */\n    public function getMediaId()\n    {\n        return md5($this->source);\n    }\n\n    /**\n     * Get is watermark.\n     *\n     * @return bool\n     */\n    public function isWatermark()\n    {\n        return $this->watermark;\n    }\n\n    /**\n     * Set is watermark.\n     *\n     * @param bool $value\n     */\n    public function setIsWatermark($value): void\n    {\n        $this->watermark = $value;\n    }\n\n    /**\n     * Get image type.\n     *\n     * @return string\n     */\n    public function getImageType()\n    {\n        return $this->imageType;\n    }\n\n    /**\n     * Get image create function.\n     *\n     * @return string\n     */\n    public function getImageCreateFunction()\n    {\n        return $this->imageCreateFunc;\n    }\n\n    /**\n     * Get image function.\n     *\n     * @return null|callable(resource): void\n     */\n    public function getImageFunction(): ?callable\n    {\n        return $this->imageFunc;\n    }\n\n    /**\n     * Get image quality.\n     */\n    public function getImageQuality(): ?int\n    {\n        return $this->imageQuality;\n    }\n\n    /**\n     * Get image extension.\n     *\n     * @return string\n     */\n    public function getImageExtension()\n    {\n        return $this->imageExtension;\n    }\n\n    /**\n     * Get is memory image.\n     *\n     * @return bool\n     */\n    public function isMemImage()\n    {\n        return $this->memoryImage;\n    }\n\n    /**\n     * Get target file name.\n     *\n     * @return string\n     */\n    public function getTarget()\n    {\n        return $this->target;\n    }\n\n    /**\n     * Set target file name.\n     *\n     * @param string $value\n     */\n    public function setTarget($value): void\n    {\n        $this->target = $value;\n    }\n\n    /**\n     * Get media index.\n     *\n     * @return int\n     */\n    public function getMediaIndex()\n    {\n        return $this->mediaIndex;\n    }\n\n    /**\n     * Set media index.\n     *\n     * @param int $value\n     */\n    public function setMediaIndex($value): void\n    {\n        $this->mediaIndex = $value;\n    }\n\n    /**\n     * Get image string.\n     */\n    public function getImageString(): ?string\n    {\n        $source = $this->source;\n        $actualSource = null;\n        $imageBinary = null;\n        $isTemp = false;\n\n        // Get actual source from archive image or other source\n        // Return null if not found\n        if ($this->sourceType == self::SOURCE_ARCHIVE) {\n            $source = substr($source, 6);\n            [$zipFilename, $imageFilename] = explode('#', $source);\n\n            $zip = new ZipArchive();\n            if ($zip->open($zipFilename) !== false) {\n                if ($zip->locateName($imageFilename) !== false) {\n                    $isTemp = true;\n                    $zip->extractTo(Settings::getTempDir(), $imageFilename);\n                    $actualSource = Settings::getTempDir() . DIRECTORY_SEPARATOR . $imageFilename;\n                }\n            }\n            $zip->close();\n        } else {\n            $actualSource = $source;\n        }\n\n        // Can't find any case where $actualSource = null hasn't captured by\n        // preceding exceptions. Please uncomment when you find the case and\n        // put the case into Element\\ImageTest.\n        // if ($actualSource === null) {\n        //     return null;\n        // }\n\n        // Read image binary data and convert to hex/base64 string\n        if ($this->sourceType == self::SOURCE_GD) {\n            $imageResource = call_user_func($this->imageCreateFunc, $actualSource);\n            if ($this->imageType === 'image/png') {\n                // PNG images need to preserve alpha channel information\n                imagesavealpha($imageResource, true);\n            }\n            ob_start();\n            $callback = $this->imageFunc;\n            $callback($imageResource);\n            $imageBinary = ob_get_contents();\n            ob_end_clean();\n        } elseif ($this->sourceType == self::SOURCE_STRING) {\n            $imageBinary = $this->source;\n        } else {\n            $fileHandle = fopen($actualSource, 'rb', false);\n            $fileSize = filesize($actualSource);\n            if ($fileHandle !== false && $fileSize > 0) {\n                $imageBinary = fread($fileHandle, $fileSize);\n                fclose($fileHandle);\n            }\n        }\n\n        // Delete temporary file if necessary\n        if ($isTemp === true) {\n            @unlink($actualSource);\n        }\n\n        return $imageBinary;\n    }\n\n    /**\n     * Get image string data.\n     *\n     * @param bool $base64\n     *\n     * @return null|string\n     *\n     * @since 0.11.0\n     */\n    public function getImageStringData($base64 = false)\n    {\n        $imageBinary = $this->getImageString();\n        if ($imageBinary === null) {\n            return null;\n        }\n\n        if ($base64) {\n            return base64_encode($imageBinary);\n        }\n\n        return bin2hex($imageBinary);\n    }\n\n    /**\n     * Check memory image, supported type, image functions, and proportional width/height.\n     */\n    private function checkImage(): void\n    {\n        $this->setSourceType();\n\n        // Check image data\n        if ($this->sourceType == self::SOURCE_ARCHIVE) {\n            $imageData = $this->getArchiveImageSize($this->source);\n        } elseif ($this->sourceType == self::SOURCE_STRING) {\n            $imageData = @getimagesizefromstring($this->source);\n        } else {\n            $imageData = @getimagesize($this->source);\n        }\n        if (!is_array($imageData)) {\n            throw new InvalidImageException(sprintf('Invalid image: %s', $this->source));\n        }\n        [$actualWidth, $actualHeight, $imageType] = $imageData;\n\n        // Check image type support\n        $supportedTypes = [IMAGETYPE_JPEG, IMAGETYPE_GIF, IMAGETYPE_PNG];\n        if ($this->sourceType != self::SOURCE_GD && $this->sourceType != self::SOURCE_STRING) {\n            $supportedTypes = array_merge($supportedTypes, [IMAGETYPE_BMP, IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM]);\n        }\n        if (!in_array($imageType, $supportedTypes)) {\n            throw new UnsupportedImageTypeException();\n        }\n\n        // Define image functions\n        $this->imageType = image_type_to_mime_type($imageType);\n        $this->setFunctions();\n        $this->setProportionalSize($actualWidth, $actualHeight);\n    }\n\n    /**\n     * Set source type.\n     */\n    private function setSourceType(): void\n    {\n        if (stripos(strrev($this->source), strrev('.php')) === 0) {\n            $this->memoryImage = true;\n            $this->sourceType = self::SOURCE_GD;\n        } elseif (strpos($this->source, 'zip://') !== false) {\n            $this->memoryImage = false;\n            $this->sourceType = self::SOURCE_ARCHIVE;\n        } elseif (filter_var($this->source, FILTER_VALIDATE_URL) !== false) {\n            $this->memoryImage = true;\n            if (strpos($this->source, 'https') === 0) {\n                $fileContent = file_get_contents($this->source);\n                $this->source = $fileContent;\n                $this->sourceType = self::SOURCE_STRING;\n            } else {\n                $this->sourceType = self::SOURCE_GD;\n            }\n        } elseif ((strpos($this->source, chr(0)) === false) && @file_exists($this->source)) {\n            $this->memoryImage = false;\n            $this->sourceType = self::SOURCE_LOCAL;\n        } else {\n            $this->memoryImage = true;\n            $this->sourceType = self::SOURCE_STRING;\n        }\n    }\n\n    /**\n     * Get image size from archive.\n     *\n     * @since 0.12.0 Throws CreateTemporaryFileException.\n     *\n     * @param string $source\n     *\n     * @return null|array\n     */\n    private function getArchiveImageSize($source)\n    {\n        $imageData = null;\n        $source = substr($source, 6);\n        [$zipFilename, $imageFilename] = explode('#', $source);\n\n        $tempFilename = tempnam(Settings::getTempDir(), 'PHPWordImage');\n        if (false === $tempFilename) {\n            throw new CreateTemporaryFileException(); // @codeCoverageIgnore\n        }\n\n        $zip = new ZipArchive();\n        if ($zip->open($zipFilename) !== false) {\n            if ($zip->locateName($imageFilename) !== false) {\n                $imageContent = $zip->getFromName($imageFilename);\n                if ($imageContent !== false) {\n                    file_put_contents($tempFilename, $imageContent);\n                    $imageData = getimagesize($tempFilename);\n                    unlink($tempFilename);\n                }\n            }\n            $zip->close();\n        }\n\n        return $imageData;\n    }\n\n    /**\n     * Set image functions and extensions.\n     */\n    private function setFunctions(): void\n    {\n        switch ($this->imageType) {\n            case 'image/png':\n                $this->imageCreateFunc = $this->sourceType == self::SOURCE_STRING ? 'imagecreatefromstring' : 'imagecreatefrompng';\n                $this->imageFunc = function ($resource): void {\n                    imagepng($resource, null, $this->imageQuality);\n                };\n                $this->imageExtension = 'png';\n                $this->imageQuality = -1;\n\n                break;\n            case 'image/gif':\n                $this->imageCreateFunc = $this->sourceType == self::SOURCE_STRING ? 'imagecreatefromstring' : 'imagecreatefromgif';\n                $this->imageFunc = function ($resource): void {\n                    imagegif($resource);\n                };\n                $this->imageExtension = 'gif';\n                $this->imageQuality = null;\n\n                break;\n            case 'image/jpeg':\n            case 'image/jpg':\n                $this->imageCreateFunc = $this->sourceType == self::SOURCE_STRING ? 'imagecreatefromstring' : 'imagecreatefromjpeg';\n                $this->imageFunc = function ($resource): void {\n                    imagejpeg($resource, null, $this->imageQuality);\n                };\n                $this->imageExtension = 'jpg';\n                $this->imageQuality = 100;\n\n                break;\n            case 'image/bmp':\n            case 'image/x-ms-bmp':\n                $this->imageType = 'image/bmp';\n                $this->imageFunc = null;\n                $this->imageExtension = 'bmp';\n                $this->imageQuality = null;\n\n                break;\n            case 'image/tiff':\n                $this->imageType = 'image/tiff';\n                $this->imageFunc = null;\n                $this->imageExtension = 'tif';\n                $this->imageQuality = null;\n\n                break;\n        }\n    }\n\n    /**\n     * Set proportional width/height if one dimension not available.\n     *\n     * @param int $actualWidth\n     * @param int $actualHeight\n     */\n    private function setProportionalSize($actualWidth, $actualHeight): void\n    {\n        $styleWidth = $this->style->getWidth();\n        $styleHeight = $this->style->getHeight();\n        if (!($styleWidth && $styleHeight)) {\n            if ($styleWidth == null && $styleHeight == null) {\n                $this->style->setWidth($actualWidth);\n                $this->style->setHeight($actualHeight);\n            } elseif ($styleWidth) {\n                $this->style->setHeight($actualHeight * ($styleWidth / $actualWidth));\n            } else {\n                $this->style->setWidth($actualWidth * ($styleHeight / $actualHeight));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/Line.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\nuse PhpOffice\\PhpWord\\Style\\Line as LineStyle;\n\n/**\n * Line element.\n */\nclass Line extends AbstractElement\n{\n    /**\n     * Line style.\n     *\n     * @var ?LineStyle\n     */\n    private $style;\n\n    /**\n     * Create new line element.\n     *\n     * @param mixed $style\n     */\n    public function __construct($style = null)\n    {\n        $this->style = $this->setNewStyle(new LineStyle(), $style);\n    }\n\n    /**\n     * Get line style.\n     *\n     * @return ?LineStyle\n     */\n    public function getStyle()\n    {\n        return $this->style;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/Link.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\nuse PhpOffice\\PhpWord\\Shared\\Text as SharedText;\nuse PhpOffice\\PhpWord\\Style\\Font;\nuse PhpOffice\\PhpWord\\Style\\Paragraph;\n\n/**\n * Link element.\n */\nclass Link extends AbstractElement\n{\n    /**\n     * Link source.\n     *\n     * @var string\n     */\n    private $source;\n\n    /**\n     * Link text.\n     *\n     * @var string\n     */\n    private $text;\n\n    /**\n     * Font style.\n     *\n     * @var null|Font|string\n     */\n    private $fontStyle;\n\n    /**\n     * Paragraph style.\n     *\n     * @var null|Paragraph|string\n     */\n    private $paragraphStyle;\n\n    /**\n     * Has media relation flag; true for Link, Image, and Object.\n     *\n     * @var bool\n     */\n    protected $mediaRelation = true;\n\n    /**\n     * Has internal flag - anchor to internal bookmark.\n     *\n     * @var bool\n     */\n    protected $internal = false;\n\n    /**\n     * Create a new Link Element.\n     *\n     * @param string $source\n     * @param string $text\n     * @param mixed $fontStyle\n     * @param mixed $paragraphStyle\n     * @param bool $internal\n     */\n    public function __construct($source, $text = null, $fontStyle = null, $paragraphStyle = null, $internal = false)\n    {\n        $this->source = SharedText::toUTF8($source);\n        $this->text = null === $text ? $this->source : SharedText::toUTF8($text);\n        $this->fontStyle = $this->setNewStyle(new Font('text'), $fontStyle);\n        $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle);\n        $this->internal = $internal;\n    }\n\n    /**\n     * Get link source.\n     *\n     * @return string\n     */\n    public function getSource()\n    {\n        return $this->source;\n    }\n\n    /**\n     * Get link text.\n     */\n    public function getText(): string\n    {\n        return $this->text;\n    }\n\n    /**\n     * Get Text style.\n     *\n     * @return null|Font|string\n     */\n    public function getFontStyle()\n    {\n        return $this->fontStyle;\n    }\n\n    /**\n     * Get Paragraph style.\n     *\n     * @return null|Paragraph|string\n     */\n    public function getParagraphStyle()\n    {\n        return $this->paragraphStyle;\n    }\n\n    /**\n     * is internal.\n     *\n     * @return bool\n     */\n    public function isInternal()\n    {\n        return $this->internal;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/ListItem.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\nuse PhpOffice\\PhpWord\\Shared\\Text as SharedText;\nuse PhpOffice\\PhpWord\\Style\\ListItem as ListItemStyle;\n\n/**\n * List item element.\n */\nclass ListItem extends AbstractElement\n{\n    /**\n     * Element style.\n     *\n     * @var ?ListItemStyle\n     */\n    private $style;\n\n    /**\n     * Text object.\n     *\n     * @var Text\n     */\n    private $textObject;\n\n    /**\n     * Depth.\n     *\n     * @var int\n     */\n    private $depth;\n\n    /**\n     * Create a new ListItem.\n     *\n     * @param string $text\n     * @param int $depth\n     * @param mixed $fontStyle\n     * @param null|array|string $listStyle\n     * @param mixed $paragraphStyle\n     */\n    public function __construct($text, $depth = 0, $fontStyle = null, $listStyle = null, $paragraphStyle = null)\n    {\n        $this->textObject = new Text(SharedText::toUTF8($text), $fontStyle, $paragraphStyle);\n        $this->depth = $depth;\n\n        // Version >= 0.10.0 will pass numbering style name. Older version will use old method\n        if (null !== $listStyle && is_string($listStyle)) {\n            $this->style = new ListItemStyle($listStyle); // @codeCoverageIgnore\n        } else {\n            $this->style = $this->setNewStyle(new ListItemStyle(), $listStyle, true);\n        }\n    }\n\n    /**\n     * Get style.\n     *\n     * @return ?ListItemStyle\n     */\n    public function getStyle()\n    {\n        return $this->style;\n    }\n\n    /**\n     * Get Text object.\n     *\n     * @return Text\n     */\n    public function getTextObject()\n    {\n        return $this->textObject;\n    }\n\n    /**\n     * Get depth.\n     *\n     * @return int\n     */\n    public function getDepth()\n    {\n        return $this->depth;\n    }\n\n    /**\n     * Get text.\n     *\n     * @return string\n     *\n     * @since 0.11.0\n     */\n    public function getText()\n    {\n        return $this->textObject->getText();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/ListItemRun.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\nuse PhpOffice\\PhpWord\\Style\\ListItem as ListItemStyle;\n\n/**\n * List item element.\n */\nclass ListItemRun extends TextRun\n{\n    /**\n     * @var string Container type\n     */\n    protected $container = 'ListItemRun';\n\n    /**\n     * ListItem Style.\n     *\n     * @var ?ListItemStyle\n     */\n    private $style;\n\n    /**\n     * ListItem Depth.\n     *\n     * @var int\n     */\n    private $depth;\n\n    /**\n     * Create a new ListItem.\n     *\n     * @param int $depth\n     * @param null|array|string $listStyle\n     * @param mixed $paragraphStyle\n     */\n    public function __construct($depth = 0, $listStyle = null, $paragraphStyle = null)\n    {\n        $this->depth = $depth;\n\n        // Version >= 0.10.0 will pass numbering style name. Older version will use old method\n        if (null !== $listStyle && is_string($listStyle)) {\n            $this->style = new ListItemStyle($listStyle);\n        } else {\n            $this->style = $this->setNewStyle(new ListItemStyle(), $listStyle, true);\n        }\n        parent::__construct($paragraphStyle);\n    }\n\n    /**\n     * Get ListItem style.\n     *\n     * @return ?ListItemStyle\n     */\n    public function getStyle()\n    {\n        return $this->style;\n    }\n\n    /**\n     * Get ListItem depth.\n     *\n     * @return int\n     */\n    public function getDepth()\n    {\n        return $this->depth;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/OLEObject.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\nuse PhpOffice\\PhpWord\\Exception\\InvalidObjectException;\nuse PhpOffice\\PhpWord\\Style\\Image as ImageStyle;\n\n/**\n * OLEObject element.\n */\nclass OLEObject extends AbstractElement\n{\n    /**\n     * Ole-Object Src.\n     *\n     * @var string\n     */\n    private $source;\n\n    /**\n     * Image Style.\n     *\n     * @var ?ImageStyle\n     */\n    private $style;\n\n    /**\n     * Icon.\n     *\n     * @var string\n     */\n    private $icon;\n\n    /**\n     * Image Relation ID.\n     *\n     * @var int\n     */\n    private $imageRelationId;\n\n    /**\n     * Has media relation flag; true for Link, Image, and Object.\n     *\n     * @var bool\n     */\n    protected $mediaRelation = true;\n\n    /**\n     * Create a new Ole-Object Element.\n     *\n     * @param string $source\n     * @param mixed $style\n     */\n    public function __construct($source, $style = null)\n    {\n        $supportedTypes = ['xls', 'doc', 'ppt', 'xlsx', 'docx', 'pptx'];\n        $pathInfoExtension = pathinfo($source, PATHINFO_EXTENSION);\n\n        if (file_exists($source) && in_array($pathInfoExtension, $supportedTypes)) {\n            if (strlen($pathInfoExtension) == 4 && strtolower(substr($pathInfoExtension, -1)) == 'x') {\n                $pathInfoExtension = substr($pathInfoExtension, 0, -1);\n            }\n\n            $this->source = $source;\n            $this->style = $this->setNewStyle(new ImageStyle(), $style, true);\n            $this->icon = realpath(__DIR__ . \"/../resources/{$pathInfoExtension}.png\");\n\n            return;\n        }\n\n        throw new InvalidObjectException();\n    }\n\n    /**\n     * Get object source.\n     *\n     * @return string\n     */\n    public function getSource()\n    {\n        return $this->source;\n    }\n\n    /**\n     * Get object style.\n     *\n     * @return ?ImageStyle\n     */\n    public function getStyle()\n    {\n        return $this->style;\n    }\n\n    /**\n     * Get object icon.\n     *\n     * @return string\n     */\n    public function getIcon()\n    {\n        return $this->icon;\n    }\n\n    /**\n     * Get image relation ID.\n     *\n     * @return int\n     */\n    public function getImageRelationId()\n    {\n        return $this->imageRelationId;\n    }\n\n    /**\n     * Set Image Relation ID.\n     *\n     * @param int $rId\n     */\n    public function setImageRelationId($rId): void\n    {\n        $this->imageRelationId = $rId;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/PageBreak.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\n/**\n * Page break element.\n */\nclass PageBreak extends AbstractElement\n{\n    /**\n     * Create new page break.\n     */\n    public function __construct()\n    {\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/PreserveText.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\nuse PhpOffice\\PhpWord\\Shared\\Text as SharedText;\nuse PhpOffice\\PhpWord\\Style\\Font;\nuse PhpOffice\\PhpWord\\Style\\Paragraph;\n\n/**\n * Preserve text/field element.\n */\nclass PreserveText extends AbstractElement\n{\n    /**\n     * Text content.\n     *\n     * @var null|array|string\n     */\n    private $text;\n\n    /**\n     * Text style.\n     *\n     * @var null|Font|string\n     */\n    private $fontStyle;\n\n    /**\n     * Paragraph style.\n     *\n     * @var null|Paragraph|string\n     */\n    private $paragraphStyle;\n\n    /**\n     * Create a new Preserve Text Element.\n     *\n     * @param string $text\n     * @param mixed $fontStyle\n     * @param mixed $paragraphStyle\n     */\n    public function __construct($text = null, $fontStyle = null, $paragraphStyle = null)\n    {\n        $this->fontStyle = $this->setNewStyle(new Font('text'), $fontStyle);\n        $this->paragraphStyle = $this->setNewStyle(new Paragraph(), $paragraphStyle);\n\n        $this->text = SharedText::toUTF8($text);\n        $matches = preg_split('/({.*?})/', $this->text ?? '', -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);\n        if (isset($matches[0])) {\n            $this->text = $matches;\n        }\n    }\n\n    /**\n     * Get Text style.\n     *\n     * @return null|Font|string\n     */\n    public function getFontStyle()\n    {\n        return $this->fontStyle;\n    }\n\n    /**\n     * Get Paragraph style.\n     *\n     * @return null|Paragraph|string\n     */\n    public function getParagraphStyle()\n    {\n        return $this->paragraphStyle;\n    }\n\n    /**\n     * Get Text content.\n     *\n     * @return null|array|string\n     */\n    public function getText()\n    {\n        return $this->text;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/Row.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\nuse PhpOffice\\PhpWord\\Style\\Row as RowStyle;\n\n/**\n * Table row element.\n *\n * @since 0.8.0\n */\nclass Row extends AbstractElement\n{\n    /**\n     * Row height.\n     *\n     * @var ?int\n     */\n    private $height;\n\n    /**\n     * Row style.\n     *\n     * @var ?RowStyle\n     */\n    private $style;\n\n    /**\n     * Row cells.\n     *\n     * @var Cell[]\n     */\n    private $cells = [];\n\n    /**\n     * Create a new table row.\n     *\n     * @param int $height\n     * @param mixed $style\n     */\n    public function __construct($height = null, $style = null)\n    {\n        $this->height = $height;\n        $this->style = $this->setNewStyle(new RowStyle(), $style, true);\n    }\n\n    /**\n     * Add a cell.\n     *\n     * @param int $width\n     * @param mixed $style\n     *\n     * @return Cell\n     */\n    public function addCell($width = null, $style = null)\n    {\n        $cell = new Cell($width, $style);\n        $cell->setParentContainer($this);\n        $this->cells[] = $cell;\n\n        return $cell;\n    }\n\n    /**\n     * Get all cells.\n     *\n     * @return Cell[]\n     */\n    public function getCells()\n    {\n        return $this->cells;\n    }\n\n    /**\n     * Get row style.\n     *\n     * @return ?RowStyle\n     */\n    public function getStyle()\n    {\n        return $this->style;\n    }\n\n    /**\n     * Get row height.\n     *\n     * @return ?int\n     */\n    public function getHeight()\n    {\n        return $this->height;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/Ruby.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\nuse PhpOffice\\PhpWord\\ComplexType\\RubyProperties;\n\n/**\n * Ruby element.\n *\n * @see https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.wordprocessing.ruby?view=openxml-3.0.1\n */\nclass Ruby extends AbstractElement\n{\n    /**\n     * Ruby properties.\n     *\n     * @var RubyProperties\n     */\n    protected $properties;\n\n    /**\n     * Ruby text run.\n     *\n     * @var TextRun\n     */\n    protected $rubyTextRun;\n\n    /**\n     * Ruby base text run.\n     *\n     * @var TextRun\n     */\n    protected $baseTextRun;\n\n    /**\n     * Create a new Ruby Element.\n     */\n    public function __construct(TextRun $baseTextRun, TextRun $rubyTextRun, RubyProperties $properties)\n    {\n        $this->baseTextRun = $baseTextRun;\n        $this->rubyTextRun = $rubyTextRun;\n        $this->properties = $properties;\n    }\n\n    /**\n     * Get base text run.\n     */\n    public function getBaseTextRun(): TextRun\n    {\n        return $this->baseTextRun;\n    }\n\n    /**\n     * Set the base text run.\n     */\n    public function setBaseTextRun(TextRun $textRun): self\n    {\n        $this->baseTextRun = $textRun;\n\n        return $this;\n    }\n\n    /**\n     * Get ruby text run.\n     */\n    public function getRubyTextRun(): TextRun\n    {\n        return $this->rubyTextRun;\n    }\n\n    /**\n     * Set the ruby text run.\n     */\n    public function setRubyTextRun(TextRun $textRun): self\n    {\n        $this->rubyTextRun = $textRun;\n\n        return $this;\n    }\n\n    /**\n     * Get ruby properties.\n     */\n    public function getProperties(): RubyProperties\n    {\n        return $this->properties;\n    }\n\n    /**\n     * Set the ruby properties.\n     */\n    public function setProperties(RubyProperties $properties): self\n    {\n        $this->properties = $properties;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/SDT.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\n/**\n * Structured document tag (SDT) element.\n *\n * @since 0.12.0\n */\nclass SDT extends Text\n{\n    /**\n     * Form field type: comboBox|dropDownList|date.\n     *\n     * @var string\n     */\n    private $type;\n\n    /**\n     * Value.\n     *\n     * @var null|bool|int|string\n     */\n    private $value;\n\n    /**\n     * CheckBox/DropDown list entries.\n     *\n     * @var array\n     */\n    private $listItems = [];\n\n    /**\n     * Alias.\n     *\n     * @var string\n     */\n    private $alias;\n\n    /**\n     * Tag.\n     *\n     * @var string\n     */\n    private $tag;\n\n    /**\n     * Create new instance.\n     *\n     * @param string $type\n     * @param mixed $fontStyle\n     * @param mixed $paragraphStyle\n     */\n    public function __construct($type, $fontStyle = null, $paragraphStyle = null)\n    {\n        parent::__construct(null, $fontStyle, $paragraphStyle);\n        $this->setType($type);\n    }\n\n    /**\n     * Get type.\n     *\n     * @return string\n     */\n    public function getType()\n    {\n        return $this->type;\n    }\n\n    /**\n     * Set type.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setType($value)\n    {\n        $enum = ['plainText', 'comboBox', 'dropDownList', 'date'];\n        $this->type = $this->setEnumVal($value, $enum, 'comboBox');\n\n        return $this;\n    }\n\n    /**\n     * Get value.\n     *\n     * @return null|bool|int|string\n     */\n    public function getValue()\n    {\n        return $this->value;\n    }\n\n    /**\n     * Set value.\n     *\n     * @param null|bool|int|string $value\n     *\n     * @return self\n     */\n    public function setValue($value)\n    {\n        $this->value = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get listItems.\n     *\n     * @return array\n     */\n    public function getListItems()\n    {\n        return $this->listItems;\n    }\n\n    /**\n     * Set listItems.\n     *\n     * @param array $value\n     *\n     * @return self\n     */\n    public function setListItems($value)\n    {\n        $this->listItems = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get tag.\n     *\n     * @return string\n     */\n    public function getTag()\n    {\n        return $this->tag;\n    }\n\n    /**\n     * Set tag.\n     *\n     * @param string $tag\n     *\n     * @return self\n     */\n    public function setTag($tag)\n    {\n        $this->tag = $tag;\n\n        return $this;\n    }\n\n    /**\n     * Get alias.\n     *\n     * @return string\n     */\n    public function getAlias()\n    {\n        return $this->alias;\n    }\n\n    /**\n     * Set alias.\n     *\n     * @param string $alias\n     *\n     * @return self\n     */\n    public function setAlias($alias)\n    {\n        $this->alias = $alias;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/Section.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\nuse Exception;\nuse PhpOffice\\PhpWord\\ComplexType\\FootnoteProperties;\nuse PhpOffice\\PhpWord\\Style\\Section as SectionStyle;\n\nclass Section extends AbstractContainer\n{\n    /**\n     * @var string Container type\n     */\n    protected $container = 'Section';\n\n    /**\n     * Section style.\n     *\n     * @var ?SectionStyle\n     */\n    private $style;\n\n    /**\n     * Section headers, indexed from 1, not zero.\n     *\n     * @var Header[]\n     */\n    private $headers = [];\n\n    /**\n     * Section footers, indexed from 1, not zero.\n     *\n     * @var Footer[]\n     */\n    private $footers = [];\n\n    /**\n     * The properties for the footnote of this section.\n     *\n     * @var FootnoteProperties\n     */\n    private $footnoteProperties;\n\n    /**\n     * Create new instance.\n     *\n     * @param int $sectionCount\n     * @param null|array|\\PhpOffice\\PhpWord\\Style|string $style\n     */\n    public function __construct($sectionCount, $style = null)\n    {\n        $this->sectionId = $sectionCount;\n        $this->setDocPart($this->container, $this->sectionId);\n        if (null === $style) {\n            $style = new SectionStyle();\n        }\n        $this->style = $this->setNewStyle(new SectionStyle(), $style);\n    }\n\n    /**\n     * Set section style.\n     */\n    public function setStyle(?array $style = null): void\n    {\n        if (null !== $style) {\n            $this->style->setStyleByArray($style);\n        }\n    }\n\n    /**\n     * Get section style.\n     *\n     * @return ?SectionStyle\n     */\n    public function getStyle()\n    {\n        return $this->style;\n    }\n\n    /**\n     * Add header.\n     *\n     * @since 0.10.0\n     *\n     * @param string $type\n     *\n     * @return Header\n     */\n    public function addHeader($type = Header::AUTO)\n    {\n        return $this->addHeaderFooter($type, true);\n    }\n\n    /**\n     * Add footer.\n     *\n     * @since 0.10.0\n     *\n     * @param string $type\n     *\n     * @return Footer\n     */\n    public function addFooter($type = Header::AUTO)\n    {\n        return $this->addHeaderFooter($type, false);\n    }\n\n    /**\n     * Get header elements.\n     *\n     * @return Header[]\n     */\n    public function getHeaders()\n    {\n        return $this->headers;\n    }\n\n    /**\n     * Get footer elements.\n     *\n     * @return Footer[]\n     */\n    public function getFooters()\n    {\n        return $this->footers;\n    }\n\n    /**\n     * Get the footnote properties.\n     *\n     * @return FootnoteProperties\n     */\n    public function getFootnoteProperties()\n    {\n        return $this->footnoteProperties;\n    }\n\n    /**\n     * Set the footnote properties.\n     */\n    public function setFootnoteProperties(?FootnoteProperties $footnoteProperties = null): void\n    {\n        $this->footnoteProperties = $footnoteProperties;\n    }\n\n    /**\n     * Is there a header for this section that is for the first page only?\n     *\n     * If any of the Header instances have a type of Header::FIRST then this method returns true.\n     * False otherwise.\n     *\n     * @return bool\n     */\n    public function hasDifferentFirstPage()\n    {\n        foreach ($this->headers as $header) {\n            if ($header->getType() == Header::FIRST) {\n                return true;\n            }\n        }\n        foreach ($this->footers as $footer) {\n            if ($footer->getType() == Header::FIRST) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Add header/footer.\n     *\n     * @since 0.10.0\n     *\n     * @param string $type\n     * @param bool $header\n     *\n     * @return Footer|Header\n     */\n    private function addHeaderFooter($type = Header::AUTO, $header = true)\n    {\n        $containerClass = substr(static::class, 0, strrpos(static::class, '\\\\') ?: 0) . '\\\\' .\n            ($header ? 'Header' : 'Footer');\n        $collectionArray = $header ? 'headers' : 'footers';\n        $collection = &$this->$collectionArray;\n\n        if (in_array($type, [Header::AUTO, Header::FIRST, Header::EVEN])) {\n            $index = count($collection);\n            /** @var AbstractContainer $container Type hint */\n            $container = new $containerClass($this->sectionId, ++$index, $type);\n            $container->setPhpWord($this->phpWord);\n\n            $collection[$index] = $container;\n\n            return $container;\n        }\n\n        throw new Exception('Invalid header/footer type.');\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/Shape.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\nuse PhpOffice\\PhpWord\\Style\\Shape as ShapeStyle;\n\n/**\n * Shape element.\n *\n * @since 0.12.0\n */\nclass Shape extends AbstractElement\n{\n    /**\n     * Shape type arc|curve|line|polyline|rect|oval.\n     *\n     * @var string\n     */\n    private $type;\n\n    /**\n     * Shape style.\n     *\n     * @var ?ShapeStyle\n     */\n    private $style;\n\n    /**\n     * Create new instance.\n     *\n     * @param string $type\n     * @param mixed $style\n     */\n    public function __construct($type, $style = null)\n    {\n        $this->setType($type);\n        $this->style = $this->setNewStyle(new ShapeStyle(), $style);\n    }\n\n    /**\n     * Get type.\n     *\n     * @return string\n     */\n    public function getType()\n    {\n        return $this->type;\n    }\n\n    /**\n     * Set pattern.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setType($value = null)\n    {\n        $enum = ['arc', 'curve', 'line', 'polyline', 'rect', 'oval'];\n        $this->type = $this->setEnumVal($value, $enum, null);\n\n        return $this;\n    }\n\n    /**\n     * Get shape style.\n     *\n     * @return ?ShapeStyle\n     */\n    public function getStyle()\n    {\n        return $this->style;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/TOC.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Style\\Font;\nuse PhpOffice\\PhpWord\\Style\\TOC as TOCStyle;\n\n/**\n * Table of contents.\n */\nclass TOC extends AbstractElement\n{\n    /**\n     * TOC style.\n     *\n     * @var TOCStyle\n     */\n    private $tocStyle;\n\n    /**\n     * Font style.\n     *\n     * @var Font|string\n     */\n    private $fontStyle;\n\n    /**\n     * Min title depth to show.\n     *\n     * @var int\n     */\n    private $minDepth = 1;\n\n    /**\n     * Max title depth to show.\n     *\n     * @var int\n     */\n    private $maxDepth = 9;\n\n    /**\n     * Create a new Table-of-Contents Element.\n     *\n     * @param mixed $fontStyle\n     * @param int $minDepth\n     * @param int $maxDepth\n     */\n    public function __construct($fontStyle = null, ?array $tocStyle = null, $minDepth = 1, $maxDepth = 9)\n    {\n        $this->tocStyle = new TOCStyle();\n\n        if (null !== $tocStyle) {\n            $this->tocStyle->setStyleByArray($tocStyle);\n        }\n\n        if (null !== $fontStyle && is_array($fontStyle)) {\n            $this->fontStyle = new Font();\n            $this->fontStyle->setStyleByArray($fontStyle);\n        } else {\n            $this->fontStyle = $fontStyle;\n        }\n\n        $this->minDepth = $minDepth;\n        $this->maxDepth = $maxDepth;\n    }\n\n    /**\n     * Get all titles.\n     *\n     * @return array\n     */\n    public function getTitles()\n    {\n        if (!$this->phpWord instanceof PhpWord) {\n            return [];\n        }\n\n        $titles = $this->phpWord->getTitles()->getItems();\n        foreach ($titles as $i => $title) {\n            /** @var Title $title Type hint */\n            $depth = $title->getDepth();\n            if ($this->minDepth > $depth) {\n                unset($titles[$i]);\n            }\n            if (($this->maxDepth != 0) && ($this->maxDepth < $depth)) {\n                unset($titles[$i]);\n            }\n        }\n\n        return $titles;\n    }\n\n    /**\n     * Get TOC Style.\n     *\n     * @return TOCStyle\n     */\n    public function getStyleTOC()\n    {\n        return $this->tocStyle;\n    }\n\n    /**\n     * Get Font Style.\n     *\n     * @return Font|string\n     */\n    public function getStyleFont()\n    {\n        return $this->fontStyle;\n    }\n\n    /**\n     * Set max depth.\n     *\n     * @param int $value\n     */\n    public function setMaxDepth($value): void\n    {\n        $this->maxDepth = $value;\n    }\n\n    /**\n     * Get Max Depth.\n     *\n     * @return int Max depth of titles\n     */\n    public function getMaxDepth()\n    {\n        return $this->maxDepth;\n    }\n\n    /**\n     * Set min depth.\n     *\n     * @param int $value\n     */\n    public function setMinDepth($value): void\n    {\n        $this->minDepth = $value;\n    }\n\n    /**\n     * Get Min Depth.\n     *\n     * @return int Min depth of titles\n     */\n    public function getMinDepth()\n    {\n        return $this->minDepth;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/Table.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\nuse PhpOffice\\PhpWord\\Style\\Table as TableStyle;\n\n/**\n * Table element.\n */\nclass Table extends AbstractElement\n{\n    /**\n     * Table style.\n     *\n     * @var ?TableStyle\n     */\n    private $style;\n\n    /**\n     * Table rows.\n     *\n     * @var Row[]\n     */\n    private $rows = [];\n\n    /**\n     * Table width.\n     *\n     * @var ?int\n     */\n    private $width;\n\n    /**\n     * Create a new table.\n     *\n     * @param mixed $style\n     */\n    public function __construct($style = null)\n    {\n        $this->style = $this->setNewStyle(new TableStyle(), $style);\n    }\n\n    /**\n     * Add a row.\n     *\n     * @param int $height\n     * @param mixed $style\n     *\n     * @return Row\n     */\n    public function addRow($height = null, $style = null)\n    {\n        $row = new Row($height, $style);\n        $row->setParentContainer($this);\n        $this->rows[] = $row;\n\n        return $row;\n    }\n\n    /**\n     * Add a cell.\n     *\n     * @param int $width\n     * @param mixed $style\n     *\n     * @return Cell\n     */\n    public function addCell($width = null, $style = null)\n    {\n        $index = count($this->rows) - 1;\n        $row = $this->rows[$index];\n        $cell = $row->addCell($width, $style);\n\n        return $cell;\n    }\n\n    /**\n     * Get all rows.\n     *\n     * @return Row[]\n     */\n    public function getRows()\n    {\n        return $this->rows;\n    }\n\n    /**\n     * Get table style.\n     *\n     * @return null|string|TableStyle\n     */\n    public function getStyle()\n    {\n        return $this->style;\n    }\n\n    /**\n     * Get table width.\n     *\n     * @return ?int\n     */\n    public function getWidth()\n    {\n        return $this->width;\n    }\n\n    /**\n     * Set table width.\n     *\n     * @param int $width\n     */\n    public function setWidth($width): void\n    {\n        $this->width = $width;\n    }\n\n    /**\n     * Get column count.\n     *\n     * @return int\n     */\n    public function countColumns()\n    {\n        $columnCount = 0;\n\n        $rowCount = count($this->rows);\n        for ($i = 0; $i < $rowCount; ++$i) {\n            /** @var Row $row Type hint */\n            $row = $this->rows[$i];\n            $cellCount = count($row->getCells());\n            if ($columnCount < $cellCount) {\n                $columnCount = $cellCount;\n            }\n        }\n\n        return $columnCount;\n    }\n\n    /**\n     * The first declared cell width for each column.\n     *\n     * @return int[]\n     */\n    public function findFirstDefinedCellWidths()\n    {\n        $cellWidths = [];\n\n        foreach ($this->rows as $row) {\n            $cells = $row->getCells();\n            if (count($cells) <= count($cellWidths)) {\n                continue;\n            }\n            $cellWidths = [];\n            foreach ($cells as $cell) {\n                $cellWidths[] = $cell->getWidth();\n            }\n        }\n\n        return $cellWidths;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/Text.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\nuse PhpOffice\\PhpWord\\Shared\\Text as SharedText;\nuse PhpOffice\\PhpWord\\Style\\Font;\nuse PhpOffice\\PhpWord\\Style\\Paragraph;\n\n/**\n * Text element.\n */\nclass Text extends AbstractElement\n{\n    /**\n     * Text content.\n     *\n     * @var ?string\n     */\n    protected $text;\n\n    /**\n     * Text style.\n     *\n     * @var Font|string\n     */\n    protected $fontStyle;\n\n    /**\n     * Paragraph style.\n     *\n     * @var Paragraph|string\n     */\n    protected $paragraphStyle;\n\n    /**\n     * Create a new Text Element.\n     *\n     * @param string $text\n     * @param mixed $fontStyle\n     * @param mixed $paragraphStyle\n     */\n    public function __construct($text = null, $fontStyle = null, $paragraphStyle = null)\n    {\n        $this->setText($text);\n        $paragraphStyle = $this->setParagraphStyle($paragraphStyle);\n        $this->setFontStyle($fontStyle, $paragraphStyle);\n    }\n\n    /**\n     * Set Text style.\n     *\n     * @param array|Font|string $style\n     * @param array|Paragraph|string $paragraphStyle\n     *\n     * @return Font|string\n     */\n    public function setFontStyle($style = null, $paragraphStyle = null)\n    {\n        if ($style instanceof Font) {\n            $this->fontStyle = $style;\n            $this->setParagraphStyle($paragraphStyle);\n        } elseif (is_array($style)) {\n            $this->fontStyle = new Font('text', $paragraphStyle);\n            $this->fontStyle->setStyleByArray($style);\n        } elseif (null === $style) {\n            $this->fontStyle = new Font('text', $paragraphStyle);\n        } else {\n            $this->fontStyle = $style;\n            $this->setParagraphStyle($paragraphStyle);\n        }\n\n        return $this->fontStyle;\n    }\n\n    /**\n     * Get Text style.\n     *\n     * @return Font|string\n     */\n    public function getFontStyle()\n    {\n        return $this->fontStyle;\n    }\n\n    /**\n     * Set Paragraph style.\n     *\n     * @param array|Paragraph|string $style\n     *\n     * @return Paragraph|string\n     */\n    public function setParagraphStyle($style = null)\n    {\n        if (is_array($style)) {\n            $this->paragraphStyle = new Paragraph();\n            $this->paragraphStyle->setStyleByArray($style);\n        } elseif ($style instanceof Paragraph) {\n            $this->paragraphStyle = $style;\n        } elseif (null === $style) {\n            $this->paragraphStyle = new Paragraph();\n        } else {\n            $this->paragraphStyle = $style;\n        }\n\n        return $this->paragraphStyle;\n    }\n\n    /**\n     * Get Paragraph style.\n     *\n     * @return Paragraph|string\n     */\n    public function getParagraphStyle()\n    {\n        return $this->paragraphStyle;\n    }\n\n    /**\n     * Set text content.\n     *\n     * @param string $text\n     *\n     * @return self\n     */\n    public function setText($text)\n    {\n        $this->text = SharedText::toUTF8($text);\n\n        return $this;\n    }\n\n    /**\n     * Get Text content.\n     */\n    public function getText(): ?string\n    {\n        return $this->text;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/TextBox.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\nuse PhpOffice\\PhpWord\\Style\\TextBox as TextBoxStyle;\n\n/**\n * TextBox element.\n *\n * @since 0.11.0\n */\nclass TextBox extends AbstractContainer\n{\n    /**\n     * @var string Container type\n     */\n    protected $container = 'TextBox';\n\n    /**\n     * TextBox style.\n     *\n     * @var ?TextBoxStyle\n     */\n    private $style;\n\n    /**\n     * Create a new textbox.\n     *\n     * @param mixed $style\n     */\n    public function __construct($style = null)\n    {\n        $this->style = $this->setNewStyle(new TextBoxStyle(), $style);\n    }\n\n    /**\n     * Get textbox style.\n     *\n     * @return ?TextBoxStyle\n     */\n    public function getStyle()\n    {\n        return $this->style;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/TextBreak.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\nuse PhpOffice\\PhpWord\\Style\\Font;\nuse PhpOffice\\PhpWord\\Style\\Paragraph;\n\n/**\n * Text break element.\n */\nclass TextBreak extends AbstractElement\n{\n    /**\n     * Paragraph style.\n     *\n     * @var null|Paragraph|string\n     */\n    private $paragraphStyle;\n\n    /**\n     * Text style.\n     *\n     * @var null|Font|string\n     */\n    private $fontStyle;\n\n    /**\n     * Create a new TextBreak Element.\n     *\n     * @param mixed $fontStyle\n     * @param mixed $paragraphStyle\n     */\n    public function __construct($fontStyle = null, $paragraphStyle = null)\n    {\n        if (null !== $paragraphStyle) {\n            $paragraphStyle = $this->setParagraphStyle($paragraphStyle);\n        }\n        if (null !== $fontStyle) {\n            $this->setFontStyle($fontStyle, $paragraphStyle);\n        }\n    }\n\n    /**\n     * Set Text style.\n     *\n     * @param mixed $style\n     * @param mixed $paragraphStyle\n     *\n     * @return Font|string\n     */\n    public function setFontStyle($style = null, $paragraphStyle = null)\n    {\n        if ($style instanceof Font) {\n            $this->fontStyle = $style;\n            $this->setParagraphStyle($paragraphStyle);\n        } elseif (is_array($style)) {\n            $this->fontStyle = new Font('text', $paragraphStyle);\n            $this->fontStyle->setStyleByArray($style);\n        } else {\n            $this->fontStyle = $style;\n            $this->setParagraphStyle($paragraphStyle);\n        }\n\n        return $this->fontStyle;\n    }\n\n    /**\n     * Get Text style.\n     *\n     * @return null|Font|string\n     */\n    public function getFontStyle()\n    {\n        return $this->fontStyle;\n    }\n\n    /**\n     * Set Paragraph style.\n     *\n     * @param   array|Paragraph|string $style\n     *\n     * @return  Paragraph|string\n     */\n    public function setParagraphStyle($style = null)\n    {\n        if (is_array($style)) {\n            $this->paragraphStyle = new Paragraph();\n            $this->paragraphStyle->setStyleByArray($style);\n        } elseif ($style instanceof Paragraph) {\n            $this->paragraphStyle = $style;\n        } else {\n            $this->paragraphStyle = $style;\n        }\n\n        return $this->paragraphStyle;\n    }\n\n    /**\n     * Get Paragraph style.\n     *\n     * @return null|Paragraph|string\n     */\n    public function getParagraphStyle()\n    {\n        return $this->paragraphStyle;\n    }\n\n    /**\n     * Has font/paragraph style defined.\n     *\n     * @return bool\n     */\n    public function hasStyle()\n    {\n        return null !== $this->fontStyle || null !== $this->paragraphStyle;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/TextRun.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\nuse PhpOffice\\PhpWord\\Style\\Paragraph;\n\n/**\n * Textrun/paragraph element.\n */\nclass TextRun extends AbstractContainer\n{\n    /**\n     * @var string Container type\n     */\n    protected $container = 'TextRun';\n\n    /**\n     * Paragraph style.\n     *\n     * @var Paragraph|string\n     */\n    protected $paragraphStyle;\n\n    /**\n     * Create new instance.\n     *\n     * @param array|Paragraph|string $paragraphStyle\n     */\n    public function __construct($paragraphStyle = null)\n    {\n        $this->paragraphStyle = $this->setParagraphStyle($paragraphStyle);\n    }\n\n    /**\n     * Get Paragraph style.\n     *\n     * @return Paragraph|string\n     */\n    public function getParagraphStyle()\n    {\n        return $this->paragraphStyle;\n    }\n\n    /**\n     * Set Paragraph style.\n     *\n     * @param array|Paragraph|string $style\n     *\n     * @return Paragraph|string\n     */\n    public function setParagraphStyle($style = null)\n    {\n        if (is_array($style)) {\n            $this->paragraphStyle = new Paragraph();\n            $this->paragraphStyle->setStyleByArray($style);\n        } elseif ($style instanceof Paragraph) {\n            $this->paragraphStyle = $style;\n        } elseif (null === $style) {\n            $this->paragraphStyle = new Paragraph();\n        } else {\n            $this->paragraphStyle = $style;\n        }\n\n        return $this->paragraphStyle;\n    }\n\n    public function getText(): string\n    {\n        $outstr = '';\n        foreach ($this->getElements() as $element) {\n            if ($element instanceof Text) {\n                $outstr .= $element->getText();\n            } elseif ($element instanceof Ruby) {\n                $outstr .= $element->getBaseTextRun()->getText() .\n                    ' (' . $element->getRubyTextRun()->getText() . ')';\n            }\n        }\n\n        return $outstr;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/Title.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\nuse InvalidArgumentException;\nuse PhpOffice\\PhpWord\\Shared\\Text as SharedText;\nuse PhpOffice\\PhpWord\\Style;\n\n/**\n * Title element.\n */\nclass Title extends AbstractElement\n{\n    /**\n     * Title Text content.\n     *\n     * @var string|TextRun\n     */\n    private $text;\n\n    /**\n     * Title depth.\n     *\n     * @var int\n     */\n    private $depth = 1;\n\n    /**\n     * Name of the heading style, e.g. 'Heading1'.\n     *\n     * @var ?string\n     */\n    private $style;\n\n    /**\n     * Is part of collection.\n     *\n     * @var bool\n     */\n    protected $collectionRelation = true;\n\n    /**\n     * Page number.\n     *\n     * @var int\n     */\n    private $pageNumber;\n\n    /**\n     * Create a new Title Element.\n     *\n     * @param string|TextRun $text\n     * @param int $depth\n     */\n    public function __construct($text, $depth = 1, ?int $pageNumber = null)\n    {\n        if (is_string($text)) {\n            $this->text = SharedText::toUTF8($text);\n        } elseif ($text instanceof TextRun) {\n            $this->text = $text;\n        } else {\n            throw new InvalidArgumentException('Invalid text, should be a string or a TextRun');\n        }\n\n        $this->depth = $depth;\n        $styleName = $depth === 0 ? 'Title' : \"Heading_{$this->depth}\";\n        if (array_key_exists($styleName, Style::getStyles())) {\n            $this->style = str_replace('_', '', $styleName);\n        }\n\n        if ($pageNumber !== null) {\n            $this->pageNumber = $pageNumber;\n        }\n    }\n\n    /**\n     * Get Title Text content.\n     *\n     * @return string|TextRun\n     */\n    public function getText()\n    {\n        return $this->text;\n    }\n\n    /**\n     * Get depth.\n     *\n     * @return int\n     */\n    public function getDepth()\n    {\n        return $this->depth;\n    }\n\n    /**\n     * Get Title style.\n     *\n     * @return ?string\n     */\n    public function getStyle()\n    {\n        return $this->style;\n    }\n\n    /**\n     * Get page number.\n     */\n    public function getPageNumber(): ?int\n    {\n        return $this->pageNumber;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Element/TrackChange.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Element;\n\nuse DateTime;\n\n/**\n * TrackChange element.\n *\n * @see http://datypic.com/sc/ooxml/t-w_CT_TrackChange.html\n * @see http://datypic.com/sc/ooxml/t-w_CT_RunTrackChange.html\n */\nclass TrackChange extends AbstractContainer\n{\n    const INSERTED = 'INSERTED';\n    const DELETED = 'DELETED';\n\n    /**\n     * @var string Container type\n     */\n    protected $container = 'TrackChange';\n\n    /**\n     * The type of change, (insert or delete), not applicable for PhpOffice\\PhpWord\\Element\\Comment.\n     *\n     * @var string\n     */\n    private $changeType;\n\n    /**\n     * Author.\n     *\n     * @var string\n     */\n    private $author;\n\n    /**\n     * Date.\n     *\n     * @var DateTime\n     */\n    private $date;\n\n    /**\n     * Create a new TrackChange Element.\n     *\n     * @param string $changeType\n     * @param string $author\n     * @param null|bool|DateTime|int $date\n     */\n    public function __construct($changeType = null, $author = null, $date = null)\n    {\n        $this->changeType = $changeType;\n        $this->author = $author;\n        if ($date !== null && $date !== false) {\n            $this->date = ($date instanceof DateTime) ? $date : new DateTime('@' . $date);\n        }\n    }\n\n    /**\n     * Get TrackChange Author.\n     *\n     * @return string\n     */\n    public function getAuthor()\n    {\n        return $this->author;\n    }\n\n    /**\n     * Get TrackChange Date.\n     *\n     * @return DateTime\n     */\n    public function getDate()\n    {\n        return $this->date;\n    }\n\n    /**\n     * Get the Change type.\n     *\n     * @return string\n     */\n    public function getChangeType()\n    {\n        return $this->changeType;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Escaper/AbstractEscaper.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Escaper;\n\n/**\n * @since 0.13.0\n *\n * @codeCoverageIgnore\n */\nabstract class AbstractEscaper implements EscaperInterface\n{\n    /**\n     * @param ?string $input\n     *\n     * @return string\n     */\n    abstract protected function escapeSingleValue($input);\n\n    public function escape($input)\n    {\n        if (is_array($input)) {\n            foreach ($input as &$item) {\n                $item = $this->escapeSingleValue($item);\n            }\n        } else {\n            $input = $this->escapeSingleValue($input);\n        }\n\n        return $input;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Escaper/EscaperInterface.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Escaper;\n\n/**\n * @since 0.13.0\n *\n * @codeCoverageIgnore\n */\ninterface EscaperInterface\n{\n    /**\n     * @param mixed $input\n     *\n     * @return mixed\n     */\n    public function escape($input);\n}\n"
  },
  {
    "path": "src/PhpWord/Escaper/RegExp.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Escaper;\n\n/**\n * @since 0.13.0\n *\n * @codeCoverageIgnore\n */\nclass RegExp extends AbstractEscaper\n{\n    const REG_EXP_DELIMITER = '/';\n\n    protected function escapeSingleValue($input)\n    {\n        return self::REG_EXP_DELIMITER . preg_quote($input, self::REG_EXP_DELIMITER) . self::REG_EXP_DELIMITER . 'u';\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Escaper/Rtf.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Escaper;\n\n/**\n * @since 0.13.0\n *\n * @codeCoverageIgnore\n */\nclass Rtf extends AbstractEscaper\n{\n    protected function escapeAsciiCharacter($code)\n    {\n        if ($code == 9) {\n            return '{\\\\tab}';\n        }\n        if (0x20 > $code || $code >= 0x80) {\n            return '{\\\\u' . $code . '}';\n        }\n        if ($code == 123 || $code == 125 || $code == 92) { // open or close brace or backslash\n            return '\\\\' . chr($code);\n        }\n\n        return chr($code);\n    }\n\n    protected function escapeMultibyteCharacter($code)\n    {\n        return '\\\\uc0{\\\\u' . $code . '}';\n    }\n\n    /**\n     * @see http://www.randomchaos.com/documents/?source=php_and_unicode\n     *\n     * @param ?string $input\n     */\n    protected function escapeSingleValue($input)\n    {\n        $escapedValue = '';\n\n        $numberOfBytes = 1;\n        $bytes = [];\n        for ($i = 0; $i < strlen($input); ++$i) {\n            $character = $input[$i];\n            $asciiCode = ord($character);\n\n            if ($asciiCode < 128) {\n                $escapedValue .= $this->escapeAsciiCharacter($asciiCode);\n            } else {\n                if (0 == count($bytes)) {\n                    if ($asciiCode < 224) {\n                        $numberOfBytes = 2;\n                    } elseif ($asciiCode < 240) {\n                        $numberOfBytes = 3;\n                    } elseif ($asciiCode < 248) {\n                        $numberOfBytes = 4;\n                    }\n                }\n\n                $bytes[] = $asciiCode;\n\n                if ($numberOfBytes == count($bytes)) {\n                    if (4 == $numberOfBytes) {\n                        $multibyteCode = ($bytes[0] % 8) * 262144 + ($bytes[1] % 64) * 4096 + ($bytes[2] % 64) * 64 + ($bytes[3] % 64);\n                    } elseif (3 == $numberOfBytes) {\n                        $multibyteCode = ($bytes[0] % 16) * 4096 + ($bytes[1] % 64) * 64 + ($bytes[2] % 64);\n                    } else {\n                        $multibyteCode = ($bytes[0] % 32) * 64 + ($bytes[1] % 64);\n                    }\n\n                    if (65279 != $multibyteCode) {\n                        $escapedValue .= $multibyteCode < 128 ? $this->escapeAsciiCharacter($multibyteCode) : $this->escapeMultibyteCharacter($multibyteCode);\n                    }\n\n                    $numberOfBytes = 1;\n                    $bytes = [];\n                }\n            }\n        }\n\n        return $escapedValue;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Escaper/Xml.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Escaper;\n\n/**\n * @since 0.13.0\n *\n * @codeCoverageIgnore\n */\nclass Xml extends AbstractEscaper\n{\n    protected function escapeSingleValue($input)\n    {\n        return (null !== $input) ? htmlspecialchars($input, ENT_QUOTES) : '';\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Exception/CopyFileException.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Exception;\n\n/**\n * @since 0.12.0\n */\nfinal class CopyFileException extends Exception\n{\n    /**\n     * @param string $source The fully qualified source file name\n     * @param string $destination The fully qualified destination file name\n     * @param int $code The user defined exception code\n     * @param \\Exception $previous The previous exception used for the exception chaining\n     */\n    public function __construct($source, $destination, $code = 0, ?\\Exception $previous = null)\n    {\n        parent::__construct(\n            sprintf('Could not copy \\'%s\\' file to \\'%s\\'.', $source, $destination),\n            $code,\n            $previous\n        );\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Exception/CreateTemporaryFileException.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Exception;\n\n/**\n * @since 0.12.0\n */\nfinal class CreateTemporaryFileException extends Exception\n{\n    /**\n     * @param int $code The user defined exception code\n     * @param \\Exception $previous The previous exception used for the exception chaining\n     */\n    public function __construct($code = 0, ?\\Exception $previous = null)\n    {\n        parent::__construct(\n            'Could not create a temporary file with unique name in the specified directory.',\n            $code,\n            $previous\n        );\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Exception/Exception.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Exception;\n\n/**\n * General exception.\n */\nclass Exception extends \\Exception\n{\n}\n"
  },
  {
    "path": "src/PhpWord/Exception/InvalidImageException.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Exception;\n\n/**\n * Exception used for when an image is not found.\n */\nclass InvalidImageException extends Exception\n{\n}\n"
  },
  {
    "path": "src/PhpWord/Exception/InvalidObjectException.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Exception;\n\n/**\n * Exception used for when an image is not found.\n */\nclass InvalidObjectException extends Exception\n{\n}\n"
  },
  {
    "path": "src/PhpWord/Exception/InvalidStyleException.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Exception;\n\nuse InvalidArgumentException;\n\n/**\n * Exception used for when a style value is invalid.\n */\nclass InvalidStyleException extends InvalidArgumentException\n{\n}\n"
  },
  {
    "path": "src/PhpWord/Exception/UnsupportedImageTypeException.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Exception;\n\n/**\n * Exception used for when an image type is unsupported.\n */\nclass UnsupportedImageTypeException extends Exception\n{\n}\n"
  },
  {
    "path": "src/PhpWord/IOFactory.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord;\n\nuse PhpOffice\\PhpWord\\Element\\Text;\nuse PhpOffice\\PhpWord\\Element\\TextRun;\nuse PhpOffice\\PhpWord\\Exception\\Exception;\nuse PhpOffice\\PhpWord\\Reader\\ReaderInterface;\nuse PhpOffice\\PhpWord\\Writer\\WriterInterface;\nuse ReflectionClass;\n\nabstract class IOFactory\n{\n    /**\n     * Create new writer.\n     *\n     * @param string $name\n     *\n     * @return WriterInterface\n     */\n    public static function createWriter(PhpWord $phpWord, $name = 'Word2007')\n    {\n        if ($name !== 'WriterInterface' && !in_array($name, ['ODText', 'RTF', 'Word2007', 'HTML', 'PDF', 'EPub3'], true)) {\n            throw new Exception(\"\\\"{$name}\\\" is not a valid writer.\");\n        }\n\n        $fqName = \"PhpOffice\\\\PhpWord\\\\Writer\\\\{$name}\";\n\n        return new $fqName($phpWord);\n    }\n\n    /**\n     * Create new reader.\n     *\n     * @param string $name\n     *\n     * @return ReaderInterface\n     */\n    public static function createReader($name = 'Word2007')\n    {\n        return self::createObject('Reader', $name);\n    }\n\n    /**\n     * Create new object.\n     *\n     * @param string $type\n     * @param string $name\n     * @param PhpWord $phpWord\n     *\n     * @return ReaderInterface|WriterInterface\n     */\n    private static function createObject($type, $name, $phpWord = null)\n    {\n        $class = \"PhpOffice\\\\PhpWord\\\\{$type}\\\\{$name}\";\n        if (class_exists($class) && self::isConcreteClass($class)) {\n            return new $class($phpWord);\n        }\n\n        throw new Exception(\"\\\"{$name}\\\" is not a valid {$type}.\");\n    }\n\n    /**\n     * Loads PhpWord from file.\n     *\n     * @param string $filename The name of the file\n     * @param string $readerName\n     *\n     * @return PhpWord $phpWord\n     */\n    public static function load($filename, $readerName = 'Word2007')\n    {\n        /** @var ReaderInterface $reader */\n        $reader = self::createReader($readerName);\n\n        return $reader->load($filename);\n    }\n\n    /**\n     * Loads PhpWord ${variable} from file.\n     *\n     * @param string $filename The name of the file\n     *\n     * @return array The extracted variables\n     */\n    public static function extractVariables(string $filename, string $readerName = 'Word2007'): array\n    {\n        /** @var ReaderInterface $reader */\n        $reader = self::createReader($readerName);\n        $document = $reader->load($filename);\n        $extractedVariables = [];\n        foreach ($document->getSections() as $section) {\n            $concatenatedText = '';\n            foreach ($section->getElements() as $element) {\n                if ($element instanceof TextRun) {\n                    foreach ($element->getElements() as $textElement) {\n                        if ($textElement instanceof Text) {\n                            $text = $textElement->getText();\n                            $concatenatedText .= $text;\n                        }\n                    }\n                }\n            }\n            preg_match_all('/\\$\\{([^}]+)\\}/', $concatenatedText, $matches);\n            if (!empty($matches[1])) {\n                foreach ($matches[1] as $match) {\n                    $trimmedMatch = trim($match);\n                    $extractedVariables[] = $trimmedMatch;\n                }\n            }\n        }\n\n        return $extractedVariables;\n    }\n\n    /**\n     * Check if it's a concrete class (not abstract nor interface).\n     *\n     * @param string $class\n     *\n     * @return bool\n     */\n    private static function isConcreteClass($class)\n    {\n        $reflection = new ReflectionClass($class);\n\n        return !$reflection->isAbstract() && !$reflection->isInterface();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Media.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord;\n\nuse PhpOffice\\PhpWord\\Element\\Image;\nuse PhpOffice\\PhpWord\\Exception\\Exception;\n\n/**\n * Media collection.\n */\nclass Media\n{\n    /**\n     * Media elements.\n     *\n     * @var array\n     */\n    private static $elements = [];\n\n    /**\n     * Add new media element.\n     *\n     * @since 0.10.0\n     * @since 0.9.2\n     *\n     * @param string $container section|headerx|footerx|footnote|endnote\n     * @param string $mediaType image|object|link\n     * @param string $source\n     *\n     * @return int\n     */\n    public static function addElement($container, $mediaType, $source, ?Image $image = null)\n    {\n        // Assign unique media Id and initiate media container if none exists\n        $mediaId = md5($container . $source);\n        if (!isset(self::$elements[$container])) {\n            self::$elements[$container] = [];\n        }\n\n        // Add media if not exists or point to existing media\n        if (!isset(self::$elements[$container][$mediaId])) {\n            $mediaCount = self::countElements($container);\n            $mediaTypeCount = self::countElements($container, $mediaType);\n            ++$mediaTypeCount;\n            $rId = ++$mediaCount;\n            $target = null;\n            $mediaData = ['mediaIndex' => $mediaTypeCount];\n\n            switch ($mediaType) {\n                // Images\n                case 'image':\n                    if (null === $image) {\n                        throw new Exception('Image object not assigned.');\n                    }\n                    $isMemImage = $image->isMemImage();\n                    $extension = $image->getImageExtension();\n                    $mediaData['imageExtension'] = $extension;\n                    $mediaData['imageType'] = $image->getImageType();\n                    if ($isMemImage) {\n                        $mediaData['isMemImage'] = true;\n                        $mediaData['imageString'] = $image->getImageString();\n                    }\n                    $target = \"{$container}_image{$mediaTypeCount}.{$extension}\";\n                    $image->setTarget($target);\n                    $image->setMediaIndex($mediaTypeCount);\n\n                    break;\n                    // Objects\n                case 'object':\n                    $target = \"{$container}_oleObject{$mediaTypeCount}.bin\";\n\n                    break;\n                    // Links\n                case 'link':\n                    $target = $source;\n\n                    break;\n            }\n\n            $mediaData['source'] = $source;\n            $mediaData['target'] = $target;\n            $mediaData['type'] = $mediaType;\n            $mediaData['rID'] = $rId;\n            self::$elements[$container][$mediaId] = $mediaData;\n\n            return $rId;\n        }\n\n        $mediaData = self::$elements[$container][$mediaId];\n        if (null !== $image) {\n            $image->setTarget($mediaData['target']);\n            $image->setMediaIndex($mediaData['mediaIndex']);\n        }\n\n        return $mediaData['rID'];\n    }\n\n    /**\n     * Get media elements count.\n     *\n     * @param string $container section|headerx|footerx|footnote|endnote\n     * @param string $mediaType image|object|link\n     *\n     * @return int\n     *\n     * @since 0.10.0\n     */\n    public static function countElements($container, $mediaType = null)\n    {\n        $mediaCount = 0;\n\n        if (isset(self::$elements[$container])) {\n            foreach (self::$elements[$container] as $mediaData) {\n                if (null !== $mediaType) {\n                    if ($mediaType == $mediaData['type']) {\n                        ++$mediaCount;\n                    }\n                } else {\n                    ++$mediaCount;\n                }\n            }\n        }\n\n        return $mediaCount;\n    }\n\n    /**\n     * Get media elements.\n     *\n     * @param string $container section|headerx|footerx|footnote|endnote\n     * @param string $type image|object|link\n     *\n     * @return array\n     *\n     * @since 0.10.0\n     */\n    public static function getElements($container, $type = null)\n    {\n        $elements = [];\n\n        // If header/footer, search for headerx and footerx where x is number\n        if ($container == 'header' || $container == 'footer') {\n            foreach (self::$elements as $key => $val) {\n                if (substr($key, 0, 6) == $container) {\n                    $elements[$key] = $val;\n                }\n            }\n\n            return $elements;\n        }\n\n        if (!isset(self::$elements[$container])) {\n            return $elements;\n        }\n\n        return self::getElementsByType($container, $type);\n    }\n\n    /**\n     * Get elements by media type.\n     *\n     * @param string $container section|footnote|endnote\n     * @param string $type image|object|link\n     *\n     * @return array\n     *\n     * @since 0.11.0 Splitted from `getElements` to reduce complexity\n     */\n    private static function getElementsByType($container, $type = null)\n    {\n        $elements = [];\n\n        foreach (self::$elements[$container] as $key => $data) {\n            if ($type !== null) {\n                if ($type == $data['type']) {\n                    $elements[$key] = $data;\n                }\n            } else {\n                $elements[$key] = $data;\n            }\n        }\n\n        return $elements;\n    }\n\n    /**\n     * Reset media elements.\n     */\n    public static function resetElements(): void\n    {\n        self::$elements = [];\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Metadata/Compatibility.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Metadata;\n\n/**\n * Compatibility setting class.\n *\n * @since 0.12.0\n * @see  http://www.datypic.com/sc/ooxml/t-w_CT_Compat.html\n */\nclass Compatibility\n{\n    /**\n     * OOXML version.\n     *\n     * 12 = 2007\n     * 14 = 2010\n     * 15 = 2013\n     *\n     * @var int\n     *\n     * @see  http://msdn.microsoft.com/en-us/library/dd909048%28v=office.12%29.aspx\n     */\n    private $ooxmlVersion = 12;\n\n    /**\n     * Get OOXML version.\n     *\n     * @return int\n     */\n    public function getOoxmlVersion()\n    {\n        return $this->ooxmlVersion;\n    }\n\n    /**\n     * Set OOXML version.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setOoxmlVersion($value)\n    {\n        $this->ooxmlVersion = $value;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Metadata/DocInfo.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Metadata;\n\nuse DateTime;\n\n/**\n * Document information.\n */\nclass DocInfo\n{\n    /** @const string Property type constants */\n    const PROPERTY_TYPE_BOOLEAN = 'b';\n    const PROPERTY_TYPE_INTEGER = 'i';\n    const PROPERTY_TYPE_FLOAT = 'f';\n    const PROPERTY_TYPE_DATE = 'd';\n    const PROPERTY_TYPE_STRING = 's';\n    const PROPERTY_TYPE_UNKNOWN = 'u';\n\n    /**\n     * Creator.\n     *\n     * @var string\n     */\n    private $creator;\n\n    /**\n     * LastModifiedBy.\n     *\n     * @var string\n     */\n    private $lastModifiedBy;\n\n    /**\n     * Created.\n     *\n     * @var int\n     */\n    private $created;\n\n    /**\n     * Modified.\n     *\n     * @var int\n     */\n    private $modified;\n\n    /**\n     * Title.\n     *\n     * @var string\n     */\n    private $title;\n\n    /**\n     * Description.\n     *\n     * @var string\n     */\n    private $description;\n\n    /**\n     * Subject.\n     *\n     * @var string\n     */\n    private $subject;\n\n    /**\n     * Keywords.\n     *\n     * @var string\n     */\n    private $keywords;\n\n    /**\n     * Category.\n     *\n     * @var string\n     */\n    private $category;\n\n    /**\n     * Company.\n     *\n     * @var string\n     */\n    private $company;\n\n    /**\n     * Manager.\n     *\n     * @var string\n     */\n    private $manager;\n\n    /**\n     * Custom Properties.\n     *\n     * @var array\n     */\n    private $customProperties = [];\n\n    /**\n     * Create new instance.\n     */\n    public function __construct()\n    {\n        $this->creator = '';\n        $this->lastModifiedBy = $this->creator;\n        $this->created = time();\n        $this->modified = time();\n        $this->title = '';\n        $this->subject = '';\n        $this->description = '';\n        $this->keywords = '';\n        $this->category = '';\n        $this->company = '';\n        $this->manager = '';\n    }\n\n    /**\n     * Get Creator.\n     *\n     * @return string\n     */\n    public function getCreator()\n    {\n        return $this->creator;\n    }\n\n    /**\n     * Set Creator.\n     *\n     * @param  string $value\n     *\n     * @return self\n     */\n    public function setCreator($value = '')\n    {\n        $this->creator = $this->setValue($value, '');\n\n        return $this;\n    }\n\n    /**\n     * Get Last Modified By.\n     *\n     * @return string\n     */\n    public function getLastModifiedBy()\n    {\n        return $this->lastModifiedBy;\n    }\n\n    /**\n     * Set Last Modified By.\n     *\n     * @param  string $value\n     *\n     * @return self\n     */\n    public function setLastModifiedBy($value = '')\n    {\n        $this->lastModifiedBy = $this->setValue($value, $this->creator);\n\n        return $this;\n    }\n\n    /**\n     * Get Created.\n     *\n     * @return int\n     */\n    public function getCreated()\n    {\n        return $this->created;\n    }\n\n    /**\n     * Set Created.\n     *\n     * @param  int $value\n     *\n     * @return self\n     */\n    public function setCreated($value = null)\n    {\n        $this->created = $this->setValue($value, time());\n\n        return $this;\n    }\n\n    /**\n     * Get Modified.\n     *\n     * @return int\n     */\n    public function getModified()\n    {\n        return $this->modified;\n    }\n\n    /**\n     * Set Modified.\n     *\n     * @param  int $value\n     *\n     * @return self\n     */\n    public function setModified($value = null)\n    {\n        $this->modified = $this->setValue($value, time());\n\n        return $this;\n    }\n\n    /**\n     * Get Title.\n     *\n     * @return string\n     */\n    public function getTitle()\n    {\n        return $this->title;\n    }\n\n    /**\n     * Set Title.\n     *\n     * @param  string $value\n     *\n     * @return self\n     */\n    public function setTitle($value = '')\n    {\n        $this->title = $this->setValue($value, '');\n\n        return $this;\n    }\n\n    /**\n     * Get Description.\n     *\n     * @return string\n     */\n    public function getDescription()\n    {\n        return $this->description;\n    }\n\n    /**\n     * Set Description.\n     *\n     * @param  string $value\n     *\n     * @return self\n     */\n    public function setDescription($value = '')\n    {\n        $this->description = $this->setValue($value, '');\n\n        return $this;\n    }\n\n    /**\n     * Get Subject.\n     *\n     * @return string\n     */\n    public function getSubject()\n    {\n        return $this->subject;\n    }\n\n    /**\n     * Set Subject.\n     *\n     * @param  string $value\n     *\n     * @return self\n     */\n    public function setSubject($value = '')\n    {\n        $this->subject = $this->setValue($value, '');\n\n        return $this;\n    }\n\n    /**\n     * Get Keywords.\n     *\n     * @return string\n     */\n    public function getKeywords()\n    {\n        return $this->keywords;\n    }\n\n    /**\n     * Set Keywords.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setKeywords($value = '')\n    {\n        $this->keywords = $this->setValue($value, '');\n\n        return $this;\n    }\n\n    /**\n     * Get Category.\n     *\n     * @return string\n     */\n    public function getCategory()\n    {\n        return $this->category;\n    }\n\n    /**\n     * Set Category.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setCategory($value = '')\n    {\n        $this->category = $this->setValue($value, '');\n\n        return $this;\n    }\n\n    /**\n     * Get Company.\n     *\n     * @return string\n     */\n    public function getCompany()\n    {\n        return $this->company;\n    }\n\n    /**\n     * Set Company.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setCompany($value = '')\n    {\n        $this->company = $this->setValue($value, '');\n\n        return $this;\n    }\n\n    /**\n     * Get Manager.\n     *\n     * @return string\n     */\n    public function getManager()\n    {\n        return $this->manager;\n    }\n\n    /**\n     * Set Manager.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setManager($value = '')\n    {\n        $this->manager = $this->setValue($value, '');\n\n        return $this;\n    }\n\n    /**\n     * Get a List of Custom Property Names.\n     *\n     * @return array of string\n     */\n    public function getCustomProperties()\n    {\n        return array_keys($this->customProperties);\n    }\n\n    /**\n     * Check if a Custom Property is defined.\n     *\n     * @param string $propertyName\n     *\n     * @return bool\n     */\n    public function isCustomPropertySet($propertyName)\n    {\n        return isset($this->customProperties[$propertyName]);\n    }\n\n    /**\n     * Get a Custom Property Value.\n     *\n     * @param string $propertyName\n     *\n     * @return mixed\n     */\n    public function getCustomPropertyValue($propertyName)\n    {\n        if ($this->isCustomPropertySet($propertyName)) {\n            return $this->customProperties[$propertyName]['value'];\n        }\n\n        return null;\n    }\n\n    /**\n     * Get a Custom Property Type.\n     *\n     * @param string $propertyName\n     *\n     * @return ?string\n     */\n    public function getCustomPropertyType($propertyName)\n    {\n        if ($this->isCustomPropertySet($propertyName)) {\n            return $this->customProperties[$propertyName]['type'];\n        }\n\n        return null;\n    }\n\n    /**\n     * Set a Custom Property.\n     *\n     * @param string $propertyName\n     * @param mixed $propertyValue\n     * @param string $propertyType\n     *   'i': Integer\n     *   'f': Floating Point\n     *   's': String\n     *   'd': Date/Time\n     *   'b': Boolean\n     *\n     * @return self\n     */\n    public function setCustomProperty($propertyName, $propertyValue = '', $propertyType = null)\n    {\n        $propertyTypes = [\n            self::PROPERTY_TYPE_INTEGER,\n            self::PROPERTY_TYPE_FLOAT,\n            self::PROPERTY_TYPE_STRING,\n            self::PROPERTY_TYPE_DATE,\n            self::PROPERTY_TYPE_BOOLEAN,\n        ];\n        if (($propertyType === null) || (!in_array($propertyType, $propertyTypes))) {\n            if ($propertyValue === null) {\n                $propertyType = self::PROPERTY_TYPE_STRING;\n            } elseif (is_float($propertyValue)) {\n                $propertyType = self::PROPERTY_TYPE_FLOAT;\n            } elseif (is_int($propertyValue)) {\n                $propertyType = self::PROPERTY_TYPE_INTEGER;\n            } elseif (is_bool($propertyValue)) {\n                $propertyType = self::PROPERTY_TYPE_BOOLEAN;\n            } elseif ($propertyValue instanceof DateTime) {\n                $propertyType = self::PROPERTY_TYPE_DATE;\n            } else {\n                $propertyType = self::PROPERTY_TYPE_STRING;\n            }\n        }\n\n        $this->customProperties[$propertyName] = [\n            'value' => $propertyValue,\n            'type' => $propertyType,\n        ];\n\n        return $this;\n    }\n\n    /**\n     * Convert document property based on type.\n     *\n     * @param string $propertyValue\n     * @param string $propertyType\n     *\n     * @return mixed\n     */\n    public static function convertProperty($propertyValue, $propertyType)\n    {\n        $conversion = self::getConversion($propertyType);\n\n        switch ($conversion) {\n            case 'empty': // Empty\n                return '';\n            case 'null': // Null\n                return null;\n            case 'int': // Signed integer\n                return (int) $propertyValue;\n            case 'uint': // Unsigned integer\n                return abs((int) $propertyValue);\n            case 'float': // Float\n                return (float) $propertyValue;\n            case 'date': // Date\n                return strtotime($propertyValue);\n            case 'bool': // Boolean\n                return $propertyValue == 'true';\n        }\n\n        return $propertyValue;\n    }\n\n    /**\n     * Convert document property type.\n     *\n     * @param string $propertyType\n     *\n     * @return string\n     */\n    public static function convertPropertyType($propertyType)\n    {\n        $typeGroups = [\n            self::PROPERTY_TYPE_INTEGER => ['i1', 'i2', 'i4', 'i8', 'int', 'ui1', 'ui2', 'ui4', 'ui8', 'uint'],\n            self::PROPERTY_TYPE_FLOAT => ['r4', 'r8', 'decimal'],\n            self::PROPERTY_TYPE_STRING => ['empty', 'null', 'lpstr', 'lpwstr', 'bstr'],\n            self::PROPERTY_TYPE_DATE => ['date', 'filetime'],\n            self::PROPERTY_TYPE_BOOLEAN => ['bool'],\n        ];\n        foreach ($typeGroups as $groupId => $groupMembers) {\n            if (in_array($propertyType, $groupMembers)) {\n                return $groupId;\n            }\n        }\n\n        return self::PROPERTY_TYPE_UNKNOWN;\n    }\n\n    /**\n     * Set default for null and empty value.\n     *\n     * @param mixed $value\n     * @param mixed $default\n     *\n     * @return mixed\n     */\n    private function setValue($value, $default)\n    {\n        if ($value === null || $value == '') {\n            $value = $default;\n        }\n\n        return $value;\n    }\n\n    /**\n     * Get conversion model depending on property type.\n     *\n     * @param string $propertyType\n     *\n     * @return string\n     */\n    private static function getConversion($propertyType)\n    {\n        $conversions = [\n            'empty' => ['empty'],\n            'null' => ['null'],\n            'int' => ['i1', 'i2', 'i4', 'i8', 'int'],\n            'uint' => ['ui1', 'ui2', 'ui4', 'ui8', 'uint'],\n            'float' => ['r4', 'r8', 'decimal'],\n            'bool' => ['bool'],\n            'date' => ['date', 'filetime'],\n        ];\n        foreach ($conversions as $conversion => $types) {\n            if (in_array($propertyType, $types)) {\n                return $conversion;\n            }\n        }\n\n        return 'string';\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Metadata/Protection.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Metadata;\n\nuse InvalidArgumentException;\nuse PhpOffice\\PhpWord\\Shared\\Microsoft\\PasswordEncoder;\nuse PhpOffice\\PhpWord\\SimpleType\\DocProtect;\n\n/**\n * Document protection class.\n *\n * @since 0.12.0\n * @see http://www.datypic.com/sc/ooxml/t-w_CT_DocProtect.html\n */\nclass Protection\n{\n    /**\n     * Editing restriction none|readOnly|comments|trackedChanges|forms.\n     *\n     * @var string\n     *\n     * @see  http://www.datypic.com/sc/ooxml/a-w_edit-1.html\n     */\n    private $editing;\n\n    /**\n     * password.\n     *\n     * @var string\n     */\n    private $password;\n\n    /**\n     * Iterations to Run Hashing Algorithm.\n     *\n     * @var int\n     */\n    private $spinCount = 100000;\n\n    /**\n     * Cryptographic Hashing Algorithm (see constants defined in \\PhpOffice\\PhpWord\\Shared\\Microsoft\\PasswordEncoder).\n     *\n     * @var string\n     */\n    private $algorithm = PasswordEncoder::ALGORITHM_SHA_1;\n\n    /**\n     * Salt for Password Verifier.\n     *\n     * @var string\n     */\n    private $salt;\n\n    /**\n     * Create a new instance.\n     *\n     * @param string $editing\n     */\n    public function __construct($editing = null)\n    {\n        if ($editing != null) {\n            $this->setEditing($editing);\n        }\n    }\n\n    /**\n     * Get editing protection.\n     *\n     * @return string\n     */\n    public function getEditing()\n    {\n        return $this->editing;\n    }\n\n    /**\n     * Set editing protection.\n     *\n     * @param string $editing Any value of \\PhpOffice\\PhpWord\\SimpleType\\DocProtect\n     *\n     * @return self\n     */\n    public function setEditing($editing = null)\n    {\n        DocProtect::validate($editing);\n        $this->editing = $editing;\n\n        return $this;\n    }\n\n    /**\n     * Get password.\n     *\n     * @return string\n     */\n    public function getPassword()\n    {\n        return $this->password;\n    }\n\n    /**\n     * Set password.\n     *\n     * @param string $password\n     *\n     * @return self\n     */\n    public function setPassword($password)\n    {\n        $this->password = $password;\n\n        return $this;\n    }\n\n    /**\n     * Get count for hash iterations.\n     *\n     * @return int\n     */\n    public function getSpinCount()\n    {\n        return $this->spinCount;\n    }\n\n    /**\n     * Set count for hash iterations.\n     *\n     * @param int $spinCount\n     *\n     * @return self\n     */\n    public function setSpinCount($spinCount)\n    {\n        $this->spinCount = $spinCount;\n\n        return $this;\n    }\n\n    /**\n     * Get algorithm.\n     *\n     * @return string\n     */\n    public function getAlgorithm()\n    {\n        return $this->algorithm;\n    }\n\n    /**\n     * Set algorithm.\n     *\n     * @param string $algorithm\n     *\n     * @return self\n     */\n    public function setAlgorithm($algorithm)\n    {\n        $this->algorithm = $algorithm;\n\n        return $this;\n    }\n\n    /**\n     * Get salt.\n     *\n     * @return string\n     */\n    public function getSalt()\n    {\n        return $this->salt;\n    }\n\n    /**\n     * Set salt. Salt HAS to be 16 characters, or an exception will be thrown.\n     *\n     * @param string $salt\n     *\n     * @return self\n     */\n    public function setSalt($salt)\n    {\n        if ($salt !== null && strlen($salt) !== 16) {\n            throw new InvalidArgumentException('salt has to be of exactly 16 bytes length');\n        }\n\n        $this->salt = $salt;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Metadata/Settings.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Metadata;\n\nuse PhpOffice\\PhpWord\\ComplexType\\ProofState;\nuse PhpOffice\\PhpWord\\ComplexType\\TrackChangesView;\nuse PhpOffice\\PhpWord\\SimpleType\\Zoom;\nuse PhpOffice\\PhpWord\\Style\\Language;\n\n/**\n * Setting class.\n *\n * @since 0.14.0\n * @see  http://www.datypic.com/sc/ooxml/t-w_CT_Settings.html\n */\nclass Settings\n{\n    /**\n     * Magnification Setting.\n     *\n     * @see  http://www.datypic.com/sc/ooxml/e-w_zoom-1.html\n     *\n     * @var mixed either integer, in which case it treated as a percent, or one of PhpOffice\\PhpWord\\SimpleType\\Zoom\n     */\n    private $zoom = 100;\n\n    /**\n     * Mirror Page Margins.\n     *\n     * @see http://www.datypic.com/sc/ooxml/e-w_mirrorMargins-1.html\n     *\n     * @var bool\n     */\n    private $mirrorMargins;\n\n    /**\n     * Hide spelling errors.\n     *\n     * @var bool\n     */\n    private $hideSpellingErrors = false;\n\n    /**\n     * Hide grammatical errors.\n     *\n     * @var bool\n     */\n    private $hideGrammaticalErrors = false;\n\n    /**\n     * Visibility of Annotation Types.\n     *\n     * @var TrackChangesView\n     */\n    private $revisionView;\n\n    /**\n     * Track Revisions to Document.\n     *\n     * @var bool\n     */\n    private $trackRevisions = false;\n\n    /**\n     * Do Not Use Move Syntax When Tracking Revisions.\n     *\n     * @var bool\n     */\n    private $doNotTrackMoves = false;\n\n    /**\n     * Do Not Track Formatting Revisions When Tracking Revisions.\n     *\n     * @var bool\n     */\n    private $doNotTrackFormatting = false;\n\n    /**\n     * Spelling and Grammatical Checking State.\n     *\n     * @var ProofState\n     */\n    private $proofState;\n\n    /**\n     * Document Editing Restrictions.\n     *\n     * @var Protection\n     */\n    private $documentProtection;\n\n    /**\n     * Enables different header for odd and even pages.\n     *\n     * @var bool\n     */\n    private $evenAndOddHeaders = false;\n\n    /**\n     * Theme Font Languages.\n     *\n     * @var ?Language\n     */\n    private $themeFontLang;\n\n    /**\n     * Automatically Recalculate Fields on Open.\n     *\n     * @var bool\n     */\n    private $updateFields = false;\n\n    /**\n     * Radix Point for Field Code Evaluation.\n     *\n     * @var string\n     */\n    private $decimalSymbol = '.';\n\n    /**\n     * Automatically hyphenate document contents when displayed.\n     *\n     * @var null|bool\n     */\n    private $autoHyphenation;\n\n    /**\n     * Maximum number of consecutively hyphenated lines.\n     *\n     * @var null|int\n     */\n    private $consecutiveHyphenLimit;\n\n    /**\n     * The allowed amount of whitespace before hyphenation is applied.\n     *\n     * @var null|float|int\n     */\n    private $hyphenationZone;\n\n    /**\n     * Do not hyphenate words in all capital letters.\n     *\n     * @var null|bool\n     */\n    private $doNotHyphenateCaps;\n\n    /**\n     * Enable or disable book-folded printing.\n     *\n     * @var bool\n     */\n    private $bookFoldPrinting = false;\n\n    /**\n     * @return Protection\n     */\n    public function getDocumentProtection()\n    {\n        if ($this->documentProtection == null) {\n            $this->documentProtection = new Protection();\n        }\n\n        return $this->documentProtection;\n    }\n\n    /**\n     * @param Protection $documentProtection\n     */\n    public function setDocumentProtection($documentProtection): void\n    {\n        $this->documentProtection = $documentProtection;\n    }\n\n    /**\n     * @return ProofState\n     */\n    public function getProofState()\n    {\n        if ($this->proofState == null) {\n            $this->proofState = new ProofState();\n        }\n\n        return $this->proofState;\n    }\n\n    /**\n     * @param ProofState $proofState\n     */\n    public function setProofState($proofState): void\n    {\n        $this->proofState = $proofState;\n    }\n\n    /**\n     * Are spelling errors hidden.\n     *\n     * @return bool\n     */\n    public function hasHideSpellingErrors()\n    {\n        return $this->hideSpellingErrors;\n    }\n\n    /**\n     * Hide spelling errors.\n     *\n     * @param ?bool $hideSpellingErrors\n     */\n    public function setHideSpellingErrors($hideSpellingErrors): void\n    {\n        $this->hideSpellingErrors = $hideSpellingErrors === null ? true : $hideSpellingErrors;\n    }\n\n    /**\n     * Are grammatical errors hidden.\n     *\n     * @return bool\n     */\n    public function hasHideGrammaticalErrors()\n    {\n        return $this->hideGrammaticalErrors;\n    }\n\n    /**\n     * Hide grammatical errors.\n     *\n     * @param ?bool $hideGrammaticalErrors\n     */\n    public function setHideGrammaticalErrors($hideGrammaticalErrors): void\n    {\n        $this->hideGrammaticalErrors = $hideGrammaticalErrors === null ? true : $hideGrammaticalErrors;\n    }\n\n    /**\n     * @return bool\n     */\n    public function hasEvenAndOddHeaders()\n    {\n        return $this->evenAndOddHeaders;\n    }\n\n    /**\n     * @param ?bool $evenAndOddHeaders\n     */\n    public function setEvenAndOddHeaders($evenAndOddHeaders): void\n    {\n        $this->evenAndOddHeaders = $evenAndOddHeaders === null ? true : $evenAndOddHeaders;\n    }\n\n    /**\n     * Get the Visibility of Annotation Types.\n     *\n     * @return TrackChangesView\n     */\n    public function getRevisionView()\n    {\n        return $this->revisionView;\n    }\n\n    /**\n     * Set the Visibility of Annotation Types.\n     */\n    public function setRevisionView(?TrackChangesView $trackChangesView = null): void\n    {\n        $this->revisionView = $trackChangesView;\n    }\n\n    /**\n     * @return bool\n     */\n    public function hasTrackRevisions()\n    {\n        return $this->trackRevisions;\n    }\n\n    /**\n     * @param ?bool $trackRevisions\n     */\n    public function setTrackRevisions($trackRevisions): void\n    {\n        $this->trackRevisions = $trackRevisions === null ? true : $trackRevisions;\n    }\n\n    /**\n     * @return bool\n     */\n    public function hasDoNotTrackMoves()\n    {\n        return $this->doNotTrackMoves;\n    }\n\n    /**\n     * @param ?bool $doNotTrackMoves\n     */\n    public function setDoNotTrackMoves($doNotTrackMoves): void\n    {\n        $this->doNotTrackMoves = $doNotTrackMoves === null ? true : $doNotTrackMoves;\n    }\n\n    /**\n     * @return bool\n     */\n    public function hasDoNotTrackFormatting()\n    {\n        return $this->doNotTrackFormatting;\n    }\n\n    /**\n     * @param ?bool $doNotTrackFormatting\n     */\n    public function setDoNotTrackFormatting($doNotTrackFormatting): void\n    {\n        $this->doNotTrackFormatting = $doNotTrackFormatting === null ? true : $doNotTrackFormatting;\n    }\n\n    /**\n     * @return mixed\n     */\n    public function getZoom()\n    {\n        return $this->zoom;\n    }\n\n    /**\n     * @param mixed $zoom\n     */\n    public function setZoom($zoom): void\n    {\n        if (is_numeric($zoom)) {\n            // zoom is a percentage\n            $this->zoom = $zoom;\n        } else {\n            Zoom::validate($zoom);\n            $this->zoom = $zoom;\n        }\n    }\n\n    /**\n     * @return bool\n     */\n    public function hasMirrorMargins()\n    {\n        return $this->mirrorMargins;\n    }\n\n    /**\n     * @param bool $mirrorMargins\n     */\n    public function setMirrorMargins($mirrorMargins): void\n    {\n        $this->mirrorMargins = $mirrorMargins;\n    }\n\n    /**\n     * Returns the Language.\n     */\n    public function getThemeFontLang(): ?Language\n    {\n        return $this->themeFontLang;\n    }\n\n    /**\n     * Sets the Language for this document.\n     */\n    public function setThemeFontLang(Language $themeFontLang): self\n    {\n        $this->themeFontLang = $themeFontLang;\n\n        return $this;\n    }\n\n    /**\n     * @return bool\n     */\n    public function hasUpdateFields()\n    {\n        return $this->updateFields;\n    }\n\n    /**\n     * @param ?bool $updateFields\n     */\n    public function setUpdateFields($updateFields): void\n    {\n        $this->updateFields = $updateFields === null ? false : $updateFields;\n    }\n\n    /**\n     * Returns the Radix Point for Field Code Evaluation.\n     *\n     * @return string\n     */\n    public function getDecimalSymbol()\n    {\n        return $this->decimalSymbol;\n    }\n\n    /**\n     * sets the Radix Point for Field Code Evaluation.\n     *\n     * @param string $decimalSymbol\n     */\n    public function setDecimalSymbol($decimalSymbol): void\n    {\n        $this->decimalSymbol = $decimalSymbol;\n    }\n\n    /**\n     * @return null|bool\n     */\n    public function hasAutoHyphenation()\n    {\n        return $this->autoHyphenation;\n    }\n\n    /**\n     * @param bool $autoHyphenation\n     */\n    public function setAutoHyphenation($autoHyphenation): void\n    {\n        $this->autoHyphenation = (bool) $autoHyphenation;\n    }\n\n    /**\n     * @return null|int\n     */\n    public function getConsecutiveHyphenLimit()\n    {\n        return $this->consecutiveHyphenLimit;\n    }\n\n    /**\n     * @param int $consecutiveHyphenLimit\n     */\n    public function setConsecutiveHyphenLimit($consecutiveHyphenLimit): void\n    {\n        $this->consecutiveHyphenLimit = (int) $consecutiveHyphenLimit;\n    }\n\n    /**\n     * @return null|float|int\n     */\n    public function getHyphenationZone()\n    {\n        return $this->hyphenationZone;\n    }\n\n    /**\n     * @param null|float|int $hyphenationZone Measurement unit is twip\n     */\n    public function setHyphenationZone($hyphenationZone): void\n    {\n        $this->hyphenationZone = $hyphenationZone;\n    }\n\n    /**\n     * @return null|bool\n     */\n    public function hasDoNotHyphenateCaps()\n    {\n        return $this->doNotHyphenateCaps;\n    }\n\n    /**\n     * @param bool $doNotHyphenateCaps\n     */\n    public function setDoNotHyphenateCaps($doNotHyphenateCaps): void\n    {\n        $this->doNotHyphenateCaps = (bool) $doNotHyphenateCaps;\n    }\n\n    public function hasBookFoldPrinting(): bool\n    {\n        return $this->bookFoldPrinting;\n    }\n\n    public function setBookFoldPrinting(bool $bookFoldPrinting): self\n    {\n        $this->bookFoldPrinting = $bookFoldPrinting;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/PhpWord.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord;\n\nuse BadMethodCallException;\nuse PhpOffice\\PhpWord\\Element\\Section;\nuse PhpOffice\\PhpWord\\Exception\\Exception;\n\n/**\n * PHPWord main class.\n *\n * @method Collection\\Titles getTitles()\n * @method Collection\\Footnotes getFootnotes()\n * @method Collection\\Endnotes getEndnotes()\n * @method Collection\\Charts getCharts()\n * @method Collection\\Comments getComments()\n * @method int addBookmark(Element\\Bookmark $bookmark)\n * @method int addTitle(Element\\Title $title)\n * @method int addFootnote(Element\\Footnote $footnote)\n * @method int addEndnote(Element\\Endnote $endnote)\n * @method int addChart(Element\\Chart $chart)\n * @method int addComment(Element\\Comment $comment)\n * @method Style\\Paragraph addParagraphStyle(string $styleName, mixed $styles)\n * @method Style\\Font addFontStyle(string $styleName, mixed $fontStyle, mixed $paragraphStyle = null)\n * @method Style\\Font addLinkStyle(string $styleName, mixed $styles)\n * @method Style\\Font addTitleStyle(mixed $depth, mixed $fontStyle, mixed $paragraphStyle = null)\n * @method Style\\Table addTableStyle(string $styleName, mixed $styleTable, mixed $styleFirstRow = null)\n * @method Style\\Numbering addNumberingStyle(string $styleName, mixed $styles)\n */\nclass PhpWord\n{\n    /**\n     * Collection of sections.\n     *\n     * @var Section[]\n     */\n    private $sections = [];\n\n    /**\n     * Collections.\n     *\n     * @var array\n     */\n    private $collections = [];\n\n    /**\n     * Metadata.\n     *\n     * @var array\n     *\n     * @since 0.12.0\n     */\n    private $metadata = [];\n\n    /**\n     * Create new instance.\n     *\n     * Collections are created dynamically\n     */\n    public function __construct()\n    {\n        // Reset Media and styles\n        Media::resetElements();\n        Style::resetStyles();\n        Settings::setDefaultRtl(null);\n\n        // Collection\n        $collections = ['Bookmarks', 'Titles', 'Footnotes', 'Endnotes', 'Charts', 'Comments'];\n        foreach ($collections as $collection) {\n            $class = 'PhpOffice\\\\PhpWord\\\\Collection\\\\' . $collection;\n            $this->collections[$collection] = new $class();\n        }\n\n        // Metadata\n        $metadata = ['DocInfo', 'Settings', 'Compatibility'];\n        foreach ($metadata as $meta) {\n            $class = 'PhpOffice\\\\PhpWord\\\\Metadata\\\\' . $meta;\n            $this->metadata[$meta] = new $class();\n        }\n    }\n\n    /**\n     * Dynamic function call to reduce static dependency.\n     *\n     * @since 0.12.0\n     *\n     * @param mixed $function\n     * @param mixed $args\n     *\n     * @return mixed\n     */\n    public function __call($function, $args)\n    {\n        $function = strtolower($function);\n\n        $getCollection = [];\n        $addCollection = [];\n        $addStyle = [];\n\n        $collections = ['Bookmark', 'Title', 'Footnote', 'Endnote', 'Chart', 'Comment'];\n        foreach ($collections as $collection) {\n            $getCollection[] = strtolower(\"get{$collection}s\");\n            $addCollection[] = strtolower(\"add{$collection}\");\n        }\n\n        $styles = ['Paragraph', 'Font', 'Table', 'Numbering', 'Link', 'Title'];\n        foreach ($styles as $style) {\n            $addStyle[] = strtolower(\"add{$style}Style\");\n        }\n\n        // Run get collection method\n        if (in_array($function, $getCollection)) {\n            $key = ucfirst(str_replace('get', '', $function));\n\n            return $this->collections[$key];\n        }\n\n        // Run add collection item method\n        if (in_array($function, $addCollection)) {\n            $key = ucfirst(str_replace('add', '', $function) . 's');\n\n            $collectionObject = $this->collections[$key];\n\n            return $collectionObject->addItem($args[0] ?? null);\n        }\n\n        // Run add style method\n        if (in_array($function, $addStyle)) {\n            return forward_static_call_array(['PhpOffice\\\\PhpWord\\\\Style', $function], $args);\n        }\n\n        // Exception\n        throw new BadMethodCallException(\"Method $function is not defined.\");\n    }\n\n    /**\n     * Get document properties object.\n     *\n     * @return Metadata\\DocInfo\n     */\n    public function getDocInfo()\n    {\n        return $this->metadata['DocInfo'];\n    }\n\n    /**\n     * Get compatibility.\n     *\n     * @return Metadata\\Compatibility\n     *\n     * @since 0.12.0\n     */\n    public function getCompatibility()\n    {\n        return $this->metadata['Compatibility'];\n    }\n\n    /**\n     * Get compatibility.\n     *\n     * @return Metadata\\Settings\n     *\n     * @since 0.14.0\n     */\n    public function getSettings()\n    {\n        return $this->metadata['Settings'];\n    }\n\n    /**\n     * Get all sections.\n     *\n     * @return Section[]\n     */\n    public function getSections()\n    {\n        return $this->sections;\n    }\n\n    /**\n     * Returns the section at the requested position.\n     *\n     * @param int $index\n     *\n     * @return null|Section\n     */\n    public function getSection($index)\n    {\n        if (array_key_exists($index, $this->sections)) {\n            return $this->sections[$index];\n        }\n\n        return null;\n    }\n\n    /**\n     * Create new section.\n     *\n     * @param null|array|string $style\n     *\n     * @return Section\n     */\n    public function addSection($style = null)\n    {\n        $section = new Section(count($this->sections) + 1, $style);\n        $section->setPhpWord($this);\n        $this->sections[] = $section;\n\n        return $section;\n    }\n\n    /**\n     * Sorts the sections using the callable passed.\n     *\n     * @see http://php.net/manual/en/function.usort.php for usage\n     *\n     * @param callable $sorter\n     */\n    public function sortSections($sorter): void\n    {\n        usort($this->sections, $sorter);\n    }\n\n    /**\n     * Get default font name.\n     *\n     * @return string\n     */\n    public function getDefaultFontName()\n    {\n        return Settings::getDefaultFontName();\n    }\n\n    /**\n     * Set default font name.\n     *\n     * @param string $fontName\n     */\n    public function setDefaultFontName($fontName): void\n    {\n        Settings::setDefaultFontName($fontName);\n    }\n\n    /**\n     * Get default asian font name.\n     */\n    public function getDefaultAsianFontName(): string\n    {\n        return Settings::getDefaultAsianFontName();\n    }\n\n    /**\n     * Set default asian font name.\n     *\n     * @param string $fontName\n     */\n    public function setDefaultAsianFontName($fontName): void\n    {\n        Settings::setDefaultAsianFontName($fontName);\n    }\n\n    /**\n     * Set default font color.\n     */\n    public function setDefaultFontColor(string $fontColor): void\n    {\n        Settings::setDefaultFontColor($fontColor);\n    }\n\n    /**\n     * Get default font color.\n     */\n    public function getDefaultFontColor(): string\n    {\n        return Settings::getDefaultFontColor();\n    }\n\n    /**\n     * Get default font size.\n     *\n     * @return int\n     */\n    public function getDefaultFontSize()\n    {\n        return Settings::getDefaultFontSize();\n    }\n\n    /**\n     * Set default font size.\n     *\n     * @param int $fontSize\n     */\n    public function setDefaultFontSize($fontSize): void\n    {\n        Settings::setDefaultFontSize($fontSize);\n    }\n\n    /**\n     * Set default paragraph style definition to styles.xml.\n     *\n     * @param array $styles Paragraph style definition\n     *\n     * @return Style\\Paragraph\n     */\n    public function setDefaultParagraphStyle($styles)\n    {\n        return Style::setDefaultParagraphStyle($styles);\n    }\n\n    /**\n     * Save to file or download.\n     *\n     * All exceptions should already been handled by the writers\n     *\n     * @param string $filename\n     * @param string $format\n     * @param bool $download\n     *\n     * @return bool\n     */\n    public function save($filename, $format = 'Word2007', $download = false)\n    {\n        $mime = [\n            'Word2007' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n            'ODText' => 'application/vnd.oasis.opendocument.text',\n            'RTF' => 'application/rtf',\n            'HTML' => 'text/html',\n            'PDF' => 'application/pdf',\n        ];\n\n        $writer = IOFactory::createWriter($this, $format);\n\n        if ($download === true) {\n            header('Content-Description: File Transfer');\n            header('Content-Disposition: attachment; filename=\"' . $filename . '\"');\n            header('Content-Type: ' . $mime[$format]);\n            header('Content-Transfer-Encoding: binary');\n            header('Cache-Control: must-revalidate, post-check=0, pre-check=0');\n            header('Expires: 0');\n            $filename = 'php://output'; // Change filename to force download\n        }\n\n        $writer->save($filename);\n\n        return true;\n    }\n\n    /**\n     * Create new section.\n     *\n     * @deprecated 0.10.0\n     *\n     * @param array $settings\n     *\n     * @return Section\n     *\n     * @codeCoverageIgnore\n     */\n    public function createSection($settings = null)\n    {\n        return $this->addSection($settings);\n    }\n\n    /**\n     * Get document properties object.\n     *\n     * @deprecated 0.12.0\n     *\n     * @return Metadata\\DocInfo\n     *\n     * @codeCoverageIgnore\n     */\n    public function getDocumentProperties()\n    {\n        return $this->getDocInfo();\n    }\n\n    /**\n     * Set document properties object.\n     *\n     * @deprecated 0.12.0\n     *\n     * @param Metadata\\DocInfo $documentProperties\n     *\n     * @return self\n     *\n     * @codeCoverageIgnore\n     */\n    public function setDocumentProperties($documentProperties)\n    {\n        $this->metadata['Document'] = $documentProperties;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Reader/AbstractReader.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Reader;\n\nuse PhpOffice\\PhpWord\\Exception\\Exception;\n\n/**\n * Reader abstract class.\n *\n * @since 0.8.0\n *\n * @codeCoverageIgnore Abstract class\n */\nabstract class AbstractReader implements ReaderInterface\n{\n    /**\n     * Read data only?\n     *\n     * @var bool\n     */\n    protected $readDataOnly = true;\n\n    /**\n     * File pointer.\n     *\n     * @var bool|resource\n     */\n    protected $fileHandle;\n\n    /**\n     * Load images.\n     *\n     * @var bool\n     */\n    protected $imageLoading = true;\n\n    /**\n     * Read data only?\n     *\n     * @return bool\n     */\n    public function isReadDataOnly()\n    {\n        // return $this->readDataOnly;\n        return true;\n    }\n\n    /**\n     * Set read data only.\n     *\n     * @param bool $value\n     *\n     * @return self\n     */\n    public function setReadDataOnly($value = true)\n    {\n        $this->readDataOnly = $value;\n\n        return $this;\n    }\n\n    public function hasImageLoading(): bool\n    {\n        return $this->imageLoading;\n    }\n\n    public function setImageLoading(bool $value): self\n    {\n        $this->imageLoading = $value;\n\n        return $this;\n    }\n\n    /**\n     * Open file for reading.\n     *\n     * @param string $filename\n     *\n     * @return resource\n     */\n    protected function openFile($filename)\n    {\n        // Check if file exists\n        if (!file_exists($filename) || !is_readable($filename)) {\n            throw new Exception(\"Could not open $filename for reading! File does not exist.\");\n        }\n\n        // Open file\n        $this->fileHandle = fopen($filename, 'rb');\n        if ($this->fileHandle === false) {\n            throw new Exception(\"Could not open file $filename for reading.\");\n        }\n    }\n\n    /**\n     * Can the current ReaderInterface read the file?\n     *\n     * @param string $filename\n     *\n     * @return bool\n     */\n    public function canRead($filename)\n    {\n        // Check if file exists\n        try {\n            $this->openFile($filename);\n        } catch (Exception $e) {\n            return false;\n        }\n        if (is_resource($this->fileHandle)) {\n            fclose($this->fileHandle);\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Reader/HTML.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Reader;\n\nuse Exception;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Shared\\Html as HTMLParser;\n\n/**\n * HTML Reader class.\n *\n * @since 0.11.0\n */\nclass HTML extends AbstractReader implements ReaderInterface\n{\n    /**\n     * Loads PhpWord from file.\n     *\n     * @param string $docFile\n     *\n     * @return PhpWord\n     */\n    public function load($docFile)\n    {\n        $phpWord = new PhpWord();\n\n        if ($this->canRead($docFile)) {\n            $section = $phpWord->addSection();\n            HTMLParser::addHtml($section, file_get_contents($docFile), true);\n        } else {\n            throw new Exception(\"Cannot read {$docFile}.\");\n        }\n\n        return $phpWord;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Reader/MsDoc.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Reader;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Shared\\Drawing;\nuse PhpOffice\\PhpWord\\Shared\\OLERead;\nuse PhpOffice\\PhpWord\\Style;\nuse stdClass;\n\n/**\n * Reader for Word97.\n *\n * @since 0.10.0\n */\nclass MsDoc extends AbstractReader implements ReaderInterface\n{\n    /**\n     * PhpWord object.\n     *\n     * @var PhpWord\n     */\n    private $phpWord;\n\n    /**\n     * WordDocument Stream.\n     */\n    private $dataWorkDocument;\n\n    /**\n     * 1Table Stream.\n     */\n    private $data1Table;\n\n    /**\n     * Data Stream.\n     */\n    private $dataData;\n\n    /**\n     * Object Pool Stream.\n     */\n    private $dataObjectPool;\n\n    /**\n     * @var stdClass[]\n     */\n    private $arrayCharacters = [];\n\n    /**\n     * @var array\n     */\n    private $arrayFib = [];\n\n    /**\n     * @var string[]\n     */\n    private $arrayFonts = [];\n\n    /**\n     * @var string[]\n     */\n    private $arrayParagraphs = [];\n\n    /**\n     * @var stdClass[]\n     */\n    private $arraySections = [];\n\n    /** @var string */\n    private $summaryInformation;\n\n    /** @var string */\n    private $documentSummaryInformation;\n\n    const VERSION_97 = '97';\n    const VERSION_2000 = '2000';\n    const VERSION_2002 = '2002';\n    const VERSION_2003 = '2003';\n    const VERSION_2007 = '2007';\n\n    const SPRA_VALUE = 10;\n    const SPRA_VALUE_OPPOSITE = 20;\n\n    const OFFICEARTBLIPEMF = 0xF01A;\n    const OFFICEARTBLIPWMF = 0xF01B;\n    const OFFICEARTBLIPPICT = 0xF01C;\n    const OFFICEARTBLIPJPG = 0xF01D;\n    const OFFICEARTBLIPPNG = 0xF01E;\n    const OFFICEARTBLIPDIB = 0xF01F;\n    const OFFICEARTBLIPTIFF = 0xF029;\n    const OFFICEARTBLIPJPEG = 0xF02A;\n\n    const MSOBLIPERROR = 0x00;\n    const MSOBLIPUNKNOWN = 0x01;\n    const MSOBLIPEMF = 0x02;\n    const MSOBLIPWMF = 0x03;\n    const MSOBLIPPICT = 0x04;\n    const MSOBLIPJPEG = 0x05;\n    const MSOBLIPPNG = 0x06;\n    const MSOBLIPDIB = 0x07;\n    const MSOBLIPTIFF = 0x11;\n    const MSOBLIPCMYKJPEG = 0x12;\n\n    /**\n     * Loads PhpWord from file.\n     *\n     * @param string $filename\n     *\n     * @return PhpWord\n     */\n    public function load($filename)\n    {\n        $this->phpWord = new PhpWord();\n\n        $this->loadOLE($filename);\n\n        $this->readFib($this->dataWorkDocument);\n        $this->readFibContent();\n\n        return $this->phpWord;\n    }\n\n    /**\n     * Load an OLE Document.\n     *\n     * @param string $filename\n     */\n    private function loadOLE($filename): void\n    {\n        // OLE reader\n        $ole = new OLERead();\n        $ole->read($filename);\n\n        // Get WorkDocument stream\n        $this->dataWorkDocument = $ole->getStream($ole->wrkdocument);\n        // Get 1Table stream\n        $this->data1Table = $ole->getStream($ole->wrk1Table);\n        // Get Data stream\n        $this->dataData = $ole->getStream($ole->wrkData);\n        // Get Data stream\n        $this->dataObjectPool = $ole->getStream($ole->wrkObjectPool);\n        // Get Summary Information data\n        $this->summaryInformation = $ole->getStream($ole->summaryInformation);\n        // Get Document Summary Information data\n        $this->documentSummaryInformation = $ole->getStream($ole->docSummaryInfos);\n    }\n\n    private function getNumInLcb($lcb, $iSize)\n    {\n        return ($lcb - 4) / (4 + $iSize);\n    }\n\n    private function getArrayCP($data, $posMem, $iNum)\n    {\n        $arrayCP = [];\n        for ($inc = 0; $inc < $iNum; ++$inc) {\n            $arrayCP[$inc] = self::getInt4d($data, $posMem);\n            $posMem += 4;\n        }\n\n        return $arrayCP;\n    }\n\n    /**\n     * @see  http://msdn.microsoft.com/en-us/library/dd949344%28v=office.12%29.aspx\n     * @see  https://igor.io/2012/09/24/binary-parsing.html\n     *\n     * @param string $data\n     */\n    private function readFib($data)\n    {\n        $pos = 0;\n        //----- FibBase\n        // wIdent\n        $pos += 2;\n        // nFib\n        $pos += 2;\n        // unused\n        $pos += 2;\n        // lid : Language Identifier\n        $pos += 2;\n        // pnNext\n        $pos += 2;\n\n        // $mem = self::getInt2d($data, $pos);\n        // $fDot = ($mem >> 15) & 1;\n        // $fGlsy = ($mem >> 14) & 1;\n        // $fComplex = ($mem >> 13) & 1;\n        // $fHasPic = ($mem >> 12) & 1;\n        // $cQuickSaves = ($mem >> 8) & bindec('1111');\n        // $fEncrypted = ($mem >> 7) & 1;\n        // $fWhichTblStm = ($mem >> 6) & 1;\n        // $fReadOnlyRecommended = ($mem >> 5) & 1;\n        // $fWriteReservation = ($mem >> 4) & 1;\n        // $fExtChar = ($mem >> 3) & 1;\n        // $fLoadOverride = ($mem >> 2) & 1;\n        // $fFarEast = ($mem >> 1) & 1;\n        // $fObfuscated = ($mem >> 0) & 1;\n        $pos += 2;\n        // nFibBack\n        $pos += 2;\n        // lKey\n        $pos += 4;\n        // envr\n        ++$pos;\n\n        // $mem = self::getInt1d($data, $pos);\n        // $fMac = ($mem >> 7) & 1;\n        // $fEmptySpecial = ($mem >> 6) & 1;\n        // $fLoadOverridePage = ($mem >> 5) & 1;\n        // $reserved1 = ($mem >> 4) & 1;\n        // $reserved2 = ($mem >> 3) & 1;\n        // $fSpare0 = ($mem >> 0) & bindec('111');\n        ++$pos;\n\n        // reserved3\n        $pos += 2;\n        // reserved4\n        $pos += 2;\n        // reserved5\n        $pos += 4;\n        // reserved6\n        $pos += 4;\n\n        //----- csw\n        $pos += 2;\n\n        //----- fibRgW\n        // reserved1\n        $pos += 2;\n        // reserved2\n        $pos += 2;\n        // reserved3\n        $pos += 2;\n        // reserved4\n        $pos += 2;\n        // reserved5\n        $pos += 2;\n        // reserved6\n        $pos += 2;\n        // reserved7\n        $pos += 2;\n        // reserved8\n        $pos += 2;\n        // reserved9\n        $pos += 2;\n        // reserved10\n        $pos += 2;\n        // reserved11\n        $pos += 2;\n        // reserved12\n        $pos += 2;\n        // reserved13\n        $pos += 2;\n        // lidFE\n        $pos += 2;\n\n        //----- cslw\n        $pos += 2;\n\n        //----- fibRgLw\n        // cbMac\n        $pos += 4;\n        // reserved1\n        $pos += 4;\n        // reserved2\n        $pos += 4;\n        $this->arrayFib['ccpText'] = self::getInt4d($data, $pos);\n        $pos += 4;\n        $this->arrayFib['ccpFtn'] = self::getInt4d($data, $pos);\n        $pos += 4;\n        $this->arrayFib['ccpHdd'] = self::getInt4d($data, $pos);\n        $pos += 4;\n        // reserved3\n        $pos += 4;\n        // ccpAtn\n        $pos += 4;\n        // ccpEdn\n        $pos += 4;\n        // ccpTxbx\n        $pos += 4;\n        // ccpHdrTxbx\n        $pos += 4;\n        // reserved4\n        $pos += 4;\n        // reserved5\n        $pos += 4;\n        // reserved6\n        $pos += 4;\n        // reserved7\n        $pos += 4;\n        // reserved8\n        $pos += 4;\n        // reserved9\n        $pos += 4;\n        // reserved10\n        $pos += 4;\n        // reserved11\n        $pos += 4;\n        // reserved12\n        $pos += 4;\n        // reserved13\n        $pos += 4;\n        // reserved14\n        $pos += 4;\n\n        //----- cbRgFcLcb\n        $cbRgFcLcb = self::getInt2d($data, $pos);\n        $pos += 2;\n        //----- fibRgFcLcbBlob\n        switch ($cbRgFcLcb) {\n            case 0x005D:\n                $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_97);\n\n                break;\n            case 0x006C:\n                $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_97);\n                $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_2000);\n\n                break;\n            case 0x0088:\n                $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_97);\n                $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_2000);\n                $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_2002);\n\n                break;\n            case 0x00A4:\n                $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_97);\n                $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_2000);\n                $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_2002);\n                $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_2003);\n\n                break;\n            case 0x00B7:\n                $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_97);\n                $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_2000);\n                $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_2002);\n                $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_2003);\n                $pos = $this->readBlockFibRgFcLcb($data, $pos, self::VERSION_2007);\n\n                break;\n        }\n        //----- cswNew\n        $this->arrayFib['cswNew'] = self::getInt2d($data, $pos);\n        $pos += 2;\n\n        if ($this->arrayFib['cswNew'] != 0) {\n            //@todo : fibRgCswNew\n        }\n\n        return $pos;\n    }\n\n    private function readBlockFibRgFcLcb($data, $pos, $version)\n    {\n        if ($version == self::VERSION_97) {\n            $this->arrayFib['fcStshfOrig'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbStshfOrig'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcStshf'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbStshf'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcffndRef'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcffndRef'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcffndTxt'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcffndTxt'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfandRef'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfandRef'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfandTxt'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfandTxt '] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfSed'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfSed'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcPad'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcPad'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfPhe'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfPhe'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcSttbfGlsy'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbSttbfGlsy'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfGlsy'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfGlsy'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfHdd'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfHdd'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfBteChpx'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfBteChpx'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfBtePapx'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfBtePapx'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfSea'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfSea'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcSttbfFfn'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbSttbfFfn'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfFldMom'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfFldMom'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfFldHdr'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfFldHdr'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfFldFtn'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfFldFtn'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfFldAtn'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfFldAtn'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfFldMcr'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfFldMcr'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcSttbfBkmk'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbSttbfBkmk'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfBkf'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfBkf'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfBkl'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfBkl'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcCmds'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbCmds'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcUnused1'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbUnused1'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcSttbfMcr'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbSttbfMcr'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPrDrvr'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPrDrvr'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPrEnvPort'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPrEnvPort'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPrEnvLand'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPrEnvLand'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcWss'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbWss'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcDop'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbDop'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcSttbfAssoc'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbSttbfAssoc'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcClx'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbClx'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfPgdFtn'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfPgdFtn'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcAutosaveSource'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbAutosaveSource'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcGrpXstAtnOwners'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbGrpXstAtnOwners'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcSttbfAtnBkmk'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbSttbfAtnBkmk'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcUnused2'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbUnused2'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcUnused3'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbUnused3'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcSpaMom'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcSpaMom'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcSpaHdr'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcSpaHdr'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfAtnBkf'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfAtnBkf'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfAtnBkl'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfAtnBkl'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPms'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPms'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcFormFldSttbs'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbFormFldSttbs'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfendRef'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfendRef'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfendTxt'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfendTxt'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfFldEdn'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfFldEdn'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcUnused4'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbUnused4'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcDggInfo'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbDggInfo'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcSttbfRMark'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbSttbfRMark'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcSttbfCaption'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbSttbfCaption'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcSttbfAutoCaption'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbSttbfAutoCaption'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfWkb'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfWkb'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfSpl'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfSpl'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcftxbxTxt'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcftxbxTxt'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfFldTxbx'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfFldTxbx'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfHdrtxbxTxt'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfHdrtxbxTxt'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcffldHdrTxbx'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcffldHdrTxbx'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcStwUser'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbStwUser'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcSttbTtmbd'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbSttbTtmbd'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcCookieData'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbCookieData'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPgdMotherOldOld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPgdMotherOldOld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcBkdMotherOldOld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbBkdMotherOldOld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPgdFtnOldOld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPgdFtnOldOld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcBkdFtnOldOld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbBkdFtnOldOld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPgdEdnOldOld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPgdEdnOldOld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcBkdEdnOldOld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbBkdEdnOldOld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcSttbfIntlFld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbSttbfIntlFld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcRouteSlip'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbRouteSlip'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcSttbSavedBy'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbSttbSavedBy'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcSttbFnm'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbSttbFnm'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlfLst'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlfLst'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlfLfo'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlfLfo'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfTxbxBkd'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfTxbxBkd'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfTxbxHdrBkd'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfTxbxHdrBkd'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcDocUndoWord9'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbDocUndoWord9'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcRgbUse'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbRgbUse'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcUsp'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbUsp'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcUskf'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbUskf'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcupcRgbUse'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcupcRgbUse'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcupcUsp'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcupcUsp'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcSttbGlsyStyle'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbSttbGlsyStyle'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlgosl'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlgosl'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcocx'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcocx'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfBteLvc'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfBteLvc'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['dwLowDateTime'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['dwHighDateTime'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfLvcPre10'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfLvcPre10'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfAsumy'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfAsumy'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfGram'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfGram'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcSttbListNames'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbSttbListNames'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcSttbfUssr'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbSttbfUssr'] = self::getInt4d($data, $pos);\n            $pos += 4;\n        }\n        if ($version == self::VERSION_2000) {\n            $this->arrayFib['fcPlcfTch'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfTch'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcRmdThreading'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbRmdThreading'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcMid'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbMid'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcSttbRgtplc'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbSttbRgtplc'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcMsoEnvelope'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbMsoEnvelope'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfLad'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfLad'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcRgDofr'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbRgDofr'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcosl'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcosl'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfCookieOld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfCookieOld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPgdMotherOld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPgdMotherOld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcBkdMotherOld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbBkdMotherOld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPgdFtnOld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPgdFtnOld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcBkdFtnOld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbBkdFtnOld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPgdEdnOld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPgdEdnOld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcBkdEdnOld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbBkdEdnOld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n        }\n        if ($version == self::VERSION_2002) {\n            $this->arrayFib['fcUnused1'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbUnused1'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfPgp'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfPgp'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfuim'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfuim'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlfguidUim'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlfguidUim'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcAtrdExtra'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbAtrdExtra'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlrsid'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlrsid'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcSttbfBkmkFactoid'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbSttbfBkmkFactoid'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfBkfFactoid'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfBkfFactoid'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfcookie'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfcookie'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfBklFactoid'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfBklFactoid'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcFactoidData'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbFactoidData'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcDocUndo'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbDocUndo'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcSttbfBkmkFcc'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbSttbfBkmkFcc'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfBkfFcc'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfBkfFcc'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfBklFcc'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfBklFcc'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcSttbfbkmkBPRepairs'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbSttbfbkmkBPRepairs'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfbkfBPRepairs'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfbkfBPRepairs'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfbklBPRepairs'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfbklBPRepairs'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPmsNew'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPmsNew'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcODSO'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbODSO'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfpmiOldXP'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfpmiOldXP'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfpmiNewXP'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfpmiNewXP'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfpmiMixedXP'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfpmiMixedXP'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcUnused2'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbUnused2'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcffactoid'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcffactoid'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcflvcOldXP'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcflvcOldXP'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcflvcNewXP'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcflvcNewXP'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcflvcMixedXP'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcflvcMixedXP'] = self::getInt4d($data, $pos);\n            $pos += 4;\n        }\n        if ($version == self::VERSION_2003) {\n            $this->arrayFib['fcHplxsdr'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbHplxsdr'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcSttbfBkmkSdt'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbSttbfBkmkSdt'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfBkfSdt'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfBkfSdt'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfBklSdt'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfBklSdt'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcCustomXForm'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbCustomXForm'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcSttbfBkmkProt'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbSttbfBkmkProt'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfBkfProt'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfBkfProt'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfBklProt'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfBklProt'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcSttbProtUser'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbSttbProtUser'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcUnused'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbUnused'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfpmiOld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfpmiOld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfpmiOldInline'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfpmiOldInline'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfpmiNew'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfpmiNew'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfpmiNewInline'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfpmiNewInline'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcflvcOld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcflvcOld'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcflvcOldInline'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcflvcOldInline'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcflvcNew'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcflvcNew'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcflvcNewInline'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcflvcNewInline'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPgdMother'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPgdMother'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcBkdMother'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbBkdMother'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcAfdMother'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbAfdMother'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPgdFtn'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPgdFtn'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcBkdFtn'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbBkdFtn'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcAfdFtn'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbAfdFtn'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPgdEdn'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPgdEdn'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcBkdEdn'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbBkdEdn'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcAfdEdn'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbAfdEdn'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcAfd'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbAfd'] = self::getInt4d($data, $pos);\n            $pos += 4;\n        }\n        if ($version == self::VERSION_2007) {\n            $this->arrayFib['fcPlcfmthd'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfmthd'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcSttbfBkmkMoveFrom'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbSttbfBkmkMoveFrom'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfBkfMoveFrom'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfBkfMoveFrom'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfBklMoveFrom'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfBklMoveFrom'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcSttbfBkmkMoveTo'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbSttbfBkmkMoveTo'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfBkfMoveTo'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfBkfMoveTo'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfBklMoveTo'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfBklMoveTo'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcUnused1'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbUnused1'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcUnused2'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbUnused2'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcUnused3'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbUnused3'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcSttbfBkmkArto'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbSttbfBkmkArto'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfBkfArto'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfBkfArto'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcPlcfBklArto'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbPlcfBklArto'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcArtoData'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbArtoData'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcUnused4'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbUnused4'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcUnused5'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbUnused5'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcUnused6'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbUnused6'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcOssTheme'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbOssTheme'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['fcColorSchemeMapping'] = self::getInt4d($data, $pos);\n            $pos += 4;\n            $this->arrayFib['lcbColorSchemeMapping'] = self::getInt4d($data, $pos);\n            $pos += 4;\n        }\n\n        return $pos;\n    }\n\n    private function readFibContent(): void\n    {\n        // Informations about Font\n        $this->readRecordSttbfFfn();\n\n        // Informations about page\n        $this->readRecordPlcfSed();\n\n        // reading paragraphs\n        //@see  https://github.com/notmasteryet/CompoundFile/blob/ec118f354efebdee9102e41b5b7084fce81125b0/WordFileReader/WordDocument.cs#L86\n        $this->readRecordPlcfBtePapx();\n\n        // reading character formattings\n        //@see  https://github.com/notmasteryet/CompoundFile/blob/ec118f354efebdee9102e41b5b7084fce81125b0/WordFileReader/WordDocument.cs#L94\n        $this->readRecordPlcfBteChpx();\n\n        $this->generatePhpWord();\n    }\n\n    /**\n     * Section and information about them.\n     *\n     * @see  http://msdn.microsoft.com/en-us/library/dd924458%28v=office.12%29.aspx\n     */\n    private function readRecordPlcfSed(): void\n    {\n        $posMem = $this->arrayFib['fcPlcfSed'];\n        // PlcfSed\n        // PlcfSed : aCP\n        $aCP = [];\n        $aCP[0] = self::getInt4d($this->data1Table, $posMem);\n        $posMem += 4;\n        $aCP[1] = self::getInt4d($this->data1Table, $posMem);\n        $posMem += 4;\n\n        // PlcfSed : aSed\n        //@see  http://msdn.microsoft.com/en-us/library/dd950194%28v=office.12%29.aspx\n        $numSed = $this->getNumInLcb($this->arrayFib['lcbPlcfSed'], 12);\n\n        $aSed = [];\n        for ($iInc = 0; $iInc < $numSed; ++$iInc) {\n            // Sed : http://msdn.microsoft.com/en-us/library/dd950982%28v=office.12%29.aspx\n            // fn\n            $posMem += 2;\n            // fnMpr\n            $aSed[$iInc] = self::getInt4d($this->data1Table, $posMem);\n            $posMem += 4;\n            // fnMpr\n            $posMem += 2;\n            // fcMpr\n            $posMem += 4;\n        }\n\n        foreach ($aSed as $offsetSed) {\n            // Sepx : http://msdn.microsoft.com/en-us/library/dd921348%28v=office.12%29.aspx\n            $cb = self::getInt2d($this->dataWorkDocument, $offsetSed);\n            $offsetSed += 2;\n\n            $oStylePrl = $this->readPrl($this->dataWorkDocument, $offsetSed, $cb);\n            $offsetSed += $oStylePrl->length;\n\n            $this->arraySections[] = $oStylePrl;\n        }\n    }\n\n    /**\n     * Specifies the fonts that are used in the document.\n     *\n     * @see  http://msdn.microsoft.com/en-us/library/dd943880%28v=office.12%29.aspx\n     */\n    private function readRecordSttbfFfn(): void\n    {\n        $posMem = $this->arrayFib['fcSttbfFfn'];\n\n        $cData = self::getInt2d($this->data1Table, $posMem);\n        $posMem += 2;\n        $cbExtra = self::getInt2d($this->data1Table, $posMem);\n        $posMem += 2;\n\n        if ($cData < 0x7FF0 && $cbExtra == 0) {\n            for ($inc = 0; $inc < $cData; ++$inc) {\n                // len\n                ++$posMem;\n                // ffid\n                ++$posMem;\n                // wWeight (400 : Normal - 700 bold)\n                $posMem += 2;\n                // chs\n                ++$posMem;\n                // ixchSzAlt\n                $ixchSzAlt = self::getInt1d($this->data1Table, $posMem);\n                ++$posMem;\n                // panose\n                $posMem += 10;\n                // fs\n                $posMem += 24;\n                // xszFfn\n                $xszFfn = '';\n                do {\n                    $char = self::getInt2d($this->data1Table, $posMem);\n                    $posMem += 2;\n                    if ($char > 0) {\n                        $xszFfn .= chr($char);\n                    }\n                } while ($char != 0);\n                // xszAlt\n                $xszAlt = '';\n                if ($ixchSzAlt > 0) {\n                    do {\n                        $char = self::getInt2d($this->data1Table, $posMem);\n                        $posMem += 2;\n                        if ($char == 0) {\n                            break;\n                        }\n                        $xszAlt .= chr($char);\n                    } while ($char != 0);\n                }\n                $this->arrayFonts[] = [\n                    'main' => $xszFfn,\n                    'alt' => $xszAlt,\n                ];\n            }\n        }\n    }\n\n    /**\n     * Paragraph and information about them.\n     *\n     * @see  http://msdn.microsoft.com/en-us/library/dd908569%28v=office.12%29.aspx\n     */\n    private function readRecordPlcfBtePapx(): void\n    {\n        $posMem = $this->arrayFib['fcPlcfBtePapx'];\n        $num = $this->getNumInLcb($this->arrayFib['lcbPlcfBtePapx'], 4);\n        $posMem += 4 * ($num + 1);\n        $arrAPnBtePapx = $this->getArrayCP($this->data1Table, $posMem, $num);\n        $posMem += 4 * $num;\n\n        foreach ($arrAPnBtePapx as $aPnBtePapx) {\n            $offsetBase = $aPnBtePapx * 512;\n            $offset = $offsetBase;\n\n            $string = '';\n\n            $numRun = self::getInt1d($this->dataWorkDocument, $offset + 511);\n            $arrayRGFC = [];\n            for ($inc = 0; $inc <= $numRun; ++$inc) {\n                $arrayRGFC[$inc] = self::getInt4d($this->dataWorkDocument, $offset);\n                $offset += 4;\n            }\n            $arrayRGB = [];\n            for ($inc = 1; $inc <= $numRun; ++$inc) {\n                // @see  http://msdn.microsoft.com/en-us/library/dd925804(v=office.12).aspx\n                $arrayRGB[$inc] = self::getInt1d($this->dataWorkDocument, $offset);\n                ++$offset;\n                // reserved\n                $offset += 12;\n            }\n\n            foreach (array_keys($arrayRGFC) as $key) {\n                if (!isset($arrayRGFC[$key + 1])) {\n                    break;\n                }\n                $strLen = $arrayRGFC[$key + 1] - $arrayRGFC[$key] - 1;\n                for ($inc = 0; $inc < ($strLen * 2); ++$inc) {\n                    $byte = self::getInt2d($this->dataWorkDocument, $arrayRGFC[$key] + ($inc * 2));\n                    if ($byte > 0) {\n                        $string .= mb_chr($byte, 'UTF-8');\n                    } else {\n                        break;\n                    }\n                }\n            }\n            $this->arrayParagraphs[] = $string;\n\n            //@todo readPrl for paragraphs\n            /*// use $this->readPrl()\n            foreach ($arrayRGB as $key => $rgb) {\n                $offset = $offsetBase + ($rgb * 2);\n\n                $cb = self::getInt1d($this->dataWorkDocument, $offset);\n                $offset += 1;\n                print_r('$cb : '.$cb.PHP_EOL);\n                if ($cb == 0) {\n                    $cb = self::getInt1d($this->dataWorkDocument, $offset);\n                    $cb = $cb * 2;\n                    $offset += 1;\n                    print_r('$cb0 : '.$cb.PHP_EOL);\n                } else {\n                    $cb = $cb * 2 - 1;\n                    print_r('$cbD : '.$cb.PHP_EOL);\n                }\n                $istd = self::getInt2d($this->dataWorkDocument, $offset);\n                $offset += 2;\n                $cb -= 2;\n                print_r('$istd : '.$istd.($istd == 0 ? ' (Normal)' : '').PHP_EOL);\n                if ($cb > 0) {\n                    do{\n                        $sprm = self::getInt2d($this->dataWorkDocument, $offset);\n                        $offset += 2;\n                        $cb -= 2;\n                        $sprm_IsPmd = $sprm & 0x01FF;\n                        $sprm_F = ($sprm/512) & 0x0001;\n                        $sprm_Sgc = ($sprm/1024) & 0x0007;\n                        $sprm_Spra = ($sprm/8192);\n\n                        print_r('$sprm : 0x'.dechex($sprm).PHP_EOL);\n                        print_r('$sprm.ispmd : 0x'.dechex($sprm_IsPmd).PHP_EOL);\n                        print_r('$sprm.f : 0x'.dechex($sprm_F).PHP_EOL);\n                        print_r('$sprm.sgc : 0x'.dechex($sprm_Sgc));\n                        switch (dechex($sprm_Sgc)) {\n                            case 0x01:\n                                print_r(' (Paragraph property)');\n                                break;\n                            case 0x02:\n                                print_r(' (Character property)');\n                                break;\n                            case 0x03:\n                                print_r(' (Picture property)');\n                                break;\n                            case 0x04:\n                                print_r(' (Section property)');\n                                break;\n                            case 0x05:\n                                print_r(' (Table property)');\n                                break;\n                        }\n                        print_r(PHP_EOL);\n                        print_r('$sprm.spra : 0x'.dechex($sprm_Spra).PHP_EOL);\n                        switch (dechex($sprm_Spra)) {\n                            case 0x0:\n                                $operand = self::getInt1d($this->dataWorkDocument, $offset);\n                                $offset += 1;\n                                $cb -= 1;\n                                switch (dechex($operand)) {\n                                    case 0x00:\n                                        $operand = 'OFF';\n                                        break;\n                                    case 0x01:\n                                        $operand = 'ON';\n                                        break;\n                                    case 0x80:\n                                        $operand = 'CURRENT VALUE';\n                                        print_r(''.PHP_EOL.PHP_EOL);\n                                        break;\n                                    case 0x81:\n                                        $operand = 'OPPOSITE OF THE CURRENT VALUE';\n                                        break;\n                                }\n                                break;\n                            case 0x1:\n                                $operand = self::getInt1d($this->dataWorkDocument, $offset);\n                                $offset += 1;\n                                $cb -= 1;\n                                print_r('$operand : 0x'.dechex($operand).PHP_EOL);\n                                break;\n                            case 0x2:\n                            case 0x4:\n                            case 0x5:\n                                $operand = self::getInt2d($this->dataWorkDocument, $offset);\n                                $offset += 2;\n                                $cb -= 2;\n                                print_r('$operand : 0x'.dechex($operand).PHP_EOL);\n                                break;\n                            case 0x3:\n                                if ($sprm_IsPmd != 0x70) {\n                                    $operand = self::getInt4d($this->dataWorkDocument, $offset);\n                                    $offset += 4;\n                                    $cb -= 4;\n                                    print_r('$operand : 0x'.dechex($operand).PHP_EOL);\n                                }\n                                break;\n                            case 0x7:\n                                $operand = self::getInt3d($this->dataWorkDocument, $offset);\n                                $offset += 3;\n                                $cb -= 3;\n                                print_r('$operand : 0x'.dechex($operand).PHP_EOL);\n                                break;\n                            default:\n                                print_r('YO YO YO : '.PHP_EOL);\n                        }\n\n                        //\n                        switch (dechex($sprm_Sgc)) {\n                            case 0x01: // Sprm is modifying a paragraph property.\n                                switch ($sprm_IsPmd) {\n                                    case 0x0A: // sprmPIlvl\n                                        print_r('sprmPIlvl : '.$operand.PHP_EOL.PHP_EOL);\n                                        break;\n                                    case 0x0B: // sprmPIlfo\n                                        print_r('sprmPIlfo : '.$operand.PHP_EOL.PHP_EOL);\n                                        break;\n                                    default:\n                                        print_r('$sprm_IsPmd(1) : '.$sprm_IsPmd.PHP_EOL.PHP_EOL);\n                                        break;\n                                }\n                                break;\n                            case 0x02: // Sprm is modifying a character property.\n                                switch ($sprm_IsPmd) {\n                                    default:\n                                        print_r('$sprm_IsPmd(2) : '.$sprm_IsPmd.PHP_EOL.PHP_EOL);\n                                        break;\n                                }\n                                break;\n                            case 0x03: // Sprm is modifying a picture property.\n                                switch ($sprm_IsPmd) {\n                                    default:\n                                        print_r('$sprm_IsPmd(3) : '.$sprm_IsPmd.PHP_EOL.PHP_EOL);\n                                        break;\n                                }\n                                break;\n                            case 0x04: // Sprm is modifying a section property.\n                                switch ($sprm_IsPmd) {\n                                    default:\n                                        print_r('$sprm_IsPmd(4) : '.$sprm_IsPmd.PHP_EOL.PHP_EOL);\n                                        break;\n                                }\n                                break;\n                            case 0x05: // Sprm is modifying a table property.\n                                switch ($sprm_IsPmd) {\n                                    default:\n                                        print_r('$sprm_IsPmd(4) : '.$sprm_IsPmd.PHP_EOL.PHP_EOL);\n                                        break;\n                                }\n                                break;\n                            default:\n                                print_r('$sprm_Sgc : '.dechex($sprm_Sgc).PHP_EOL.PHP_EOL);\n                                break;\n                        }\n                    } while ($cb > 0);\n                } else {\n                    if ($istd > 0) {\n                        // @todo : Determining Properties of a Paragraph Style\n                        # @see  http://msdn.microsoft.com/en-us/library/dd948631%28v=office.12%29.aspx\n                    }\n                }\n            }*/\n        }\n    }\n\n    /**\n     * Character formatting properties to text in a document.\n     *\n     * @see  http://msdn.microsoft.com/en-us/library/dd907108%28v=office.12%29.aspx\n     */\n    private function readRecordPlcfBteChpx(): void\n    {\n        $posMem = $this->arrayFib['fcPlcfBteChpx'];\n        $num = $this->getNumInLcb($this->arrayFib['lcbPlcfBteChpx'], 4);\n        $aPnBteChpx = [];\n        for ($inc = 0; $inc <= $num; ++$inc) {\n            $aPnBteChpx[$inc] = self::getInt4d($this->data1Table, $posMem);\n            $posMem += 4;\n        }\n        $pnFkpChpx = self::getInt4d($this->data1Table, $posMem);\n        $posMem += 4;\n\n        $offsetBase = $pnFkpChpx * 512;\n        $offset = $offsetBase;\n\n        // ChpxFkp\n        // @see  http://msdn.microsoft.com/en-us/library/dd910989%28v=office.12%29.aspx\n        $numRGFC = self::getInt1d($this->dataWorkDocument, $offset + 511);\n        $arrayRGFC = [];\n        for ($inc = 0; $inc <= $numRGFC; ++$inc) {\n            $arrayRGFC[$inc] = self::getInt4d($this->dataWorkDocument, $offset);\n            $offset += 4;\n        }\n\n        $arrayRGB = [];\n        for ($inc = 1; $inc <= $numRGFC; ++$inc) {\n            $arrayRGB[$inc] = self::getInt1d($this->dataWorkDocument, $offset);\n            ++$offset;\n        }\n\n        $start = 0;\n        foreach ($arrayRGB as $keyRGB => $rgb) {\n            $oStyle = new stdClass();\n            $oStyle->pos_start = $start;\n            $oStyle->pos_len = (int) ceil((($arrayRGFC[$keyRGB] - 1) - $arrayRGFC[$keyRGB - 1]) / 2);\n            $start += $oStyle->pos_len;\n\n            if ($rgb > 0) {\n                // Chp Structure\n                // @see  http://msdn.microsoft.com/en-us/library/dd772849%28v=office.12%29.aspx\n                $posRGB = $offsetBase + $rgb * 2;\n\n                $cb = self::getInt1d($this->dataWorkDocument, $posRGB);\n                ++$posRGB;\n\n                $oStyle->style = $this->readPrl($this->dataWorkDocument, $posRGB, $cb);\n                $posRGB += $oStyle->style->length;\n            }\n            $this->arrayCharacters[] = $oStyle;\n        }\n    }\n\n    /**\n     * @return stdClass\n     */\n    private function readSprm($sprm)\n    {\n        $oSprm = new stdClass();\n        $oSprm->isPmd = $sprm & 0x01FF;\n        $oSprm->f = (int) ($sprm / 512) & 0x0001;\n        $oSprm->sgc = (int) ($sprm / 1024) & 0x0007;\n        $oSprm->spra = (int) ($sprm / 8192);\n\n        return $oSprm;\n    }\n\n    /**\n     * @param string $data\n     * @param int $pos\n     * @param stdClass $oSprm\n     *\n     * @return array\n     */\n    private function readSprmSpra($data, $pos, $oSprm)\n    {\n        $length = 0;\n        $operand = null;\n\n        switch (dechex($oSprm->spra)) {\n            case 0x0:\n                $operand = self::getInt1d($data, $pos);\n                $length = 1;\n                switch (dechex($operand)) {\n                    case 0x00:\n                        $operand = false;\n\n                        break;\n                    case 0x01:\n                        $operand = true;\n\n                        break;\n                    case 0x80:\n                        $operand = self::SPRA_VALUE;\n\n                        break;\n                    case 0x81:\n                        $operand = self::SPRA_VALUE_OPPOSITE;\n\n                        break;\n                }\n\n                break;\n            case 0x1:\n                $operand = self::getInt1d($data, $pos);\n                $length = 1;\n\n                break;\n            case 0x2:\n            case 0x4:\n            case 0x5:\n                $operand = self::getInt2d($data, $pos);\n                $length = 2;\n\n                break;\n            case 0x3:\n                if ($oSprm->isPmd != 0x70) {\n                    $operand = self::getInt4d($data, $pos);\n                    $length = 4;\n                }\n\n                break;\n            case 0x7:\n                $operand = self::getInt3d($data, $pos);\n                $length = 3;\n\n                break;\n            default:\n                // print_r('YO YO YO : '.PHP_EOL);\n        }\n\n        return [\n            'length' => $length,\n            'operand' => $operand,\n        ];\n    }\n\n    /**\n     * @param $data int\n     * @param $pos int\n     * @param $cbNum int\n     *\n     * @return stdClass\n     *\n     * @see  http://msdn.microsoft.com/en-us/library/dd772849%28v=office.12%29.aspx\n     */\n    private function readPrl($data, $pos, $cbNum)\n    {\n        $posStart = $pos;\n        $oStylePrl = new stdClass();\n\n        // Variables\n        $sprmCPicLocation = null;\n        $sprmCFData = null;\n        //$sprmCFSpec = null;\n\n        do {\n            // Variables\n            $operand = null;\n\n            $sprm = self::getInt2d($data, $pos);\n            $oSprm = $this->readSprm($sprm);\n            $pos += 2;\n            $cbNum -= 2;\n\n            $arrayReturn = $this->readSprmSpra($data, $pos, $oSprm);\n            $pos += $arrayReturn['length'];\n            $cbNum -= $arrayReturn['length'];\n            $operand = $arrayReturn['operand'];\n\n            switch (dechex($oSprm->sgc)) {\n                // Paragraph property\n                case 0x01:\n                    break;\n                    // Character property\n                case 0x02:\n                    if (!isset($oStylePrl->styleFont)) {\n                        $oStylePrl->styleFont = [];\n                    }\n                    switch ($oSprm->isPmd) {\n                        // sprmCFRMarkIns\n                        case 0x01:\n                            break;\n                            // sprmCFFldVanish\n                        case 0x02:\n                            break;\n                            // sprmCPicLocation\n                        case 0x03:\n                            $sprmCPicLocation = $operand;\n\n                            break;\n                            // sprmCFData\n                        case 0x06:\n                            $sprmCFData = dechex($operand) != 0x00;\n\n                            break;\n                            // sprmCFItalic\n                        case 0x36:\n                            // By default, text is not italicized.\n                            switch ($operand) {\n                                case false:\n                                case true:\n                                    $oStylePrl->styleFont['italic'] = $operand;\n\n                                    break;\n                                case self::SPRA_VALUE:\n                                    $oStylePrl->styleFont['italic'] = false;\n\n                                    break;\n                                case self::SPRA_VALUE_OPPOSITE:\n                                    $oStylePrl->styleFont['italic'] = true;\n\n                                    break;\n                            }\n\n                            break;\n                            // sprmCIstd\n                        case 0x30:\n                            //print_r('sprmCIstd : '.dechex($operand).PHP_EOL.PHP_EOL);\n                            break;\n                            // sprmCFBold\n                        case 0x35:\n                            // By default, text is not bold.\n                            switch ($operand) {\n                                case false:\n                                case true:\n                                    $oStylePrl->styleFont['bold'] = $operand;\n\n                                    break;\n                                case self::SPRA_VALUE:\n                                    $oStylePrl->styleFont['bold'] = false;\n\n                                    break;\n                                case self::SPRA_VALUE_OPPOSITE:\n                                    $oStylePrl->styleFont['bold'] = true;\n\n                                    break;\n                            }\n\n                            break;\n                            // sprmCFStrike\n                        case 0x37:\n                            // By default, text is not struck through.\n                            switch ($operand) {\n                                case false:\n                                case true:\n                                    $oStylePrl->styleFont['strikethrough'] = $operand;\n\n                                    break;\n                                case self::SPRA_VALUE:\n                                    $oStylePrl->styleFont['strikethrough'] = false;\n\n                                    break;\n                                case self::SPRA_VALUE_OPPOSITE:\n                                    $oStylePrl->styleFont['strikethrough'] = true;\n\n                                    break;\n                            }\n\n                            break;\n                            // sprmCKul\n                        case 0x3E:\n                            switch (dechex($operand)) {\n                                case 0x00:\n                                    $oStylePrl->styleFont['underline'] = Style\\Font::UNDERLINE_NONE;\n\n                                    break;\n                                case 0x01:\n                                    $oStylePrl->styleFont['underline'] = Style\\Font::UNDERLINE_SINGLE;\n\n                                    break;\n                                case 0x02:\n                                    $oStylePrl->styleFont['underline'] = Style\\Font::UNDERLINE_WORDS;\n\n                                    break;\n                                case 0x03:\n                                    $oStylePrl->styleFont['underline'] = Style\\Font::UNDERLINE_DOUBLE;\n\n                                    break;\n                                case 0x04:\n                                    $oStylePrl->styleFont['underline'] = Style\\Font::UNDERLINE_DOTTED;\n\n                                    break;\n                                case 0x06:\n                                    $oStylePrl->styleFont['underline'] = Style\\Font::UNDERLINE_HEAVY;\n\n                                    break;\n                                case 0x07:\n                                    $oStylePrl->styleFont['underline'] = Style\\Font::UNDERLINE_DASH;\n\n                                    break;\n                                case 0x09:\n                                    $oStylePrl->styleFont['underline'] = Style\\Font::UNDERLINE_DOTDASH;\n\n                                    break;\n                                case 0x0A:\n                                    $oStylePrl->styleFont['underline'] = Style\\Font::UNDERLINE_DOTDOTDASH;\n\n                                    break;\n                                case 0x0B:\n                                    $oStylePrl->styleFont['underline'] = Style\\Font::UNDERLINE_WAVY;\n\n                                    break;\n                                case 0x14:\n                                    $oStylePrl->styleFont['underline'] = Style\\Font::UNDERLINE_DOTTEDHEAVY;\n\n                                    break;\n                                case 0x17:\n                                    $oStylePrl->styleFont['underline'] = Style\\Font::UNDERLINE_DASHHEAVY;\n\n                                    break;\n                                case 0x19:\n                                    $oStylePrl->styleFont['underline'] = Style\\Font::UNDERLINE_DOTDASHHEAVY;\n\n                                    break;\n                                case 0x1A:\n                                    $oStylePrl->styleFont['underline'] = Style\\Font::UNDERLINE_DOTDOTDASHHEAVY;\n\n                                    break;\n                                case 0x1B:\n                                    $oStylePrl->styleFont['underline'] = Style\\Font::UNDERLINE_WAVYHEAVY;\n\n                                    break;\n                                case 0x27:\n                                    $oStylePrl->styleFont['underline'] = Style\\Font::UNDERLINE_DASHLONG;\n\n                                    break;\n                                case 0x2B:\n                                    $oStylePrl->styleFont['underline'] = Style\\Font::UNDERLINE_WAVYDOUBLE;\n\n                                    break;\n                                case 0x37:\n                                    $oStylePrl->styleFont['underline'] = Style\\Font::UNDERLINE_DASHLONGHEAVY;\n\n                                    break;\n                                default:\n                                    $oStylePrl->styleFont['underline'] = Style\\Font::UNDERLINE_NONE;\n\n                                    break;\n                            }\n\n                            break;\n                            // sprmCIco\n                            //@see  http://msdn.microsoft.com/en-us/library/dd773060%28v=office.12%29.aspx\n                        case 0x42:\n                            switch (dechex($operand)) {\n                                case 0x00:\n                                case 0x01:\n                                    $oStylePrl->styleFont['color'] = '000000';\n\n                                    break;\n                                case 0x02:\n                                    $oStylePrl->styleFont['color'] = '0000FF';\n\n                                    break;\n                                case 0x03:\n                                    $oStylePrl->styleFont['color'] = '00FFFF';\n\n                                    break;\n                                case 0x04:\n                                    $oStylePrl->styleFont['color'] = '00FF00';\n\n                                    break;\n                                case 0x05:\n                                    $oStylePrl->styleFont['color'] = 'FF00FF';\n\n                                    break;\n                                case 0x06:\n                                    $oStylePrl->styleFont['color'] = 'FF0000';\n\n                                    break;\n                                case 0x07:\n                                    $oStylePrl->styleFont['color'] = 'FFFF00';\n\n                                    break;\n                                case 0x08:\n                                    $oStylePrl->styleFont['color'] = 'FFFFFF';\n\n                                    break;\n                                case 0x09:\n                                    $oStylePrl->styleFont['color'] = '000080';\n\n                                    break;\n                                case 0x0A:\n                                    $oStylePrl->styleFont['color'] = '008080';\n\n                                    break;\n                                case 0x0B:\n                                    $oStylePrl->styleFont['color'] = '008000';\n\n                                    break;\n                                case 0x0C:\n                                    $oStylePrl->styleFont['color'] = '800080';\n\n                                    break;\n                                case 0x0D:\n                                    $oStylePrl->styleFont['color'] = '800080';\n\n                                    break;\n                                case 0x0E:\n                                    $oStylePrl->styleFont['color'] = '808000';\n\n                                    break;\n                                case 0x0F:\n                                    $oStylePrl->styleFont['color'] = '808080';\n\n                                    break;\n                                case 0x10:\n                                    $oStylePrl->styleFont['color'] = 'C0C0C0';\n                            }\n\n                            break;\n                            // sprmCHps\n                        case 0x43:\n                            $oStylePrl->styleFont['size'] = $operand / 2;\n\n                            break;\n                            // sprmCIss\n                        case 0x48:\n                            if (!isset($oStylePrl->styleFont['superScript'])) {\n                                $oStylePrl->styleFont['superScript'] = false;\n                            }\n                            if (!isset($oStylePrl->styleFont['subScript'])) {\n                                $oStylePrl->styleFont['subScript'] = false;\n                            }\n                            switch (dechex($operand)) {\n                                case 0x00:\n                                    // Normal text\n                                    break;\n                                case 0x01:\n                                    $oStylePrl->styleFont['superScript'] = true;\n\n                                    break;\n                                case 0x02:\n                                    $oStylePrl->styleFont['subScript'] = true;\n\n                                    break;\n                            }\n\n                            break;\n                            // sprmCRgFtc0\n                        case 0x4F:\n                            $oStylePrl->styleFont['name'] = '';\n                            if (isset($this->arrayFonts[$operand])) {\n                                $oStylePrl->styleFont['name'] = $this->arrayFonts[$operand]['main'];\n                            }\n\n                            break;\n                            // sprmCRgFtc1\n                        case 0x50:\n                            // if the language for the text is an East Asian language\n                            break;\n                            // sprmCRgFtc2\n                        case 0x51:\n                            // if the character falls outside the Unicode character range\n                            break;\n                            // sprmCFSpec\n                        case 0x55:\n                            //$sprmCFSpec = $operand;\n                            break;\n                            // sprmCFtcBi\n                        case 0x5E:\n                            break;\n                            // sprmCFItalicBi\n                        case 0x5D:\n                            break;\n                            // sprmCHpsBi\n                        case 0x61:\n                            break;\n                            // sprmCShd80\n                            //@see  http://msdn.microsoft.com/en-us/library/dd923447%28v=office.12%29.aspx\n                        case 0x66:\n                            // $operand = self::getInt2d($data, $pos);\n                            $pos += 2;\n                            $cbNum -= 2;\n\n                            // $ipat = ($operand >> 0) && bindec('111111');\n                            // $icoBack = ($operand >> 6) && bindec('11111');\n                            // $icoFore = ($operand >> 11) && bindec('11111');\n                            break;\n                            // sprmCCv\n                            //@see  http://msdn.microsoft.com/en-us/library/dd952824%28v=office.12%29.aspx\n                        case 0x70:\n                            $red = str_pad(dechex(self::getInt1d($this->dataWorkDocument, $pos)), 2, '0', STR_PAD_LEFT);\n                            ++$pos;\n                            $green = str_pad(dechex(self::getInt1d($this->dataWorkDocument, $pos)), 2, '0', STR_PAD_LEFT);\n                            ++$pos;\n                            $blue = str_pad(dechex(self::getInt1d($this->dataWorkDocument, $pos)), 2, '0', STR_PAD_LEFT);\n                            ++$pos;\n                            ++$pos;\n                            $oStylePrl->styleFont['color'] = $red . $green . $blue;\n                            $cbNum -= 4;\n\n                            break;\n                        default:\n                            // print_r('@todo Character : 0x'.dechex($oSprm->isPmd));\n                            // print_r(PHP_EOL);\n                    }\n\n                    break;\n                    // Picture property\n                case 0x03:\n                    break;\n                    // Section property\n                case 0x04:\n                    if (!isset($oStylePrl->styleSection)) {\n                        $oStylePrl->styleSection = [];\n                    }\n                    switch ($oSprm->isPmd) {\n                        // sprmSNfcPgn\n                        case 0x0E:\n                            // numbering format used for page numbers\n                            break;\n                            // sprmSXaPage\n                        case 0x1F:\n                            $oStylePrl->styleSection['pageSizeW'] = $operand;\n\n                            break;\n                            // sprmSYaPage\n                        case 0x20:\n                            $oStylePrl->styleSection['pageSizeH'] = $operand;\n\n                            break;\n                            // sprmSDxaLeft\n                        case 0x21:\n                            $oStylePrl->styleSection['marginLeft'] = $operand;\n\n                            break;\n                            // sprmSDxaRight\n                        case 0x22:\n                            $oStylePrl->styleSection['marginRight'] = $operand;\n\n                            break;\n                            // sprmSDyaTop\n                        case 0x23:\n                            $oStylePrl->styleSection['marginTop'] = $operand;\n\n                            break;\n                            // sprmSDyaBottom\n                        case 0x24:\n                            $oStylePrl->styleSection['marginBottom'] = $operand;\n\n                            break;\n                            // sprmSFBiDi\n                        case 0x28:\n                            // RTL layout\n                            break;\n                            // sprmSDxtCharSpace\n                        case 0x30:\n                            // characpter pitch\n                            break;\n                            // sprmSDyaLinePitch\n                        case 0x31:\n                            // line height\n                            break;\n                            // sprmSClm\n                        case 0x32:\n                            // document grid mode\n                            break;\n                            // sprmSTextFlow\n                        case 0x33:\n                            // text flow\n                            break;\n                        default:\n                            // print_r('@todo Section : 0x'.dechex($oSprm->isPmd));\n                            // print_r(PHP_EOL);\n                    }\n\n                    break;\n                    // Table property\n                case 0x05:\n                    break;\n            }\n        } while ($cbNum > 0);\n\n        if (null !== $sprmCPicLocation) {\n            if (null !== $sprmCFData && $sprmCFData == 0x01) {\n                // NilPICFAndBinData\n                //@todo Read Hyperlink structure\n                /*$lcb = self::getInt4d($this->dataData, $sprmCPicLocation);\n                $sprmCPicLocation += 4;\n                $cbHeader = self::getInt2d($this->dataData, $sprmCPicLocation);\n                $sprmCPicLocation += 2;\n                // ignored\n                $sprmCPicLocation += 62;\n                // depending of the element\n                // Hyperlink => HFD\n                // HFD > bits\n                $sprmCPicLocation += 1;\n                // HFD > clsid\n                $sprmCPicLocation += 16;\n                // HFD > hyperlink\n                //@see  http://msdn.microsoft.com/en-us/library/dd909835%28v=office.12%29.aspx\n                $streamVersion = self::getInt4d($this->dataData, $sprmCPicLocation);\n                $sprmCPicLocation += 4;\n                $data = self::getInt4d($this->dataData, $sprmCPicLocation);\n                $sprmCPicLocation += 4;\n                $hlstmfAbsFromGetdataRel = ($data >> 9) & bindec('1');\n                $hlstmfMonikerSavedAsStr = ($data >> 8) & bindec('1');\n                $hlstmfHasFrameName = ($data >> 7) & bindec('1');\n                $hlstmfHasCreationTime = ($data >> 6) & bindec('1');\n                $hlstmfHasGUID = ($data >> 5) & bindec('1');\n                $hlstmfHasDisplayName = ($data >> 4) & bindec('1');\n                $hlstmfHasLocationStr = ($data >> 3) & bindec('1');\n                $hlstmfSiteGaveDisplayName = ($data >> 2) & bindec('1');\n                $hlstmfIsAbsolute = ($data >> 1) & bindec('1');\n                $hlstmfHasMoniker = ($data >> 0) & bindec('1');\n                for ($inc = 0; $inc <= 32; $inc++) {\n                    echo ($data >> $inc) & bindec('1');\n                }\n\n                print_r('$hlstmfHasMoniker > '.$hlstmfHasMoniker.PHP_EOL);\n                print_r('$hlstmfIsAbsolute > '.$hlstmfIsAbsolute.PHP_EOL);\n                print_r('$hlstmfSiteGaveDisplayName > '.$hlstmfSiteGaveDisplayName.PHP_EOL);\n                print_r('$hlstmfHasLocationStr > '.$hlstmfHasLocationStr.PHP_EOL);\n                print_r('$hlstmfHasDisplayName > '.$hlstmfHasDisplayName.PHP_EOL);\n                print_r('$hlstmfHasGUID > '.$hlstmfHasGUID.PHP_EOL);\n                print_r('$hlstmfHasCreationTime > '.$hlstmfHasCreationTime.PHP_EOL);\n                print_r('$hlstmfHasFrameName > '.$hlstmfHasFrameName.PHP_EOL);\n                print_r('$hlstmfMonikerSavedAsStr > '.$hlstmfMonikerSavedAsStr.PHP_EOL);\n                print_r('$hlstmfAbsFromGetdataRel > '.$hlstmfAbsFromGetdataRel.PHP_EOL);\n                if ($streamVersion == 2) {\n                    $AAA = self::getInt4d($this->dataData, $sprmCPicLocation);\n                    echo 'AAAA : '.$AAA.PHP_EOL;\n                    if ($hlstmfHasDisplayName == 1) {\n                        echo 'displayName'.PHP_EOL;\n                    }\n                    if ($hlstmfHasFrameName == 1) {\n                        echo 'targetFrameName'.PHP_EOL;\n                    }\n                    if ($hlstmfHasMoniker == 1 || $hlstmfMonikerSavedAsStr == 1) {\n                        $sprmCPicLocation += 16;\n                        $length = self::getInt4d($this->dataData, $sprmCPicLocation);\n                        $sprmCPicLocation += 4;\n                        for ($inc = 0; $inc < ($length / 2); $inc++) {\n                            $chr = self::getInt2d($this->dataData, $sprmCPicLocation);\n                            $sprmCPicLocation += 2;\n                            print_r(chr($chr));\n                        }\n                        echo PHP_EOL;\n                        echo 'moniker : '.$length.PHP_EOL;\n                    }\n                    if ($hlstmfHasMoniker == 1 || $hlstmfMonikerSavedAsStr == 1) {\n                        echo 'oleMoniker'.PHP_EOL;\n                    }\n                    if ($hlstmfHasLocationStr == 1) {\n                        echo 'location'.PHP_EOL;\n                    }\n                    if ($hlstmfHasGUID == 1) {\n                        echo 'guid'.PHP_EOL;\n                        $sprmCPicLocation += 16;\n                    }\n                    if ($hlstmfHasCreationTime == 1) {\n                        echo 'fileTime'.PHP_EOL;\n                        $sprmCPicLocation += 4;\n                    }\n                    echo 'HYPERLINK'.PHP_EOL;\n                }*/\n            } else {\n                // Pictures\n                //@see  http://msdn.microsoft.com/en-us/library/dd925458%28v=office.12%29.aspx\n                //@see  http://msdn.microsoft.com/en-us/library/dd926136%28v=office.12%29.aspx\n                // PICF : lcb\n                $sprmCPicLocation += 4;\n                // PICF : cbHeader\n                $sprmCPicLocation += 2;\n                // PICF : mfpf : mm\n                $mfpfMm = self::getInt2d($this->dataData, $sprmCPicLocation);\n                $sprmCPicLocation += 2;\n                // PICF : mfpf : xExt\n                $sprmCPicLocation += 2;\n                // PICF : mfpf : yExt\n                $sprmCPicLocation += 2;\n                // PICF : mfpf : swHMF\n                $sprmCPicLocation += 2;\n                // PICF : innerHeader : grf\n                $sprmCPicLocation += 4;\n                // PICF : innerHeader : padding1\n                $sprmCPicLocation += 4;\n                // PICF : innerHeader : mmPM\n                $sprmCPicLocation += 2;\n                // PICF : innerHeader : padding2\n                $sprmCPicLocation += 4;\n                // PICF : picmid : dxaGoal\n                $picmidDxaGoal = self::getInt2d($this->dataData, $sprmCPicLocation);\n                $sprmCPicLocation += 2;\n                // PICF : picmid : dyaGoal\n                $picmidDyaGoal = self::getInt2d($this->dataData, $sprmCPicLocation);\n                $sprmCPicLocation += 2;\n                // PICF : picmid : mx\n                $picmidMx = self::getInt2d($this->dataData, $sprmCPicLocation);\n                $sprmCPicLocation += 2;\n                // PICF : picmid : my\n                $picmidMy = self::getInt2d($this->dataData, $sprmCPicLocation);\n                $sprmCPicLocation += 2;\n                // PICF : picmid : dxaReserved1\n                $picmidDxaCropLeft = self::getInt2d($this->dataData, $sprmCPicLocation);\n                $sprmCPicLocation += 2;\n                // PICF : picmid : dyaReserved1\n                $picmidDxaCropTop = self::getInt2d($this->dataData, $sprmCPicLocation);\n                $sprmCPicLocation += 2;\n                // PICF : picmid : dxaReserved2\n                $picmidDxaCropRight = self::getInt2d($this->dataData, $sprmCPicLocation);\n                $sprmCPicLocation += 2;\n                // PICF : picmid : dyaReserved2\n                $picmidDxaCropBottom = self::getInt2d($this->dataData, $sprmCPicLocation);\n                $sprmCPicLocation += 2;\n                // PICF : picmid : fReserved\n                ++$sprmCPicLocation;\n                // PICF : picmid : bpp\n                ++$sprmCPicLocation;\n                // PICF : picmid : brcTop80\n                $sprmCPicLocation += 4;\n                // PICF : picmid : brcLeft80\n                $sprmCPicLocation += 4;\n                // PICF : picmid : brcBottom80\n                $sprmCPicLocation += 4;\n                // PICF : picmid : brcRight80\n                $sprmCPicLocation += 4;\n                // PICF : picmid : dxaReserved3\n                $sprmCPicLocation += 2;\n                // PICF : picmid : dyaReserved3\n                $sprmCPicLocation += 2;\n                // PICF : cProps\n                $sprmCPicLocation += 2;\n\n                if ($mfpfMm == 0x0066) {\n                    // cchPicName\n                    $cchPicName = self::getInt1d($this->dataData, $sprmCPicLocation);\n                    ++$sprmCPicLocation;\n\n                    // stPicName\n                    //$stPicName = '';\n                    for ($inc = 0; $inc <= $cchPicName; ++$inc) {\n                        //$chr = self::getInt1d($this->dataData, $sprmCPicLocation);\n                        ++$sprmCPicLocation;\n                        //$stPicName .= chr($chr);\n                    }\n                }\n\n                // picture (OfficeArtInlineSpContainer)\n                // picture : shape\n                $shapeRH = $this->loadRecordHeader($this->dataData, $sprmCPicLocation);\n                $sprmCPicLocation += 8;\n                if ($shapeRH['recVer'] == 0xF && $shapeRH['recInstance'] == 0x000 && $shapeRH['recType'] == 0xF004) {\n                    $sprmCPicLocation += $shapeRH['recLen'];\n                }\n                // picture : rgfb\n                //@see  http://msdn.microsoft.com/en-us/library/dd950560%28v=office.12%29.aspx\n                $fileBlockRH = $this->loadRecordHeader($this->dataData, $sprmCPicLocation);\n                while ($fileBlockRH['recType'] == 0xF007 || ($fileBlockRH['recType'] >= 0xF018 && $fileBlockRH['recType'] <= 0xF117)) {\n                    $sprmCPicLocation += 8;\n                    switch ($fileBlockRH['recType']) {\n                        // OfficeArtFBSE\n                        //@see  http://msdn.microsoft.com/en-us/library/dd944923%28v=office.12%29.aspx\n                        case 0xF007:\n                            // btWin32\n                            ++$sprmCPicLocation;\n                            // btMacOS\n                            ++$sprmCPicLocation;\n                            // rgbUid\n                            $sprmCPicLocation += 16;\n                            // tag\n                            $sprmCPicLocation += 2;\n                            // size\n                            $sprmCPicLocation += 4;\n                            // cRef\n                            $sprmCPicLocation += 4;\n                            // foDelay\n                            $sprmCPicLocation += 4;\n                            // unused1\n                            ++$sprmCPicLocation;\n                            // cbName\n                            $cbName = self::getInt1d($this->dataData, $sprmCPicLocation);\n                            ++$sprmCPicLocation;\n                            // unused2\n                            ++$sprmCPicLocation;\n                            // unused3\n                            ++$sprmCPicLocation;\n                            // nameData\n                            if ($cbName > 0) {\n                                //$nameData = '';\n                                for ($inc = 0; $inc <= ($cbName / 2); ++$inc) {\n                                    //$chr = self::getInt2d($this->dataData, $sprmCPicLocation);\n                                    $sprmCPicLocation += 2;\n                                    //$nameData .= chr($chr);\n                                }\n                            }\n                            // embeddedBlip\n                            //@see  http://msdn.microsoft.com/en-us/library/dd910081%28v=office.12%29.aspx\n                            $embeddedBlipRH = $this->loadRecordHeader($this->dataData, $sprmCPicLocation);\n                            switch ($embeddedBlipRH['recType']) {\n                                case self::OFFICEARTBLIPJPG:\n                                case self::OFFICEARTBLIPJPEG:\n                                    if (!isset($oStylePrl->image)) {\n                                        $oStylePrl->image = [];\n                                    }\n                                    $sprmCPicLocation += 8;\n                                    // embeddedBlip : rgbUid1\n                                    $sprmCPicLocation += 16;\n                                    if ($embeddedBlipRH['recInstance'] == 0x6E1) {\n                                        // rgbUid2\n                                        $sprmCPicLocation += 16;\n                                    }\n                                    // embeddedBlip : tag\n                                    ++$sprmCPicLocation;\n                                    // embeddedBlip : BLIPFileData\n                                    $oStylePrl->image['data'] = substr($this->dataData, $sprmCPicLocation, $embeddedBlipRH['recLen']);\n                                    $oStylePrl->image['format'] = 'jpg';\n                                    // Image Size\n                                    $iCropWidth = $picmidDxaGoal - ($picmidDxaCropLeft + $picmidDxaCropRight);\n                                    $iCropHeight = $picmidDyaGoal - ($picmidDxaCropTop + $picmidDxaCropBottom);\n                                    if (!$iCropWidth) {\n                                        $iCropWidth = 1;\n                                    }\n                                    if (!$iCropHeight) {\n                                        $iCropHeight = 1;\n                                    }\n                                    $oStylePrl->image['width'] = Drawing::twipsToPixels($iCropWidth * $picmidMx / 1000);\n                                    $oStylePrl->image['height'] = Drawing::twipsToPixels($iCropHeight * $picmidMy / 1000);\n\n                                    $sprmCPicLocation += $embeddedBlipRH['recLen'];\n\n                                    break;\n                                case self::OFFICEARTBLIPPNG:\n                                    break;\n                                default:\n                                    // print_r(dechex($embeddedBlipRH['recType']));\n                            }\n\n                            break;\n                    }\n                    $fileBlockRH = $this->loadRecordHeader($this->dataData, $sprmCPicLocation);\n                }\n            }\n        }\n\n        $oStylePrl->length = $pos - $posStart;\n\n        return $oStylePrl;\n    }\n\n    /**\n     * Read a record header.\n     *\n     * @param string $stream\n     * @param int $pos\n     *\n     * @return array\n     */\n    private function loadRecordHeader($stream, $pos)\n    {\n        $rec = self::getInt2d($stream, $pos);\n        $recType = self::getInt2d($stream, $pos + 2);\n        $recLen = self::getInt4d($stream, $pos + 4);\n\n        return [\n            'recVer' => ($rec >> 0) & bindec('1111'),\n            'recInstance' => ($rec >> 4) & bindec('111111111111'),\n            'recType' => $recType,\n            'recLen' => $recLen,\n        ];\n    }\n\n    private function generatePhpWord(): void\n    {\n        foreach ($this->arraySections as $itmSection) {\n            $oSection = $this->phpWord->addSection();\n            $oSection->setStyle($itmSection->styleSection);\n\n            $sHYPERLINK = '';\n            foreach ($this->arrayParagraphs as $itmParagraph) {\n                $textPara = $itmParagraph;\n                foreach ($this->arrayCharacters as $oCharacters) {\n                    $subText = mb_substr($textPara, $oCharacters->pos_start, $oCharacters->pos_len);\n                    $subText = str_replace(chr(13), PHP_EOL, $subText);\n                    $arrayText = explode(PHP_EOL, $subText);\n                    if (end($arrayText) == '') {\n                        array_pop($arrayText);\n                    }\n                    if (reset($arrayText) == '') {\n                        array_shift($arrayText);\n                    }\n\n                    // Style Character\n                    $styleFont = [];\n                    if (isset($oCharacters->style)) {\n                        if (isset($oCharacters->style->styleFont)) {\n                            $styleFont = $oCharacters->style->styleFont;\n                        }\n                    }\n\n                    foreach ($arrayText as $sText) {\n                        // HyperLink\n                        if (empty($sText) && !empty($sHYPERLINK)) {\n                            $arrHYPERLINK = explode('\"', $sHYPERLINK);\n                            $oSection->addLink($arrHYPERLINK[1], null);\n                            // print_r('>addHyperLink<'.$sHYPERLINK.'>'.ord($sHYPERLINK[0]).EOL);\n                            $sHYPERLINK = '';\n                        }\n\n                        // TextBreak\n                        if (empty($sText)) {\n                            $oSection->addTextBreak();\n                            $sHYPERLINK = '';\n                            // print_r('>addTextBreak<' . EOL);\n                        }\n\n                        if (!empty($sText)) {\n                            if (!empty($sHYPERLINK) && ord($sText[0]) > 20) {\n                                $sHYPERLINK .= $sText;\n                            }\n                            if (empty($sHYPERLINK)) {\n                                if (ord($sText[0]) > 20) {\n                                    if (strpos(trim($sText), 'HYPERLINK \"') === 0) {\n                                        $sHYPERLINK = $sText;\n                                    } else {\n                                        $oSection->addText($sText, $styleFont);\n                                        // print_r('>addText<'.$sText.'>'.ord($sText[0]).EOL);\n                                    }\n                                }\n                                if (ord($sText[0]) == 1) {\n                                    if (isset($oCharacters->style->image)) {\n                                        $fileImage = tempnam(sys_get_temp_dir(), 'PHPWord_MsDoc') . '.' . $oCharacters->style->image['format'];\n                                        file_put_contents($fileImage, $oCharacters->style->image['data']);\n                                        $oSection->addImage($fileImage, ['width' => $oCharacters->style->image['width'], 'height' => $oCharacters->style->image['height']]);\n                                        // print_r('>addImage<'.$fileImage.'>'.EOL);\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Read 8-bit unsigned integer.\n     *\n     * @param string $data\n     * @param int $pos\n     *\n     * @return int\n     */\n    public static function getInt1d($data, $pos)\n    {\n        return ord($data[$pos]);\n    }\n\n    /**\n     * Read 16-bit unsigned integer.\n     *\n     * @param string $data\n     * @param int $pos\n     *\n     * @return int\n     */\n    public static function getInt2d($data, $pos)\n    {\n        return ord($data[$pos]) | (ord($data[$pos + 1]) << 8);\n    }\n\n    /**\n     * Read 24-bit signed integer.\n     *\n     * @param string $data\n     * @param int $pos\n     *\n     * @return int\n     */\n    public static function getInt3d($data, $pos)\n    {\n        return ord($data[$pos]) | (ord($data[$pos + 1]) << 8) | (ord($data[$pos + 2]) << 16);\n    }\n\n    /**\n     * Read 32-bit signed integer.\n     *\n     * @param string $data\n     * @param int $pos\n     *\n     * @return int\n     */\n    public static function getInt4d($data, $pos)\n    {\n        // FIX: represent numbers correctly on 64-bit system\n        // http://sourceforge.net/tracker/index.php?func=detail&aid=1487372&group_id=99160&atid=623334\n        // Hacked by Andreas Rehm 2006 to ensure correct result of the <<24 block on 32 and 64bit systems\n        $or24 = ord($data[$pos + 3]);\n        if ($or24 >= 128) {\n            // negative number\n            $ord24 = -abs((256 - $or24) << 24);\n        } else {\n            $ord24 = ($or24 & 127) << 24;\n        }\n\n        return ord($data[$pos]) | (ord($data[$pos + 1]) << 8) | (ord($data[$pos + 2]) << 16) | $ord24;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Reader/ODText/AbstractPart.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Reader\\ODText;\n\nuse PhpOffice\\PhpWord\\Reader\\Word2007\\AbstractPart as Word2007AbstractPart;\n\n/**\n * Abstract part reader.\n *\n * @since 0.10.0\n *\n * @codeCoverageIgnore\n */\nabstract class AbstractPart extends Word2007AbstractPart\n{\n}\n"
  },
  {
    "path": "src/PhpWord/Reader/ODText/Content.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Reader\\ODText;\n\nuse DateTime;\nuse DOMElement;\nuse DOMNodeList;\nuse PhpOffice\\Math\\Reader\\MathML;\nuse PhpOffice\\PhpWord\\Element\\Section;\nuse PhpOffice\\PhpWord\\Element\\TrackChange;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Shared\\XMLReader;\n\n/**\n * Content reader.\n *\n * @since 0.10.0\n */\nclass Content extends AbstractPart\n{\n    /** @var ?Section */\n    private $section;\n\n    /**\n     * Read content.xml.\n     */\n    public function read(PhpWord $phpWord): void\n    {\n        $xmlReader = new XMLReader();\n        $xmlReader->getDomFromZip($this->docFile, $this->xmlFile);\n\n        $nodes = $xmlReader->getElements('office:body/office:text/*');\n        $this->section = null;\n        $this->processNodes($nodes, $xmlReader, $phpWord);\n        $this->section = null;\n    }\n\n    /** @param DOMNodeList<DOMElement> $nodes */\n    public function processNodes(DOMNodeList $nodes, XMLReader $xmlReader, PhpWord $phpWord): void\n    {\n        if ($nodes->length > 0) {\n            foreach ($nodes as $node) {\n                // $styleName = $xmlReader->getAttribute('text:style-name', $node);\n                switch ($node->nodeName) {\n                    case 'text:h': // Heading\n                        $depth = $xmlReader->getAttribute('text:outline-level', $node);\n                        $this->getSection($phpWord)->addTitle($node->nodeValue, $depth);\n\n                        break;\n                    case 'text:p': // Paragraph\n                        $styleName = $xmlReader->getAttribute('text:style-name', $node);\n                        if (substr($styleName, 0, 2) === 'SB') {\n                            break;\n                        }\n                        $element = $xmlReader->getElement('draw:frame/draw:object', $node);\n                        if ($element) {\n                            $mathFile = str_replace('./', '', $element->getAttribute('xlink:href')) . '/content.xml';\n\n                            $xmlReaderObject = new XMLReader();\n                            $mathElement = $xmlReaderObject->getDomFromZip($this->docFile, $mathFile);\n                            if ($mathElement) {\n                                $mathXML = $mathElement->saveXML($mathElement);\n\n                                if (is_string($mathXML)) {\n                                    $reader = new MathML();\n                                    $math = $reader->read($mathXML);\n\n                                    $this->getSection($phpWord)->addFormula($math);\n                                }\n                            }\n                        } else {\n                            $children = $node->childNodes;\n                            $spans = false;\n                            /** @var DOMElement $child */\n                            foreach ($children as $child) {\n                                switch ($child->nodeName) {\n                                    case 'text:change-start':\n                                        $changeId = $child->getAttribute('text:change-id');\n                                        if (isset($trackedChanges[$changeId])) {\n                                            $changed = $trackedChanges[$changeId];\n                                        }\n\n                                        break;\n                                    case 'text:change-end':\n                                        unset($changed);\n\n                                        break;\n                                    case 'text:change':\n                                        $changeId = $child->getAttribute('text:change-id');\n                                        if (isset($trackedChanges[$changeId])) {\n                                            $changed = $trackedChanges[$changeId];\n                                        }\n\n                                        break;\n                                    case 'text:span':\n                                        $spans = true;\n\n                                        break;\n                                }\n                            }\n\n                            if ($spans) {\n                                $element = $this->getSection($phpWord)->addTextRun();\n                                foreach ($children as $child) {\n                                    switch ($child->nodeName) {\n                                        case 'text:span':\n                                            /** @var DOMElement $child2 */\n                                            foreach ($child->childNodes as $child2) {\n                                                switch ($child2->nodeName) {\n                                                    case '#text':\n                                                        $element->addText($child2->nodeValue);\n\n                                                        break;\n                                                    case 'text:tab':\n                                                        $element->addText(\"\\t\");\n\n                                                        break;\n                                                    case 'text:s':\n                                                        $spaces = (int) $child2->getAttribute('text:c') ?: 1;\n                                                        $element->addText(str_repeat(' ', $spaces));\n\n                                                        break;\n                                                }\n                                            }\n\n                                            break;\n                                    }\n                                }\n                            } else {\n                                $element = $this->getSection($phpWord)->addText($node->nodeValue);\n                            }\n                            if (isset($changed) && is_array($changed)) {\n                                $element->setTrackChange($changed['changed']);\n                                if (isset($changed['textNodes'])) {\n                                    foreach ($changed['textNodes'] as $changedNode) {\n                                        $element = $this->getSection($phpWord)->addText($changedNode->nodeValue);\n                                        $element->setTrackChange($changed['changed']);\n                                    }\n                                }\n                            }\n                        }\n\n                        break;\n                    case 'text:list': // List\n                        $listItems = $xmlReader->getElements('text:list-item/text:p', $node);\n                        foreach ($listItems as $listItem) {\n                            // $listStyleName = $xmlReader->getAttribute('text:style-name', $listItem);\n                            $this->getSection($phpWord)->addListItem($listItem->nodeValue, 0);\n                        }\n\n                        break;\n                    case 'text:tracked-changes':\n                        $changedRegions = $xmlReader->getElements('text:changed-region', $node);\n                        foreach ($changedRegions as $changedRegion) {\n                            $type = ($changedRegion->firstChild->nodeName == 'text:insertion') ? TrackChange::INSERTED : TrackChange::DELETED;\n                            $creatorNode = $xmlReader->getElements('office:change-info/dc:creator', $changedRegion->firstChild);\n                            $author = $creatorNode[0]->nodeValue;\n                            $dateNode = $xmlReader->getElements('office:change-info/dc:date', $changedRegion->firstChild);\n                            $date = $dateNode[0]->nodeValue;\n                            $date = preg_replace('/\\.\\d+$/', '', $date);\n                            $date = DateTime::createFromFormat('Y-m-d\\TH:i:s', $date);\n                            $changed = new TrackChange($type, $author, $date);\n                            $textNodes = $xmlReader->getElements('text:deletion/text:p', $changedRegion);\n                            $trackedChanges[$changedRegion->getAttribute('text:id')] = ['changed' => $changed, 'textNodes' => $textNodes];\n                        }\n\n                        break;\n                    case 'text:section': // Section\n                        // $sectionStyleName = $xmlReader->getAttribute('text:style-name', $listItem);\n                        $this->section = $phpWord->addSection();\n                        /** @var DOMNodeList<DOMElement> $children */\n                        $children = $node->childNodes;\n                        $this->processNodes($children, $xmlReader, $phpWord);\n\n                        break;\n                }\n            }\n        }\n    }\n\n    private function getSection(PhpWord $phpWord): Section\n    {\n        $section = $this->section;\n        if ($section === null) {\n            $section = $this->section = $phpWord->addSection();\n        }\n\n        return $section;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Reader/ODText/Meta.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Reader\\ODText;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Shared\\XMLReader;\n\n/**\n * Meta reader.\n *\n * @since 0.11.0\n */\nclass Meta extends AbstractPart\n{\n    /**\n     * Read meta.xml.\n     *\n     * @todo Process property type\n     */\n    public function read(PhpWord $phpWord): void\n    {\n        $xmlReader = new XMLReader();\n        $xmlReader->getDomFromZip($this->docFile, $this->xmlFile);\n        $docProps = $phpWord->getDocInfo();\n\n        $metaNode = $xmlReader->getElement('office:meta');\n\n        // Standard properties\n        $properties = [\n            'title' => 'dc:title',\n            'subject' => 'dc:subject',\n            'description' => 'dc:description',\n            'keywords' => 'meta:keyword',\n            'creator' => 'meta:initial-creator',\n            'lastModifiedBy' => 'dc:creator',\n            // 'created'        => 'meta:creation-date',\n            // 'modified'       => 'dc:date',\n        ];\n        foreach ($properties as $property => $path) {\n            $method = \"set{$property}\";\n            $propertyNode = $xmlReader->getElement($path, $metaNode);\n            if ($propertyNode !== null && method_exists($docProps, $method)) {\n                $docProps->$method($propertyNode->nodeValue);\n            }\n        }\n\n        // Custom properties\n        $propertyNodes = $xmlReader->getElements('meta:user-defined', $metaNode);\n        foreach ($propertyNodes as $propertyNode) {\n            $property = $xmlReader->getAttribute('meta:name', $propertyNode);\n\n            // Set category, company, and manager property\n            if (in_array($property, ['Category', 'Company', 'Manager'])) {\n                $method = \"set{$property}\";\n                $docProps->$method($propertyNode->nodeValue);\n            } else {\n                // Set other custom properties\n                $docProps->setCustomProperty($property, $propertyNode->nodeValue);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Reader/ODText.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Reader;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Shared\\XMLReader;\n\n/**\n * Reader for ODText.\n *\n * @since 0.10.0\n */\nclass ODText extends AbstractReader implements ReaderInterface\n{\n    /**\n     * Loads PhpWord from file.\n     *\n     * @param string $docFile\n     *\n     * @return PhpWord\n     */\n    public function load($docFile)\n    {\n        $phpWord = new PhpWord();\n        $relationships = $this->readRelationships($docFile);\n\n        $readerParts = [\n            'content.xml' => 'Content',\n            'meta.xml' => 'Meta',\n        ];\n\n        foreach ($readerParts as $xmlFile => $partName) {\n            $this->readPart($phpWord, $relationships, $partName, $docFile, $xmlFile);\n        }\n\n        return $phpWord;\n    }\n\n    /**\n     * Read document part.\n     */\n    private function readPart(PhpWord $phpWord, array $relationships, string $partName, string $docFile, string $xmlFile): void\n    {\n        $partClass = \"PhpOffice\\\\PhpWord\\\\Reader\\\\ODText\\\\{$partName}\";\n        if (class_exists($partClass)) {\n            /** @var ODText\\AbstractPart $part Type hint */\n            $part = new $partClass($docFile, $xmlFile);\n            $part->setRels($relationships);\n            $part->read($phpWord);\n        }\n    }\n\n    /**\n     * Read all relationship files.\n     */\n    private function readRelationships(string $docFile): array\n    {\n        $rels = [];\n        $xmlFile = 'META-INF/manifest.xml';\n        $xmlReader = new XMLReader();\n        $xmlReader->getDomFromZip($docFile, $xmlFile);\n        $nodes = $xmlReader->getElements('manifest:file-entry');\n        foreach ($nodes as $node) {\n            $type = $xmlReader->getAttribute('manifest:media-type', $node);\n            $target = $xmlReader->getAttribute('manifest:full-path', $node);\n            $rels[] = ['type' => $type, 'target' => $target];\n        }\n\n        return $rels;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Reader/RTF/Document.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Reader\\RTF;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\n\n/**\n * RTF document reader.\n *\n * References:\n * - How to Write an RTF Reader http://latex2rtf.sourceforge.net/rtfspec_45.html\n * - PHP rtfclass by Markus Fischer https://github.com/mfn/rtfclass\n * - JavaScript RTF-parser by LazyGyu https://github.com/lazygyu/RTF-parser\n *\n * @since 0.11.0\n *\n * @SuppressWarnings(\"PHPMD.UnusedPrivateMethod\")\n */\nclass Document\n{\n    /** @const int */\n    const PARA = 'readParagraph';\n    const STYL = 'readStyle';\n    const SKIP = 'readSkip';\n\n    /**\n     * PhpWord object.\n     *\n     * @var PhpWord\n     */\n    private $phpWord;\n\n    /**\n     * Section object.\n     *\n     * @var \\PhpOffice\\PhpWord\\Element\\Section\n     */\n    private $section;\n\n    /**\n     * Textrun object.\n     *\n     * @var \\PhpOffice\\PhpWord\\Element\\TextRun\n     */\n    private $textrun;\n\n    /**\n     * RTF content.\n     *\n     * @var string\n     */\n    public $rtf;\n\n    /**\n     * Content length.\n     *\n     * @var int\n     */\n    private $length = 0;\n\n    /**\n     * Character index.\n     *\n     * @var int\n     */\n    private $offset = 0;\n\n    /**\n     * Current control word.\n     *\n     * @var string\n     */\n    private $control = '';\n\n    /**\n     * Text content.\n     *\n     * @var string\n     */\n    private $text = '';\n\n    /**\n     * Parsing a control word flag.\n     *\n     * @var bool\n     */\n    private $isControl = false;\n\n    /**\n     * First character flag: watch out for control symbols.\n     *\n     * @var bool\n     */\n    private $isFirst = false;\n\n    /**\n     * Group groups.\n     *\n     * @var array\n     */\n    private $groups = [];\n\n    /**\n     * Parser flags; not used.\n     *\n     * @var array\n     */\n    private $flags = [];\n\n    /**\n     * Parse RTF content.\n     *\n     * - Marks controlling characters `{`, `}`, and `\\`\n     * - Removes line endings\n     * - Builds control words and control symbols\n     * - Pushes every other character into the text queue\n     *\n     * @todo Use `fread` stream for scalability\n     */\n    public function read(PhpWord $phpWord): void\n    {\n        $markers = [\n            123 => 'markOpening',   // {\n            125 => 'markClosing',   // }\n            92 => 'markBackslash', // \\\n            10 => 'markNewline',   // LF\n            13 => 'markNewline',   // CR\n        ];\n\n        $this->phpWord = $phpWord;\n        $this->section = $phpWord->addSection();\n        $this->textrun = $this->section->addTextRun();\n        $this->length = strlen($this->rtf);\n\n        $this->flags['paragraph'] = true; // Set paragraph flag from the beginning\n\n        // Walk each characters\n        while ($this->offset < $this->length) {\n            $char = $this->rtf[$this->offset];\n            $ascii = ord($char);\n\n            if (isset($markers[$ascii])) { // Marker found: {, }, \\, LF, or CR\n                $markerFunction = $markers[$ascii];\n                $this->$markerFunction();\n            } else {\n                if (false === $this->isControl) { // Non control word: Push character\n                    $this->pushText($char);\n                } else {\n                    if (preg_match('/^[a-zA-Z0-9-]?$/', $char)) { // No delimiter: Buffer control\n                        $this->control .= $char;\n                        $this->isFirst = false;\n                    } else { // Delimiter found: Parse buffered control\n                        if ($this->isFirst) {\n                            $this->isFirst = false;\n                        } else {\n                            if (' ' == $char) { // Discard space as a control word delimiter\n                                $this->flushControl(true);\n                            }\n                        }\n                    }\n                }\n            }\n            ++$this->offset;\n        }\n        $this->flushText();\n    }\n\n    /**\n     * Mark opening braket `{` character.\n     */\n    private function markOpening(): void\n    {\n        $this->flush(true);\n        array_push($this->groups, $this->flags);\n    }\n\n    /**\n     * Mark closing braket `}` character.\n     */\n    private function markClosing(): void\n    {\n        $this->flush(true);\n        $this->flags = array_pop($this->groups);\n    }\n\n    /**\n     * Mark backslash `\\` character.\n     */\n    private function markBackslash(): void\n    {\n        if ($this->isFirst) {\n            $this->setControl(false);\n            $this->text .= '\\\\';\n        } else {\n            $this->flush();\n            $this->setControl(true);\n            $this->control = '';\n        }\n    }\n\n    /**\n     * Mark newline character: Flush control word because it's not possible to span multiline.\n     */\n    private function markNewline(): void\n    {\n        if ($this->isControl) {\n            $this->flushControl(true);\n        }\n    }\n\n    /**\n     * Flush control word or text.\n     *\n     * @param bool $isControl\n     */\n    private function flush($isControl = false): void\n    {\n        if ($this->isControl) {\n            $this->flushControl($isControl);\n        } else {\n            $this->flushText();\n        }\n    }\n\n    /**\n     * Flush control word.\n     *\n     * @param bool $isControl\n     */\n    private function flushControl($isControl = false): void\n    {\n        if (1 === preg_match('/^([A-Za-z]+)(-?[0-9]*) ?$/', $this->control, $match)) {\n            [, $control, $parameter] = $match;\n            $this->parseControl($control, $parameter);\n        }\n\n        if (true === $isControl) {\n            $this->setControl(false);\n        }\n    }\n\n    /**\n     * Flush text in queue.\n     */\n    private function flushText(): void\n    {\n        if ($this->text != '') {\n            if (isset($this->flags['property'])) { // Set property\n                $this->flags['value'] = $this->text;\n            } else { // Set text\n                if (true === $this->flags['paragraph']) {\n                    $this->flags['paragraph'] = false;\n                    $this->flags['text'] = $this->text;\n                }\n            }\n\n            // Add text if it's not flagged as skipped\n            if (!isset($this->flags['skipped'])) {\n                $this->readText();\n            }\n\n            $this->text = '';\n        }\n    }\n\n    /**\n     * Reset control word and first char state.\n     *\n     * @param bool $value\n     */\n    private function setControl($value): void\n    {\n        $this->isControl = $value;\n        $this->isFirst = $value;\n    }\n\n    /**\n     * Push text into queue.\n     *\n     * @param string $char\n     */\n    private function pushText($char): void\n    {\n        if ('<' == $char) {\n            $this->text .= '&lt;';\n        } elseif ('>' == $char) {\n            $this->text .= '&gt;';\n        } else {\n            $this->text .= $char;\n        }\n    }\n\n    /**\n     * Parse control.\n     *\n     * @param string $control\n     * @param string $parameter\n     */\n    private function parseControl($control, $parameter): void\n    {\n        $controls = [\n            'par' => [self::PARA,    'paragraph',    true],\n            'b' => [self::STYL,    'font',         'bold',          true],\n            'i' => [self::STYL,    'font',         'italic',        true],\n            'u' => [self::STYL,    'font',         'underline',     true],\n            'strike' => [self::STYL,    'font',         'strikethrough', true],\n            'fs' => [self::STYL,    'font',         'size',          $parameter],\n            'qc' => [self::STYL,    'paragraph',    'alignment',     Jc::CENTER],\n            'sa' => [self::STYL,    'paragraph',    'spaceAfter',    $parameter],\n            'fonttbl' => [self::SKIP,    'fonttbl',      null],\n            'colortbl' => [self::SKIP,    'colortbl',     null],\n            'info' => [self::SKIP,    'info',         null],\n            'generator' => [self::SKIP,    'generator',    null],\n            'title' => [self::SKIP,    'title',        null],\n            'subject' => [self::SKIP,    'subject',      null],\n            'category' => [self::SKIP,    'category',     null],\n            'keywords' => [self::SKIP,    'keywords',     null],\n            'comment' => [self::SKIP,    'comment',      null],\n            'shppict' => [self::SKIP,    'pic',          null],\n            'fldinst' => [self::SKIP,    'link',         null],\n        ];\n\n        if (isset($controls[$control])) {\n            [$function] = $controls[$control];\n            if (method_exists($this, $function)) {\n                $directives = $controls[$control];\n                array_shift($directives); // remove the function variable; we won't need it\n                $this->$function($directives);\n            }\n        }\n    }\n\n    /**\n     * Read paragraph.\n     *\n     * @param array $directives\n     */\n    private function readParagraph($directives): void\n    {\n        [$property, $value] = $directives;\n        $this->textrun = $this->section->addTextRun();\n        $this->flags[$property] = $value;\n    }\n\n    /**\n     * Read style.\n     *\n     * @param array $directives\n     */\n    private function readStyle($directives): void\n    {\n        [$style, $property, $value] = $directives;\n        $this->flags['styles'][$style][$property] = $value;\n    }\n\n    /**\n     * Read skip.\n     *\n     * @param array $directives\n     */\n    private function readSkip($directives): void\n    {\n        [$property] = $directives;\n        $this->flags['property'] = $property;\n        $this->flags['skipped'] = true;\n    }\n\n    /**\n     * Read text.\n     */\n    private function readText(): void\n    {\n        $text = $this->textrun->addText($this->text);\n        if (isset($this->flags['styles']['font'])) {\n            $text->getFontStyle()->setStyleByArray($this->flags['styles']['font']);\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Reader/RTF.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Reader;\n\nuse Exception;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Reader\\RTF\\Document;\n\n/**\n * RTF Reader class.\n *\n * @since 0.11.0\n */\nclass RTF extends AbstractReader implements ReaderInterface\n{\n    /**\n     * Loads PhpWord from file.\n     *\n     * @param string $docFile\n     *\n     * @return PhpWord\n     */\n    public function load($docFile)\n    {\n        $phpWord = new PhpWord();\n\n        if ($this->canRead($docFile)) {\n            $doc = new Document();\n            $doc->rtf = file_get_contents($docFile);\n            $doc->read($phpWord);\n        } else {\n            throw new Exception(\"Cannot read {$docFile}.\");\n        }\n\n        return $phpWord;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Reader/ReaderInterface.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Reader;\n\n/**\n * Reader interface.\n *\n * @since 0.8.0\n */\ninterface ReaderInterface\n{\n    /**\n     * Can the current ReaderInterface read the file?\n     *\n     * @param  string $filename\n     *\n     * @return bool\n     */\n    public function canRead($filename);\n\n    /**\n     * Loads PhpWord from file.\n     *\n     * @param string $filename\n     */\n    public function load($filename);\n}\n"
  },
  {
    "path": "src/PhpWord/Reader/Word2007/AbstractPart.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Reader\\Word2007;\n\nuse DateTime;\nuse DOMElement;\nuse InvalidArgumentException;\nuse PhpOffice\\Math\\Reader\\OfficeMathML;\nuse PhpOffice\\PhpWord\\ComplexType\\RubyProperties;\nuse PhpOffice\\PhpWord\\ComplexType\\TblWidth as TblWidthComplexType;\nuse PhpOffice\\PhpWord\\Element\\AbstractContainer;\nuse PhpOffice\\PhpWord\\Element\\AbstractElement;\nuse PhpOffice\\PhpWord\\Element\\FormField;\nuse PhpOffice\\PhpWord\\Element\\Ruby;\nuse PhpOffice\\PhpWord\\Element\\Text;\nuse PhpOffice\\PhpWord\\Element\\TextRun;\nuse PhpOffice\\PhpWord\\Element\\TrackChange;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Shared\\XMLReader;\n\n/**\n * Abstract part reader.\n *\n * This class is inherited by ODText reader\n *\n * @since 0.10.0\n */\nabstract class AbstractPart\n{\n    /**\n     * Conversion method.\n     *\n     * @const int\n     */\n    const READ_VALUE = 'attributeValue';            // Read attribute value\n    const READ_EQUAL = 'attributeEquals';           // Read `true` when attribute value equals specified value\n    const READ_TRUE = 'attributeTrue';              // Read `true` when element exists\n    const READ_FALSE = 'attributeFalse';            // Read `false` when element exists\n    const READ_SIZE = 'attributeMultiplyByTwo';     // Read special attribute value for Font::$size\n\n    /**\n     * Document file.\n     *\n     * @var string\n     */\n    protected $docFile;\n\n    /**\n     * XML file.\n     *\n     * @var string\n     */\n    protected $xmlFile;\n\n    /**\n     * Part relationships.\n     *\n     * @var array\n     */\n    protected $rels = [];\n\n    /**\n     * Comment references.\n     *\n     * @var array<string, array<string, AbstractElement>>\n     */\n    protected $commentRefs = [];\n\n    /**\n     * Image Loading.\n     *\n     * @var bool\n     */\n    protected $imageLoading = true;\n\n    /**\n     * Read part.\n     */\n    abstract public function read(PhpWord $phpWord);\n\n    /**\n     * Create new instance.\n     *\n     * @param string $docFile\n     * @param string $xmlFile\n     */\n    public function __construct($docFile, $xmlFile)\n    {\n        $this->docFile = $docFile;\n        $this->xmlFile = $xmlFile;\n    }\n\n    /**\n     * Set relationships.\n     *\n     * @param array $value\n     */\n    public function setRels($value): void\n    {\n        $this->rels = $value;\n    }\n\n    public function setImageLoading(bool $value): self\n    {\n        $this->imageLoading = $value;\n\n        return $this;\n    }\n\n    public function hasImageLoading(): bool\n    {\n        return $this->imageLoading;\n    }\n\n    /**\n     * Get comment references.\n     *\n     * @return array<string, array<string, null|AbstractElement>>\n     */\n    public function getCommentReferences(): array\n    {\n        return $this->commentRefs;\n    }\n\n    /**\n     * Set comment references.\n     *\n     * @param array<string, array<string, null|AbstractElement>> $commentRefs\n     */\n    public function setCommentReferences(array $commentRefs): self\n    {\n        $this->commentRefs = $commentRefs;\n\n        return $this;\n    }\n\n    /**\n     * Set comment reference.\n     */\n    private function setCommentReference(string $type, string $id, AbstractElement $element): self\n    {\n        if (!in_array($type, ['start', 'end'])) {\n            throw new InvalidArgumentException('Type must be \"start\" or \"end\"');\n        }\n\n        if (!array_key_exists($id, $this->commentRefs)) {\n            $this->commentRefs[$id] = [\n                'start' => null,\n                'end' => null,\n            ];\n        }\n        $this->commentRefs[$id][$type] = $element;\n\n        return $this;\n    }\n\n    /**\n     * Get comment reference.\n     *\n     * @return array<string, null|AbstractElement>\n     */\n    protected function getCommentReference(string $id): array\n    {\n        if (!array_key_exists($id, $this->commentRefs)) {\n            throw new InvalidArgumentException(sprintf('Comment with id %s isn\\'t referenced in document', $id));\n        }\n\n        return $this->commentRefs[$id];\n    }\n\n    /**\n     * Read w:p.\n     *\n     * @param AbstractContainer $parent\n     * @param string $docPart\n     *\n     * @todo Get font style for preserve text\n     */\n    protected function readParagraph(XMLReader $xmlReader, DOMElement $domNode, $parent, $docPart = 'document'): void\n    {\n        // Paragraph style\n        $paragraphStyle = $xmlReader->elementExists('w:pPr', $domNode) ? $this->readParagraphStyle($xmlReader, $domNode) : null;\n\n        if ($xmlReader->elementExists('w:r/w:fldChar/w:ffData', $domNode)) {\n            // FormField\n            $partOfFormField = false;\n            $formNodes = [];\n            $formType = null;\n            $textRunContainers = $xmlReader->countElements('w:r|w:ins|w:del|w:hyperlink|w:smartTag', $domNode);\n            if ($textRunContainers > 0) {\n                $nodes = $xmlReader->getElements('*', $domNode);\n                $paragraph = $parent->addTextRun($paragraphStyle);\n                foreach ($nodes as $node) {\n                    if ($xmlReader->elementExists('w:fldChar/w:ffData', $node)) {\n                        $partOfFormField = true;\n                        $formNodes[] = $node;\n                        if ($xmlReader->elementExists('w:fldChar/w:ffData/w:ddList', $node)) {\n                            $formType = 'dropdown';\n                        } elseif ($xmlReader->elementExists('w:fldChar/w:ffData/w:textInput', $node)) {\n                            $formType = 'textinput';\n                        } elseif ($xmlReader->elementExists('w:fldChar/w:ffData/w:checkBox', $node)) {\n                            $formType = 'checkbox';\n                        }\n                    } elseif ($partOfFormField &&\n                        $xmlReader->elementExists('w:fldChar', $node) &&\n                        'end' == $xmlReader->getAttribute('w:fldCharType', $node, 'w:fldChar')\n                    ) {\n                        $formNodes[] = $node;\n                        $partOfFormField = false;\n                        // Process the form fields\n                        $this->readFormField($xmlReader, $formNodes, $paragraph, $paragraphStyle, $formType);\n                    } elseif ($partOfFormField) {\n                        $formNodes[] = $node;\n                    } else {\n                        // normal runs\n                        $this->readRun($xmlReader, $node, $paragraph, $docPart, $paragraphStyle);\n                    }\n                }\n            }\n        } elseif ($xmlReader->elementExists('w:r/w:instrText', $domNode)) {\n            // PreserveText\n            $ignoreText = false;\n            $textContent = '';\n            $fontStyle = $this->readFontStyle($xmlReader, $domNode);\n            $nodes = $xmlReader->getElements('w:r', $domNode);\n            foreach ($nodes as $node) {\n                if ($xmlReader->elementExists('w:lastRenderedPageBreak', $node)) {\n                    $parent->addPageBreak();\n                }\n                $instrText = $xmlReader->getValue('w:instrText', $node);\n                if (null !== $instrText) {\n                    $textContent .= '{' . $instrText . '}';\n                } else {\n                    if ($xmlReader->elementExists('w:fldChar', $node)) {\n                        $fldCharType = $xmlReader->getAttribute('w:fldCharType', $node, 'w:fldChar');\n                        if ('begin' == $fldCharType) {\n                            $ignoreText = true;\n                        } elseif ('end' == $fldCharType) {\n                            $ignoreText = false;\n                        }\n                    }\n                    if (false === $ignoreText) {\n                        $textContent .= $xmlReader->getValue('w:t', $node);\n                    }\n                }\n            }\n            $parent->addPreserveText(htmlspecialchars($textContent, ENT_QUOTES, 'UTF-8'), $fontStyle, $paragraphStyle);\n\n            return;\n        }\n\n        // Formula\n        $xmlReader->registerNamespace('m', 'http://schemas.openxmlformats.org/officeDocument/2006/math');\n        if ($xmlReader->elementExists('m:oMath', $domNode)) {\n            $mathElement = $xmlReader->getElement('m:oMath', $domNode);\n            $mathXML = $mathElement->ownerDocument->saveXML($mathElement);\n            if (is_string($mathXML)) {\n                $reader = new OfficeMathML();\n                $math = $reader->read($mathXML);\n\n                $parent->addFormula($math);\n            }\n\n            return;\n        }\n\n        // List item\n        if ($xmlReader->elementExists('w:pPr/w:numPr', $domNode)) {\n            $numId = $xmlReader->getAttribute('w:val', $domNode, 'w:pPr/w:numPr/w:numId');\n            $levelId = $xmlReader->getAttribute('w:val', $domNode, 'w:pPr/w:numPr/w:ilvl');\n            $nodes = $xmlReader->getElements('*', $domNode);\n\n            $listItemRun = $parent->addListItemRun($levelId, \"PHPWordList{$numId}\", $paragraphStyle);\n\n            foreach ($nodes as $node) {\n                $this->readRun($xmlReader, $node, $listItemRun, $docPart, $paragraphStyle);\n            }\n\n            return;\n        }\n\n        // Heading or Title\n        $headingDepth = $xmlReader->elementExists('w:pPr', $domNode) ? $this->getHeadingDepth($paragraphStyle) : null;\n        if ($headingDepth !== null) {\n            $textContent = null;\n            $nodes = $xmlReader->getElements('w:r|w:hyperlink', $domNode);\n            $hasRubyElement = $xmlReader->elementExists('w:r/w:ruby', $domNode);\n            if ($nodes->length === 1 && !$hasRubyElement) {\n                $textContent = htmlspecialchars($xmlReader->getValue('w:t', $nodes->item(0)), ENT_QUOTES, 'UTF-8');\n            } else {\n                $textContent = new TextRun($paragraphStyle);\n                foreach ($nodes as $node) {\n                    $this->readRun($xmlReader, $node, $textContent, $docPart, $paragraphStyle);\n                }\n            }\n            $parent->addTitle($textContent, $headingDepth);\n\n            return;\n        }\n\n        // Text and TextRun\n        $textRunContainers = $xmlReader->countElements('w:r|w:ins|w:del|w:hyperlink|w:smartTag|w:commentReference|w:commentRangeStart|w:commentRangeEnd', $domNode);\n        if (0 === $textRunContainers) {\n            $parent->addTextBreak(1, $paragraphStyle);\n        } else {\n            $nodes = $xmlReader->getElements('*', $domNode);\n            $paragraph = $parent->addTextRun($paragraphStyle);\n            foreach ($nodes as $node) {\n                $this->readRun($xmlReader, $node, $paragraph, $docPart, $paragraphStyle);\n            }\n        }\n    }\n\n    /**\n     * @param DOMElement[] $domNodes\n     * @param AbstractContainer $parent\n     * @param mixed $paragraphStyle\n     * @param string $formType\n     */\n    private function readFormField(XMLReader $xmlReader, array $domNodes, $parent, $paragraphStyle, $formType): void\n    {\n        if (!in_array($formType, ['textinput', 'checkbox', 'dropdown'])) {\n            return;\n        }\n\n        $formField = $parent->addFormField($formType, null, $paragraphStyle);\n        $ffData = $xmlReader->getElement('w:fldChar/w:ffData', $domNodes[0]);\n\n        foreach ($xmlReader->getElements('*', $ffData) as $node) {\n            /** @var DOMElement $node */\n            switch ($node->localName) {\n                case 'name':\n                    $formField->setName($node->getAttribute('w:val'));\n\n                    break;\n                case 'ddList':\n                    $listEntries = [];\n                    foreach ($xmlReader->getElements('*', $node) as $ddListNode) {\n                        switch ($ddListNode->localName) {\n                            case 'result':\n                                $formField->setValue($xmlReader->getAttribute('w:val', $ddListNode));\n\n                                break;\n                            case 'default':\n                                $formField->setDefault($xmlReader->getAttribute('w:val', $ddListNode));\n\n                                break;\n                            case 'listEntry':\n                                $listEntries[] = $xmlReader->getAttribute('w:val', $ddListNode);\n\n                                break;\n                        }\n                    }\n                    $formField->setEntries($listEntries);\n                    if (null !== $formField->getValue()) {\n                        $formField->setText($listEntries[$formField->getValue()]);\n                    }\n\n                    break;\n                case 'textInput':\n                    foreach ($xmlReader->getElements('*', $node) as $ddListNode) {\n                        switch ($ddListNode->localName) {\n                            case 'default':\n                                $formField->setDefault($xmlReader->getAttribute('w:val', $ddListNode));\n\n                                break;\n                            case 'format':\n                            case 'maxLength':\n                                break;\n                        }\n                    }\n\n                    break;\n                case 'checkBox':\n                    foreach ($xmlReader->getElements('*', $node) as $ddListNode) {\n                        switch ($ddListNode->localName) {\n                            case 'default':\n                                $formField->setDefault($xmlReader->getAttribute('w:val', $ddListNode));\n\n                                break;\n                            case 'checked':\n                                $formField->setValue($xmlReader->getAttribute('w:val', $ddListNode));\n\n                                break;\n                            case 'size':\n                            case 'sizeAuto':\n                                break;\n                        }\n                    }\n\n                    break;\n            }\n        }\n\n        if ('textinput' == $formType) {\n            $ignoreText = true;\n            $textContent = '';\n            foreach ($domNodes as $node) {\n                if ($xmlReader->elementExists('w:fldChar', $node)) {\n                    $fldCharType = $xmlReader->getAttribute('w:fldCharType', $node, 'w:fldChar');\n                    if ('separate' == $fldCharType) {\n                        $ignoreText = false;\n                    } elseif ('end' == $fldCharType) {\n                        $ignoreText = true;\n                    }\n                }\n\n                if (false === $ignoreText) {\n                    $textContent .= $xmlReader->getValue('w:t', $node);\n                }\n            }\n            $formField->setValue(htmlspecialchars($textContent, ENT_QUOTES, 'UTF-8'));\n            $formField->setText(htmlspecialchars($textContent, ENT_QUOTES, 'UTF-8'));\n        }\n    }\n\n    /**\n     * Returns the depth of the Heading, returns 0 for a Title.\n     *\n     * @return null|number\n     */\n    private function getHeadingDepth(?array $paragraphStyle = null)\n    {\n        if (is_array($paragraphStyle) && isset($paragraphStyle['styleName'])) {\n            if ('Title' === $paragraphStyle['styleName']) {\n                return 0;\n            }\n\n            $headingMatches = [];\n            preg_match('/Heading(\\d)/', $paragraphStyle['styleName'], $headingMatches);\n            if (!empty($headingMatches)) {\n                return $headingMatches[1];\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * Read w:r.\n     *\n     * @param AbstractContainer $parent\n     * @param string $docPart\n     * @param mixed $paragraphStyle\n     *\n     * @todo Footnote paragraph style\n     */\n    protected function readRun(XMLReader $xmlReader, DOMElement $domNode, $parent, $docPart, $paragraphStyle = null): void\n    {\n        if (in_array($domNode->nodeName, ['w:ins', 'w:del', 'w:smartTag', 'w:hyperlink', 'w:commentReference'])) {\n            $nodes = $xmlReader->getElements('*', $domNode);\n            foreach ($nodes as $node) {\n                $this->readRun($xmlReader, $node, $parent, $docPart, $paragraphStyle);\n            }\n        } elseif ($domNode->nodeName == 'w:r') {\n            $fontStyle = $this->readFontStyle($xmlReader, $domNode);\n            $nodes = $xmlReader->getElements('*', $domNode);\n            foreach ($nodes as $node) {\n                $this->readRunChild($xmlReader, $node, $parent, $docPart, $paragraphStyle, $fontStyle);\n            }\n        }\n\n        if ($xmlReader->elementExists('.//*[\"commentReference\"=local-name()]', $domNode)) {\n            $node = iterator_to_array($xmlReader->getElements('.//*[\"commentReference\"=local-name()]', $domNode))[0];\n            $attributeIdentifier = $node->attributes->getNamedItem('id');\n            if ($attributeIdentifier) {\n                $id = $attributeIdentifier->nodeValue;\n\n                $this->setCommentReference('start', $id, $parent->getElement($parent->countElements() - 1));\n                $this->setCommentReference('end', $id, $parent->getElement($parent->countElements() - 1));\n            }\n        }\n    }\n\n    /**\n     * Parses nodes under w:r.\n     *\n     * @param string $docPart\n     * @param mixed $paragraphStyle\n     * @param mixed $fontStyle\n     */\n    protected function readRunChild(XMLReader $xmlReader, DOMElement $node, AbstractContainer $parent, $docPart, $paragraphStyle = null, $fontStyle = null): void\n    {\n        $runParent = $node->parentNode->parentNode;\n        if ($node->nodeName == 'w:footnoteReference') {\n            // Footnote\n            $wId = $xmlReader->getAttribute('w:id', $node);\n            $footnote = $parent->addFootnote();\n            $footnote->setRelationId($wId);\n        } elseif ($node->nodeName == 'w:endnoteReference') {\n            // Endnote\n            $wId = $xmlReader->getAttribute('w:id', $node);\n            $endnote = $parent->addEndnote();\n            $endnote->setRelationId($wId);\n        } elseif ($node->nodeName == 'w:pict') {\n            // Image\n            $rId = $xmlReader->getAttribute('r:id', $node, 'v:shape/v:imagedata');\n            $target = $this->getMediaTarget($docPart, $rId);\n            if ($this->hasImageLoading() && null !== $target) {\n                if ('External' == $this->getTargetMode($docPart, $rId)) {\n                    $imageSource = $target;\n                } else {\n                    $imageSource = \"zip://{$this->docFile}#{$target}\";\n                }\n                $parent->addImage($imageSource);\n            }\n        } elseif ($node->nodeName == 'w:drawing') {\n            // Office 2011 Image\n            $xmlReader->registerNamespace('wp', 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing');\n            $xmlReader->registerNamespace('r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');\n            $xmlReader->registerNamespace('pic', 'http://schemas.openxmlformats.org/drawingml/2006/picture');\n            $xmlReader->registerNamespace('a', 'http://schemas.openxmlformats.org/drawingml/2006/main');\n\n            $name = $xmlReader->getAttribute('name', $node, 'wp:inline/a:graphic/a:graphicData/pic:pic/pic:nvPicPr/pic:cNvPr');\n            $embedId = $xmlReader->getAttribute('r:embed', $node, 'wp:inline/a:graphic/a:graphicData/pic:pic/pic:blipFill/a:blip');\n            if ($name === null && $embedId === null) { // some Converters puts images on a different path\n                $name = $xmlReader->getAttribute('name', $node, 'wp:anchor/a:graphic/a:graphicData/pic:pic/pic:nvPicPr/pic:cNvPr');\n                $embedId = $xmlReader->getAttribute('r:embed', $node, 'wp:anchor/a:graphic/a:graphicData/pic:pic/pic:blipFill/a:blip');\n            }\n            $target = $this->getMediaTarget($docPart, $embedId);\n            if ($this->hasImageLoading() && null !== $target) {\n                $imageSource = \"zip://{$this->docFile}#{$target}\";\n                $parent->addImage($imageSource, null, false, $name);\n            }\n        } elseif ($node->nodeName == 'w:object') {\n            // Object\n            $rId = $xmlReader->getAttribute('r:id', $node, 'o:OLEObject');\n            // $rIdIcon = $xmlReader->getAttribute('r:id', $domNode, 'w:object/v:shape/v:imagedata');\n            $target = $this->getMediaTarget($docPart, $rId);\n            if (null !== $target) {\n                $textContent = \"&lt;Object: {$target}>\";\n                $parent->addText($textContent, $fontStyle, $paragraphStyle);\n            }\n        } elseif ($node->nodeName == 'w:br') {\n            $parent->addTextBreak();\n        } elseif ($node->nodeName == 'w:tab') {\n            $parent->addText(\"\\t\");\n        } elseif ($node->nodeName == 'mc:AlternateContent') {\n            if ($node->hasChildNodes()) {\n                // Get fallback instead of mc:Choice to make sure it is compatible\n                $fallbackElements = $node->getElementsByTagName('Fallback');\n\n                if ($fallbackElements->length) {\n                    $fallback = $fallbackElements->item(0);\n                    // TextRun\n                    $textContent = htmlspecialchars($fallback->nodeValue, ENT_QUOTES, 'UTF-8');\n\n                    $parent->addText($textContent, $fontStyle, $paragraphStyle);\n                }\n            }\n        } elseif ($node->nodeName == 'w:t' || $node->nodeName == 'w:delText') {\n            // TextRun\n            $textContent = htmlspecialchars($xmlReader->getValue('.', $node), ENT_QUOTES, 'UTF-8');\n\n            if ($runParent->nodeName == 'w:hyperlink') {\n                $rId = $xmlReader->getAttribute('r:id', $runParent);\n                $target = $this->getMediaTarget($docPart, $rId);\n                if (null !== $target) {\n                    $parent->addLink($target, $textContent, $fontStyle, $paragraphStyle);\n                } else {\n                    $parent->addText($textContent, $fontStyle, $paragraphStyle);\n                }\n            } else {\n                /** @var AbstractElement $element */\n                $element = $parent->addText($textContent, $fontStyle, $paragraphStyle);\n                if (in_array($runParent->nodeName, ['w:ins', 'w:del'])) {\n                    $type = ($runParent->nodeName == 'w:del') ? TrackChange::DELETED : TrackChange::INSERTED;\n                    $author = $runParent->getAttribute('w:author');\n                    $date = DateTime::createFromFormat('Y-m-d\\TH:i:s\\Z', $runParent->getAttribute('w:date'));\n                    $date = $date instanceof DateTime ? $date : null;\n                    $element->setChangeInfo($type, $author, $date);\n                }\n            }\n        } elseif ($node->nodeName == 'w:softHyphen') {\n            $element = $parent->addText(\"\\u{200c}\", $fontStyle, $paragraphStyle);\n        } elseif ($node->nodeName == 'w:ruby') {\n            $rubyPropertiesNode = $xmlReader->getElement('w:rubyPr', $node);\n            $properties = $this->readRubyProperties($xmlReader, $rubyPropertiesNode);\n            // read base text node\n            $baseText = new TextRun($paragraphStyle);\n            $baseTextNode = $xmlReader->getElement('w:rubyBase/w:r', $node);\n            $this->readRun($xmlReader, $baseTextNode, $baseText, $docPart, $paragraphStyle);\n            // read the actual ruby text (e.g. furigana in Japanese)\n            $rubyText = new TextRun($paragraphStyle);\n            $rubyTextNode = $xmlReader->getElement('w:rt/w:r', $node);\n            $this->readRun($xmlReader, $rubyTextNode, $rubyText, $docPart, $paragraphStyle);\n            // add element to parent\n            $parent->addRuby($baseText, $rubyText, $properties);\n        }\n    }\n\n    /**\n     * Read w:rubyPr element.\n     *\n     * @param XMLReader $xmlReader reader for XML\n     * @param DOMElement $domNode w:RubyPr element\n     *\n     * @return RubyProperties ruby properties from element\n     */\n    protected function readRubyProperties(XMLReader $xmlReader, DOMElement $domNode): RubyProperties\n    {\n        $rubyAlignment = $xmlReader->getElement('w:rubyAlign', $domNode)->getAttribute('w:val');\n        $rubyHps = $xmlReader->getElement('w:hps', $domNode)->getAttribute('w:val'); // font face\n        $rubyHpsRaise = $xmlReader->getElement('w:hpsRaise', $domNode)->getAttribute('w:val'); // pts above base text\n        $rubyHpsBaseText = $xmlReader->getElement('w:hpsBaseText', $domNode)->getAttribute('w:val'); // base text size\n        $rubyLid = $xmlReader->getElement('w:lid', $domNode)->getAttribute('w:val'); // type of ruby\n        $properties = new RubyProperties();\n        $properties->setAlignment($rubyAlignment);\n        $properties->setFontFaceSize((float) $rubyHps);\n        $properties->setFontPointsAboveBaseText((float) $rubyHpsRaise);\n        $properties->setFontSizeForBaseText((float) $rubyHpsBaseText);\n        $properties->setLanguageId($rubyLid);\n\n        return $properties;\n    }\n\n    /**\n     * Read w:tbl.\n     *\n     * @param mixed $parent\n     * @param string $docPart\n     */\n    protected function readTable(XMLReader $xmlReader, DOMElement $domNode, $parent, $docPart = 'document'): void\n    {\n        // Table style\n        $tblStyle = null;\n        if ($xmlReader->elementExists('w:tblPr', $domNode)) {\n            $tblStyle = $this->readTableStyle($xmlReader, $domNode);\n        }\n\n        /** @var \\PhpOffice\\PhpWord\\Element\\Table $table Type hint */\n        $table = $parent->addTable($tblStyle);\n        $tblNodes = $xmlReader->getElements('*', $domNode);\n        foreach ($tblNodes as $tblNode) {\n            if ('w:tblGrid' == $tblNode->nodeName) { // Column\n                // @todo Do something with table columns\n            } elseif ('w:tr' == $tblNode->nodeName) { // Row\n                $rowHeight = $xmlReader->getAttribute('w:val', $tblNode, 'w:trPr/w:trHeight');\n                $rowHRule = $xmlReader->getAttribute('w:hRule', $tblNode, 'w:trPr/w:trHeight');\n                $rowHRule = $rowHRule == 'exact';\n                $rowStyle = [\n                    'tblHeader' => $xmlReader->elementExists('w:trPr/w:tblHeader', $tblNode),\n                    'cantSplit' => $xmlReader->elementExists('w:trPr/w:cantSplit', $tblNode),\n                    'exactHeight' => $rowHRule,\n                ];\n\n                $row = $table->addRow($rowHeight, $rowStyle);\n                $rowNodes = $xmlReader->getElements('*', $tblNode);\n                foreach ($rowNodes as $rowNode) {\n                    if ('w:trPr' == $rowNode->nodeName) { // Row style\n                        // @todo Do something with row style\n                    } elseif ('w:tc' == $rowNode->nodeName) { // Cell\n                        $cellWidth = $xmlReader->getAttribute('w:w', $rowNode, 'w:tcPr/w:tcW');\n                        $cellStyle = null;\n                        if ($xmlReader->elementExists('w:tcPr', $rowNode)) {\n                            $cellStyle = $this->readCellStyle($xmlReader, $rowNode);\n                        }\n\n                        $cell = $row->addCell($cellWidth, $cellStyle);\n                        $cellNodes = $xmlReader->getElements('*', $rowNode);\n                        foreach ($cellNodes as $cellNode) {\n                            if ('w:p' == $cellNode->nodeName) { // Paragraph\n                                $this->readParagraph($xmlReader, $cellNode, $cell, $docPart);\n                            } elseif ($cellNode->nodeName == 'w:tbl') { // Table\n                                $this->readTable($xmlReader, $cellNode, $cell, $docPart);\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Read w:pPr.\n     *\n     * @return null|array\n     */\n    protected function readParagraphStyle(XMLReader $xmlReader, DOMElement $domNode)\n    {\n        if (!$xmlReader->elementExists('w:pPr', $domNode)) {\n            return null;\n        }\n\n        $styleNode = $xmlReader->getElement('w:pPr', $domNode);\n        $styleDefs = [\n            'styleName' => [self::READ_VALUE, ['w:pStyle', 'w:name']],\n            'alignment' => [self::READ_VALUE, 'w:jc'],\n            'basedOn' => [self::READ_VALUE, 'w:basedOn'],\n            'next' => [self::READ_VALUE, 'w:next'],\n            'indentLeft' => [self::READ_VALUE, 'w:ind', 'w:left'],\n            'indentRight' => [self::READ_VALUE, 'w:ind', 'w:right'],\n            'indentHanging' => [self::READ_VALUE, 'w:ind', 'w:hanging'],\n            'indentFirstLine' => [self::READ_VALUE, 'w:ind', 'w:firstLine'],\n            'indentFirstLineChars' => [self::READ_VALUE, 'w:ind', 'w:firstLineChars'],\n            'spaceAfter' => [self::READ_VALUE, 'w:spacing', 'w:after'],\n            'spaceBefore' => [self::READ_VALUE, 'w:spacing', 'w:before'],\n            'widowControl' => [self::READ_FALSE, 'w:widowControl'],\n            'keepNext' => [self::READ_TRUE,  'w:keepNext'],\n            'keepLines' => [self::READ_TRUE,  'w:keepLines'],\n            'pageBreakBefore' => [self::READ_TRUE,  'w:pageBreakBefore'],\n            'contextualSpacing' => [self::READ_TRUE,  'w:contextualSpacing'],\n            'bidi' => [self::READ_TRUE,  'w:bidi'],\n            'suppressAutoHyphens' => [self::READ_TRUE,  'w:suppressAutoHyphens'],\n            'borderTopStyle' => [self::READ_VALUE, 'w:pBdr/w:top'],\n            'borderTopColor' => [self::READ_VALUE, 'w:pBdr/w:top', 'w:color'],\n            'borderTopSize' => [self::READ_VALUE, 'w:pBdr/w:top', 'w:sz'],\n            'borderRightStyle' => [self::READ_VALUE, 'w:pBdr/w:right'],\n            'borderRightColor' => [self::READ_VALUE, 'w:pBdr/w:right', 'w:color'],\n            'borderRightSize' => [self::READ_VALUE, 'w:pBdr/w:right', 'w:sz'],\n            'borderBottomStyle' => [self::READ_VALUE, 'w:pBdr/w:bottom'],\n            'borderBottomColor' => [self::READ_VALUE, 'w:pBdr/w:bottom', 'w:color'],\n            'borderBottomSize' => [self::READ_VALUE, 'w:pBdr/w:bottom', 'w:sz'],\n            'borderLeftStyle' => [self::READ_VALUE, 'w:pBdr/w:left'],\n            'borderLeftColor' => [self::READ_VALUE, 'w:pBdr/w:left', 'w:color'],\n            'borderLeftSize' => [self::READ_VALUE, 'w:pBdr/w:left', 'w:sz'],\n        ];\n\n        return $this->readStyleDefs($xmlReader, $styleNode, $styleDefs);\n    }\n\n    /**\n     * Read w:rPr.\n     *\n     * @return null|array\n     */\n    protected function readFontStyle(XMLReader $xmlReader, DOMElement $domNode)\n    {\n        if (null === $domNode) {\n            return null;\n        }\n        // Hyperlink has an extra w:r child\n        if ('w:hyperlink' == $domNode->nodeName) {\n            $domNode = $xmlReader->getElement('w:r', $domNode);\n        }\n        if (!$xmlReader->elementExists('w:rPr', $domNode)) {\n            return null;\n        }\n\n        $styleNode = $xmlReader->getElement('w:rPr', $domNode);\n        $styleDefs = [\n            'styleName' => [self::READ_VALUE, 'w:rStyle'],\n            'name' => [self::READ_VALUE, 'w:rFonts', ['w:ascii', 'w:hAnsi', 'w:eastAsia', 'w:cs']],\n            'hint' => [self::READ_VALUE, 'w:rFonts', 'w:hint'],\n            'size' => [self::READ_SIZE,  ['w:sz', 'w:szCs']],\n            'color' => [self::READ_VALUE, 'w:color'],\n            'underline' => [self::READ_VALUE, 'w:u'],\n            'bold' => [self::READ_TRUE,  'w:b'],\n            'italic' => [self::READ_TRUE,  'w:i'],\n            'strikethrough' => [self::READ_TRUE,  'w:strike'],\n            'doubleStrikethrough' => [self::READ_TRUE,  'w:dstrike'],\n            'smallCaps' => [self::READ_TRUE,  'w:smallCaps'],\n            'allCaps' => [self::READ_TRUE,  'w:caps'],\n            'superScript' => [self::READ_EQUAL, 'w:vertAlign', 'w:val', 'superscript'],\n            'subScript' => [self::READ_EQUAL, 'w:vertAlign', 'w:val', 'subscript'],\n            'fgColor' => [self::READ_VALUE, 'w:highlight'],\n            'rtl' => [self::READ_TRUE,  'w:rtl'],\n            'lang' => [self::READ_VALUE, 'w:lang'],\n            'position' => [self::READ_VALUE, 'w:position'],\n            'hidden' => [self::READ_TRUE,  'w:vanish'],\n        ];\n\n        return $this->readStyleDefs($xmlReader, $styleNode, $styleDefs);\n    }\n\n    /**\n     * Read w:tblPr.\n     *\n     * @return null|array|string\n     *\n     * @todo Capture w:tblStylePr w:type=\"firstRow\"\n     */\n    protected function readTableStyle(XMLReader $xmlReader, DOMElement $domNode)\n    {\n        $style = null;\n        $margins = ['top', 'left', 'bottom', 'right'];\n        $borders = array_merge($margins, ['insideH', 'insideV']);\n\n        if ($xmlReader->elementExists('w:tblPr', $domNode)) {\n            if ($xmlReader->elementExists('w:tblPr/w:tblStyle', $domNode)) {\n                $style = $xmlReader->getAttribute('w:val', $domNode, 'w:tblPr/w:tblStyle');\n            } else {\n                $styleNode = $xmlReader->getElement('w:tblPr', $domNode);\n                $styleDefs = [];\n                foreach ($margins as $side) {\n                    $ucfSide = ucfirst($side);\n                    $styleDefs[\"cellMargin$ucfSide\"] = [self::READ_VALUE, \"w:tblCellMar/w:$side\", 'w:w'];\n                }\n                foreach ($borders as $side) {\n                    $ucfSide = ucfirst($side);\n                    $styleDefs[\"border{$ucfSide}Size\"] = [self::READ_VALUE, \"w:tblBorders/w:$side\", 'w:sz'];\n                    $styleDefs[\"border{$ucfSide}Color\"] = [self::READ_VALUE, \"w:tblBorders/w:$side\", 'w:color'];\n                    $styleDefs[\"border{$ucfSide}Style\"] = [self::READ_VALUE, \"w:tblBorders/w:$side\", 'w:val'];\n                }\n                $styleDefs['layout'] = [self::READ_VALUE, 'w:tblLayout', 'w:type'];\n                $styleDefs['bidiVisual'] = [self::READ_TRUE, 'w:bidiVisual'];\n                $styleDefs['cellSpacing'] = [self::READ_VALUE, 'w:tblCellSpacing', 'w:w'];\n                $style = $this->readStyleDefs($xmlReader, $styleNode, $styleDefs);\n\n                $tablePositionNode = $xmlReader->getElement('w:tblpPr', $styleNode);\n                if ($tablePositionNode !== null) {\n                    $style['position'] = $this->readTablePosition($xmlReader, $tablePositionNode);\n                }\n\n                $indentNode = $xmlReader->getElement('w:tblInd', $styleNode);\n                if ($indentNode !== null) {\n                    $style['indent'] = $this->readTableIndent($xmlReader, $indentNode);\n                }\n            }\n        }\n\n        return $style;\n    }\n\n    /**\n     * Read w:tblpPr.\n     *\n     * @return array\n     */\n    private function readTablePosition(XMLReader $xmlReader, DOMElement $domNode)\n    {\n        $styleDefs = [\n            'leftFromText' => [self::READ_VALUE, '.', 'w:leftFromText'],\n            'rightFromText' => [self::READ_VALUE, '.', 'w:rightFromText'],\n            'topFromText' => [self::READ_VALUE, '.', 'w:topFromText'],\n            'bottomFromText' => [self::READ_VALUE, '.', 'w:bottomFromText'],\n            'vertAnchor' => [self::READ_VALUE, '.', 'w:vertAnchor'],\n            'horzAnchor' => [self::READ_VALUE, '.', 'w:horzAnchor'],\n            'tblpXSpec' => [self::READ_VALUE, '.', 'w:tblpXSpec'],\n            'tblpX' => [self::READ_VALUE, '.', 'w:tblpX'],\n            'tblpYSpec' => [self::READ_VALUE, '.', 'w:tblpYSpec'],\n            'tblpY' => [self::READ_VALUE, '.', 'w:tblpY'],\n        ];\n\n        return $this->readStyleDefs($xmlReader, $domNode, $styleDefs);\n    }\n\n    /**\n     * Read w:tblInd.\n     *\n     * @return TblWidthComplexType\n     */\n    private function readTableIndent(XMLReader $xmlReader, DOMElement $domNode)\n    {\n        $styleDefs = [\n            'value' => [self::READ_VALUE, '.', 'w:w'],\n            'type' => [self::READ_VALUE, '.', 'w:type'],\n        ];\n        $styleDefs = $this->readStyleDefs($xmlReader, $domNode, $styleDefs);\n\n        return new TblWidthComplexType((int) $styleDefs['value'], $styleDefs['type']);\n    }\n\n    /**\n     * Read w:tcPr.\n     *\n     * @return null|array\n     */\n    private function readCellStyle(XMLReader $xmlReader, DOMElement $domNode)\n    {\n        $styleDefs = [\n            'valign' => [self::READ_VALUE, 'w:vAlign'],\n            'textDirection' => [self::READ_VALUE, 'w:textDirection'],\n            'gridSpan' => [self::READ_VALUE, 'w:gridSpan'],\n            'vMerge' => [self::READ_VALUE, 'w:vMerge', null, null, 'continue'],\n            'bgColor' => [self::READ_VALUE, 'w:shd', 'w:fill'],\n            'noWrap' => [self::READ_VALUE, 'w:noWrap', null, null, true],\n        ];\n        $style = null;\n\n        if ($xmlReader->elementExists('w:tcPr', $domNode)) {\n            $styleNode = $xmlReader->getElement('w:tcPr', $domNode);\n\n            $borders = ['top', 'left', 'bottom', 'right'];\n            foreach ($borders as $side) {\n                $ucfSide = ucfirst($side);\n\n                $styleDefs['border' . $ucfSide . 'Size'] = [self::READ_VALUE, 'w:tcBorders/w:' . $side, 'w:sz'];\n                $styleDefs['border' . $ucfSide . 'Color'] = [self::READ_VALUE, 'w:tcBorders/w:' . $side, 'w:color'];\n                $styleDefs['border' . $ucfSide . 'Style'] = [self::READ_VALUE, 'w:tcBorders/w:' . $side, 'w:val'];\n            }\n\n            $style = $this->readStyleDefs($xmlReader, $styleNode, $styleDefs);\n        }\n\n        return $style;\n    }\n\n    /**\n     * Returns the first child element found.\n     *\n     * @param null|array|string $elements\n     *\n     * @return null|string\n     */\n    private function findPossibleElement(XMLReader $xmlReader, ?DOMElement $parentNode = null, $elements = null)\n    {\n        if (is_array($elements)) {\n            //if element is an array, we take the first element that exists in the XML\n            foreach ($elements as $possibleElement) {\n                if ($xmlReader->elementExists($possibleElement, $parentNode)) {\n                    return $possibleElement;\n                }\n            }\n        } else {\n            return $elements;\n        }\n\n        return null;\n    }\n\n    /**\n     * Returns the first attribute found.\n     *\n     * @param array|string $attributes\n     *\n     * @return null|string\n     */\n    private function findPossibleAttribute(XMLReader $xmlReader, DOMElement $node, $attributes)\n    {\n        //if attribute is an array, we take the first attribute that exists in the XML\n        if (is_array($attributes)) {\n            foreach ($attributes as $possibleAttribute) {\n                if ($xmlReader->getAttribute($possibleAttribute, $node)) {\n                    return $possibleAttribute;\n                }\n            }\n\n            return null;\n        }\n\n        return $attributes;\n    }\n\n    /**\n     * Read style definition.\n     *\n     * @param array $styleDefs\n     *\n     * @ignoreScrutinizerPatch\n     *\n     * @return array\n     */\n    protected function readStyleDefs(XMLReader $xmlReader, ?DOMElement $parentNode = null, $styleDefs = [])\n    {\n        $styles = [];\n\n        foreach ($styleDefs as $styleProp => $styleVal) {\n            [$method, $element, $attribute, $expected, $default] = array_pad($styleVal, 5, null);\n\n            $element = $this->findPossibleElement($xmlReader, $parentNode, $element);\n            if ($element === null) {\n                continue;\n            }\n\n            if ($xmlReader->elementExists($element, $parentNode)) {\n                $node = $xmlReader->getElement($element, $parentNode);\n\n                $attribute = $this->findPossibleAttribute($xmlReader, $node, $attribute);\n\n                // Use w:val as default if no attribute assigned\n                $attribute = ($attribute === null) ? 'w:val' : $attribute;\n                $attributeValue = $xmlReader->getAttribute($attribute, $node) ?? $default;\n\n                $styleValue = $this->readStyleDef($method, $attributeValue, $expected);\n                if ($styleValue !== null) {\n                    $styles[$styleProp] = $styleValue;\n                }\n            }\n        }\n\n        return $styles;\n    }\n\n    /**\n     * Return style definition based on conversion method.\n     *\n     * @param string $method\n     *\n     * @ignoreScrutinizerPatch\n     *\n     * @param null|string $attributeValue\n     * @param mixed $expected\n     *\n     * @return mixed\n     */\n    private function readStyleDef($method, $attributeValue, $expected)\n    {\n        $style = $attributeValue;\n\n        if (self::READ_SIZE == $method) {\n            $style = $attributeValue / 2;\n        } elseif (self::READ_TRUE == $method) {\n            $style = $this->isOn($attributeValue);\n        } elseif (self::READ_FALSE == $method) {\n            $style = !$this->isOn($attributeValue);\n        } elseif (self::READ_EQUAL == $method) {\n            $style = $attributeValue == $expected;\n        }\n\n        return $style;\n    }\n\n    /**\n     * Parses the value of the on/off value, null is considered true as it means the w:val attribute was not present.\n     *\n     * @see http://www.datypic.com/sc/ooxml/t-w_ST_OnOff.html\n     *\n     * @param string $value\n     *\n     * @return bool\n     */\n    private function isOn($value = null)\n    {\n        return $value === null || $value === '1' || $value === 'true' || $value === 'on';\n    }\n\n    /**\n     * Returns the target of image, object, or link as stored in ::readMainRels.\n     *\n     * @param string $docPart\n     * @param string $rId\n     *\n     * @return null|string\n     */\n    private function getMediaTarget($docPart, $rId)\n    {\n        $target = null;\n\n        if (isset($this->rels[$docPart], $this->rels[$docPart][$rId])) {\n            $target = $this->rels[$docPart][$rId]['target'];\n        }\n\n        return $target;\n    }\n\n    /**\n     * Returns the target mode.\n     *\n     * @param string $docPart\n     * @param string $rId\n     *\n     * @return null|string\n     */\n    private function getTargetMode($docPart, $rId)\n    {\n        $mode = null;\n\n        if (isset($this->rels[$docPart], $this->rels[$docPart][$rId])) {\n            $mode = $this->rels[$docPart][$rId]['targetMode'];\n        }\n\n        return $mode;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Reader/Word2007/Comments.php",
    "content": "<?php\n\nnamespace PhpOffice\\PhpWord\\Reader\\Word2007;\n\nuse DateTime;\nuse PhpOffice\\PhpWord\\Element\\Comment;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Shared\\XMLReader;\n\nclass Comments extends AbstractPart\n{\n    /**\n     * Collection name comments.\n     *\n     * @var string\n     */\n    protected $collection = 'comments';\n\n    /**\n     * Read settings.xml.\n     */\n    public function read(PhpWord $phpWord): void\n    {\n        $xmlReader = new XMLReader();\n        $xmlReader->getDomFromZip($this->docFile, $this->xmlFile);\n\n        $comments = $phpWord->getComments();\n\n        $nodes = $xmlReader->getElements('*');\n\n        foreach ($nodes as $node) {\n            $name = str_replace('w:', '', $node->nodeName);\n\n            $author = $xmlReader->getAttribute('w:author', $node);\n            $date = $xmlReader->getAttribute('w:date', $node);\n            $initials = $xmlReader->getAttribute('w:initials', $node);\n\n            $element = new Comment($author, new DateTime($date), $initials);\n\n            $range = $this->getCommentReference($xmlReader->getAttribute('w:id', $node));\n            if ($range['start']) {\n                $range['start']->setCommentRangeStart($element);\n            }\n            if ($range['end']) {\n                $range['end']->setCommentRangeEnd($element);\n            }\n\n            $pNodes = $xmlReader->getElements('w:p/w:r', $node);\n            foreach ($pNodes as $pNode) {\n                $this->readRun($xmlReader, $pNode, $element, $this->collection);\n            }\n\n            $phpWord->getComments()->addItem($element);\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Reader/Word2007/DocPropsApp.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Reader\\Word2007;\n\n/**\n * Extended properties reader.\n *\n * @since 0.10.0\n */\nclass DocPropsApp extends DocPropsCore\n{\n    /**\n     * Property mapping.\n     *\n     * @var array\n     */\n    protected $mapping = ['Company' => 'setCompany', 'Manager' => 'setManager'];\n\n    /**\n     * Callback functions.\n     *\n     * @var array\n     */\n    protected $callbacks = [];\n}\n"
  },
  {
    "path": "src/PhpWord/Reader/Word2007/DocPropsCore.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Reader\\Word2007;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Shared\\XMLReader;\n\n/**\n * Core properties reader.\n *\n * @since 0.10.0\n */\nclass DocPropsCore extends AbstractPart\n{\n    /**\n     * Property mapping.\n     *\n     * @var array\n     */\n    protected $mapping = [\n        'dc:creator' => 'setCreator',\n        'dc:title' => 'setTitle',\n        'dc:description' => 'setDescription',\n        'dc:subject' => 'setSubject',\n        'cp:keywords' => 'setKeywords',\n        'cp:category' => 'setCategory',\n        'cp:lastModifiedBy' => 'setLastModifiedBy',\n        'dcterms:created' => 'setCreated',\n        'dcterms:modified' => 'setModified',\n    ];\n\n    /**\n     * Callback functions.\n     *\n     * @var array\n     */\n    protected $callbacks = ['dcterms:created' => 'strtotime', 'dcterms:modified' => 'strtotime'];\n\n    /**\n     * Read core/extended document properties.\n     */\n    public function read(PhpWord $phpWord): void\n    {\n        $xmlReader = new XMLReader();\n        $xmlReader->getDomFromZip($this->docFile, $this->xmlFile);\n\n        $docProps = $phpWord->getDocInfo();\n\n        $nodes = $xmlReader->getElements('*');\n        if ($nodes->length > 0) {\n            foreach ($nodes as $node) {\n                if (!isset($this->mapping[$node->nodeName])) {\n                    continue;\n                }\n                $method = $this->mapping[$node->nodeName];\n                $value = $node->nodeValue == '' ? null : $node->nodeValue;\n                if (isset($this->callbacks[$node->nodeName])) {\n                    $value = $this->callbacks[$node->nodeName]($value);\n                }\n                if (method_exists($docProps, $method)) {\n                    $docProps->$method($value);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Reader/Word2007/DocPropsCustom.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Reader\\Word2007;\n\nuse PhpOffice\\PhpWord\\Metadata\\DocInfo;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Shared\\XMLReader;\n\n/**\n * Custom properties reader.\n *\n * @since 0.11.0\n */\nclass DocPropsCustom extends AbstractPart\n{\n    /**\n     * Read custom document properties.\n     */\n    public function read(PhpWord $phpWord): void\n    {\n        $xmlReader = new XMLReader();\n        $xmlReader->getDomFromZip($this->docFile, $this->xmlFile);\n        $docProps = $phpWord->getDocInfo();\n\n        $nodes = $xmlReader->getElements('*');\n        if ($nodes->length > 0) {\n            foreach ($nodes as $node) {\n                $propertyName = $xmlReader->getAttribute('name', $node);\n                $attributeNode = $xmlReader->getElement('*', $node);\n                $attributeType = $attributeNode->nodeName;\n                $attributeValue = $attributeNode->nodeValue;\n                $attributeValue = DocInfo::convertProperty($attributeValue, $attributeType);\n                $attributeType = DocInfo::convertPropertyType($attributeType);\n                $docProps->setCustomProperty($propertyName, $attributeValue, $attributeType);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Reader/Word2007/Document.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Reader\\Word2007;\n\nuse DOMElement;\nuse PhpOffice\\PhpWord\\Element\\Section;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Shared\\XMLReader;\n\n/**\n * Document reader.\n *\n * @since 0.10.0\n *\n * @SuppressWarnings(\"PHPMD.UnusedPrivateMethod\") For readWPNode\n */\nclass Document extends AbstractPart\n{\n    /**\n     * PhpWord object.\n     *\n     * @var PhpWord\n     */\n    private $phpWord;\n\n    /**\n     * Read document.xml.\n     */\n    public function read(PhpWord $phpWord): void\n    {\n        $this->phpWord = $phpWord;\n        $xmlReader = new XMLReader();\n        $xmlReader->getDomFromZip($this->docFile, $this->xmlFile);\n        $readMethods = ['w:p' => 'readWPNode', 'w:tbl' => 'readTable', 'w:sectPr' => 'readWSectPrNode'];\n\n        $nodes = $xmlReader->getElements('w:body/*');\n        if ($nodes->length > 0) {\n            $section = $this->phpWord->addSection();\n            foreach ($nodes as $node) {\n                if (isset($readMethods[$node->nodeName])) {\n                    $readMethod = $readMethods[$node->nodeName];\n                    $this->$readMethod($xmlReader, $node, $section);\n                }\n            }\n        }\n    }\n\n    /**\n     * Read header footer.\n     *\n     * @param array $settings\n     */\n    private function readHeaderFooter($settings, Section &$section): void\n    {\n        $readMethods = ['w:p' => 'readParagraph', 'w:tbl' => 'readTable'];\n\n        if (is_array($settings) && isset($settings['hf'])) {\n            foreach ($settings['hf'] as $rId => $hfSetting) {\n                if (isset($this->rels['document'][$rId])) {\n                    [$hfType, $xmlFile, $docPart] = array_values($this->rels['document'][$rId]);\n                    $addMethod = \"add{$hfType}\";\n                    $hfObject = $section->$addMethod($hfSetting['type']);\n\n                    // Read header/footer content\n                    $xmlReader = new XMLReader();\n                    $xmlReader->getDomFromZip($this->docFile, $xmlFile);\n                    $nodes = $xmlReader->getElements('*');\n                    if ($nodes->length > 0) {\n                        foreach ($nodes as $node) {\n                            if (isset($readMethods[$node->nodeName])) {\n                                $readMethod = $readMethods[$node->nodeName];\n                                $this->$readMethod($xmlReader, $node, $hfObject, $docPart);\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Read w:sectPr.\n     *\n     * @ignoreScrutinizerPatch\n     *\n     * @return array\n     */\n    private function readSectionStyle(XMLReader $xmlReader, DOMElement $domNode)\n    {\n        $styleDefs = [\n            'breakType' => [self::READ_VALUE, 'w:type'],\n            'vAlign' => [self::READ_VALUE, 'w:vAlign'],\n            'pageSizeW' => [self::READ_VALUE, 'w:pgSz', 'w:w'],\n            'pageSizeH' => [self::READ_VALUE, 'w:pgSz', 'w:h'],\n            'orientation' => [self::READ_VALUE, 'w:pgSz', 'w:orient'],\n            'colsNum' => [self::READ_VALUE, 'w:cols', 'w:num'],\n            'colsSpace' => [self::READ_VALUE, 'w:cols', 'w:space'],\n            'marginTop' => [self::READ_VALUE, 'w:pgMar', 'w:top'],\n            'marginLeft' => [self::READ_VALUE, 'w:pgMar', 'w:left'],\n            'marginBottom' => [self::READ_VALUE, 'w:pgMar', 'w:bottom'],\n            'marginRight' => [self::READ_VALUE, 'w:pgMar', 'w:right'],\n            'headerHeight' => [self::READ_VALUE, 'w:pgMar', 'w:header'],\n            'footerHeight' => [self::READ_VALUE, 'w:pgMar', 'w:footer'],\n            'gutter' => [self::READ_VALUE, 'w:pgMar', 'w:gutter'],\n        ];\n        $styles = $this->readStyleDefs($xmlReader, $domNode, $styleDefs);\n\n        // Header and footer\n        // @todo Cleanup this part\n        $nodes = $xmlReader->getElements('*', $domNode);\n        foreach ($nodes as $node) {\n            if ($node->nodeName == 'w:headerReference' || $node->nodeName == 'w:footerReference') {\n                $id = $xmlReader->getAttribute('r:id', $node);\n                $styles['hf'][$id] = [\n                    'method' => str_replace('w:', '', str_replace('Reference', '', $node->nodeName)),\n                    'type' => $xmlReader->getAttribute('w:type', $node),\n                ];\n            }\n        }\n\n        return $styles;\n    }\n\n    /**\n     * Read w:p node.\n     */\n    private function readWPNode(XMLReader $xmlReader, DOMElement $node, Section &$section): void\n    {\n        // Page break\n        if ($xmlReader->getAttribute('w:type', $node, 'w:r/w:br') == 'page') {\n            $section->addPageBreak(); // PageBreak\n        }\n\n        // Paragraph\n        $this->readParagraph($xmlReader, $node, $section);\n\n        // Section properties\n        if ($xmlReader->elementExists('w:pPr/w:sectPr', $node)) {\n            $sectPrNode = $xmlReader->getElement('w:pPr/w:sectPr', $node);\n            if ($sectPrNode !== null) {\n                $this->readWSectPrNode($xmlReader, $sectPrNode, $section);\n            }\n            $section = $this->phpWord->addSection();\n        }\n    }\n\n    /**\n     * Read w:sectPr node.\n     */\n    private function readWSectPrNode(XMLReader $xmlReader, DOMElement $node, Section &$section): void\n    {\n        $style = $this->readSectionStyle($xmlReader, $node);\n        $section->setStyle($style);\n        $this->readHeaderFooter($style, $section);\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Reader/Word2007/Endnotes.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Reader\\Word2007;\n\n/**\n * Endnotes reader.\n *\n * @since 0.10.0\n */\nclass Endnotes extends Footnotes\n{\n    /**\n     * Collection name.\n     *\n     * @var string\n     */\n    protected $collection = 'endnotes';\n\n    /**\n     * Element name.\n     *\n     * @var string\n     */\n    protected $element = 'endnote';\n}\n"
  },
  {
    "path": "src/PhpWord/Reader/Word2007/Footnotes.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Reader\\Word2007;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Shared\\XMLReader;\n\n/**\n * Footnotes reader.\n *\n * @since 0.10.0\n */\nclass Footnotes extends AbstractPart\n{\n    /**\n     * Collection name footnotes|endnotes.\n     *\n     * @var string\n     */\n    protected $collection = 'footnotes';\n\n    /**\n     * Element name footnote|endnote.\n     *\n     * @var string\n     */\n    protected $element = 'footnote';\n\n    /**\n     * Read (footnotes|endnotes).xml.\n     */\n    public function read(PhpWord $phpWord): void\n    {\n        $xmlReader = new XMLReader();\n        $xmlReader->getDomFromZip($this->docFile, $this->xmlFile);\n        $nodes = $xmlReader->getElements('*');\n        if ($nodes->length > 0) {\n            foreach ($nodes as $node) {\n                $id = $xmlReader->getAttribute('w:id', $node);\n                $type = $xmlReader->getAttribute('w:type', $node);\n\n                // Avoid w:type \"separator\" and \"continuationSeparator\"\n                // Only look for <footnote> or <endnote> without w:type attribute, or with w:type = normal\n                if ((null === $type || $type === 'normal')) {\n                    $element = $this->getElement($phpWord, $id);\n                    if ($element !== null) {\n                        $pNodes = $xmlReader->getElements('w:p/*', $node);\n                        foreach ($pNodes as $pNode) {\n                            $this->readRun($xmlReader, $pNode, $element, $this->collection);\n                        }\n                        $addMethod = \"add{$this->element}\";\n                        $phpWord->$addMethod($element);\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Searches for the element with the given relationId.\n     *\n     * @param int $relationId\n     *\n     * @return null|\\PhpOffice\\PhpWord\\Element\\AbstractContainer\n     */\n    private function getElement(PhpWord $phpWord, $relationId)\n    {\n        $getMethod = \"get{$this->collection}\";\n        $collection = $phpWord->$getMethod()->getItems();\n\n        //not found by key, looping to search by relationId\n        foreach ($collection as $collectionElement) {\n            if ($collectionElement->getRelationId() == $relationId) {\n                return $collectionElement;\n            }\n        }\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Reader/Word2007/Numbering.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Reader\\Word2007;\n\nuse DOMElement;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Shared\\XMLReader;\n\n/**\n * Numbering reader.\n *\n * @since 0.10.0\n */\nclass Numbering extends AbstractPart\n{\n    /**\n     * Read numbering.xml.\n     */\n    public function read(PhpWord $phpWord): void\n    {\n        $abstracts = [];\n        $numberings = [];\n        $xmlReader = new XMLReader();\n        $xmlReader->getDomFromZip($this->docFile, $this->xmlFile);\n\n        // Abstract numbering definition\n        $nodes = $xmlReader->getElements('w:abstractNum');\n        if ($nodes->length > 0) {\n            foreach ($nodes as $node) {\n                $abstractId = $xmlReader->getAttribute('w:abstractNumId', $node);\n                $abstracts[$abstractId] = ['levels' => []];\n                $abstract = &$abstracts[$abstractId];\n                $subnodes = $xmlReader->getElements('*', $node);\n                foreach ($subnodes as $subnode) {\n                    switch ($subnode->nodeName) {\n                        case 'w:multiLevelType':\n                            $abstract['type'] = $xmlReader->getAttribute('w:val', $subnode);\n\n                            break;\n                        case 'w:lvl':\n                            $levelId = $xmlReader->getAttribute('w:ilvl', $subnode);\n                            $abstract['levels'][$levelId] = $this->readLevel($xmlReader, $subnode, $levelId);\n\n                            break;\n                    }\n                }\n            }\n        }\n\n        // Numbering instance definition\n        $nodes = $xmlReader->getElements('w:num');\n        if ($nodes->length > 0) {\n            foreach ($nodes as $node) {\n                $numId = $xmlReader->getAttribute('w:numId', $node);\n                $abstractId = $xmlReader->getAttribute('w:val', $node, 'w:abstractNumId');\n                $numberings[$numId] = $abstracts[$abstractId];\n                $numberings[$numId]['numId'] = $numId;\n                $subnodes = $xmlReader->getElements('w:lvlOverride/w:lvl', $node);\n                foreach ($subnodes as $subnode) {\n                    $levelId = $xmlReader->getAttribute('w:ilvl', $subnode);\n                    $overrides = $this->readLevel($xmlReader, $subnode, $levelId);\n                    foreach ($overrides as $key => $value) {\n                        $numberings[$numId]['levels'][$levelId][$key] = $value;\n                    }\n                }\n            }\n        }\n\n        // Push to Style collection\n        foreach ($numberings as $numId => $numbering) {\n            $phpWord->addNumberingStyle(\"PHPWordList{$numId}\", $numbering);\n        }\n    }\n\n    /**\n     * Read numbering level definition from w:abstractNum and w:num.\n     *\n     * @param int $levelId\n     *\n     * @return array\n     */\n    private function readLevel(XMLReader $xmlReader, DOMElement $subnode, $levelId)\n    {\n        $level = [];\n\n        $level['level'] = $levelId;\n        $level['start'] = $xmlReader->getAttribute('w:val', $subnode, 'w:start');\n        $level['format'] = $xmlReader->getAttribute('w:val', $subnode, 'w:numFmt');\n        $level['restart'] = $xmlReader->getAttribute('w:val', $subnode, 'w:lvlRestart');\n        $level['suffix'] = $xmlReader->getAttribute('w:val', $subnode, 'w:suff');\n        $level['text'] = $xmlReader->getAttribute('w:val', $subnode, 'w:lvlText');\n        $level['alignment'] = $xmlReader->getAttribute('w:val', $subnode, 'w:lvlJc');\n        $level['tab'] = $xmlReader->getAttribute('w:pos', $subnode, 'w:pPr/w:tabs/w:tab');\n        $level['left'] = $xmlReader->getAttribute('w:left', $subnode, 'w:pPr/w:ind');\n        $level['hanging'] = $xmlReader->getAttribute('w:hanging', $subnode, 'w:pPr/w:ind');\n        $level['font'] = $xmlReader->getAttribute('w:ascii', $subnode, 'w:rPr/w:rFonts');\n        $level['hint'] = $xmlReader->getAttribute('w:hint', $subnode, 'w:rPr/w:rFonts');\n\n        foreach ($level as $key => $value) {\n            if (null === $value) {\n                unset($level[$key]);\n            }\n        }\n\n        return $level;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Reader/Word2007/Settings.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Reader\\Word2007;\n\nuse DOMElement;\nuse PhpOffice\\PhpWord\\ComplexType\\TrackChangesView;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Shared\\XMLReader;\nuse PhpOffice\\PhpWord\\Style\\Language;\n\n/**\n * Settings reader.\n *\n * @since 0.14.0\n */\nclass Settings extends AbstractPart\n{\n    /**\n     * @var array<string>\n     */\n    private $booleanProperties = [\n        'mirrorMargins',\n        'hideSpellingErrors',\n        'hideGrammaticalErrors',\n        'trackRevisions',\n        'doNotTrackMoves',\n        'doNotTrackFormatting',\n        'evenAndOddHeaders',\n        'updateFields',\n        'autoHyphenation',\n        'doNotHyphenateCaps',\n        'bookFoldPrinting',\n    ];\n\n    /**\n     * Read settings.xml.\n     */\n    public function read(PhpWord $phpWord): void\n    {\n        $xmlReader = new XMLReader();\n        $xmlReader->getDomFromZip($this->docFile, $this->xmlFile);\n\n        $docSettings = $phpWord->getSettings();\n\n        $nodes = $xmlReader->getElements('*');\n        if ($nodes->length > 0) {\n            foreach ($nodes as $node) {\n                $name = str_replace('w:', '', $node->nodeName);\n                $value = $xmlReader->getAttribute('w:val', $node);\n                $method = 'set' . $name;\n\n                if (in_array($name, $this->booleanProperties)) {\n                    $docSettings->$method($value !== 'false');\n                } elseif (method_exists($this, $method)) {\n                    $this->$method($xmlReader, $phpWord, $node);\n                } elseif (method_exists($docSettings, $method)) {\n                    $docSettings->$method($value);\n                }\n            }\n        }\n    }\n\n    /**\n     * Sets the document Language.\n     */\n    protected function setThemeFontLang(XMLReader $xmlReader, PhpWord $phpWord, DOMElement $node): void\n    {\n        $val = $xmlReader->getAttribute('w:val', $node);\n        $eastAsia = $xmlReader->getAttribute('w:eastAsia', $node);\n        $bidi = $xmlReader->getAttribute('w:bidi', $node);\n\n        $themeFontLang = new Language();\n        $themeFontLang->setLatin($val);\n        $themeFontLang->setEastAsia($eastAsia);\n        $themeFontLang->setBidirectional($bidi);\n\n        $phpWord->getSettings()->setThemeFontLang($themeFontLang);\n    }\n\n    /**\n     * Sets the document protection.\n     */\n    protected function setDocumentProtection(XMLReader $xmlReader, PhpWord $phpWord, DOMElement $node): void\n    {\n        $documentProtection = $phpWord->getSettings()->getDocumentProtection();\n\n        $edit = $xmlReader->getAttribute('w:edit', $node);\n        if ($edit !== null) {\n            $documentProtection->setEditing($edit);\n        }\n    }\n\n    /**\n     * Sets the proof state.\n     */\n    protected function setProofState(XMLReader $xmlReader, PhpWord $phpWord, DOMElement $node): void\n    {\n        $proofState = $phpWord->getSettings()->getProofState();\n\n        $spelling = $xmlReader->getAttribute('w:spelling', $node);\n        $grammar = $xmlReader->getAttribute('w:grammar', $node);\n\n        if ($spelling !== null) {\n            $proofState->setSpelling($spelling);\n        }\n        if ($grammar !== null) {\n            $proofState->setGrammar($grammar);\n        }\n    }\n\n    /**\n     * Sets the proof state.\n     */\n    protected function setZoom(XMLReader $xmlReader, PhpWord $phpWord, DOMElement $node): void\n    {\n        $percent = $xmlReader->getAttribute('w:percent', $node);\n        $val = $xmlReader->getAttribute('w:val', $node);\n\n        if ($percent !== null || $val !== null) {\n            $phpWord->getSettings()->setZoom($percent === null ? $val : $percent);\n        }\n    }\n\n    /**\n     * Set the Revision view.\n     */\n    protected function setRevisionView(XMLReader $xmlReader, PhpWord $phpWord, DOMElement $node): void\n    {\n        $revisionView = new TrackChangesView();\n        $revisionView->setMarkup(filter_var($xmlReader->getAttribute('w:markup', $node), FILTER_VALIDATE_BOOLEAN));\n        $revisionView->setComments($xmlReader->getAttribute('w:comments', $node));\n        $revisionView->setInsDel(filter_var($xmlReader->getAttribute('w:insDel', $node), FILTER_VALIDATE_BOOLEAN));\n        $revisionView->setFormatting(filter_var($xmlReader->getAttribute('w:formatting', $node), FILTER_VALIDATE_BOOLEAN));\n        $revisionView->setInkAnnotations(filter_var($xmlReader->getAttribute('w:inkAnnotations', $node), FILTER_VALIDATE_BOOLEAN));\n        $phpWord->getSettings()->setRevisionView($revisionView);\n    }\n\n    protected function setConsecutiveHyphenLimit(XMLReader $xmlReader, PhpWord $phpWord, DOMElement $node): void\n    {\n        $value = $xmlReader->getAttribute('w:val', $node);\n\n        if ($value !== null) {\n            $phpWord->getSettings()->setConsecutiveHyphenLimit($value);\n        }\n    }\n\n    protected function setHyphenationZone(XMLReader $xmlReader, PhpWord $phpWord, DOMElement $node): void\n    {\n        $value = $xmlReader->getAttribute('w:val', $node);\n\n        if ($value !== null) {\n            $phpWord->getSettings()->setHyphenationZone($value);\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Reader/Word2007/Styles.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Reader\\Word2007;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Shared\\XMLReader;\nuse PhpOffice\\PhpWord\\Style\\Language;\n\n/**\n * Styles reader.\n *\n * @since 0.10.0\n */\nclass Styles extends AbstractPart\n{\n    /**\n     * Read styles.xml.\n     */\n    public function read(PhpWord $phpWord): void\n    {\n        $xmlReader = new XMLReader();\n        $xmlReader->getDomFromZip($this->docFile, $this->xmlFile);\n\n        $fontDefaults = $xmlReader->getElement('w:docDefaults/w:rPrDefault');\n        if ($fontDefaults !== null) {\n            $fontDefaultStyle = $this->readFontStyle($xmlReader, $fontDefaults);\n            if ($fontDefaultStyle) {\n                if (array_key_exists('name', $fontDefaultStyle)) {\n                    $phpWord->setDefaultFontName($fontDefaultStyle['name']);\n                }\n                if (array_key_exists('size', $fontDefaultStyle)) {\n                    $phpWord->setDefaultFontSize($fontDefaultStyle['size']);\n                }\n                if (array_key_exists('color', $fontDefaultStyle)) {\n                    $phpWord->setDefaultFontColor($fontDefaultStyle['color']);\n                }\n                if (array_key_exists('lang', $fontDefaultStyle)) {\n                    $phpWord->getSettings()->setThemeFontLang(new Language($fontDefaultStyle['lang']));\n                }\n            }\n        }\n\n        $paragraphDefaults = $xmlReader->getElement('w:docDefaults/w:pPrDefault');\n        if ($paragraphDefaults !== null) {\n            $paragraphDefaultStyle = $this->readParagraphStyle($xmlReader, $paragraphDefaults);\n            if ($paragraphDefaultStyle != null) {\n                $phpWord->setDefaultParagraphStyle($paragraphDefaultStyle);\n            }\n        }\n\n        $nodes = $xmlReader->getElements('w:style');\n        if ($nodes->length > 0) {\n            foreach ($nodes as $node) {\n                $type = $xmlReader->getAttribute('w:type', $node);\n                $name = $xmlReader->getAttribute('w:val', $node, 'w:name');\n                if (null === $name) {\n                    $name = $xmlReader->getAttribute('w:styleId', $node);\n                }\n                $headingMatches = [];\n                preg_match('/Heading\\s*(\\d)/i', $name, $headingMatches);\n                // $default = ($xmlReader->getAttribute('w:default', $node) == 1);\n                switch ($type) {\n                    case 'paragraph':\n                        $paragraphStyle = $this->readParagraphStyle($xmlReader, $node);\n                        $fontStyle = $this->readFontStyle($xmlReader, $node);\n                        if (!empty($headingMatches)) {\n                            $phpWord->addTitleStyle($headingMatches[1], $fontStyle, $paragraphStyle);\n                        } else {\n                            if (empty($fontStyle)) {\n                                if (is_array($paragraphStyle)) {\n                                    $phpWord->addParagraphStyle($name, $paragraphStyle);\n                                }\n                            } else {\n                                $phpWord->addFontStyle($name, $fontStyle, $paragraphStyle);\n                            }\n                        }\n\n                        break;\n                    case 'character':\n                        $fontStyle = $this->readFontStyle($xmlReader, $node);\n                        if (!empty($fontStyle)) {\n                            $phpWord->addFontStyle($name, $fontStyle);\n                        }\n\n                        break;\n                    case 'table':\n                        $tStyle = $this->readTableStyle($xmlReader, $node);\n                        if (!empty($tStyle)) {\n                            $phpWord->addTableStyle($name, $tStyle);\n                        }\n\n                        break;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Reader/Word2007.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Reader;\n\nuse Exception;\nuse PhpOffice\\PhpWord\\Element\\AbstractElement;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Reader\\Word2007\\AbstractPart;\nuse PhpOffice\\PhpWord\\Shared\\XMLReader;\nuse PhpOffice\\PhpWord\\Shared\\ZipArchive;\n\n/**\n * Reader for Word2007.\n *\n * @since 0.8.0\n *\n * @todo watermark, checkbox, toc\n * @todo Partly done: image, object\n */\nclass Word2007 extends AbstractReader implements ReaderInterface\n{\n    /**\n     * Loads PhpWord from file.\n     *\n     * @param string $docFile\n     *\n     * @return PhpWord\n     */\n    public function load($docFile)\n    {\n        $phpWord = new PhpWord();\n        $relationships = $this->readRelationships($docFile);\n        $commentRefs = [];\n\n        $steps = [\n            [\n                'stepPart' => 'document',\n                'stepItems' => [\n                    'styles' => 'Styles',\n                    'numbering' => 'Numbering',\n                ],\n            ],\n            [\n                'stepPart' => 'main',\n                'stepItems' => [\n                    'officeDocument' => 'Document',\n                    'core-properties' => 'DocPropsCore',\n                    'extended-properties' => 'DocPropsApp',\n                    'custom-properties' => 'DocPropsCustom',\n                ],\n            ],\n            [\n                'stepPart' => 'document',\n                'stepItems' => [\n                    'endnotes' => 'Endnotes',\n                    'footnotes' => 'Footnotes',\n                    'settings' => 'Settings',\n                    'comments' => 'Comments',\n                ],\n            ],\n        ];\n\n        foreach ($steps as $step) {\n            $stepPart = $step['stepPart'];\n            $stepItems = $step['stepItems'];\n            if (!isset($relationships[$stepPart])) {\n                continue;\n            }\n            foreach ($relationships[$stepPart] as $relItem) {\n                $relType = $relItem['type'];\n                if (isset($stepItems[$relType])) {\n                    $partName = $stepItems[$relType];\n                    $xmlFile = $relItem['target'];\n                    $part = $this->readPart($phpWord, $relationships, $commentRefs, $partName, $docFile, $xmlFile);\n                    $commentRefs = $part->getCommentReferences();\n                }\n            }\n        }\n\n        return $phpWord;\n    }\n\n    /**\n     * Read document part.\n     *\n     * @param array<string, array<string, null|AbstractElement>> $commentRefs\n     */\n    private function readPart(PhpWord $phpWord, array $relationships, array $commentRefs, string $partName, string $docFile, string $xmlFile): AbstractPart\n    {\n        $partClass = \"PhpOffice\\\\PhpWord\\\\Reader\\\\Word2007\\\\{$partName}\";\n        if (!class_exists($partClass)) {\n            throw new Exception(sprintf('The part \"%s\" doesn\\'t exist', $partClass));\n        }\n\n        /** @var AbstractPart $part Type hint */\n        $part = new $partClass($docFile, $xmlFile);\n        $part->setImageLoading($this->hasImageLoading());\n        $part->setRels($relationships);\n        $part->setCommentReferences($commentRefs);\n        $part->read($phpWord);\n\n        return $part;\n    }\n\n    /**\n     * Read all relationship files.\n     *\n     * @param string $docFile\n     *\n     * @return array\n     */\n    private function readRelationships($docFile)\n    {\n        $relationships = [];\n\n        // _rels/.rels\n        $relationships['main'] = $this->getRels($docFile, '_rels/.rels');\n\n        // word/_rels/*.xml.rels\n        $wordRelsPath = 'word/_rels/';\n        $zip = new ZipArchive();\n        if ($zip->open($docFile) === true) {\n            for ($i = 0; $i < $zip->numFiles; ++$i) {\n                $xmlFile = $zip->getNameIndex($i);\n                if (!is_string($xmlFile)) {\n                    continue;\n                }\n                if ((substr($xmlFile, 0, strlen($wordRelsPath))) == $wordRelsPath && (substr($xmlFile, -1)) != '/') {\n                    $docPart = str_replace(\n                        '.xml.rels',\n                        '',\n                        str_replace($wordRelsPath, '', $xmlFile)\n                    );\n                    $relationships[$docPart] = $this->getRels($docFile, $xmlFile, 'word/');\n                }\n            }\n            $zip->close();\n        }\n\n        return $relationships;\n    }\n\n    /**\n     * Get relationship array.\n     *\n     * @param string $docFile\n     * @param string $xmlFile\n     * @param string $targetPrefix\n     *\n     * @return array\n     */\n    private function getRels($docFile, $xmlFile, $targetPrefix = '')\n    {\n        $metaPrefix = 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/';\n        $officePrefix = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/';\n\n        $rels = [];\n\n        $xmlReader = new XMLReader();\n        $xmlReader->getDomFromZip($docFile, $xmlFile);\n        $nodes = $xmlReader->getElements('*');\n        foreach ($nodes as $node) {\n            $rId = $xmlReader->getAttribute('Id', $node);\n            $type = $xmlReader->getAttribute('Type', $node);\n            $target = $xmlReader->getAttribute('Target', $node);\n            $mode = $xmlReader->getAttribute('TargetMode', $node);\n\n            // Remove URL prefixes from $type to make it easier to read\n            $type = str_replace($metaPrefix, '', $type);\n            $type = str_replace($officePrefix, '', $type);\n            $docPart = str_replace('.xml', '', $target);\n\n            // Do not add prefix to link source\n            if ($type != 'hyperlink' && $mode != 'External') {\n                $target = $targetPrefix . $target;\n            }\n\n            // Push to return array\n            $rels[$rId] = ['type' => $type, 'target' => $target, 'docPart' => $docPart, 'targetMode' => $mode];\n        }\n        ksort($rels);\n\n        return $rels;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Settings.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord;\n\n/**\n * PHPWord settings class.\n *\n * @since 0.8.0\n */\nclass Settings\n{\n    /**\n     * Zip libraries.\n     *\n     * @const string\n     */\n    public const ZIPARCHIVE = 'ZipArchive';\n    public const PCLZIP = 'PclZip';\n    public const OLD_LIB = Shared\\ZipArchive::class; // @deprecated 0.11\n\n    /**\n     * PDF rendering libraries.\n     *\n     * @const string\n     */\n    public const PDF_RENDERER_DOMPDF = 'DomPDF';\n    public const PDF_RENDERER_TCPDF = 'TCPDF';\n    public const PDF_RENDERER_MPDF = 'MPDF';\n\n    /**\n     * Measurement units multiplication factor.\n     * Applied to:\n     * - Section: margins, header/footer height, gutter, column spacing\n     * - Tab: position\n     * - Indentation: left, right, firstLine, hanging\n     * - Spacing: before, after.\n     *\n     * @const string\n     */\n    public const UNIT_TWIP = 'twip'; // = 1/20 point\n    public const UNIT_CM = 'cm';\n    public const UNIT_MM = 'mm';\n    public const UNIT_INCH = 'inch';\n    public const UNIT_POINT = 'point'; // = 1/72 inch\n    public const UNIT_PICA = 'pica'; // = 1/6 inch = 12 points\n\n    /**\n     * Default font settings.\n     * OOXML defined font size values in halfpoints, i.e. twice of what PhpWord\n     * use, and the conversion will be conducted during XML writing.\n     */\n    public const DEFAULT_FONT_NAME = 'Arial';\n    public const DEFAULT_FONT_SIZE = 10;\n    public const DEFAULT_FONT_COLOR = '000000';\n    public const DEFAULT_FONT_CONTENT_TYPE = 'default'; // default|eastAsia|cs\n    public const DEFAULT_PAPER = 'A4';\n\n    /**\n     * Compatibility option for XMLWriter.\n     *\n     * @var bool\n     */\n    private static $xmlWriterCompatibility = true;\n\n    /**\n     * Name of the class used for Zip file management.\n     *\n     * @var string\n     */\n    private static $zipClass = self::ZIPARCHIVE;\n\n    /**\n     * Name of the external Library used for rendering PDF files.\n     *\n     * @var null|string\n     */\n    private static $pdfRendererName;\n\n    /**\n     * Options used for rendering PDF files.\n     *\n     * @var array\n     */\n    private static $pdfRendererOptions = [];\n\n    /**\n     * Directory Path to the external Library used for rendering PDF files.\n     *\n     * @var null|string\n     */\n    private static $pdfRendererPath;\n\n    /**\n     * Measurement unit.\n     *\n     * @var string\n     */\n    private static $measurementUnit = self::UNIT_TWIP;\n\n    /**\n     * Default font name.\n     *\n     * @var string\n     */\n    private static $defaultFontName = self::DEFAULT_FONT_NAME;\n\n    /**\n     * Default asian font name.\n     *\n     * @var string\n     */\n    private static $defaultAsianFontName = self::DEFAULT_FONT_NAME;\n\n    /**\n     * Default font color.\n     *\n     * @var string\n     */\n    private static $defaultFontColor = self::DEFAULT_FONT_COLOR;\n\n    /**\n     * Default font size.\n     *\n     * @var float|int\n     */\n    private static $defaultFontSize = self::DEFAULT_FONT_SIZE;\n\n    /**\n     * Default paper.\n     *\n     * @var string\n     */\n    private static $defaultPaper = self::DEFAULT_PAPER;\n\n    /**\n     * Is RTL by default ?\n     *\n     * @var ?bool\n     */\n    private static $defaultRtl;\n\n    /**\n     * The user defined temporary directory.\n     *\n     * @var string\n     */\n    private static $tempDir = '';\n\n    /**\n     * Enables built-in output escaping mechanism.\n     * Default value is `false` for backward compatibility with versions below 0.13.0.\n     *\n     * @var bool\n     */\n    private static $outputEscapingEnabled = false;\n\n    /**\n     * Return the compatibility option used by the XMLWriter.\n     *\n     * @return bool Compatibility\n     */\n    public static function hasCompatibility(): bool\n    {\n        return self::$xmlWriterCompatibility;\n    }\n\n    /**\n     * Set the compatibility option used by the XMLWriter.\n     * This sets the setIndent and setIndentString for better compatibility.\n     */\n    public static function setCompatibility(bool $compatibility): bool\n    {\n        self::$xmlWriterCompatibility = $compatibility;\n\n        return true;\n    }\n\n    /**\n     * Get zip handler class.\n     */\n    public static function getZipClass(): string\n    {\n        return self::$zipClass;\n    }\n\n    /**\n     * Set zip handler class.\n     */\n    public static function setZipClass(string $zipClass): bool\n    {\n        if (in_array($zipClass, [self::PCLZIP, self::ZIPARCHIVE, self::OLD_LIB])) {\n            self::$zipClass = $zipClass;\n\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * Set details of the external library for rendering PDF files.\n     *\n     * @return bool Success or failure\n     */\n    public static function setPdfRenderer(string $libraryName, string $libraryBaseDir): bool\n    {\n        if (!self::setPdfRendererName($libraryName)) {\n            return false;\n        }\n\n        return self::setPdfRendererPath($libraryBaseDir);\n    }\n\n    /**\n     * Return the PDF Rendering Library.\n     */\n    public static function getPdfRendererName(): ?string\n    {\n        return self::$pdfRendererName;\n    }\n\n    /**\n     * Identify the external library to use for rendering PDF files.\n     */\n    public static function setPdfRendererName(?string $libraryName): bool\n    {\n        $pdfRenderers = [self::PDF_RENDERER_DOMPDF, self::PDF_RENDERER_TCPDF, self::PDF_RENDERER_MPDF];\n        if (!in_array($libraryName, $pdfRenderers)) {\n            return false;\n        }\n        self::$pdfRendererName = $libraryName;\n\n        return true;\n    }\n\n    /**\n     * Return the directory path to the PDF Rendering Library.\n     */\n    public static function getPdfRendererPath(): ?string\n    {\n        return self::$pdfRendererPath;\n    }\n\n    /**\n     * Set options of the external library for rendering PDF files.\n     */\n    public static function setPdfRendererOptions(array $options): void\n    {\n        self::$pdfRendererOptions = $options;\n    }\n\n    /**\n     * Return the PDF Rendering Options.\n     */\n    public static function getPdfRendererOptions(): array\n    {\n        return self::$pdfRendererOptions;\n    }\n\n    /**\n     * Location of external library to use for rendering PDF files.\n     *\n     * @param null|string $libraryBaseDir Directory path to the library's base folder\n     *\n     * @return bool Success or failure\n     */\n    public static function setPdfRendererPath(?string $libraryBaseDir): bool\n    {\n        if (!$libraryBaseDir || false === file_exists($libraryBaseDir) || false === is_readable($libraryBaseDir)) {\n            return false;\n        }\n        self::$pdfRendererPath = $libraryBaseDir;\n\n        return true;\n    }\n\n    /**\n     * Get measurement unit.\n     */\n    public static function getMeasurementUnit(): string\n    {\n        return self::$measurementUnit;\n    }\n\n    /**\n     * Set measurement unit.\n     */\n    public static function setMeasurementUnit(string $value): bool\n    {\n        $units = [\n            self::UNIT_TWIP,\n            self::UNIT_CM,\n            self::UNIT_MM,\n            self::UNIT_INCH,\n            self::UNIT_POINT,\n            self::UNIT_PICA,\n        ];\n        if (!in_array($value, $units)) {\n            return false;\n        }\n        self::$measurementUnit = $value;\n\n        return true;\n    }\n\n    /**\n     * Sets the user defined path to temporary directory.\n     *\n     * @param string $tempDir The user defined path to temporary directory\n     *\n     * @since 0.12.0\n     */\n    public static function setTempDir(string $tempDir): void\n    {\n        self::$tempDir = $tempDir;\n    }\n\n    /**\n     * Returns path to temporary directory.\n     *\n     * @since 0.12.0\n     */\n    public static function getTempDir(): string\n    {\n        if (!empty(self::$tempDir)) {\n            $tempDir = self::$tempDir;\n        } else {\n            $tempDir = sys_get_temp_dir();\n        }\n\n        return $tempDir;\n    }\n\n    /**\n     * @since 0.13.0\n     */\n    public static function isOutputEscapingEnabled(): bool\n    {\n        return self::$outputEscapingEnabled;\n    }\n\n    /**\n     * @since 0.13.0\n     */\n    public static function setOutputEscapingEnabled(bool $outputEscapingEnabled): void\n    {\n        self::$outputEscapingEnabled = $outputEscapingEnabled;\n    }\n\n    /**\n     * Get default font name.\n     */\n    public static function getDefaultFontName(): string\n    {\n        return self::$defaultFontName;\n    }\n\n    /**\n     * Get default font name.\n     */\n    public static function getDefaultAsianFontName(): string\n    {\n        return self::$defaultAsianFontName;\n    }\n\n    /**\n     * Set default font name.\n     */\n    public static function setDefaultFontName(string $value): bool\n    {\n        if (trim($value) !== '') {\n            self::$defaultFontName = $value;\n\n            return true;\n        }\n\n        return false;\n    }\n\n    public static function setDefaultAsianFontName(string $value): bool\n    {\n        if (trim($value) !== '') {\n            self::$defaultAsianFontName = $value;\n\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * Get default font color.\n     */\n    public static function getDefaultFontColor(): string\n    {\n        return self::$defaultFontColor;\n    }\n\n    /**\n     * Set default font color.\n     */\n    public static function setDefaultFontColor(string $value): bool\n    {\n        if (trim($value) !== '') {\n            self::$defaultFontColor = $value;\n\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * Get default font size.\n     *\n     * @return float|int\n     */\n    public static function getDefaultFontSize()\n    {\n        return self::$defaultFontSize;\n    }\n\n    /**\n     * Set default font size.\n     *\n     * @param null|float|int $value\n     */\n    public static function setDefaultFontSize($value): bool\n    {\n        if ((is_int($value) || is_float($value)) && (int) $value > 0) {\n            self::$defaultFontSize = $value;\n\n            return true;\n        }\n\n        return false;\n    }\n\n    public static function setDefaultRtl(?bool $defaultRtl): void\n    {\n        self::$defaultRtl = $defaultRtl;\n    }\n\n    public static function isDefaultRtl(): ?bool\n    {\n        return self::$defaultRtl;\n    }\n\n    /**\n     * Load setting from phpword.yml or phpword.yml.dist.\n     */\n    public static function loadConfig(?string $filename = null): array\n    {\n        // Get config file\n        $configFile = null;\n        $configPath = __DIR__ . '/../../';\n        if ($filename !== null) {\n            $files = [$filename];\n        } else {\n            $files = [\"{$configPath}phpword.ini\", \"{$configPath}phpword.ini.dist\"];\n        }\n        foreach ($files as $file) {\n            if (file_exists($file)) {\n                $configFile = realpath($file);\n\n                break;\n            }\n        }\n\n        // Parse config file\n        $config = [];\n        if ($configFile !== null) {\n            $config = @parse_ini_file($configFile);\n            if ($config === false) {\n                return [];\n            }\n        }\n\n        // Set config value\n        $appliedConfig = [];\n        foreach ($config as $key => $value) {\n            $method = \"set{$key}\";\n            if (method_exists(__CLASS__, $method)) {\n                self::$method($value);\n                $appliedConfig[$key] = $value;\n            }\n        }\n\n        return $appliedConfig;\n    }\n\n    /**\n     * Get default paper.\n     */\n    public static function getDefaultPaper(): string\n    {\n        return self::$defaultPaper;\n    }\n\n    /**\n     * Set default paper.\n     */\n    public static function setDefaultPaper(string $value): bool\n    {\n        if (trim($value) !== '') {\n            self::$defaultPaper = $value;\n\n            return true;\n        }\n\n        return false;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Shared/AbstractEnum.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Shared;\n\nuse InvalidArgumentException;\nuse ReflectionClass;\n\nabstract class AbstractEnum\n{\n    private static $constCacheArray;\n\n    private static function getConstants()\n    {\n        if (self::$constCacheArray == null) {\n            self::$constCacheArray = [];\n        }\n        $calledClass = static::class;\n        if (!array_key_exists($calledClass, self::$constCacheArray)) {\n            $reflect = new ReflectionClass($calledClass);\n            self::$constCacheArray[$calledClass] = $reflect->getConstants();\n        }\n\n        return self::$constCacheArray[$calledClass];\n    }\n\n    /**\n     * Returns all values for this enum.\n     *\n     * @return array\n     */\n    public static function values()\n    {\n        return array_values(self::getConstants());\n    }\n\n    /**\n     * Returns true the value is valid for this enum.\n     *\n     * @param string $value\n     *\n     * @return bool true if value is valid\n     */\n    public static function isValid($value)\n    {\n        $values = array_values(self::getConstants());\n\n        return in_array($value, $values, true);\n    }\n\n    /**\n     * Validates that the value passed is a valid value.\n     *\n     * @param string $value\n     */\n    public static function validate($value): void\n    {\n        if (!self::isValid($value)) {\n            $calledClass = static::class;\n            $values = array_values(self::getConstants());\n\n            throw new InvalidArgumentException(\"$value is not a valid value for $calledClass, possible values are \" . implode(', ', $values));\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Shared/Converter.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Shared;\n\n/**\n * Common converter functions.\n */\nclass Converter\n{\n    const INCH_TO_CM = 2.54;\n    const INCH_TO_TWIP = 1440;\n    const INCH_TO_PIXEL = 96;\n    const INCH_TO_POINT = 72;\n    const INCH_TO_PICA = 6;\n    const PIXEL_TO_EMU = 9525;\n    const DEGREE_TO_ANGLE = 60000;\n\n    /**\n     * Convert centimeter to twip.\n     *\n     * @param float $centimeter\n     *\n     * @return float\n     */\n    public static function cmToTwip($centimeter = 1)\n    {\n        return $centimeter / self::INCH_TO_CM * self::INCH_TO_TWIP;\n    }\n\n    /**\n     * Convert centimeter to inch.\n     *\n     * @param float $centimeter\n     *\n     * @return float\n     */\n    public static function cmToInch($centimeter = 1)\n    {\n        return $centimeter / self::INCH_TO_CM;\n    }\n\n    /**\n     * Convert centimeter to pixel.\n     *\n     * @param float $centimeter\n     *\n     * @return float\n     */\n    public static function cmToPixel($centimeter = 1)\n    {\n        return $centimeter / self::INCH_TO_CM * self::INCH_TO_PIXEL;\n    }\n\n    /**\n     * Convert centimeter to point.\n     *\n     * @param float $centimeter\n     *\n     * @return float\n     */\n    public static function cmToPoint($centimeter = 1)\n    {\n        return $centimeter / self::INCH_TO_CM * self::INCH_TO_POINT;\n    }\n\n    /**\n     * Convert centimeter to EMU.\n     *\n     * @param float $centimeter\n     *\n     * @return float\n     */\n    public static function cmToEmu($centimeter = 1)\n    {\n        return round($centimeter / self::INCH_TO_CM * self::INCH_TO_PIXEL * self::PIXEL_TO_EMU);\n    }\n\n    /**\n     * Convert inch to twip.\n     *\n     * @param float $inch\n     *\n     * @return float\n     */\n    public static function inchToTwip($inch = 1)\n    {\n        return $inch * self::INCH_TO_TWIP;\n    }\n\n    /**\n     * Convert inch to centimeter.\n     *\n     * @param float $inch\n     *\n     * @return float\n     */\n    public static function inchToCm($inch = 1)\n    {\n        return $inch * self::INCH_TO_CM;\n    }\n\n    /**\n     * Convert inch to pixel.\n     *\n     * @param float $inch\n     *\n     * @return float\n     */\n    public static function inchToPixel($inch = 1)\n    {\n        return $inch * self::INCH_TO_PIXEL;\n    }\n\n    /**\n     * Convert inch to point.\n     *\n     * @param float $inch\n     *\n     * @return float\n     */\n    public static function inchToPoint($inch = 1)\n    {\n        return $inch * self::INCH_TO_POINT;\n    }\n\n    /**\n     * Convert inch to EMU.\n     *\n     * @param float $inch\n     *\n     * @return int\n     */\n    public static function inchToEmu($inch = 1)\n    {\n        return round($inch * self::INCH_TO_PIXEL * self::PIXEL_TO_EMU);\n    }\n\n    /**\n     * Convert pixel to twip.\n     *\n     * @param float $pixel\n     *\n     * @return float\n     */\n    public static function pixelToTwip($pixel = 1)\n    {\n        return $pixel / self::INCH_TO_PIXEL * self::INCH_TO_TWIP;\n    }\n\n    /**\n     * Convert pixel to centimeter.\n     *\n     * @param float $pixel\n     *\n     * @return float\n     */\n    public static function pixelToCm($pixel = 1)\n    {\n        return $pixel / self::INCH_TO_PIXEL * self::INCH_TO_CM;\n    }\n\n    /**\n     * Convert pixel to point.\n     *\n     * @param float $pixel\n     *\n     * @return float\n     */\n    public static function pixelToPoint($pixel = 1)\n    {\n        return $pixel / self::INCH_TO_PIXEL * self::INCH_TO_POINT;\n    }\n\n    /**\n     * Convert pixel to EMU.\n     *\n     * @param float $pixel\n     *\n     * @return int\n     */\n    public static function pixelToEmu($pixel = 1)\n    {\n        return round($pixel * self::PIXEL_TO_EMU);\n    }\n\n    /**\n     * Convert point to twip unit.\n     *\n     * @param float $point\n     *\n     * @return float\n     */\n    public static function pointToTwip($point = 1)\n    {\n        return $point / self::INCH_TO_POINT * self::INCH_TO_TWIP;\n    }\n\n    /**\n     * Convert point to pixel.\n     *\n     * @param float $point\n     *\n     * @return float\n     */\n    public static function pointToPixel($point = 1)\n    {\n        return $point / self::INCH_TO_POINT * self::INCH_TO_PIXEL;\n    }\n\n    /**\n     * Convert point to EMU.\n     *\n     * @param float $point\n     *\n     * @return float\n     */\n    public static function pointToEmu($point = 1)\n    {\n        return round($point / self::INCH_TO_POINT * self::INCH_TO_PIXEL * self::PIXEL_TO_EMU);\n    }\n\n    /**\n     * Convert point to cm.\n     *\n     * @param float $point\n     *\n     * @return float\n     */\n    public static function pointToCm($point = 1)\n    {\n        return $point / self::INCH_TO_POINT * self::INCH_TO_CM;\n    }\n\n    /**\n     * Convert EMU to pixel.\n     *\n     * @param float $emu\n     *\n     * @return float\n     */\n    public static function emuToPixel($emu = 1)\n    {\n        return round($emu / self::PIXEL_TO_EMU);\n    }\n\n    /**\n     * Convert pica to point.\n     *\n     * @param float $pica\n     *\n     * @return float\n     */\n    public static function picaToPoint($pica = 1)\n    {\n        return $pica / self::INCH_TO_PICA * self::INCH_TO_POINT;\n    }\n\n    /**\n     * Convert degree to angle.\n     *\n     * @param float $degree\n     *\n     * @return int\n     */\n    public static function degreeToAngle($degree = 1)\n    {\n        return (int) round($degree * self::DEGREE_TO_ANGLE);\n    }\n\n    /**\n     * Convert angle to degrees.\n     *\n     * @param float $angle\n     *\n     * @return int\n     */\n    public static function angleToDegree($angle = 1)\n    {\n        return round($angle / self::DEGREE_TO_ANGLE);\n    }\n\n    /**\n     * Convert colorname as string to RGB.\n     *\n     * @param string $value color name\n     *\n     * @return string color as hex RGB string, or original value if unknown\n     */\n    public static function stringToRgb($value)\n    {\n        switch ($value) {\n            case \\PhpOffice\\PhpWord\\Style\\Font::FGCOLOR_YELLOW:\n                return 'FFFF00';\n            case \\PhpOffice\\PhpWord\\Style\\Font::FGCOLOR_LIGHTGREEN:\n                return '90EE90';\n            case \\PhpOffice\\PhpWord\\Style\\Font::FGCOLOR_CYAN:\n                return '00FFFF';\n            case \\PhpOffice\\PhpWord\\Style\\Font::FGCOLOR_MAGENTA:\n                return 'FF00FF';\n            case \\PhpOffice\\PhpWord\\Style\\Font::FGCOLOR_BLUE:\n                return '0000FF';\n            case \\PhpOffice\\PhpWord\\Style\\Font::FGCOLOR_RED:\n                return 'FF0000';\n            case \\PhpOffice\\PhpWord\\Style\\Font::FGCOLOR_DARKBLUE:\n                return '00008B';\n            case \\PhpOffice\\PhpWord\\Style\\Font::FGCOLOR_DARKCYAN:\n                return '008B8B';\n            case \\PhpOffice\\PhpWord\\Style\\Font::FGCOLOR_DARKGREEN:\n                return '006400';\n            case \\PhpOffice\\PhpWord\\Style\\Font::FGCOLOR_DARKMAGENTA:\n                return '8B008B';\n            case \\PhpOffice\\PhpWord\\Style\\Font::FGCOLOR_DARKRED:\n                return '8B0000';\n            case \\PhpOffice\\PhpWord\\Style\\Font::FGCOLOR_DARKYELLOW:\n                return '8B8B00';\n            case \\PhpOffice\\PhpWord\\Style\\Font::FGCOLOR_DARKGRAY:\n                return 'A9A9A9';\n            case \\PhpOffice\\PhpWord\\Style\\Font::FGCOLOR_LIGHTGRAY:\n                return 'D3D3D3';\n            case \\PhpOffice\\PhpWord\\Style\\Font::FGCOLOR_BLACK:\n                return '000000';\n        }\n\n        return $value;\n    }\n\n    /**\n     * Convert HTML hexadecimal to RGB.\n     *\n     * @param string $value HTML Color in hexadecimal\n     *\n     * @return array Value in RGB\n     */\n    public static function htmlToRgb($value)\n    {\n        if ($value[0] == '#') {\n            $value = substr($value, 1);\n        } else {\n            $value = self::stringToRgb($value);\n        }\n\n        if (strlen($value) == 6) {\n            [$red, $green, $blue] = [$value[0] . $value[1], $value[2] . $value[3], $value[4] . $value[5]];\n        } elseif (strlen($value) == 3) {\n            [$red, $green, $blue] = [$value[0] . $value[0], $value[1] . $value[1], $value[2] . $value[2]];\n        } else {\n            return false;\n        }\n\n        $red = ctype_xdigit($red) ? hexdec($red) : 0;\n        $green = ctype_xdigit($green) ? hexdec($green) : 0;\n        $blue = ctype_xdigit($blue) ? hexdec($blue) : 0;\n\n        return [$red, $green, $blue];\n    }\n\n    /**\n     * Transforms a size in CSS format (eg. 10px, 10px, ...) to points.\n     *\n     * @param string $value\n     *\n     * @return ?float\n     */\n    public static function cssToPoint($value)\n    {\n        if ($value == '0') {\n            return 0;\n        }\n        $matches = [];\n        if (preg_match('/^[+-]?([0-9]+\\.?[0-9]*)?(px|em|ex|%|in|cm|mm|pt|pc)$/i', $value, $matches)) {\n            $size = $matches[1];\n            $unit = $matches[2];\n\n            switch ($unit) {\n                case 'pt':\n                    return $size;\n                case 'px':\n                    return self::pixelToPoint($size);\n                case 'cm':\n                    return self::cmToPoint($size);\n                case 'mm':\n                    return self::cmToPoint($size / 10);\n                case 'in':\n                    return self::inchToPoint($size);\n                case 'pc':\n                    return self::picaToPoint($size);\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * Transforms a size in CSS format (eg. 10px, 10px, ...) to twips.\n     *\n     * @param string $value\n     *\n     * @return float\n     */\n    public static function cssToTwip($value)\n    {\n        return self::pointToTwip(self::cssToPoint($value));\n    }\n\n    /**\n     * Transforms a size in CSS format (eg. 10px, 10px, ...) to pixel.\n     *\n     * @param string $value\n     *\n     * @return float\n     */\n    public static function cssToPixel($value)\n    {\n        return self::pointToPixel(self::cssToPoint($value));\n    }\n\n    /**\n     * Transforms a size in CSS format (eg. 10px, 10px, ...) to cm.\n     *\n     * @param string $value\n     *\n     * @return float\n     */\n    public static function cssToCm($value)\n    {\n        return self::pointToCm(self::cssToPoint($value));\n    }\n\n    /**\n     * Transforms a size in CSS format (eg. 10px, 10px, ...) to emu.\n     *\n     * @param string $value\n     *\n     * @return float\n     */\n    public static function cssToEmu($value)\n    {\n        return self::pointToEmu(self::cssToPoint($value));\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Shared/Css.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\ndeclare(strict_types=1);\n\nnamespace PhpOffice\\PhpWord\\Shared;\n\nclass Css\n{\n    /**\n     * @var string\n     */\n    private $cssContent;\n\n    /**\n     * @var array<string, array<string, string>>\n     */\n    private $styles = [];\n\n    public function __construct(string $cssContent)\n    {\n        $this->cssContent = $cssContent;\n    }\n\n    public function process(): void\n    {\n        $cssContent = str_replace([\"\\r\", \"\\n\"], '', $this->cssContent);\n        preg_match_all('/(.+?)\\s?\\{\\s?(.+?)\\s?\\}/', $cssContent, $cssExtracted);\n        // Check if there are x selectors and x rules\n        if (count($cssExtracted[1]) != count($cssExtracted[2])) {\n            return;\n        }\n\n        foreach ($cssExtracted[1] as $key => $selector) {\n            $rules = trim($cssExtracted[2][$key]);\n            $rules = explode(';', $rules);\n            foreach ($rules as $rule) {\n                if (empty($rule)) {\n                    continue;\n                }\n                [$key, $value] = explode(':', trim($rule));\n                $this->styles[$this->sanitize($selector)][$this->sanitize($key)] = $this->sanitize($value);\n            }\n        }\n    }\n\n    public function getStyles(): array\n    {\n        return $this->styles;\n    }\n\n    public function getStyle(string $selector): array\n    {\n        $selector = $this->sanitize($selector);\n\n        return $this->styles[$selector] ?? [];\n    }\n\n    private function sanitize(string $value): string\n    {\n        return addslashes(trim($value));\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Shared/Drawing.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Shared;\n\n/**\n * Drawing.\n */\nclass Drawing\n{\n    const DPI_96 = 96;\n\n    /**\n     * Convert pixels to EMU.\n     *\n     * @param  int $pValue Value in pixels\n     *\n     * @return int\n     */\n    public static function pixelsToEmu($pValue = 0)\n    {\n        return round($pValue * 9525);\n    }\n\n    /**\n     * Convert EMU to pixels.\n     *\n     * @param  int $pValue Value in EMU\n     *\n     * @return int\n     */\n    public static function emuToPixels($pValue = 0)\n    {\n        if ($pValue == 0) {\n            return 0;\n        }\n\n        return round($pValue / 9525);\n    }\n\n    /**\n     * Convert pixels to points.\n     *\n     * @param  int $pValue Value in pixels\n     *\n     * @return float\n     */\n    public static function pixelsToPoints($pValue = 0)\n    {\n        return $pValue * 0.67777777;\n    }\n\n    /**\n     * Convert points width to centimeters.\n     *\n     * @param  int $pValue Value in points\n     *\n     * @return float\n     */\n    public static function pointsToCentimeters($pValue = 0)\n    {\n        if ($pValue == 0) {\n            return 0;\n        }\n\n        return (($pValue * 1.333333333) / self::DPI_96) * 2.54;\n    }\n\n    /**\n     * Convert points width to pixels.\n     *\n     * @param  int $pValue Value in points\n     *\n     * @return float\n     */\n    public static function pointsToPixels($pValue = 0)\n    {\n        if ($pValue == 0) {\n            return 0;\n        }\n\n        return $pValue * 1.333333333;\n    }\n\n    /**\n     * Convert pixels to centimeters.\n     *\n     * @param  int $pValue Value in pixels\n     *\n     * @return float\n     */\n    public static function pixelsToCentimeters($pValue = 0)\n    {\n        //return $pValue * 0.028;\n        return ($pValue / self::DPI_96) * 2.54;\n    }\n\n    /**\n     * Convert centimeters width to pixels.\n     *\n     * @param  int $pValue Value in centimeters\n     *\n     * @return float\n     */\n    public static function centimetersToPixels($pValue = 0)\n    {\n        if ($pValue == 0) {\n            return 0;\n        }\n\n        return ($pValue / 2.54) * self::DPI_96;\n    }\n\n    /**\n     * Convert degrees to angle.\n     *\n     * @param  int $pValue Degrees\n     *\n     * @return int\n     */\n    public static function degreesToAngle($pValue = 0)\n    {\n        return (int) round($pValue * 60000);\n    }\n\n    /**\n     * Convert angle to degrees.\n     *\n     * @param  int $pValue Angle\n     *\n     * @return int\n     */\n    public static function angleToDegrees($pValue = 0)\n    {\n        if ($pValue == 0) {\n            return 0;\n        }\n\n        return round($pValue / 60000);\n    }\n\n    /**\n     * Convert centimeters width to twips.\n     *\n     * @param int $pValue\n     *\n     * @return float\n     */\n    public static function centimetersToTwips($pValue = 0)\n    {\n        if ($pValue == 0) {\n            return 0;\n        }\n\n        return $pValue * 566.928;\n    }\n\n    /**\n     * Convert twips width to centimeters.\n     *\n     * @param int $pValue\n     *\n     * @return float\n     */\n    public static function twipsToCentimeters($pValue = 0)\n    {\n        if ($pValue == 0) {\n            return 0;\n        }\n\n        return $pValue / 566.928;\n    }\n\n    /**\n     * Convert inches width to twips.\n     *\n     * @param int $pValue\n     *\n     * @return float\n     */\n    public static function inchesToTwips($pValue = 0)\n    {\n        if ($pValue == 0) {\n            return 0;\n        }\n\n        return $pValue * 1440;\n    }\n\n    /**\n     * Convert twips width to inches.\n     *\n     * @param int $pValue\n     *\n     * @return float\n     */\n    public static function twipsToInches($pValue = 0)\n    {\n        if ($pValue == 0) {\n            return 0;\n        }\n\n        return $pValue / 1440;\n    }\n\n    /**\n     * Convert twips width to pixels.\n     *\n     * @param int $pValue\n     *\n     * @return float\n     */\n    public static function twipsToPixels($pValue = 0)\n    {\n        if ($pValue == 0) {\n            return 0;\n        }\n\n        return round($pValue / 15.873984);\n    }\n\n    /**\n     * Convert HTML hexadecimal to RGB.\n     *\n     * @param string $pValue HTML Color in hexadecimal\n     *\n     * @return array|false Value in RGB\n     */\n    public static function htmlToRGB($pValue)\n    {\n        if ($pValue[0] == '#') {\n            $pValue = substr($pValue, 1);\n        }\n\n        if (strlen($pValue) == 6) {\n            [$colorR, $colorG, $colorB] = [$pValue[0] . $pValue[1], $pValue[2] . $pValue[3], $pValue[4] . $pValue[5]];\n        } elseif (strlen($pValue) == 3) {\n            [$colorR, $colorG, $colorB] = [$pValue[0] . $pValue[0], $pValue[1] . $pValue[1], $pValue[2] . $pValue[2]];\n        } else {\n            return false;\n        }\n\n        $colorR = hexdec($colorR);\n        $colorG = hexdec($colorG);\n        $colorB = hexdec($colorB);\n\n        return [$colorR, $colorG, $colorB];\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Shared/Html.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Shared;\n\nuse DOMDocument;\nuse DOMNode;\nuse DOMXPath;\nuse Exception;\nuse PhpOffice\\PhpWord\\ComplexType\\RubyProperties;\nuse PhpOffice\\PhpWord\\Element\\AbstractContainer;\nuse PhpOffice\\PhpWord\\Element\\Row;\nuse PhpOffice\\PhpWord\\Element\\Table;\nuse PhpOffice\\PhpWord\\Element\\TextRun;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\nuse PhpOffice\\PhpWord\\SimpleType\\NumberFormat;\nuse PhpOffice\\PhpWord\\Style\\Paragraph;\n\n/**\n * Common Html functions.\n *\n * @SuppressWarnings(\"PHPMD.UnusedPrivateMethod\") For readWPNode\n */\nclass Html\n{\n    private const RGB_REGEXP = '/^\\s*rgb\\s*[(]\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*[)]\\s*$/';\n\n    protected static $listIndex = 0;\n\n    protected static $xpath;\n\n    protected static $options;\n\n    /**\n     * @var Css\n     */\n    protected static $css;\n\n    /**\n     * Add HTML parts.\n     *\n     * Note: $stylesheet parameter is removed to avoid PHPMD error for unused parameter\n     * Warning: Do not pass user-generated HTML here, as that would allow an attacker to read arbitrary\n     * files or perform server-side request forgery by passing local file paths or URLs in <img>.\n     *\n     * @param AbstractContainer $element Where the parts need to be added\n     * @param string $html The code to parse\n     * @param bool $fullHTML If it's a full HTML, no need to add 'body' tag\n     * @param bool $preserveWhiteSpace If false, the whitespaces between nodes will be removed\n     */\n    public static function addHtml($element, $html, $fullHTML = false, $preserveWhiteSpace = true, $options = null): void\n    {\n        /*\n         * @todo parse $stylesheet for default styles.  Should result in an array based on id, class and element,\n         * which could be applied when such an element occurs in the parseNode function.\n         */\n        static::$options = $options;\n\n        // Preprocess: remove all line ends, decode HTML entity,\n        // fix ampersand and angle brackets and add body tag for HTML fragments\n        $html = str_replace([\"\\n\", \"\\r\"], '', $html);\n        $html = str_replace(['&lt;', '&gt;', '&amp;', '&quot;'], ['_lt_', '_gt_', '_amp_', '_quot_'], $html);\n        $html = html_entity_decode($html, ENT_QUOTES, 'UTF-8');\n        $html = str_replace('&', '&amp;', $html);\n        $html = str_replace(['_lt_', '_gt_', '_amp_', '_quot_'], ['&lt;', '&gt;', '&amp;', '&quot;'], $html);\n\n        if (false === $fullHTML) {\n            $html = '<body>' . $html . '</body>';\n        }\n\n        // Load DOM\n        if (\\PHP_VERSION_ID < 80000) {\n            $orignalLibEntityLoader = libxml_disable_entity_loader(true);\n        }\n        $dom = new DOMDocument();\n        $dom->preserveWhiteSpace = $preserveWhiteSpace;\n        $dom->loadXML($html);\n        static::$xpath = new DOMXPath($dom);\n        $node = $dom->getElementsByTagName('body');\n\n        static::parseNode($node->item(0), $element);\n        if (\\PHP_VERSION_ID < 80000) {\n            libxml_disable_entity_loader($orignalLibEntityLoader);\n        }\n    }\n\n    /**\n     * parse Inline style of a node.\n     *\n     * @param DOMNode $node Node to check on attributes and to compile a style array\n     * @param array<string, mixed> $styles is supplied, the inline style attributes are added to the already existing style\n     *\n     * @return array\n     */\n    protected static function parseInlineStyle($node, $styles = [])\n    {\n        if (XML_ELEMENT_NODE == $node->nodeType) {\n            $attributes = $node->attributes; // get all the attributes(eg: id, class)\n\n            $attributeDir = $attributes->getNamedItem('dir');\n            $attributeDirValue = $attributeDir ? $attributeDir->nodeValue : '';\n            $bidi = $attributeDirValue === 'rtl';\n            foreach ($attributes as $attribute) {\n                $val = $attribute->value;\n                switch (strtolower($attribute->name)) {\n                    case 'align':\n                        $styles['alignment'] = self::mapAlign(trim($val), $bidi);\n\n                        break;\n                    case 'lang':\n                        $styles['lang'] = $val;\n\n                        break;\n                    case 'width':\n                        // tables, cells\n                        $val = $val === 'auto' ? '100%' : $val;\n                        if (false !== strpos($val, '%')) {\n                            // e.g. <table width=\"100%\"> or <td width=\"50%\">\n                            $styles['width'] = (int) $val * 50;\n                            $styles['unit'] = \\PhpOffice\\PhpWord\\SimpleType\\TblWidth::PERCENT;\n                        } else {\n                            // e.g. <table width=\"250> where \"250\" = 250px (always pixels)\n                            $styles['width'] = Converter::pixelToTwip(self::convertHtmlSize($val));\n                            $styles['unit'] = \\PhpOffice\\PhpWord\\SimpleType\\TblWidth::TWIP;\n                        }\n\n                        break;\n                    case 'cellspacing':\n                        // tables e.g. <table cellspacing=\"2\">,  where \"2\" = 2px (always pixels)\n                        $styles['cellSpacing'] = Converter::pixelToTwip(self::convertHtmlSize($val));\n\n                        break;\n                    case 'bgcolor':\n                        // tables, rows, cells e.g. <tr bgColor=\"#FF0000\">\n                        $styles['bgColor'] = self::convertRgb($val);\n\n                        break;\n                    case 'valign':\n                        // cells e.g. <td valign=\"middle\">\n                        if (preg_match('#(?:top|bottom|middle|baseline)#i', $val, $matches)) {\n                            $styles['valign'] = self::mapAlignVertical($matches[0]);\n                        }\n\n                        break;\n                }\n            }\n\n            $attributeIdentifier = $attributes->getNamedItem('id');\n            if ($attributeIdentifier && self::$css) {\n                $styles = self::parseStyleDeclarations(self::$css->getStyle('#' . $attributeIdentifier->nodeValue), $styles);\n            }\n\n            $attributeClass = $attributes->getNamedItem('class');\n            if ($attributeClass) {\n                if (self::$css) {\n                    $styles = self::parseStyleDeclarations(self::$css->getStyle('.' . $attributeClass->nodeValue), $styles);\n                }\n                $styles['className'] = $attributeClass->nodeValue;\n            }\n\n            $attributeStyle = $attributes->getNamedItem('style');\n            if ($attributeStyle) {\n                $styles = self::parseStyle($attributeStyle, $styles);\n            }\n        }\n\n        return $styles;\n    }\n\n    /**\n     * Parse a node and add a corresponding element to the parent element.\n     *\n     * @param DOMNode $node node to parse\n     * @param AbstractContainer $element object to add an element corresponding with the node\n     * @param array $styles Array with all styles\n     * @param array $data Array to transport data to a next level in the DOM tree, for example level of listitems\n     */\n    protected static function parseNode($node, $element, $styles = [], $data = []): void\n    {\n        if ($node->nodeName == 'style') {\n            self::$css = new Css($node->textContent);\n            self::$css->process();\n\n            return;\n        }\n\n        // Populate styles array\n        $styleTypes = ['font', 'paragraph', 'list', 'table', 'row', 'cell'];\n        foreach ($styleTypes as $styleType) {\n            if (!isset($styles[$styleType])) {\n                $styles[$styleType] = [];\n            }\n        }\n\n        // Node mapping table\n        $nodes = [\n            // $method               $node   $element    $styles     $data   $argument1      $argument2\n            'p' => ['Paragraph',     $node,  $element,   $styles,    null,   null,           null],\n            'h1' => ['Heading',      $node,  $element,   $styles,    null,   'Heading1',     null],\n            'h2' => ['Heading',      $node,  $element,   $styles,    null,   'Heading2',     null],\n            'h3' => ['Heading',      $node,  $element,   $styles,    null,   'Heading3',     null],\n            'h4' => ['Heading',      $node,  $element,   $styles,    null,   'Heading4',     null],\n            'h5' => ['Heading',      $node,  $element,   $styles,    null,   'Heading5',     null],\n            'h6' => ['Heading',      $node,  $element,   $styles,    null,   'Heading6',     null],\n            '#text' => ['Text',      $node,  $element,   $styles,    null,   null,           null],\n            'strong' => ['Property', null,   null,       $styles,    null,   'bold',         true],\n            'b' => ['Property',    null,   null,       $styles,    null,   'bold',         true],\n            'em' => ['Property',    null,   null,       $styles,    null,   'italic',       true],\n            'i' => ['Property',    null,   null,       $styles,    null,   'italic',       true],\n            'u' => ['Property',    null,   null,       $styles,    null,   'underline',    'single'],\n            'sup' => ['Property',    null,   null,       $styles,    null,   'superScript',  true],\n            'sub' => ['Property',    null,   null,       $styles,    null,   'subScript',    true],\n            'span' => ['Span',        $node,  null,       $styles,    null,   null,           null],\n            'font' => ['Span',        $node,  null,       $styles,    null,   null,           null],\n            'table' => ['Table',       $node,  $element,   $styles,    null,   null,           null],\n            'tr' => ['Row',         $node,  $element,   $styles,    null,   null,           null],\n            'td' => ['Cell',        $node,  $element,   $styles,    null,   null,           null],\n            'th' => ['Cell',        $node,  $element,   $styles,    null,   null,           null],\n            'ul' => ['List',        $node,  $element,   $styles,    $data,  null,           null],\n            'ol' => ['List',        $node,  $element,   $styles,    $data,  null,           null],\n            'li' => ['ListItem',    $node,  $element,   $styles,    $data,  null,           null],\n            'img' => ['Image',       $node,  $element,   $styles,    null,   null,           null],\n            'br' => ['LineBreak',   null,   $element,   $styles,    null,   null,           null],\n            'a' => ['Link',        $node,  $element,   $styles,    null,   null,           null],\n            'input' => ['Input',       $node,  $element,   $styles,    null,   null,           null],\n            'hr' => ['HorizRule',   $node,  $element,   $styles,    null,   null,           null],\n            'ruby' => ['Ruby',   $node,  $element,   $styles,    null,   null,           null],\n        ];\n\n        $newElement = null;\n        $keys = ['node', 'element', 'styles', 'data', 'argument1', 'argument2'];\n\n        if (isset($nodes[$node->nodeName])) {\n            // Execute method based on node mapping table and return $newElement or null\n            // Arguments are passed by reference\n            $arguments = [];\n            $args = [];\n            [$method, $args[0], $args[1], $args[2], $args[3], $args[4], $args[5]] = $nodes[$node->nodeName];\n            for ($i = 0; $i <= 5; ++$i) {\n                if ($args[$i] !== null) {\n                    $arguments[$keys[$i]] = &$args[$i];\n                }\n            }\n            $method = \"parse{$method}\";\n            $newElement = call_user_func_array(['PhpOffice\\PhpWord\\Shared\\Html', $method], array_values($arguments));\n\n            // Retrieve back variables from arguments\n            foreach ($keys as $key) {\n                if (array_key_exists($key, $arguments)) {\n                    $$key = $arguments[$key];\n                }\n            }\n        }\n\n        if ($newElement === null) {\n            $newElement = $element;\n        }\n\n        static::parseChildNodes($node, $newElement, $styles, $data);\n    }\n\n    /**\n     * Parse child nodes.\n     *\n     * @param DOMNode $node\n     * @param AbstractContainer|Row|Table $element\n     * @param array $styles\n     * @param array $data\n     */\n    protected static function parseChildNodes($node, $element, $styles, $data): void\n    {\n        if ('li' != $node->nodeName) {\n            $cNodes = $node->childNodes;\n            if (!empty($cNodes)) {\n                foreach ($cNodes as $cNode) {\n                    if ($element instanceof AbstractContainer || $element instanceof Table || $element instanceof Row) {\n                        self::parseNode($cNode, $element, $styles, $data);\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Parse paragraph node.\n     *\n     * @param DOMNode $node\n     * @param AbstractContainer $element\n     * @param array &$styles\n     *\n     * @return \\PhpOffice\\PhpWord\\Element\\PageBreak|TextRun\n     */\n    protected static function parseParagraph($node, $element, &$styles)\n    {\n        $styles['paragraph'] = self::recursiveParseStylesInHierarchy($node, $styles['paragraph']);\n        if (isset($styles['paragraph']['isPageBreak']) && $styles['paragraph']['isPageBreak']) {\n            return $element->addPageBreak();\n        }\n\n        return $element->addTextRun($styles['paragraph']);\n    }\n\n    /**\n     * Parse input node.\n     *\n     * @param DOMNode $node\n     * @param AbstractContainer $element\n     * @param array &$styles\n     */\n    protected static function parseInput($node, $element, &$styles): void\n    {\n        $attributes = $node->attributes;\n        if (null === $attributes->getNamedItem('type')) {\n            return;\n        }\n\n        $inputType = $attributes->getNamedItem('type')->nodeValue;\n        switch ($inputType) {\n            case 'checkbox':\n                $checked = ($checked = $attributes->getNamedItem('checked')) && $checked->nodeValue === 'true' ? true : false;\n                $textrun = $element->addTextRun($styles['paragraph']);\n                $textrun->addFormField('checkbox')->setValue($checked);\n\n                break;\n        }\n    }\n\n    /**\n     * Parse heading node.\n     *\n     * @param string $argument1 Name of heading style\n     *\n     * @todo Think of a clever way of defining header styles, now it is only based on the assumption, that\n     * Heading1 - Heading6 are already defined somewhere\n     */\n    protected static function parseHeading(DOMNode $node, AbstractContainer $element, array &$styles, string $argument1): TextRun\n    {\n        $style = new Paragraph();\n        $style->setStyleName($argument1);\n        $style->setStyleByArray(self::parseInlineStyle($node, $styles['paragraph']));\n\n        return $element->addTextRun($style);\n    }\n\n    /**\n     * Parse text node.\n     *\n     * @param DOMNode $node\n     * @param AbstractContainer $element\n     * @param array &$styles\n     */\n    protected static function parseText($node, $element, &$styles): void\n    {\n        $styles['font'] = self::recursiveParseStylesInHierarchy($node, $styles['font']);\n\n        //alignment applies on paragraph, not on font. Let's copy it there\n        if (isset($styles['font']['alignment']) && is_array($styles['paragraph'])) {\n            $styles['paragraph']['alignment'] = $styles['font']['alignment'];\n        }\n\n        if (is_callable([$element, 'addText'])) {\n            $element->addText($node->nodeValue, $styles['font'], $styles['paragraph']);\n        }\n    }\n\n    /**\n     * Parse property node.\n     *\n     * @param array &$styles\n     * @param string $argument1 Style name\n     * @param string $argument2 Style value\n     */\n    protected static function parseProperty(&$styles, $argument1, $argument2): void\n    {\n        $styles['font'][$argument1] = $argument2;\n    }\n\n    /**\n     * Parse span node.\n     *\n     * @param DOMNode $node\n     * @param array &$styles\n     */\n    protected static function parseSpan($node, &$styles): void\n    {\n        self::parseInlineStyle($node, $styles['font']);\n    }\n\n    /**\n     * Parse table node.\n     *\n     * @param DOMNode $node\n     * @param AbstractContainer $element\n     * @param array &$styles\n     *\n     * @return Table $element\n     *\n     * @todo As soon as TableItem, RowItem and CellItem support relative width and height\n     */\n    protected static function parseTable($node, $element, &$styles)\n    {\n        $elementStyles = self::parseInlineStyle($node, $styles['table']);\n\n        $newElement = $element->addTable($elementStyles);\n\n        // Add style name from CSS Class\n        if (isset($elementStyles['className'])) {\n            $newElement->getStyle()->setStyleName($elementStyles['className']);\n        }\n\n        $attributes = $node->attributes;\n        if ($attributes->getNamedItem('border')) {\n            $border = (int) $attributes->getNamedItem('border')->nodeValue;\n            $newElement->getStyle()->setBorderSize(Converter::pixelToTwip($border));\n        }\n\n        return $newElement;\n    }\n\n    /**\n     * Parse a table row.\n     *\n     * @param DOMNode $node\n     * @param Table $element\n     * @param array &$styles\n     *\n     * @return Row $element\n     */\n    protected static function parseRow($node, $element, &$styles)\n    {\n        $rowStyles = self::parseInlineStyle($node, $styles['row']);\n        if ($node->parentNode->nodeName == 'thead') {\n            $rowStyles['tblHeader'] = true;\n        }\n\n        // set cell height to control row heights\n        $height = $rowStyles['height'] ?? null;\n        unset($rowStyles['height']); // would not apply\n\n        return $element->addRow($height, $rowStyles);\n    }\n\n    /**\n     * Parse table cell.\n     *\n     * @param DOMNode $node\n     * @param Table $element\n     * @param array &$styles\n     *\n     * @return \\PhpOffice\\PhpWord\\Element\\Cell|TextRun $element\n     */\n    protected static function parseCell($node, $element, &$styles)\n    {\n        $cellStyles = self::recursiveParseStylesInHierarchy($node, $styles['cell']);\n\n        $colspan = $node->getAttribute('colspan');\n        if (!empty($colspan)) {\n            $cellStyles['gridSpan'] = $colspan - 0;\n        }\n\n        // set cell width to control column widths\n        $width = $cellStyles['width'] ?? null;\n        unset($cellStyles['width']); // would not apply\n        $cell = $element->addCell($width, $cellStyles);\n\n        if (self::shouldAddTextRun($node)) {\n            return $cell->addTextRun(self::filterOutNonInheritedStyles(self::parseInlineStyle($node, $styles['paragraph'])));\n        }\n\n        return $cell;\n    }\n\n    /**\n     * Checks if $node contains an HTML element that cannot be added to TextRun.\n     *\n     * @return bool Returns true if the node contains an HTML element that cannot be added to TextRun\n     */\n    protected static function shouldAddTextRun(DOMNode $node)\n    {\n        $containsBlockElement = self::$xpath->query('.//table|./p|./ul|./ol|./h1|./h2|./h3|./h4|./h5|./h6', $node)->length > 0;\n        if ($containsBlockElement) {\n            return false;\n        }\n\n        return true;\n    }\n\n    /**\n     * Recursively parses styles on parent nodes\n     * TODO if too slow, add caching of parent nodes, !! everything is static here so watch out for concurrency !!\n     */\n    protected static function recursiveParseStylesInHierarchy(DOMNode $node, array $style)\n    {\n        $parentStyle = [];\n        if ($node->parentNode != null && XML_ELEMENT_NODE == $node->parentNode->nodeType) {\n            $parentStyle = self::recursiveParseStylesInHierarchy($node->parentNode, []);\n        }\n        if ($node->nodeName === '#text') {\n            $parentStyle = array_merge($parentStyle, $style);\n        } else {\n            $parentStyle = self::filterOutNonInheritedStyles($parentStyle);\n        }\n        $style = self::parseInlineStyle($node, $parentStyle);\n\n        return $style;\n    }\n\n    /**\n     * Removes non-inherited styles from array.\n     */\n    protected static function filterOutNonInheritedStyles(array $styles)\n    {\n        $nonInheritedStyles = [\n            'borderSize',\n            'borderTopSize',\n            'borderRightSize',\n            'borderBottomSize',\n            'borderLeftSize',\n            'borderColor',\n            'borderTopColor',\n            'borderRightColor',\n            'borderBottomColor',\n            'borderLeftColor',\n            'borderStyle',\n            'spaceAfter',\n            'spaceBefore',\n            'underline',\n            'strikethrough',\n            'hidden',\n        ];\n\n        $styles = array_diff_key($styles, array_flip($nonInheritedStyles));\n\n        return $styles;\n    }\n\n    /**\n     * Parse list node.\n     *\n     * @param DOMNode $node\n     * @param AbstractContainer $element\n     * @param array &$styles\n     * @param array &$data\n     */\n    protected static function parseList($node, $element, &$styles, &$data)\n    {\n        $isOrderedList = $node->nodeName === 'ol';\n        if (isset($data['listdepth'])) {\n            ++$data['listdepth'];\n        } else {\n            $data['listdepth'] = 0;\n            $styles['list'] = 'listStyle_' . self::$listIndex++;\n            $style = $element->getPhpWord()->addNumberingStyle($styles['list'], self::getListStyle($isOrderedList));\n\n            // extract attributes start & type e.g. <ol type=\"A\" start=\"3\">\n            $start = 0;\n            $type = '';\n            foreach ($node->attributes as $attribute) {\n                switch ($attribute->name) {\n                    case 'start':\n                        $start = (int) $attribute->value;\n\n                        break;\n                    case 'type':\n                        $type = $attribute->value;\n\n                        break;\n                }\n            }\n\n            $levels = $style->getLevels();\n            /** @var \\PhpOffice\\PhpWord\\Style\\NumberingLevel */\n            $level = $levels[0];\n            if ($start > 0) {\n                $level->setStart($start);\n            }\n            $type = $type ? self::mapListType($type) : null;\n            if ($type) {\n                $level->setFormat($type);\n            }\n        }\n        if ($node->parentNode->nodeName === 'li') {\n            return $element->getParent();\n        }\n    }\n\n    /**\n     * @param bool $isOrderedList\n     *\n     * @return array\n     */\n    protected static function getListStyle($isOrderedList)\n    {\n        if ($isOrderedList) {\n            return [\n                'type' => 'multilevel',\n                'levels' => [\n                    ['format' => NumberFormat::DECIMAL,      'text' => '%1.', 'alignment' => 'left',  'tabPos' => 720,  'left' => 720,  'hanging' => 360],\n                    ['format' => NumberFormat::LOWER_LETTER, 'text' => '%2.', 'alignment' => 'left',  'tabPos' => 1440, 'left' => 1440, 'hanging' => 360],\n                    ['format' => NumberFormat::LOWER_ROMAN,  'text' => '%3.', 'alignment' => 'right', 'tabPos' => 2160, 'left' => 2160, 'hanging' => 180],\n                    ['format' => NumberFormat::DECIMAL,      'text' => '%4.', 'alignment' => 'left',  'tabPos' => 2880, 'left' => 2880, 'hanging' => 360],\n                    ['format' => NumberFormat::LOWER_LETTER, 'text' => '%5.', 'alignment' => 'left',  'tabPos' => 3600, 'left' => 3600, 'hanging' => 360],\n                    ['format' => NumberFormat::LOWER_ROMAN,  'text' => '%6.', 'alignment' => 'right', 'tabPos' => 4320, 'left' => 4320, 'hanging' => 180],\n                    ['format' => NumberFormat::DECIMAL,      'text' => '%7.', 'alignment' => 'left',  'tabPos' => 5040, 'left' => 5040, 'hanging' => 360],\n                    ['format' => NumberFormat::LOWER_LETTER, 'text' => '%8.', 'alignment' => 'left',  'tabPos' => 5760, 'left' => 5760, 'hanging' => 360],\n                    ['format' => NumberFormat::LOWER_ROMAN,  'text' => '%9.', 'alignment' => 'right', 'tabPos' => 6480, 'left' => 6480, 'hanging' => 180],\n                ],\n            ];\n        }\n\n        return [\n            'type' => 'hybridMultilevel',\n            'levels' => [\n                ['format' => NumberFormat::BULLET, 'text' => '•', 'alignment' => 'left', 'tabPos' => 720,  'left' => 720,  'hanging' => 360, 'font' => 'Symbol',      'hint' => 'default'],\n                ['format' => NumberFormat::BULLET, 'text' => '◦',  'alignment' => 'left', 'tabPos' => 1440, 'left' => 1440, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'],\n                ['format' => NumberFormat::BULLET, 'text' => '•', 'alignment' => 'left', 'tabPos' => 2160, 'left' => 2160, 'hanging' => 360, 'font' => 'Wingdings',   'hint' => 'default'],\n                ['format' => NumberFormat::BULLET, 'text' => '•', 'alignment' => 'left', 'tabPos' => 2880, 'left' => 2880, 'hanging' => 360, 'font' => 'Symbol',      'hint' => 'default'],\n                ['format' => NumberFormat::BULLET, 'text' => '◦',  'alignment' => 'left', 'tabPos' => 3600, 'left' => 3600, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'],\n                ['format' => NumberFormat::BULLET, 'text' => '•', 'alignment' => 'left', 'tabPos' => 4320, 'left' => 4320, 'hanging' => 360, 'font' => 'Wingdings',   'hint' => 'default'],\n                ['format' => NumberFormat::BULLET, 'text' => '•', 'alignment' => 'left', 'tabPos' => 5040, 'left' => 5040, 'hanging' => 360, 'font' => 'Symbol',      'hint' => 'default'],\n                ['format' => NumberFormat::BULLET, 'text' => '◦',  'alignment' => 'left', 'tabPos' => 5760, 'left' => 5760, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'],\n                ['format' => NumberFormat::BULLET, 'text' => '•', 'alignment' => 'left', 'tabPos' => 6480, 'left' => 6480, 'hanging' => 360, 'font' => 'Wingdings',   'hint' => 'default'],\n            ],\n        ];\n    }\n\n    /**\n     * Parse list item node.\n     *\n     * @param DOMNode $node\n     * @param AbstractContainer $element\n     * @param array &$styles\n     * @param array $data\n     *\n     * @todo This function is almost the same like `parseChildNodes`. Merged?\n     * @todo As soon as ListItem inherits from AbstractContainer or TextRun delete parsing part of childNodes\n     */\n    protected static function parseListItem($node, $element, &$styles, $data): void\n    {\n        $cNodes = $node->childNodes;\n        if (!empty($cNodes)) {\n            $listRun = $element->addListItemRun($data['listdepth'], $styles['list'], $styles['paragraph']);\n            foreach ($cNodes as $cNode) {\n                self::parseNode($cNode, $listRun, $styles, $data);\n            }\n        }\n    }\n\n    /**\n     * Parse style.\n     *\n     * @param DOMNode $attribute\n     */\n    protected static function parseStyle($attribute, array $styles): array\n    {\n        $properties = explode(';', trim($attribute->nodeValue, \" \\t\\n\\r\\0\\x0B;\"));\n\n        $selectors = [];\n        foreach ($properties as $property) {\n            [$cKey, $cValue] = array_pad(explode(':', $property, 2), 2, null);\n            $selectors[strtolower(trim($cKey))] = trim($cValue ?? '');\n        }\n\n        return self::parseStyleDeclarations($selectors, $styles);\n    }\n\n    protected static function parseStyleDeclarations(array $selectors, array $styles): array\n    {\n        $bidi = ($selectors['direction'] ?? '') === 'rtl';\n        foreach ($selectors as $property => $value) {\n            switch ($property) {\n                case 'text-decoration':\n                    switch ($value) {\n                        case 'underline':\n                            $styles['underline'] = 'single';\n\n                            break;\n                        case 'line-through':\n                            $styles['strikethrough'] = true;\n\n                            break;\n                    }\n\n                    break;\n                case 'text-align':\n                    $styles['alignment'] = self::mapAlign($value, $bidi);\n\n                    break;\n                case 'ruby-align':\n                    $styles['rubyAlignment'] = self::mapRubyAlign($value);\n\n                    break;\n                case 'display':\n                    $styles['hidden'] = $value === 'none' || $value === 'hidden';\n\n                    break;\n                case 'direction':\n                    $styles['rtl'] = $value === 'rtl';\n                    $styles['bidi'] = $value === 'rtl';\n\n                    break;\n                case 'font-size':\n                    $styles['size'] = Converter::cssToPoint($value);\n\n                    break;\n                case 'font-family':\n                    $value = array_map('trim', explode(',', $value));\n                    $styles['name'] = ucwords($value[0]);\n\n                    break;\n                case 'color':\n                    $styles['color'] = self::convertRgb($value);\n\n                    break;\n                case 'background-color':\n                    $styles['bgColor'] = self::convertRgb($value);\n\n                    break;\n                case 'line-height':\n                    $matches = [];\n                    if ($value === 'normal' || $value === 'inherit') {\n                        $spacingLineRule = \\PhpOffice\\PhpWord\\SimpleType\\LineSpacingRule::AUTO;\n                        $spacing = 0;\n                    } elseif (preg_match('/([0-9]+\\.?[0-9]*[a-z]+)/', $value, $matches)) {\n                        //matches number with a unit, e.g. 12px, 15pt, 20mm, ...\n                        $spacingLineRule = \\PhpOffice\\PhpWord\\SimpleType\\LineSpacingRule::EXACT;\n                        $spacing = Converter::cssToTwip($matches[1]);\n                    } elseif (preg_match('/([0-9]+)%/', $value, $matches)) {\n                        //matches percentages\n                        $spacingLineRule = \\PhpOffice\\PhpWord\\SimpleType\\LineSpacingRule::AUTO;\n                        //we are subtracting 1 line height because the Spacing writer is adding one line\n                        $spacing = ((((int) $matches[1]) / 100) * Paragraph::LINE_HEIGHT) - Paragraph::LINE_HEIGHT;\n                    } else {\n                        //any other, wich is a multiplier. E.g. 1.2\n                        $spacingLineRule = \\PhpOffice\\PhpWord\\SimpleType\\LineSpacingRule::AUTO;\n                        //we are subtracting 1 line height because the Spacing writer is adding one line\n                        $spacing = ($value * Paragraph::LINE_HEIGHT) - Paragraph::LINE_HEIGHT;\n                    }\n                    $styles['spacingLineRule'] = $spacingLineRule;\n                    $styles['line-spacing'] = $spacing;\n\n                    break;\n                case 'letter-spacing':\n                    $styles['letter-spacing'] = Converter::cssToTwip($value);\n\n                    break;\n                case 'text-indent':\n                    $styles['indentation']['firstLine'] = Converter::cssToTwip($value);\n\n                    break;\n                case 'font-weight':\n                    $tValue = false;\n                    if (preg_match('#bold#', $value)) {\n                        $tValue = true; // also match bolder\n                    }\n                    $styles['bold'] = $tValue;\n\n                    break;\n                case 'font-style':\n                    $tValue = false;\n                    if (preg_match('#(?:italic|oblique)#', $value)) {\n                        $tValue = true;\n                    }\n                    $styles['italic'] = $tValue;\n\n                    break;\n                case 'font-variant':\n                    $tValue = false;\n                    if (preg_match('#small-caps#', $value)) {\n                        $tValue = true;\n                    }\n                    $styles['smallCaps'] = $tValue;\n\n                    break;\n                case 'margin':\n                    $value = Converter::cssToTwip($value);\n                    $styles['spaceBefore'] = $value;\n                    $styles['spaceAfter'] = $value;\n\n                    break;\n                case 'margin-top':\n                    // BC change: up to ver. 0.17.0 incorrectly converted to points - Converter::cssToPoint($value)\n                    $styles['spaceBefore'] = Converter::cssToTwip($value);\n\n                    break;\n                case 'margin-bottom':\n                    // BC change: up to ver. 0.17.0 incorrectly converted to points - Converter::cssToPoint($value)\n                    $styles['spaceAfter'] = Converter::cssToTwip($value);\n\n                    break;\n\n                case 'padding':\n                    $valueTop = $valueRight = $valueBottom = $valueLeft = null;\n                    $cValue = preg_replace('# +#', ' ', trim($value));\n                    $paddingArr = explode(' ', $cValue);\n                    $countParams = count($paddingArr);\n                    if ($countParams == 1) {\n                        $valueTop = $valueRight = $valueBottom = $valueLeft = $paddingArr[0];\n                    } elseif ($countParams == 2) {\n                        $valueTop = $valueBottom = $paddingArr[0];\n                        $valueRight = $valueLeft = $paddingArr[1];\n                    } elseif ($countParams == 3) {\n                        $valueTop = $paddingArr[0];\n                        $valueRight = $valueLeft = $paddingArr[1];\n                        $valueBottom = $paddingArr[2];\n                    } elseif ($countParams == 4) {\n                        $valueTop = $paddingArr[0];\n                        $valueRight = $paddingArr[1];\n                        $valueBottom = $paddingArr[2];\n                        $valueLeft = $paddingArr[3];\n                    }\n                    if ($valueTop !== null) {\n                        $styles['paddingTop'] = Converter::cssToTwip($valueTop);\n                    }\n                    if ($valueRight !== null) {\n                        $styles['paddingRight'] = Converter::cssToTwip($valueRight);\n                    }\n                    if ($valueBottom !== null) {\n                        $styles['paddingBottom'] = Converter::cssToTwip($valueBottom);\n                    }\n                    if ($valueLeft !== null) {\n                        $styles['paddingLeft'] = Converter::cssToTwip($valueLeft);\n                    }\n\n                    break;\n                case 'padding-top':\n                    $styles['paddingTop'] = Converter::cssToTwip($value);\n\n                    break;\n                case 'padding-right':\n                    $styles['paddingRight'] = Converter::cssToTwip($value);\n\n                    break;\n                case 'padding-bottom':\n                    $styles['paddingBottom'] = Converter::cssToTwip($value);\n\n                    break;\n                case 'padding-left':\n                    $styles['paddingLeft'] = Converter::cssToTwip($value);\n\n                    break;\n\n                case 'border-color':\n                    self::mapBorderColor($styles, $value);\n\n                    break;\n                case 'border-width':\n                    $styles['borderSize'] = Converter::cssToPoint($value);\n\n                    break;\n                case 'border-style':\n                    $styles['borderStyle'] = self::mapBorderStyle($value);\n\n                    break;\n                case 'width':\n                    if (preg_match('/([0-9]+[a-z]+)/', $value, $matches)) {\n                        $styles['width'] = Converter::cssToTwip($matches[1]);\n                        $styles['unit'] = \\PhpOffice\\PhpWord\\SimpleType\\TblWidth::TWIP;\n                    } elseif (preg_match('/([0-9]+)%/', $value, $matches)) {\n                        $styles['width'] = $matches[1] * 50;\n                        $styles['unit'] = \\PhpOffice\\PhpWord\\SimpleType\\TblWidth::PERCENT;\n                    } elseif (preg_match('/([0-9]+)/', $value, $matches)) {\n                        $styles['width'] = $matches[1];\n                        $styles['unit'] = \\PhpOffice\\PhpWord\\SimpleType\\TblWidth::AUTO;\n                    }\n\n                    break;\n                case 'height':\n                    $styles['height'] = Converter::cssToTwip($value);\n                    $styles['exactHeight'] = true;\n\n                    break;\n                case 'border':\n                case 'border-top':\n                case 'border-bottom':\n                case 'border-right':\n                case 'border-left':\n                    // must have exact order [width color style], e.g. \"1px #0011CC solid\" or \"2pt green solid\"\n                    // Word does not accept shortened hex colors e.g. #CCC, only full e.g. #CCCCCC\n                    if (preg_match('/([0-9]+[^0-9]*)\\s+(\\#[a-fA-F0-9]+|[a-zA-Z]+)\\s+([a-z]+)/', $value, $matches)) {\n                        if (false !== strpos($property, '-')) {\n                            $tmp = explode('-', $property);\n                            $which = $tmp[1];\n                            $which = ucfirst($which); // e.g. bottom -> Bottom\n                        } else {\n                            $which = '';\n                        }\n                        // Note - border width normalization:\n                        // Width of border in Word is calculated differently than HTML borders, usually showing up too bold.\n                        // Smallest 1px (or 1pt) appears in Word like 2-3px/pt in HTML once converted to twips.\n                        // Therefore we need to normalize converted twip value to cca 1/2 of value.\n                        // This may be adjusted, if better ratio or formula found.\n                        // BC change: up to ver. 0.17.0 was $size converted to points - Converter::cssToPoint($size)\n                        $size = Converter::cssToTwip($matches[1]);\n                        $size = (int) ($size / 2);\n                        // valid variants may be e.g. borderSize, borderTopSize, borderLeftColor, etc ..\n                        $styles[\"border{$which}Size\"] = $size; // twips\n                        $styles[\"border{$which}Color\"] = trim($matches[2], '#');\n                        $styles[\"border{$which}Style\"] = self::mapBorderStyle($matches[3]);\n                    }\n\n                    break;\n                case 'vertical-align':\n                    // https://developer.mozilla.org/en-US/docs/Web/CSS/vertical-align\n                    if (preg_match('#(?:top|bottom|middle|sub|baseline)#i', $value, $matches)) {\n                        $styles['valign'] = self::mapAlignVertical($matches[0]);\n                    }\n\n                    break;\n                case 'page-break-after':\n                    if ($value == 'always') {\n                        $styles['isPageBreak'] = true;\n                    }\n\n                    break;\n            }\n        }\n\n        return $styles;\n    }\n\n    /**\n     * Parse image node.\n     *\n     * @param DOMNode $node\n     * @param AbstractContainer $element\n     *\n     * @return \\PhpOffice\\PhpWord\\Element\\Image\n     */\n    protected static function parseImage($node, $element)\n    {\n        $style = [];\n        $src = null;\n        foreach ($node->attributes as $attribute) {\n            switch ($attribute->name) {\n                case 'src':\n                    $src = $attribute->value;\n\n                    break;\n                case 'width':\n                    $style['width'] = self::convertHtmlSize($attribute->value);\n                    $style['unit'] = \\PhpOffice\\PhpWord\\Style\\Image::UNIT_PX;\n\n                    break;\n                case 'height':\n                    $style['height'] = self::convertHtmlSize($attribute->value);\n                    $style['unit'] = \\PhpOffice\\PhpWord\\Style\\Image::UNIT_PX;\n\n                    break;\n                case 'style':\n                    $styleattr = explode(';', $attribute->value);\n                    foreach ($styleattr as $attr) {\n                        if (strpos($attr, ':')) {\n                            [$k, $v] = explode(':', $attr);\n                            switch ($k) {\n                                case 'float':\n                                    if (trim($v) == 'right') {\n                                        $style['hPos'] = \\PhpOffice\\PhpWord\\Style\\Image::POS_RIGHT;\n                                        $style['hPosRelTo'] = \\PhpOffice\\PhpWord\\Style\\Image::POS_RELTO_MARGIN; // inner section area\n                                        $style['pos'] = \\PhpOffice\\PhpWord\\Style\\Image::POS_RELATIVE;\n                                        $style['wrap'] = \\PhpOffice\\PhpWord\\Style\\Image::WRAP_TIGHT;\n                                        $style['overlap'] = true;\n                                    }\n                                    if (trim($v) == 'left') {\n                                        $style['hPos'] = \\PhpOffice\\PhpWord\\Style\\Image::POS_LEFT;\n                                        $style['hPosRelTo'] = \\PhpOffice\\PhpWord\\Style\\Image::POS_RELTO_MARGIN; // inner section area\n                                        $style['pos'] = \\PhpOffice\\PhpWord\\Style\\Image::POS_RELATIVE;\n                                        $style['wrap'] = \\PhpOffice\\PhpWord\\Style\\Image::WRAP_TIGHT;\n                                        $style['overlap'] = true;\n                                    }\n\n                                    break;\n                            }\n                        }\n                    }\n\n                    break;\n            }\n        }\n        $originSrc = $src;\n        if (strpos($src, 'data:image') !== false) {\n            $tmpDir = Settings::getTempDir() . '/';\n\n            $match = [];\n            preg_match('/data:image\\/(\\w+);base64,(.+)/', $src, $match);\n            if (!empty($match)) {\n                $src = $imgFile = $tmpDir . uniqid() . '.' . $match[1];\n\n                $ifp = fopen($imgFile, 'wb');\n\n                if ($ifp !== false) {\n                    fwrite($ifp, base64_decode($match[2]));\n                    fclose($ifp);\n                }\n            }\n        }\n        $src = urldecode($src);\n\n        if (!is_file($src)\n            && null !== self::$options\n            && isset(self::$options['IMG_SRC_SEARCH'], self::$options['IMG_SRC_REPLACE'])\n        ) {\n            $src = str_replace(self::$options['IMG_SRC_SEARCH'], self::$options['IMG_SRC_REPLACE'], $src);\n        }\n\n        if (!is_file($src)) {\n            if ($imgBlob = @file_get_contents($src)) {\n                $tmpDir = Settings::getTempDir() . '/';\n                $match = [];\n                preg_match('/.+\\.(\\w+)$/', $src, $match);\n                $src = $tmpDir . uniqid();\n                if (isset($match[1])) {\n                    $src .= '.' . $match[1];\n                }\n\n                $ifp = fopen($src, 'wb');\n\n                if ($ifp !== false) {\n                    fwrite($ifp, $imgBlob);\n                    fclose($ifp);\n                }\n            }\n        }\n\n        if (is_file($src)) {\n            $newElement = $element->addImage($src, $style);\n        } else {\n            throw new Exception(\"Could not load image $originSrc\");\n        }\n\n        return $newElement;\n    }\n\n    /**\n     * Transforms a CSS border style into a word border style.\n     *\n     * @param string $cssBorderStyle\n     *\n     * @return null|string\n     */\n    protected static function mapBorderStyle($cssBorderStyle)\n    {\n        switch ($cssBorderStyle) {\n            case 'none':\n            case 'dashed':\n            case 'dotted':\n            case 'double':\n                return $cssBorderStyle;\n            default:\n                return 'single';\n        }\n    }\n\n    protected static function mapBorderColor(&$styles, $cssBorderColor): void\n    {\n        $numColors = substr_count($cssBorderColor, '#');\n        if ($numColors === 1) {\n            $styles['borderColor'] = trim($cssBorderColor, '#');\n        } elseif ($numColors > 1) {\n            $colors = explode(' ', $cssBorderColor);\n            $borders = ['borderTopColor', 'borderRightColor', 'borderBottomColor', 'borderLeftColor'];\n            for ($i = 0; $i < min(4, $numColors, count($colors)); ++$i) {\n                $styles[$borders[$i]] = trim($colors[$i], '#');\n            }\n        }\n    }\n\n    /**\n     * Transforms a HTML/CSS alignment into a \\PhpOffice\\PhpWord\\SimpleType\\Jc.\n     *\n     * @param string $cssAlignment\n     * @param bool $bidi\n     *\n     * @return null|string\n     */\n    protected static function mapAlign($cssAlignment, $bidi)\n    {\n        switch ($cssAlignment) {\n            case 'right':\n                return $bidi ? Jc::START : Jc::END;\n            case 'center':\n                return Jc::CENTER;\n            case 'justify':\n                return Jc::BOTH;\n            default:\n                return $bidi ? Jc::END : Jc::START;\n        }\n    }\n\n    /**\n     * Transforms a HTML/CSS ruby alignment into a \\PhpOffice\\PhpWord\\SimpleType\\Jc.\n     */\n    protected static function mapRubyAlign(string $cssRubyAlignment): string\n    {\n        switch ($cssRubyAlignment) {\n            case 'center':\n                return RubyProperties::ALIGNMENT_CENTER;\n            case 'start':\n                return RubyProperties::ALIGNMENT_LEFT;\n            case 'space-between':\n                return RubyProperties::ALIGNMENT_DISTRIBUTE_SPACE;\n            default:\n                return '';\n        }\n    }\n\n    /**\n     * Transforms a HTML/CSS vertical alignment.\n     *\n     * @param string $alignment\n     *\n     * @return null|string\n     */\n    protected static function mapAlignVertical($alignment)\n    {\n        $alignment = strtolower($alignment);\n        switch ($alignment) {\n            case 'top':\n            case 'baseline':\n            case 'bottom':\n                return $alignment;\n            case 'middle':\n                return 'center';\n            case 'sub':\n                return 'bottom';\n            case 'text-top':\n            case 'baseline':\n                return 'top';\n            default:\n                // @discuss - which one should apply:\n                // - Word uses default vert. alignment: top\n                // - all browsers use default vert. alignment: middle\n                // Returning empty string means attribute wont be set so use Word default (top).\n                return '';\n        }\n    }\n\n    /**\n     * Map list style for ordered list.\n     *\n     * @param string $cssListType\n     */\n    protected static function mapListType($cssListType)\n    {\n        switch ($cssListType) {\n            case 'a':\n                return NumberFormat::LOWER_LETTER; // a, b, c, ..\n            case 'A':\n                return NumberFormat::UPPER_LETTER; // A, B, C, ..\n            case 'i':\n                return NumberFormat::LOWER_ROMAN; // i, ii, iii, iv, ..\n            case 'I':\n                return NumberFormat::UPPER_ROMAN; // I, II, III, IV, ..\n            case '1':\n            default:\n                return NumberFormat::DECIMAL; // 1, 2, 3, ..\n        }\n    }\n\n    /**\n     * Parse line break.\n     *\n     * @param AbstractContainer $element\n     */\n    protected static function parseLineBreak($element): void\n    {\n        $element->addTextBreak();\n    }\n\n    /**\n     * Parse link node.\n     *\n     * @param DOMNode $node\n     * @param AbstractContainer $element\n     * @param array $styles\n     */\n    protected static function parseLink($node, $element, &$styles)\n    {\n        $target = null;\n        foreach ($node->attributes as $attribute) {\n            switch ($attribute->name) {\n                case 'href':\n                    $target = $attribute->value;\n\n                    break;\n            }\n        }\n        $styles['font'] = self::parseInlineStyle($node, $styles['font']);\n\n        if (empty($target)) {\n            $target = '#';\n        }\n\n        if (strpos($target, '#') === 0 && strlen($target) > 1) {\n            return $element->addLink(substr($target, 1), $node->textContent, $styles['font'], $styles['paragraph'], true);\n        }\n\n        return $element->addLink($target, $node->textContent, $styles['font'], $styles['paragraph']);\n    }\n\n    /**\n     * Render horizontal rule\n     * Note: Word rule is not the same as HTML's <hr> since it does not support width and thus neither alignment.\n     *\n     * @param DOMNode $node\n     * @param AbstractContainer $element\n     */\n    protected static function parseHorizRule($node, $element): void\n    {\n        $styles = self::parseInlineStyle($node);\n\n        // <hr> is implemented as an empty paragraph - extending 100% inside the section\n        // Some properties may be controlled, e.g. <hr style=\"border-bottom: 3px #DDDDDD solid; margin-bottom: 0;\">\n\n        $fontStyle = $styles + ['size' => 3];\n\n        $paragraphStyle = $styles + [\n            'lineHeight' => 0.25, // multiply default line height - e.g. 1, 1.5 etc\n            'spacing' => 0, // twip\n            'spaceBefore' => 120, // twip, 240/2 (default line height)\n            'spaceAfter' => 120, // twip\n            'borderBottomSize' => empty($styles['line-height']) ? 1 : $styles['line-height'],\n            'borderBottomColor' => empty($styles['color']) ? '000000' : $styles['color'],\n            'borderBottomStyle' => 'single', // same as \"solid\"\n        ];\n\n        $element->addText('', $fontStyle, $paragraphStyle);\n\n        // Notes: <hr/> cannot be:\n        // - table - throws error \"cannot be inside textruns\", e.g. lists\n        // - line - that is a shape, has different behaviour\n        // - repeated text, e.g. underline \"_\", because of unpredictable line wrapping\n    }\n\n    /**\n     * Parse ruby node.\n     *\n     * @param DOMNode $node\n     * @param AbstractContainer $element\n     * @param array $styles\n     */\n    protected static function parseRuby($node, $element, &$styles)\n    {\n        $rubyProperties = new RubyProperties();\n        $baseTextRun = new TextRun($styles['paragraph']);\n        $rubyTextRun = new TextRun(null);\n        if ($node->hasAttributes()) {\n            $langAttr = $node->attributes->getNamedItem('lang');\n            if ($langAttr !== null) {\n                $rubyProperties->setLanguageId($langAttr->textContent);\n            }\n            $styleAttr = $node->attributes->getNamedItem('style');\n            if ($styleAttr !== null) {\n                $styles = self::parseStyle($styleAttr, $styles['paragraph']);\n                if (isset($styles['rubyAlignment']) && $styles['rubyAlignment'] !== '') {\n                    $rubyProperties->setAlignment($styles['rubyAlignment']);\n                }\n                if (isset($styles['size']) && $styles['size'] !== '') {\n                    $rubyProperties->setFontSizeForBaseText($styles['size']);\n                }\n                $baseTextRun->setParagraphStyle($styles);\n            }\n        }\n        foreach ($node->childNodes as $child) {\n            if ($child->nodeName === '#text') {\n                $content = trim($child->textContent);\n                if ($content !== '') {\n                    $baseTextRun->addText($content);\n                }\n            } elseif ($child->nodeName === 'rt') {\n                $rubyTextRun->addText(trim($child->textContent));\n                if ($child->hasAttributes()) {\n                    $styleAttr = $child->attributes->getNamedItem('style');\n                    if ($styleAttr !== null) {\n                        $styles = self::parseStyle($styleAttr, []);\n                        if (isset($styles['size']) && $styles['size'] !== '') {\n                            $rubyProperties->setFontFaceSize($styles['size']);\n                        }\n                        $rubyTextRun->setParagraphStyle($styles);\n                    }\n                }\n            }\n        }\n\n        return $element->addRuby($baseTextRun, $rubyTextRun, $rubyProperties);\n    }\n\n    private static function convertRgb(string $rgb): string\n    {\n        if (preg_match(self::RGB_REGEXP, $rgb, $matches) === 1) {\n            return sprintf('%02X%02X%02X', $matches[1], $matches[2], $matches[3]);\n        }\n\n        return trim($rgb, '# ');\n    }\n\n    /**\n     * Transform HTML sizes (pt, px) in pixels.\n     */\n    protected static function convertHtmlSize(string $size): float\n    {\n        // pt\n        if (false !== strpos($size, 'pt')) {\n            return Converter::pointToPixel((float) str_replace('pt', '', $size));\n        }\n\n        // px\n        if (false !== strpos($size, 'px')) {\n            return (float) str_replace('px', '', $size);\n        }\n\n        return (float) $size;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Shared/Microsoft/PasswordEncoder.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Shared\\Microsoft;\n\nuse PhpOffice\\PhpWord\\Exception\\Exception;\n\n/**\n * Password encoder for microsoft office applications.\n */\nclass PasswordEncoder\n{\n    const ALGORITHM_MD2 = 'MD2';\n    const ALGORITHM_MD4 = 'MD4';\n    const ALGORITHM_MD5 = 'MD5';\n    const ALGORITHM_SHA_1 = 'SHA-1';\n    const ALGORITHM_SHA_256 = 'SHA-256';\n    const ALGORITHM_SHA_384 = 'SHA-384';\n    const ALGORITHM_SHA_512 = 'SHA-512';\n    const ALGORITHM_RIPEMD = 'RIPEMD';\n    const ALGORITHM_RIPEMD_160 = 'RIPEMD-160';\n    const ALGORITHM_MAC = 'MAC';\n    const ALGORITHM_HMAC = 'HMAC';\n\n    private const ALL_ONE_BITS = (PHP_INT_SIZE > 4) ? 0xFFFFFFFF : -1;\n    private const HIGH_ORDER_BIT = (PHP_INT_SIZE > 4) ? 0x80000000 : PHP_INT_MIN;\n\n    /**\n     * Mapping between algorithm name and algorithm ID.\n     *\n     * @var array\n     *\n     * @see https://msdn.microsoft.com/en-us/library/documentformat.openxml.wordprocessing.writeprotection.cryptographicalgorithmsid(v=office.14).aspx\n     */\n    private static $algorithmMapping = [\n        self::ALGORITHM_MD2 => [1, 'md2'],\n        self::ALGORITHM_MD4 => [2, 'md4'],\n        self::ALGORITHM_MD5 => [3, 'md5'],\n        self::ALGORITHM_SHA_1 => [4, 'sha1'],\n        self::ALGORITHM_MAC => [5, ''], // 'mac' -> not possible with hash()\n        self::ALGORITHM_RIPEMD => [6, 'ripemd'],\n        self::ALGORITHM_RIPEMD_160 => [7, 'ripemd160'],\n        self::ALGORITHM_HMAC => [9, ''], //'hmac' -> not possible with hash()\n        self::ALGORITHM_SHA_256 => [12, 'sha256'],\n        self::ALGORITHM_SHA_384 => [13, 'sha384'],\n        self::ALGORITHM_SHA_512 => [14, 'sha512'],\n    ];\n\n    private static $initialCodeArray = [\n        0xE1F0,\n        0x1D0F,\n        0xCC9C,\n        0x84C0,\n        0x110C,\n        0x0E10,\n        0xF1CE,\n        0x313E,\n        0x1872,\n        0xE139,\n        0xD40F,\n        0x84F9,\n        0x280C,\n        0xA96A,\n        0x4EC3,\n    ];\n\n    private static $encryptionMatrix = [\n        [0xAEFC, 0x4DD9, 0x9BB2, 0x2745, 0x4E8A, 0x9D14, 0x2A09],\n        [0x7B61, 0xF6C2, 0xFDA5, 0xEB6B, 0xC6F7, 0x9DCF, 0x2BBF],\n        [0x4563, 0x8AC6, 0x05AD, 0x0B5A, 0x16B4, 0x2D68, 0x5AD0],\n        [0x0375, 0x06EA, 0x0DD4, 0x1BA8, 0x3750, 0x6EA0, 0xDD40],\n        [0xD849, 0xA0B3, 0x5147, 0xA28E, 0x553D, 0xAA7A, 0x44D5],\n        [0x6F45, 0xDE8A, 0xAD35, 0x4A4B, 0x9496, 0x390D, 0x721A],\n        [0xEB23, 0xC667, 0x9CEF, 0x29FF, 0x53FE, 0xA7FC, 0x5FD9],\n        [0x47D3, 0x8FA6, 0x0F6D, 0x1EDA, 0x3DB4, 0x7B68, 0xF6D0],\n        [0xB861, 0x60E3, 0xC1C6, 0x93AD, 0x377B, 0x6EF6, 0xDDEC],\n        [0x45A0, 0x8B40, 0x06A1, 0x0D42, 0x1A84, 0x3508, 0x6A10],\n        [0xAA51, 0x4483, 0x8906, 0x022D, 0x045A, 0x08B4, 0x1168],\n        [0x76B4, 0xED68, 0xCAF1, 0x85C3, 0x1BA7, 0x374E, 0x6E9C],\n        [0x3730, 0x6E60, 0xDCC0, 0xA9A1, 0x4363, 0x86C6, 0x1DAD],\n        [0x3331, 0x6662, 0xCCC4, 0x89A9, 0x0373, 0x06E6, 0x0DCC],\n        [0x1021, 0x2042, 0x4084, 0x8108, 0x1231, 0x2462, 0x48C4],\n    ];\n\n    private static $passwordMaxLength = 15;\n\n    /**\n     * Create a hashed password that MS Word will be able to work with.\n     *\n     * @see https://blogs.msdn.microsoft.com/vsod/2010/04/05/how-to-set-the-editing-restrictions-in-word-using-open-xml-sdk-2-0/\n     *\n     * @param string $password\n     * @param string $algorithmName\n     * @param string $salt\n     * @param int $spinCount\n     *\n     * @return string\n     */\n    public static function hashPassword($password, $algorithmName = self::ALGORITHM_SHA_1, $salt = null, $spinCount = 10000)\n    {\n        $origEncoding = mb_internal_encoding();\n        mb_internal_encoding('UTF-8');\n\n        $password = mb_substr($password, 0, min(self::$passwordMaxLength, mb_strlen($password)));\n\n        //   Get the single-byte values by iterating through the Unicode characters of the truncated password.\n        //   For each character, if the low byte is not equal to 0, take it. Otherwise, take the high byte.\n        $passUtf8 = mb_convert_encoding($password, 'UCS-2LE', 'UTF-8');\n        if (!is_string($passUtf8)) {\n            throw new Exception('Failed to convert password to UCS-2LE');\n        }\n\n        $byteChars = [];\n        for ($i = 0; $i < mb_strlen($password); ++$i) {\n            $byteChars[$i] = ord(substr($passUtf8, $i * 2, 1));\n\n            if ($byteChars[$i] == 0) {\n                $byteChars[$i] = ord(substr($passUtf8, $i * 2 + 1, 1));\n            }\n        }\n\n        // build low-order word and hig-order word and combine them\n        $combinedKey = self::buildCombinedKey($byteChars);\n        // build reversed hexadecimal string\n        $hex = str_pad(strtoupper(dechex($combinedKey & self::ALL_ONE_BITS)), 8, '0', \\STR_PAD_LEFT);\n        $reversedHex = $hex[6] . $hex[7] . $hex[4] . $hex[5] . $hex[2] . $hex[3] . $hex[0] . $hex[1];\n\n        $generatedKey = mb_convert_encoding($reversedHex, 'UCS-2LE', 'UTF-8');\n\n        // Implementation Notes List:\n        //   Word requires that the initial hash of the password with the salt not be considered in the count.\n        //   The initial hash of salt + key is not included in the iteration count.\n        $algorithm = self::getAlgorithm($algorithmName);\n        $generatedKey = hash($algorithm, $salt . $generatedKey, true);\n\n        for ($i = 0; $i < $spinCount; ++$i) {\n            $generatedKey = hash($algorithm, $generatedKey . pack('CCCC', $i, $i >> 8, $i >> 16, $i >> 24), true);\n        }\n        $generatedKey = base64_encode($generatedKey);\n\n        mb_internal_encoding($origEncoding);\n\n        return $generatedKey;\n    }\n\n    /**\n     * Get algorithm from self::$algorithmMapping.\n     *\n     * @param string $algorithmName\n     *\n     * @return string\n     */\n    private static function getAlgorithm($algorithmName)\n    {\n        $algorithm = self::$algorithmMapping[$algorithmName][1];\n        if ($algorithm == '') {\n            $algorithm = 'sha1';\n        }\n\n        return $algorithm;\n    }\n\n    /**\n     * Returns the algorithm ID.\n     *\n     * @param string $algorithmName\n     *\n     * @return int\n     */\n    public static function getAlgorithmId($algorithmName)\n    {\n        return self::$algorithmMapping[$algorithmName][0];\n    }\n\n    /**\n     * Build combined key from low-order word and high-order word.\n     *\n     * @param array $byteChars byte array representation of password\n     *\n     * @return int\n     */\n    private static function buildCombinedKey($byteChars)\n    {\n        $byteCharsLength = count($byteChars);\n        // Compute the high-order word\n        // Initialize from the initial code array (see above), depending on the passwords length.\n        $highOrderWord = self::$initialCodeArray[$byteCharsLength - 1];\n\n        // For each character in the password:\n        //   For every bit in the character, starting with the least significant and progressing to (but excluding)\n        //   the most significant, if the bit is set, XOR the key’s high-order word with the corresponding word from\n        //   the Encryption Matrix\n        for ($i = 0; $i < $byteCharsLength; ++$i) {\n            $tmp = self::$passwordMaxLength - $byteCharsLength + $i;\n            $matrixRow = self::$encryptionMatrix[$tmp];\n            for ($intBit = 0; $intBit < 7; ++$intBit) {\n                if (($byteChars[$i] & (0x0001 << $intBit)) != 0) {\n                    $highOrderWord = ($highOrderWord ^ $matrixRow[$intBit]);\n                }\n            }\n        }\n\n        // Compute low-order word\n        // Initialize with 0\n        $lowOrderWord = 0;\n        // For each character in the password, going backwards\n        for ($i = $byteCharsLength - 1; $i >= 0; --$i) {\n            // low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR character\n            $lowOrderWord = (((($lowOrderWord >> 14) & 0x0001) | (($lowOrderWord << 1) & 0x7FFF)) ^ $byteChars[$i]);\n        }\n        // Lastly, low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR strPassword length XOR 0xCE4B.\n        $lowOrderWord = (((($lowOrderWord >> 14) & 0x0001) | (($lowOrderWord << 1) & 0x7FFF)) ^ $byteCharsLength ^ 0xCE4B);\n\n        // Combine the Low and High Order Word\n        return self::int32(($highOrderWord << 16) + $lowOrderWord);\n    }\n\n    /**\n     * Simulate behaviour of (signed) int32.\n     *\n     * @codeCoverageIgnore\n     *\n     * @param int $value\n     *\n     * @return int\n     */\n    private static function int32($value)\n    {\n        $value = $value & self::ALL_ONE_BITS;\n\n        if ($value & self::HIGH_ORDER_BIT) {\n            $value = -((~$value & self::ALL_ONE_BITS) + 1);\n        }\n\n        return $value;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Shared/OLERead.php",
    "content": "<?php\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n * @copyright   2010-2018 PHPWord contributors\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Shared;\n\nuse PhpOffice\\PhpWord\\Exception\\Exception;\n\ndefined('IDENTIFIER_OLE') ||\ndefine('IDENTIFIER_OLE', pack('CCCCCCCC', 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1));\n\nclass OLERead\n{\n    private $data = '';\n\n    // OLE identifier\n    const IDENTIFIER_OLE = IDENTIFIER_OLE;\n\n    // Size of a sector = 512 bytes\n    const BIG_BLOCK_SIZE = 0x200;\n\n    // Size of a short sector = 64 bytes\n    const SMALL_BLOCK_SIZE = 0x40;\n\n    // Size of a directory entry always = 128 bytes\n    const PROPERTY_STORAGE_BLOCK_SIZE = 0x80;\n\n    // Minimum size of a standard stream = 4096 bytes, streams smaller than this are stored as short streams\n    const SMALL_BLOCK_THRESHOLD = 0x1000;\n\n    // header offsets\n    const NUM_BIG_BLOCK_DEPOT_BLOCKS_POS = 0x2c;\n    const ROOT_START_BLOCK_POS = 0x30;\n    const SMALL_BLOCK_DEPOT_BLOCK_POS = 0x3c;\n    const EXTENSION_BLOCK_POS = 0x44;\n    const NUM_EXTENSION_BLOCK_POS = 0x48;\n    const BIG_BLOCK_DEPOT_BLOCKS_POS = 0x4c;\n\n    // property storage offsets (directory offsets)\n    const SIZE_OF_NAME_POS = 0x40;\n    const TYPE_POS = 0x42;\n    const START_BLOCK_POS = 0x74;\n    const SIZE_POS = 0x78;\n\n    public $wrkdocument = null;\n    public $wrk1Table = null;\n    public $wrkData = null;\n    public $wrkObjectPool = null;\n    public $summaryInformation = null;\n    public $docSummaryInfos = null;\n    public $numBigBlockDepotBlocks = null;\n    public $rootStartBlock = null;\n    public $sbdStartBlock = null;\n    public $extensionBlock = null;\n    public $numExtensionBlocks = null;\n    public $bigBlockChain = null;\n    public $smallBlockChain = null;\t\n    public $entry = null;\t\n    public $rootentry = null;\n    public $wrkObjectPoolelseif = null;\n    public $props = array();\t\n\n    /**\n     * Read the file\n     *\n     * @param $sFileName string Filename\n     *\n     * @throws Exception\n     */\n    public function read($sFileName)\n    {\n        // Check if file exists and is readable\n        if (!is_readable($sFileName)) {\n            throw new Exception('Could not open ' . $sFileName . ' for reading! File does not exist, or it is not readable.');\n        }\n\n        // Get the file identifier\n        // Don't bother reading the whole file until we know it's a valid OLE file\n        $this->data = file_get_contents($sFileName, false, null, 0, 8);\n\n        // Check OLE identifier\n        if ($this->data != self::IDENTIFIER_OLE) {\n            throw new Exception('The filename ' . $sFileName . ' is not recognised as an OLE file');\n        }\n\n        // Get the file data\n        $this->data = file_get_contents($sFileName);\n\n        // Total number of sectors used for the SAT\n        $this->numBigBlockDepotBlocks = self::getInt4d($this->data, self::NUM_BIG_BLOCK_DEPOT_BLOCKS_POS);\n\n        // SecID of the first sector of the directory stream\n        $this->rootStartBlock = self::getInt4d($this->data, self::ROOT_START_BLOCK_POS);\n\n        // SecID of the first sector of the SSAT (or -2 if not extant)\n        $this->sbdStartBlock = self::getInt4d($this->data, self::SMALL_BLOCK_DEPOT_BLOCK_POS);\n\n        // SecID of the first sector of the MSAT (or -2 if no additional sectors are used)\n        $this->extensionBlock = self::getInt4d($this->data, self::EXTENSION_BLOCK_POS);\n\n        // Total number of sectors used by MSAT\n        $this->numExtensionBlocks = self::getInt4d($this->data, self::NUM_EXTENSION_BLOCK_POS);\n\n        $bigBlockDepotBlocks = array();\n        $pos = self::BIG_BLOCK_DEPOT_BLOCKS_POS;\n\n        $bbdBlocks = $this->numBigBlockDepotBlocks;\n\n        // @codeCoverageIgnoreStart\n        if ($this->numExtensionBlocks != 0) {\n            $bbdBlocks = (self::BIG_BLOCK_SIZE - self::BIG_BLOCK_DEPOT_BLOCKS_POS) / 4;\n        }\n        // @codeCoverageIgnoreEnd\n\n        for ($i = 0; $i < $bbdBlocks; ++$i) {\n            $bigBlockDepotBlocks[$i] = self::getInt4d($this->data, $pos);\n            $pos += 4;\n        }\n\n        // @codeCoverageIgnoreStart\n        for ($j = 0; $j < $this->numExtensionBlocks; ++$j) {\n            $pos = ($this->extensionBlock + 1) * self::BIG_BLOCK_SIZE;\n            $blocksToRead = min($this->numBigBlockDepotBlocks - $bbdBlocks, self::BIG_BLOCK_SIZE / 4 - 1);\n\n            for ($i = $bbdBlocks; $i < $bbdBlocks + $blocksToRead; ++$i) {\n                $bigBlockDepotBlocks[$i] = self::getInt4d($this->data, $pos);\n                $pos += 4;\n            }\n\n            $bbdBlocks += $blocksToRead;\n            if ($bbdBlocks < $this->numBigBlockDepotBlocks) {\n                $this->extensionBlock = self::getInt4d($this->data, $pos);\n            }\n        }\n        // @codeCoverageIgnoreEnd\n\n        $pos = 0;\n        $this->bigBlockChain = '';\n        $bbs = self::BIG_BLOCK_SIZE / 4;\n        for ($i = 0; $i < $this->numBigBlockDepotBlocks; ++$i) {\n            $pos = ($bigBlockDepotBlocks[$i] + 1) * self::BIG_BLOCK_SIZE;\n\n            $this->bigBlockChain .= substr($this->data, $pos, 4 * $bbs);\n            $pos += 4 * $bbs;\n        }\n\n        $pos = 0;\n        $sbdBlock = $this->sbdStartBlock;\n        $this->smallBlockChain = '';\n        while ($sbdBlock != -2) {\n            $pos = ($sbdBlock + 1) * self::BIG_BLOCK_SIZE;\n\n            $this->smallBlockChain .= substr($this->data, $pos, 4 * $bbs);\n            $pos += 4 * $bbs;\n\n            $sbdBlock = self::getInt4d($this->bigBlockChain, $sbdBlock * 4);\n        }\n\n        // read the directory stream\n        $block = $this->rootStartBlock;\n        $this->entry = $this->readData($block);\n\n        $this->readPropertySets();\n    }\n\n    /**\n     * Extract binary stream data\n     *\n     * @param mixed $stream\n     * @return string\n     */\n    public function getStream($stream)\n    {\n        if ($stream === null) {\n            return null;\n        }\n\n        $streamData = '';\n\n        if ($this->props[$stream]['size'] < self::SMALL_BLOCK_THRESHOLD) {\n            $rootdata = $this->readData($this->props[$this->rootentry]['startBlock']);\n\n            $block = $this->props[$stream]['startBlock'];\n\n            while ($block != -2) {\n                $pos = $block * self::SMALL_BLOCK_SIZE;\n                $streamData .= substr($rootdata, $pos, self::SMALL_BLOCK_SIZE);\n\n                $block = self::getInt4d($this->smallBlockChain, $block * 4);\n            }\n\n            return $streamData;\n        }\n\n        $numBlocks = $this->props[$stream]['size'] / self::BIG_BLOCK_SIZE;\n        if ($this->props[$stream]['size'] % self::BIG_BLOCK_SIZE != 0) {\n            ++$numBlocks;\n        }\n\n        if ($numBlocks == 0) {\n            return ''; // @codeCoverageIgnore\n        }\n\n        $block = $this->props[$stream]['startBlock'];\n\n        while ($block != -2) {\n            $pos = ($block + 1) * self::BIG_BLOCK_SIZE;\n            $streamData .= substr($this->data, $pos, self::BIG_BLOCK_SIZE);\n            $block = self::getInt4d($this->bigBlockChain, $block * 4);\n        }\n\n        return $streamData;\n    }\n\n    /**\n     * Read a standard stream (by joining sectors using information from SAT)\n     *\n     * @param int $blSectorId Sector ID where the stream starts\n     * @return string Data for standard stream\n     */\n    private function readData($blSectorId)\n    {\n        $block = $blSectorId;\n        $data = '';\n\n        while ($block != -2) {\n            $pos = ($block + 1) * self::BIG_BLOCK_SIZE;\n            $data .= substr($this->data, $pos, self::BIG_BLOCK_SIZE);\n            $block = self::getInt4d($this->bigBlockChain, $block * 4);\n        }\n\n        return $data;\n    }\n\n    /**\n     * Read entries in the directory stream.\n     */\n    private function readPropertySets()\n    {\n        $offset = 0;\n\n        // loop through entires, each entry is 128 bytes\n        $entryLen = strlen($this->entry);\n        while ($offset < $entryLen) {\n            // entry data (128 bytes)\n            $data = substr($this->entry, $offset, self::PROPERTY_STORAGE_BLOCK_SIZE);\n\n            // size in bytes of name\n            $nameSize = ord($data[self::SIZE_OF_NAME_POS]) | (ord($data[self::SIZE_OF_NAME_POS + 1]) << 8);\n\n            // type of entry\n            $type = ord($data[self::TYPE_POS]);\n\n            // sectorID of first sector or short sector, if this entry refers to a stream (the case with workbook)\n            // sectorID of first sector of the short-stream container stream, if this entry is root entry\n            $startBlock = self::getInt4d($data, self::START_BLOCK_POS);\n\n            $size = self::getInt4d($data, self::SIZE_POS);\n\n            $name = str_replace(\"\\x00\", '', substr($data, 0, $nameSize));\n\n            $this->props[] = array(\n                'name'       => $name,\n                'type'       => $type,\n                'startBlock' => $startBlock,\n                'size'       => $size, );\n\n            // tmp helper to simplify checks\n            $upName = strtoupper($name);\n\n            // Workbook directory entry (BIFF5 uses Book, BIFF8 uses Workbook)\n            // print_r($upName.PHP_EOL);\n            if (($upName === 'WORDDOCUMENT')) {\n                $this->wrkdocument = count($this->props) - 1;\n            } elseif ($upName === '1TABLE') {\n                $this->wrk1Table = count($this->props) - 1;\n            } elseif ($upName === 'DATA') {\n                $this->wrkData = count($this->props) - 1;\n            } elseif ($upName === 'OBJECTPOOL') {\n                $this->wrkObjectPoolelseif = count($this->props) - 1;\n            } elseif ($upName === 'ROOT ENTRY' || $upName === 'R') {\n                $this->rootentry = count($this->props) - 1;\n            }\n\n            // Summary information\n            if ($name == chr(5) . 'SummaryInformation') {\n                $this->summaryInformation = count($this->props) - 1;\n            }\n\n            // Additional Document Summary information\n            if ($name == chr(5) . 'DocumentSummaryInformation') {\n                $this->docSummaryInfos = count($this->props) - 1;\n            }\n\n            $offset += self::PROPERTY_STORAGE_BLOCK_SIZE;\n        }\n    }\n\n    /**\n     * Read 4 bytes of data at specified position\n     *\n     * @param string $data\n     * @param int $pos\n     * @return int\n     */\n    private static function getInt4d($data, $pos)\n    {\n        // FIX: represent numbers correctly on 64-bit system\n        // http://sourceforge.net/tracker/index.php?func=detail&aid=1487372&group_id=99160&atid=623334\n        // Hacked by Andreas Rehm 2006 to ensure correct result of the <<24 block on 32 and 64bit systems\n        $or24 = ord($data[$pos + 3]);\n        if ($or24 >= 128) {\n            // negative number\n            $ord24 = -abs((256 - $or24) << 24);\n        } else {\n            $ord24 = ($or24 & 127) << 24;\n        }\n\n        return ord($data[$pos]) | (ord($data[$pos + 1]) << 8) | (ord($data[$pos + 2]) << 16) | $ord24;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Shared/PCLZip/pclzip.lib.php",
    "content": "<?php\n// --------------------------------------------------------------------------------\n// PhpConcept Library - Zip Module 2.8.2\n// --------------------------------------------------------------------------------\n// License GNU/LGPL - Vincent Blavet - August 2009\n// http://www.phpconcept.net\n// --------------------------------------------------------------------------------\n//\n// Presentation :\n//   PclZip is a PHP library that manage ZIP archives.\n//   So far tests show that archives generated by PclZip are readable by\n//   WinZip application and other tools.\n//\n// Description :\n//   See readme.txt and http://www.phpconcept.net\n//\n// Warning :\n//   This library and the associated files are non commercial, non professional\n//   work.\n//   It should not have unexpected results. However if any damage is caused by\n//   this software the author can not be responsible.\n//   The use of this software is at the risk of the user.\n//\n// --------------------------------------------------------------------------------\n// $Id: pclzip.lib.php,v 1.60 2009/09/30 21:01:04 vblavet Exp $\n// --------------------------------------------------------------------------------\n\n// ----- Constants\nif (!defined('PCLZIP_READ_BLOCK_SIZE')) {\n    define('PCLZIP_READ_BLOCK_SIZE', 2048);\n}\n\n// ----- File list separator\n// In version 1.x of PclZip, the separator for file list is a space\n// (which is not a very smart choice, specifically for windows paths !).\n// A better separator should be a comma (,). This constant gives you the\n// abilty to change that.\n// However notice that changing this value, may have impact on existing\n// scripts, using space separated filenames.\n// Recommanded values for compatibility with older versions :\n//define( 'PCLZIP_SEPARATOR', ' ' );\n// Recommanded values for smart separation of filenames.\nif (!defined('PCLZIP_SEPARATOR')) {\n    define('PCLZIP_SEPARATOR', ',');\n}\n\n// ----- Error configuration\n// 0 : PclZip Class integrated error handling\n// 1 : PclError external library error handling. By enabling this\n//     you must ensure that you have included PclError library.\n// [2,...] : reserved for futur use\nif (!defined('PCLZIP_ERROR_EXTERNAL')) {\n    define('PCLZIP_ERROR_EXTERNAL', 0);\n}\n\n// ----- Optional static temporary directory\n//       By default temporary files are generated in the script current\n//       path.\n//       If defined :\n//       - MUST BE terminated by a '/'.\n//       - MUST be a valid, already created directory\n//       Samples :\n// define( 'PCLZIP_TEMPORARY_DIR', '/temp/' );\n// define( 'PCLZIP_TEMPORARY_DIR', 'C:/Temp/' );\nif (!defined('PCLZIP_TEMPORARY_DIR')) {\n    define('PCLZIP_TEMPORARY_DIR', '');\n}\n\n// ----- Optional threshold ratio for use of temporary files\n//       Pclzip sense the size of the file to add/extract and decide to\n//       use or not temporary file. The algorythm is looking for\n//       memory_limit of PHP and apply a ratio.\n//       threshold = memory_limit * ratio.\n//       Recommended values are under 0.5. Default 0.47.\n//       Samples :\n// define( 'PCLZIP_TEMPORARY_FILE_RATIO', 0.5 );\nif (!defined('PCLZIP_TEMPORARY_FILE_RATIO')) {\n    define('PCLZIP_TEMPORARY_FILE_RATIO', 0.47);\n}\n\n// --------------------------------------------------------------------------------\n// ***** UNDER THIS LINE NOTHING NEEDS TO BE MODIFIED *****\n// --------------------------------------------------------------------------------\n\n// ----- Global variables\n$g_pclzip_version = \"2.8.2\";\n\n// ----- Error codes\n//   -1 : Unable to open file in binary write mode\n//   -2 : Unable to open file in binary read mode\n//   -3 : Invalid parameters\n//   -4 : File does not exist\n//   -5 : Filename is too long (max. 255)\n//   -6 : Not a valid zip file\n//   -7 : Invalid extracted file size\n//   -8 : Unable to create directory\n//   -9 : Invalid archive extension\n//  -10 : Invalid archive format\n//  -11 : Unable to delete file (unlink)\n//  -12 : Unable to rename file (rename)\n//  -13 : Invalid header checksum\n//  -14 : Invalid archive size\ndefine('PCLZIP_ERR_USER_ABORTED', 2);\ndefine('PCLZIP_ERR_NO_ERROR', 0);\ndefine('PCLZIP_ERR_WRITE_OPEN_FAIL', -1);\ndefine('PCLZIP_ERR_READ_OPEN_FAIL', -2);\ndefine('PCLZIP_ERR_INVALID_PARAMETER', -3);\ndefine('PCLZIP_ERR_MISSING_FILE', -4);\ndefine('PCLZIP_ERR_FILENAME_TOO_LONG', -5);\ndefine('PCLZIP_ERR_INVALID_ZIP', -6);\ndefine('PCLZIP_ERR_BAD_EXTRACTED_FILE', -7);\ndefine('PCLZIP_ERR_DIR_CREATE_FAIL', -8);\ndefine('PCLZIP_ERR_BAD_EXTENSION', -9);\ndefine('PCLZIP_ERR_BAD_FORMAT', -10);\ndefine('PCLZIP_ERR_DELETE_FILE_FAIL', -11);\ndefine('PCLZIP_ERR_RENAME_FILE_FAIL', -12);\ndefine('PCLZIP_ERR_BAD_CHECKSUM', -13);\ndefine('PCLZIP_ERR_INVALID_ARCHIVE_ZIP', -14);\ndefine('PCLZIP_ERR_MISSING_OPTION_VALUE', -15);\ndefine('PCLZIP_ERR_INVALID_OPTION_VALUE', -16);\ndefine('PCLZIP_ERR_ALREADY_A_DIRECTORY', -17);\ndefine('PCLZIP_ERR_UNSUPPORTED_COMPRESSION', -18);\ndefine('PCLZIP_ERR_UNSUPPORTED_ENCRYPTION', -19);\ndefine('PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE', -20);\ndefine('PCLZIP_ERR_DIRECTORY_RESTRICTION', -21);\n\n// ----- Options values\ndefine('PCLZIP_OPT_PATH', 77001);\ndefine('PCLZIP_OPT_ADD_PATH', 77002);\ndefine('PCLZIP_OPT_REMOVE_PATH', 77003);\ndefine('PCLZIP_OPT_REMOVE_ALL_PATH', 77004);\ndefine('PCLZIP_OPT_SET_CHMOD', 77005);\ndefine('PCLZIP_OPT_EXTRACT_AS_STRING', 77006);\ndefine('PCLZIP_OPT_NO_COMPRESSION', 77007);\ndefine('PCLZIP_OPT_BY_NAME', 77008);\ndefine('PCLZIP_OPT_BY_INDEX', 77009);\ndefine('PCLZIP_OPT_BY_EREG', 77010);\ndefine('PCLZIP_OPT_BY_PREG', 77011);\ndefine('PCLZIP_OPT_COMMENT', 77012);\ndefine('PCLZIP_OPT_ADD_COMMENT', 77013);\ndefine('PCLZIP_OPT_PREPEND_COMMENT', 77014);\ndefine('PCLZIP_OPT_EXTRACT_IN_OUTPUT', 77015);\ndefine('PCLZIP_OPT_REPLACE_NEWER', 77016);\ndefine('PCLZIP_OPT_STOP_ON_ERROR', 77017);\n// Having big trouble with crypt. Need to multiply 2 long int\n// which is not correctly supported by PHP ...\n//define( 'PCLZIP_OPT_CRYPT', 77018 );\ndefine('PCLZIP_OPT_EXTRACT_DIR_RESTRICTION', 77019);\ndefine('PCLZIP_OPT_TEMP_FILE_THRESHOLD', 77020);\ndefine('PCLZIP_OPT_ADD_TEMP_FILE_THRESHOLD', 77020); // alias\ndefine('PCLZIP_OPT_TEMP_FILE_ON', 77021);\ndefine('PCLZIP_OPT_ADD_TEMP_FILE_ON', 77021); // alias\ndefine('PCLZIP_OPT_TEMP_FILE_OFF', 77022);\ndefine('PCLZIP_OPT_ADD_TEMP_FILE_OFF', 77022); // alias\n\n// ----- File description attributes\ndefine('PCLZIP_ATT_FILE_NAME', 79001);\ndefine('PCLZIP_ATT_FILE_NEW_SHORT_NAME', 79002);\ndefine('PCLZIP_ATT_FILE_NEW_FULL_NAME', 79003);\ndefine('PCLZIP_ATT_FILE_MTIME', 79004);\ndefine('PCLZIP_ATT_FILE_CONTENT', 79005);\ndefine('PCLZIP_ATT_FILE_COMMENT', 79006);\n\n// ----- Call backs values\ndefine('PCLZIP_CB_PRE_EXTRACT', 78001);\ndefine('PCLZIP_CB_POST_EXTRACT', 78002);\ndefine('PCLZIP_CB_PRE_ADD', 78003);\ndefine('PCLZIP_CB_POST_ADD', 78004);\n/* For futur use\ndefine( 'PCLZIP_CB_PRE_LIST', 78005 );\ndefine( 'PCLZIP_CB_POST_LIST', 78006 );\ndefine( 'PCLZIP_CB_PRE_DELETE', 78007 );\ndefine( 'PCLZIP_CB_POST_DELETE', 78008 );\n*/\n\n// --------------------------------------------------------------------------------\n// Class : PclZip\n// Description :\n//   PclZip is the class that represent a Zip archive.\n//   The public methods allow the manipulation of the archive.\n// Attributes :\n//   Attributes must not be accessed directly.\n// Methods :\n//   PclZip() : Object creator\n//   create() : Creates the Zip archive\n//   listContent() : List the content of the Zip archive\n//   extract() : Extract the content of the archive\n//   properties() : List the properties of the archive\n// --------------------------------------------------------------------------------\nclass PclZip\n{\n    // ----- Filename of the zip file\n    public $zipname = '';\n\n    // ----- File descriptor of the zip file\n    public $zip_fd = 0;\n\n    // ----- Internal error handling\n    public $error_code = 1;\n    public $error_string = '';\n\n    // ----- Current status of the magic_quotes_runtime\n    // This value store the php configuration for magic_quotes\n    // The class can then disable the magic_quotes and reset it after\n    public $magic_quotes_status;\n\n    // --------------------------------------------------------------------------------\n    // Function : PclZip()\n    // Description :\n    //   Creates a PclZip object and set the name of the associated Zip archive\n    //   filename.\n    //   Note that no real action is taken, if the archive does not exist it is not\n    //   created. Use create() for that.\n    // --------------------------------------------------------------------------------\n    public function __construct($p_zipname)\n    {\n\n        // ----- Tests the zlib\n        if (!function_exists('gzopen')) {\n            die('Abort ' . basename(__FILE__) . ' : Missing zlib extensions');\n        }\n\n        // ----- Set the attributes\n        $this->zipname             = $p_zipname;\n        $this->zip_fd              = 0;\n        $this->magic_quotes_status = -1;\n\n        // ----- Return\n        return;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function :\n    //   create($p_filelist, $p_add_dir=\"\", $p_remove_dir=\"\")\n    //   create($p_filelist, $p_option, $p_option_value, ...)\n    // Description :\n    //   This method supports two different synopsis. The first one is historical.\n    //   This method creates a Zip Archive. The Zip file is created in the\n    //   filesystem. The files and directories indicated in $p_filelist\n    //   are added in the archive. See the parameters description for the\n    //   supported format of $p_filelist.\n    //   When a directory is in the list, the directory and its content is added\n    //   in the archive.\n    //   In this synopsis, the function takes an optional variable list of\n    //   options. See bellow the supported options.\n    // Parameters :\n    //   $p_filelist : An array containing file or directory names, or\n    //                 a string containing one filename or one directory name, or\n    //                 a string containing a list of filenames and/or directory\n    //                 names separated by spaces.\n    //   $p_add_dir : A path to add before the real path of the archived file,\n    //                in order to have it memorized in the archive.\n    //   $p_remove_dir : A path to remove from the real path of the file to archive,\n    //                   in order to have a shorter path memorized in the archive.\n    //                   When $p_add_dir and $p_remove_dir are set, $p_remove_dir\n    //                   is removed first, before $p_add_dir is added.\n    // Options :\n    //   PCLZIP_OPT_ADD_PATH :\n    //   PCLZIP_OPT_REMOVE_PATH :\n    //   PCLZIP_OPT_REMOVE_ALL_PATH :\n    //   PCLZIP_OPT_COMMENT :\n    //   PCLZIP_CB_PRE_ADD :\n    //   PCLZIP_CB_POST_ADD :\n    // Return Values :\n    //   0 on failure,\n    //   The list of the added files, with a status of the add action.\n    //   (see PclZip::listContent() for list entry format)\n    // --------------------------------------------------------------------------------\n    public function create($p_filelist)\n    {\n        $v_result = 1;\n\n        // ----- Reset the error handler\n        $this->privErrorReset();\n\n        // ----- Set default values\n        $v_options                            = array();\n        $v_options[PCLZIP_OPT_NO_COMPRESSION] = false;\n\n        // ----- Look for variable options arguments\n        $v_size = func_num_args();\n\n        // ----- Look for arguments\n        if ($v_size > 1) {\n            // ----- Get the arguments\n            $v_arg_list = func_get_args();\n\n            // ----- Remove from the options list the first argument\n            array_shift($v_arg_list);\n            $v_size--;\n\n            // ----- Look for first arg\n            if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {\n\n                // ----- Parse the options\n                $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array(\n                    PCLZIP_OPT_REMOVE_PATH => 'optional',\n                    PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',\n                    PCLZIP_OPT_ADD_PATH => 'optional',\n                    PCLZIP_CB_PRE_ADD => 'optional',\n                    PCLZIP_CB_POST_ADD => 'optional',\n                    PCLZIP_OPT_NO_COMPRESSION => 'optional',\n                    PCLZIP_OPT_COMMENT => 'optional',\n                    PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',\n                    PCLZIP_OPT_TEMP_FILE_ON => 'optional',\n                    PCLZIP_OPT_TEMP_FILE_OFF => 'optional'\n                    //, PCLZIP_OPT_CRYPT => 'optional'\n                ));\n                if ($v_result != 1) {\n                    return 0;\n                }\n\n            // ----- Look for 2 args\n            // Here we need to support the first historic synopsis of the\n            // method.\n            } else {\n\n                // ----- Get the first argument\n                $v_options[PCLZIP_OPT_ADD_PATH] = $v_arg_list[0];\n\n                // ----- Look for the optional second argument\n                if ($v_size == 2) {\n                    $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1];\n                } elseif ($v_size > 2) {\n                    PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, \"Invalid number / type of arguments\");\n\n                    return 0;\n                }\n            }\n        }\n\n        // ----- Look for default option values\n        $this->privOptionDefaultThreshold($v_options);\n\n        // ----- Init\n        $v_string_list    = array();\n        $v_att_list       = array();\n        $v_filedescr_list = array();\n        $p_result_list    = array();\n\n        // ----- Look if the $p_filelist is really an array\n        if (is_array($p_filelist)) {\n\n            // ----- Look if the first element is also an array\n            //       This will mean that this is a file description entry\n            if (isset($p_filelist[0]) && is_array($p_filelist[0])) {\n                $v_att_list = $p_filelist;\n\n            // ----- The list is a list of string names\n            } else {\n                $v_string_list = $p_filelist;\n            }\n\n        // ----- Look if the $p_filelist is a string\n        } elseif (is_string($p_filelist)) {\n            // ----- Create a list from the string\n            $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist);\n\n        // ----- Invalid variable type for $p_filelist\n        } else {\n            PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, \"Invalid variable type p_filelist\");\n\n            return 0;\n        }\n\n        // ----- Reformat the string list\n        if (sizeof($v_string_list) != 0) {\n            foreach ($v_string_list as $v_string) {\n                if ($v_string != '') {\n                    $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string;\n                } else {\n                }\n            }\n        }\n\n        // ----- For each file in the list check the attributes\n        $v_supported_attributes = array(\n            PCLZIP_ATT_FILE_NAME => 'mandatory',\n            PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional',\n            PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional',\n            PCLZIP_ATT_FILE_MTIME => 'optional',\n            PCLZIP_ATT_FILE_CONTENT => 'optional',\n            PCLZIP_ATT_FILE_COMMENT => 'optional'\n        );\n        foreach ($v_att_list as $v_entry) {\n            $v_result = $this->privFileDescrParseAtt($v_entry, $v_filedescr_list[], $v_options, $v_supported_attributes);\n            if ($v_result != 1) {\n                return 0;\n            }\n        }\n\n        // ----- Expand the filelist (expand directories)\n        $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options);\n        if ($v_result != 1) {\n            return 0;\n        }\n\n        // ----- Call the create fct\n        $v_result = $this->privCreate($v_filedescr_list, $p_result_list, $v_options);\n        if ($v_result != 1) {\n            return 0;\n        }\n\n        // ----- Return\n        return $p_result_list;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function :\n    //   add($p_filelist, $p_add_dir=\"\", $p_remove_dir=\"\")\n    //   add($p_filelist, $p_option, $p_option_value, ...)\n    // Description :\n    //   This method supports two synopsis. The first one is historical.\n    //   This methods add the list of files in an existing archive.\n    //   If a file with the same name already exists, it is added at the end of the\n    //   archive, the first one is still present.\n    //   If the archive does not exist, it is created.\n    // Parameters :\n    //   $p_filelist : An array containing file or directory names, or\n    //                 a string containing one filename or one directory name, or\n    //                 a string containing a list of filenames and/or directory\n    //                 names separated by spaces.\n    //   $p_add_dir : A path to add before the real path of the archived file,\n    //                in order to have it memorized in the archive.\n    //   $p_remove_dir : A path to remove from the real path of the file to archive,\n    //                   in order to have a shorter path memorized in the archive.\n    //                   When $p_add_dir and $p_remove_dir are set, $p_remove_dir\n    //                   is removed first, before $p_add_dir is added.\n    // Options :\n    //   PCLZIP_OPT_ADD_PATH :\n    //   PCLZIP_OPT_REMOVE_PATH :\n    //   PCLZIP_OPT_REMOVE_ALL_PATH :\n    //   PCLZIP_OPT_COMMENT :\n    //   PCLZIP_OPT_ADD_COMMENT :\n    //   PCLZIP_OPT_PREPEND_COMMENT :\n    //   PCLZIP_CB_PRE_ADD :\n    //   PCLZIP_CB_POST_ADD :\n    // Return Values :\n    //   0 on failure,\n    //   The list of the added files, with a status of the add action.\n    //   (see PclZip::listContent() for list entry format)\n    // --------------------------------------------------------------------------------\n    public function add($p_filelist)\n    {\n        $v_result = 1;\n\n        // ----- Reset the error handler\n        $this->privErrorReset();\n\n        // ----- Set default values\n        $v_options                            = array();\n        $v_options[PCLZIP_OPT_NO_COMPRESSION] = false;\n\n        // ----- Look for variable options arguments\n        $v_size = func_num_args();\n\n        // ----- Look for arguments\n        if ($v_size > 1) {\n            // ----- Get the arguments\n            $v_arg_list = func_get_args();\n\n            // ----- Remove form the options list the first argument\n            array_shift($v_arg_list);\n            $v_size--;\n\n            // ----- Look for first arg\n            if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {\n\n                // ----- Parse the options\n                $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array(\n                    PCLZIP_OPT_REMOVE_PATH => 'optional',\n                    PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',\n                    PCLZIP_OPT_ADD_PATH => 'optional',\n                    PCLZIP_CB_PRE_ADD => 'optional',\n                    PCLZIP_CB_POST_ADD => 'optional',\n                    PCLZIP_OPT_NO_COMPRESSION => 'optional',\n                    PCLZIP_OPT_COMMENT => 'optional',\n                    PCLZIP_OPT_ADD_COMMENT => 'optional',\n                    PCLZIP_OPT_PREPEND_COMMENT => 'optional',\n                    PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',\n                    PCLZIP_OPT_TEMP_FILE_ON => 'optional',\n                    PCLZIP_OPT_TEMP_FILE_OFF => 'optional'\n                    //, PCLZIP_OPT_CRYPT => 'optional'\n                ));\n                if ($v_result != 1) {\n                    return 0;\n                }\n\n            // ----- Look for 2 args\n            // Here we need to support the first historic synopsis of the\n            // method.\n            } else {\n\n                // ----- Get the first argument\n                $v_options[PCLZIP_OPT_ADD_PATH] = $v_add_path = $v_arg_list[0];\n\n                // ----- Look for the optional second argument\n                if ($v_size == 2) {\n                    $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1];\n                } elseif ($v_size > 2) {\n                    // ----- Error log\n                    PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, \"Invalid number / type of arguments\");\n\n                    // ----- Return\n                    return 0;\n                }\n            }\n        }\n\n        // ----- Look for default option values\n        $this->privOptionDefaultThreshold($v_options);\n\n        // ----- Init\n        $v_string_list    = array();\n        $v_att_list       = array();\n        $v_filedescr_list = array();\n        $p_result_list    = array();\n\n        // ----- Look if the $p_filelist is really an array\n        if (is_array($p_filelist)) {\n\n            // ----- Look if the first element is also an array\n            //       This will mean that this is a file description entry\n            if (isset($p_filelist[0]) && is_array($p_filelist[0])) {\n                $v_att_list = $p_filelist;\n\n            // ----- The list is a list of string names\n            } else {\n                $v_string_list = $p_filelist;\n            }\n\n        // ----- Look if the $p_filelist is a string\n        } elseif (is_string($p_filelist)) {\n            // ----- Create a list from the string\n            $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist);\n\n        // ----- Invalid variable type for $p_filelist\n        } else {\n            PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, \"Invalid variable type '\" . gettype($p_filelist) . \"' for p_filelist\");\n\n            return 0;\n        }\n\n        // ----- Reformat the string list\n        if (sizeof($v_string_list) != 0) {\n            foreach ($v_string_list as $v_string) {\n                $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string;\n            }\n        }\n\n        // ----- For each file in the list check the attributes\n        $v_supported_attributes = array(\n            PCLZIP_ATT_FILE_NAME => 'mandatory',\n            PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional',\n            PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional',\n            PCLZIP_ATT_FILE_MTIME => 'optional',\n            PCLZIP_ATT_FILE_CONTENT => 'optional',\n            PCLZIP_ATT_FILE_COMMENT => 'optional'\n        );\n        foreach ($v_att_list as $v_entry) {\n            $v_result = $this->privFileDescrParseAtt($v_entry, $v_filedescr_list[], $v_options, $v_supported_attributes);\n            if ($v_result != 1) {\n                return 0;\n            }\n        }\n\n        // ----- Expand the filelist (expand directories)\n        $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options);\n        if ($v_result != 1) {\n            return 0;\n        }\n\n        // ----- Call the create fct\n        $v_result = $this->privAdd($v_filedescr_list, $p_result_list, $v_options);\n        if ($v_result != 1) {\n            return 0;\n        }\n\n        // ----- Return\n        return $p_result_list;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : listContent()\n    // Description :\n    //   This public method, gives the list of the files and directories, with their\n    //   properties.\n    //   The properties of each entries in the list are (used also in other functions) :\n    //     filename : Name of the file. For a create or add action it is the filename\n    //                given by the user. For an extract function it is the filename\n    //                of the extracted file.\n    //     stored_filename : Name of the file / directory stored in the archive.\n    //     size : Size of the stored file.\n    //     compressed_size : Size of the file's data compressed in the archive\n    //                       (without the headers overhead)\n    //     mtime : Last known modification date of the file (UNIX timestamp)\n    //     comment : Comment associated with the file\n    //     folder : true | false\n    //     index : index of the file in the archive\n    //     status : status of the action (depending of the action) :\n    //              Values are :\n    //                ok : OK !\n    //                filtered : the file / dir is not extracted (filtered by user)\n    //                already_a_directory : the file can not be extracted because a\n    //                                      directory with the same name already exists\n    //                write_protected : the file can not be extracted because a file\n    //                                  with the same name already exists and is\n    //                                  write protected\n    //                newer_exist : the file was not extracted because a newer file exists\n    //                path_creation_fail : the file is not extracted because the folder\n    //                                     does not exist and can not be created\n    //                write_error : the file was not extracted because there was a\n    //                              error while writing the file\n    //                read_error : the file was not extracted because there was a error\n    //                             while reading the file\n    //                invalid_header : the file was not extracted because of an archive\n    //                                 format error (bad file header)\n    //   Note that each time a method can continue operating when there\n    //   is an action error on a file, the error is only logged in the file status.\n    // Return Values :\n    //   0 on an unrecoverable failure,\n    //   The list of the files in the archive.\n    // --------------------------------------------------------------------------------\n    public function listContent()\n    {\n        $v_result = 1;\n\n        // ----- Reset the error handler\n        $this->privErrorReset();\n\n        // ----- Check archive\n        if (!$this->privCheckFormat()) {\n            return (0);\n        }\n\n        // ----- Call the extracting fct\n        $p_list = array();\n        if (($v_result = $this->privList($p_list)) != 1) {\n            unset($p_list);\n\n            return (0);\n        }\n\n        // ----- Return\n        return $p_list;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function :\n    //   extract($p_path=\"./\", $p_remove_path=\"\")\n    //   extract([$p_option, $p_option_value, ...])\n    // Description :\n    //   This method supports two synopsis. The first one is historical.\n    //   This method extract all the files / directories from the archive to the\n    //   folder indicated in $p_path.\n    //   If you want to ignore the 'root' part of path of the memorized files\n    //   you can indicate this in the optional $p_remove_path parameter.\n    //   By default, if a newer file with the same name already exists, the\n    //   file is not extracted.\n    //\n    //   If both PCLZIP_OPT_PATH and PCLZIP_OPT_ADD_PATH aoptions\n    //   are used, the path indicated in PCLZIP_OPT_ADD_PATH is append\n    //   at the end of the path value of PCLZIP_OPT_PATH.\n    // Parameters :\n    //   $p_path : Path where the files and directories are to be extracted\n    //   $p_remove_path : First part ('root' part) of the memorized path\n    //                    (if any similar) to remove while extracting.\n    // Options :\n    //   PCLZIP_OPT_PATH :\n    //   PCLZIP_OPT_ADD_PATH :\n    //   PCLZIP_OPT_REMOVE_PATH :\n    //   PCLZIP_OPT_REMOVE_ALL_PATH :\n    //   PCLZIP_CB_PRE_EXTRACT :\n    //   PCLZIP_CB_POST_EXTRACT :\n    // Return Values :\n    //   0 or a negative value on failure,\n    //   The list of the extracted files, with a status of the action.\n    //   (see PclZip::listContent() for list entry format)\n    // --------------------------------------------------------------------------------\n    public function extract()\n    {\n        $v_result = 1;\n\n        // ----- Reset the error handler\n        $this->privErrorReset();\n\n        // ----- Check archive\n        if (!$this->privCheckFormat()) {\n            return (0);\n        }\n\n        // ----- Set default values\n        $v_options         = array();\n        //    $v_path = \"./\";\n        $v_path            = '';\n        $v_remove_path     = \"\";\n        $v_remove_all_path = false;\n\n        // ----- Look for variable options arguments\n        $v_size = func_num_args();\n\n        // ----- Default values for option\n        $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = false;\n\n        // ----- Look for arguments\n        if ($v_size > 0) {\n            // ----- Get the arguments\n            $v_arg_list = func_get_args();\n\n            // ----- Look for first arg\n            if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {\n\n                // ----- Parse the options\n                $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array(\n                    PCLZIP_OPT_PATH => 'optional',\n                    PCLZIP_OPT_REMOVE_PATH => 'optional',\n                    PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',\n                    PCLZIP_OPT_ADD_PATH => 'optional',\n                    PCLZIP_CB_PRE_EXTRACT => 'optional',\n                    PCLZIP_CB_POST_EXTRACT => 'optional',\n                    PCLZIP_OPT_SET_CHMOD => 'optional',\n                    PCLZIP_OPT_BY_NAME => 'optional',\n                    PCLZIP_OPT_BY_EREG => 'optional',\n                    PCLZIP_OPT_BY_PREG => 'optional',\n                    PCLZIP_OPT_BY_INDEX => 'optional',\n                    PCLZIP_OPT_EXTRACT_AS_STRING => 'optional',\n                    PCLZIP_OPT_EXTRACT_IN_OUTPUT => 'optional',\n                    PCLZIP_OPT_REPLACE_NEWER => 'optional',\n                    PCLZIP_OPT_STOP_ON_ERROR => 'optional',\n                    PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional',\n                    PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',\n                    PCLZIP_OPT_TEMP_FILE_ON => 'optional',\n                    PCLZIP_OPT_TEMP_FILE_OFF => 'optional'\n                ));\n                if ($v_result != 1) {\n                    return 0;\n                }\n\n                // ----- Set the arguments\n                if (isset($v_options[PCLZIP_OPT_PATH])) {\n                    $v_path = $v_options[PCLZIP_OPT_PATH];\n                }\n                if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) {\n                    $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH];\n                }\n                if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {\n                    $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH];\n                }\n                if (isset($v_options[PCLZIP_OPT_ADD_PATH])) {\n                    // ----- Check for '/' in last path char\n                    if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) {\n                        $v_path .= '/';\n                    }\n                    $v_path .= $v_options[PCLZIP_OPT_ADD_PATH];\n                }\n\n            // ----- Look for 2 args\n            // Here we need to support the first historic synopsis of the\n            // method.\n            } else {\n\n                // ----- Get the first argument\n                $v_path = $v_arg_list[0];\n\n                // ----- Look for the optional second argument\n                if ($v_size == 2) {\n                    $v_remove_path = $v_arg_list[1];\n                } elseif ($v_size > 2) {\n                    // ----- Error log\n                    PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, \"Invalid number / type of arguments\");\n\n                    // ----- Return\n                    return 0;\n                }\n            }\n        }\n\n        // ----- Look for default option values\n        $this->privOptionDefaultThreshold($v_options);\n\n        // ----- Trace\n\n        // ----- Call the extracting fct\n        $p_list   = array();\n        $v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options);\n        if ($v_result < 1) {\n            unset($p_list);\n\n            return (0);\n        }\n\n        // ----- Return\n        return $p_list;\n    }\n    // --------------------------------------------------------------------------------\n\n\n    // --------------------------------------------------------------------------------\n    // Function :\n    //   extractByIndex($p_index, $p_path=\"./\", $p_remove_path=\"\")\n    //   extractByIndex($p_index, [$p_option, $p_option_value, ...])\n    // Description :\n    //   This method supports two synopsis. The first one is historical.\n    //   This method is doing a partial extract of the archive.\n    //   The extracted files or folders are identified by their index in the\n    //   archive (from 0 to n).\n    //   Note that if the index identify a folder, only the folder entry is\n    //   extracted, not all the files included in the archive.\n    // Parameters :\n    //   $p_index : A single index (integer) or a string of indexes of files to\n    //              extract. The form of the string is \"0,4-6,8-12\" with only numbers\n    //              and '-' for range or ',' to separate ranges. No spaces or ';'\n    //              are allowed.\n    //   $p_path : Path where the files and directories are to be extracted\n    //   $p_remove_path : First part ('root' part) of the memorized path\n    //                    (if any similar) to remove while extracting.\n    // Options :\n    //   PCLZIP_OPT_PATH :\n    //   PCLZIP_OPT_ADD_PATH :\n    //   PCLZIP_OPT_REMOVE_PATH :\n    //   PCLZIP_OPT_REMOVE_ALL_PATH :\n    //   PCLZIP_OPT_EXTRACT_AS_STRING : The files are extracted as strings and\n    //     not as files.\n    //     The resulting content is in a new field 'content' in the file\n    //     structure.\n    //     This option must be used alone (any other options are ignored).\n    //   PCLZIP_CB_PRE_EXTRACT :\n    //   PCLZIP_CB_POST_EXTRACT :\n    // Return Values :\n    //   0 on failure,\n    //   The list of the extracted files, with a status of the action.\n    //   (see PclZip::listContent() for list entry format)\n    // --------------------------------------------------------------------------------\n    //function extractByIndex($p_index, options...)\n    public function extractByIndex($p_index)\n    {\n        $v_result = 1;\n\n        // ----- Reset the error handler\n        $this->privErrorReset();\n\n        // ----- Check archive\n        if (!$this->privCheckFormat()) {\n            return (0);\n        }\n\n        // ----- Set default values\n        $v_options         = array();\n        //    $v_path = \"./\";\n        $v_path            = '';\n        $v_remove_path     = \"\";\n        $v_remove_all_path = false;\n\n        // ----- Look for variable options arguments\n        $v_size = func_num_args();\n\n        // ----- Default values for option\n        $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = false;\n\n        // ----- Look for arguments\n        if ($v_size > 1) {\n            // ----- Get the arguments\n            $v_arg_list = func_get_args();\n\n            // ----- Remove form the options list the first argument\n            array_shift($v_arg_list);\n            $v_size--;\n\n            // ----- Look for first arg\n            if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {\n\n                // ----- Parse the options\n                $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array(\n                    PCLZIP_OPT_PATH => 'optional',\n                    PCLZIP_OPT_REMOVE_PATH => 'optional',\n                    PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',\n                    PCLZIP_OPT_EXTRACT_AS_STRING => 'optional',\n                    PCLZIP_OPT_ADD_PATH => 'optional',\n                    PCLZIP_CB_PRE_EXTRACT => 'optional',\n                    PCLZIP_CB_POST_EXTRACT => 'optional',\n                    PCLZIP_OPT_SET_CHMOD => 'optional',\n                    PCLZIP_OPT_REPLACE_NEWER => 'optional',\n                    PCLZIP_OPT_STOP_ON_ERROR => 'optional',\n                    PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional',\n                    PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',\n                    PCLZIP_OPT_TEMP_FILE_ON => 'optional',\n                    PCLZIP_OPT_TEMP_FILE_OFF => 'optional'\n                ));\n                if ($v_result != 1) {\n                    return 0;\n                }\n\n                // ----- Set the arguments\n                if (isset($v_options[PCLZIP_OPT_PATH])) {\n                    $v_path = $v_options[PCLZIP_OPT_PATH];\n                }\n                if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) {\n                    $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH];\n                }\n                if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {\n                    $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH];\n                }\n                if (isset($v_options[PCLZIP_OPT_ADD_PATH])) {\n                    // ----- Check for '/' in last path char\n                    if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) {\n                        $v_path .= '/';\n                    }\n                    $v_path .= $v_options[PCLZIP_OPT_ADD_PATH];\n                }\n                if (!isset($v_options[PCLZIP_OPT_EXTRACT_AS_STRING])) {\n                    $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = false;\n                } else {\n                }\n\n            // ----- Look for 2 args\n            // Here we need to support the first historic synopsis of the\n            // method.\n            } else {\n\n                // ----- Get the first argument\n                $v_path = $v_arg_list[0];\n\n                // ----- Look for the optional second argument\n                if ($v_size == 2) {\n                    $v_remove_path = $v_arg_list[1];\n                } elseif ($v_size > 2) {\n                    // ----- Error log\n                    PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, \"Invalid number / type of arguments\");\n\n                    // ----- Return\n                    return 0;\n                }\n            }\n        }\n\n        // ----- Trace\n\n        // ----- Trick\n        // Here I want to reuse extractByRule(), so I need to parse the $p_index\n        // with privParseOptions()\n        $v_arg_trick     = array(\n            PCLZIP_OPT_BY_INDEX,\n            $p_index\n        );\n        $v_options_trick = array();\n        $v_result        = $this->privParseOptions($v_arg_trick, sizeof($v_arg_trick), $v_options_trick, array(\n            PCLZIP_OPT_BY_INDEX => 'optional'\n        ));\n        if ($v_result != 1) {\n            return 0;\n        }\n        $v_options[PCLZIP_OPT_BY_INDEX] = $v_options_trick[PCLZIP_OPT_BY_INDEX];\n\n        // ----- Look for default option values\n        $this->privOptionDefaultThreshold($v_options);\n\n        // ----- Call the extracting fct\n        if (($v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options)) < 1) {\n            return (0);\n        }\n\n        // ----- Return\n        return $p_list;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function :\n    //   delete([$p_option, $p_option_value, ...])\n    // Description :\n    //   This method removes files from the archive.\n    //   If no parameters are given, then all the archive is emptied.\n    // Parameters :\n    //   None or optional arguments.\n    // Options :\n    //   PCLZIP_OPT_BY_INDEX :\n    //   PCLZIP_OPT_BY_NAME :\n    //   PCLZIP_OPT_BY_EREG :\n    //   PCLZIP_OPT_BY_PREG :\n    // Return Values :\n    //   0 on failure,\n    //   The list of the files which are still present in the archive.\n    //   (see PclZip::listContent() for list entry format)\n    // --------------------------------------------------------------------------------\n    public function delete()\n    {\n        $v_result = 1;\n\n        // ----- Reset the error handler\n        $this->privErrorReset();\n\n        // ----- Check archive\n        if (!$this->privCheckFormat()) {\n            return (0);\n        }\n\n        // ----- Set default values\n        $v_options = array();\n\n        // ----- Look for variable options arguments\n        $v_size = func_num_args();\n\n        // ----- Look for arguments\n        if ($v_size > 0) {\n            // ----- Get the arguments\n            $v_arg_list = func_get_args();\n\n            // ----- Parse the options\n            $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array(\n                PCLZIP_OPT_BY_NAME => 'optional',\n                PCLZIP_OPT_BY_EREG => 'optional',\n                PCLZIP_OPT_BY_PREG => 'optional',\n                PCLZIP_OPT_BY_INDEX => 'optional'\n            ));\n            if ($v_result != 1) {\n                return 0;\n            }\n        }\n\n        // ----- Magic quotes trick\n        $this->privDisableMagicQuotes();\n\n        // ----- Call the delete fct\n        $v_list = array();\n        if (($v_result = $this->privDeleteByRule($v_list, $v_options)) != 1) {\n            $this->privSwapBackMagicQuotes();\n            unset($v_list);\n\n            return (0);\n        }\n\n        // ----- Magic quotes trick\n        $this->privSwapBackMagicQuotes();\n\n        // ----- Return\n        return $v_list;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : deleteByIndex()\n    // Description :\n    //   ***** Deprecated *****\n    //   delete(PCLZIP_OPT_BY_INDEX, $p_index) should be prefered.\n    // --------------------------------------------------------------------------------\n    public function deleteByIndex($p_index)\n    {\n\n        $p_list = $this->delete(PCLZIP_OPT_BY_INDEX, $p_index);\n\n        // ----- Return\n        return $p_list;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : properties()\n    // Description :\n    //   This method gives the properties of the archive.\n    //   The properties are :\n    //     nb : Number of files in the archive\n    //     comment : Comment associated with the archive file\n    //     status : not_exist, ok\n    // Parameters :\n    //   None\n    // Return Values :\n    //   0 on failure,\n    //   An array with the archive properties.\n    // --------------------------------------------------------------------------------\n    public function properties()\n    {\n\n        // ----- Reset the error handler\n        $this->privErrorReset();\n\n        // ----- Magic quotes trick\n        $this->privDisableMagicQuotes();\n\n        // ----- Check archive\n        if (!$this->privCheckFormat()) {\n            $this->privSwapBackMagicQuotes();\n\n            return (0);\n        }\n\n        // ----- Default properties\n        $v_prop            = array();\n        $v_prop['comment'] = '';\n        $v_prop['nb']      = 0;\n        $v_prop['status']  = 'not_exist';\n\n        // ----- Look if file exists\n        if (@is_file($this->zipname)) {\n            // ----- Open the zip file\n            if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) {\n                $this->privSwapBackMagicQuotes();\n\n                // ----- Error log\n                PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \\'' . $this->zipname . '\\' in binary read mode');\n\n                // ----- Return\n                return 0;\n            }\n\n            // ----- Read the central directory informations\n            $v_central_dir = array();\n            if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) {\n                $this->privSwapBackMagicQuotes();\n\n                return 0;\n            }\n\n            // ----- Close the zip file\n            $this->privCloseFd();\n\n            // ----- Set the user attributes\n            $v_prop['comment'] = $v_central_dir['comment'];\n            $v_prop['nb']      = $v_central_dir['entries'];\n            $v_prop['status']  = 'ok';\n        }\n\n        // ----- Magic quotes trick\n        $this->privSwapBackMagicQuotes();\n\n        // ----- Return\n        return $v_prop;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : duplicate()\n    // Description :\n    //   This method creates an archive by copying the content of an other one. If\n    //   the archive already exist, it is replaced by the new one without any warning.\n    // Parameters :\n    //   $p_archive : The filename of a valid archive, or\n    //                a valid PclZip object.\n    // Return Values :\n    //   1 on success.\n    //   0 or a negative value on error (error code).\n    // --------------------------------------------------------------------------------\n    public function duplicate($p_archive)\n    {\n        $v_result = 1;\n\n        // ----- Reset the error handler\n        $this->privErrorReset();\n\n        // ----- Look if the $p_archive is a PclZip object\n        if ((is_object($p_archive)) && (get_class($p_archive) == 'pclzip')) {\n\n            // ----- Duplicate the archive\n            $v_result = $this->privDuplicate($p_archive->zipname);\n\n        // ----- Look if the $p_archive is a string (so a filename)\n        } elseif (is_string($p_archive)) {\n\n            // ----- Check that $p_archive is a valid zip file\n            // TBC : Should also check the archive format\n            if (!is_file($p_archive)) {\n                // ----- Error log\n                PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, \"No file with filename '\" . $p_archive . \"'\");\n                $v_result = PCLZIP_ERR_MISSING_FILE;\n            } else {\n                // ----- Duplicate the archive\n                $v_result = $this->privDuplicate($p_archive);\n            }\n\n        // ----- Invalid variable\n        } else {\n            // ----- Error log\n            PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, \"Invalid variable type p_archive_to_add\");\n            $v_result = PCLZIP_ERR_INVALID_PARAMETER;\n        }\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : merge()\n    // Description :\n    //   This method merge the $p_archive_to_add archive at the end of the current\n    //   one ($this).\n    //   If the archive ($this) does not exist, the merge becomes a duplicate.\n    //   If the $p_archive_to_add archive does not exist, the merge is a success.\n    // Parameters :\n    //   $p_archive_to_add : It can be directly the filename of a valid zip archive,\n    //                       or a PclZip object archive.\n    // Return Values :\n    //   1 on success,\n    //   0 or negative values on error (see below).\n    // --------------------------------------------------------------------------------\n    public function merge($p_archive_to_add)\n    {\n        $v_result = 1;\n\n        // ----- Reset the error handler\n        $this->privErrorReset();\n\n        // ----- Check archive\n        if (!$this->privCheckFormat()) {\n            return (0);\n        }\n\n        // ----- Look if the $p_archive_to_add is a PclZip object\n        if ((is_object($p_archive_to_add)) && (get_class($p_archive_to_add) == 'pclzip')) {\n\n            // ----- Merge the archive\n            $v_result = $this->privMerge($p_archive_to_add);\n\n        // ----- Look if the $p_archive_to_add is a string (so a filename)\n        } elseif (is_string($p_archive_to_add)) {\n\n            // ----- Create a temporary archive\n            $v_object_archive = new PclZip($p_archive_to_add);\n\n            // ----- Merge the archive\n            $v_result = $this->privMerge($v_object_archive);\n\n        // ----- Invalid variable\n        } else {\n            // ----- Error log\n            PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, \"Invalid variable type p_archive_to_add\");\n            $v_result = PCLZIP_ERR_INVALID_PARAMETER;\n        }\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : errorCode()\n    // Description :\n    // Parameters :\n    // --------------------------------------------------------------------------------\n    public function errorCode()\n    {\n        if (PCLZIP_ERROR_EXTERNAL == 1) {\n            return (PclErrorCode());\n        }\n\n        return ($this->error_code);\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : errorName()\n    // Description :\n    // Parameters :\n    // --------------------------------------------------------------------------------\n    public function errorName($p_with_code = false)\n    {\n        $v_name = array(\n            PCLZIP_ERR_NO_ERROR => 'PCLZIP_ERR_NO_ERROR',\n            PCLZIP_ERR_WRITE_OPEN_FAIL => 'PCLZIP_ERR_WRITE_OPEN_FAIL',\n            PCLZIP_ERR_READ_OPEN_FAIL => 'PCLZIP_ERR_READ_OPEN_FAIL',\n            PCLZIP_ERR_INVALID_PARAMETER => 'PCLZIP_ERR_INVALID_PARAMETER',\n            PCLZIP_ERR_MISSING_FILE => 'PCLZIP_ERR_MISSING_FILE',\n            PCLZIP_ERR_FILENAME_TOO_LONG => 'PCLZIP_ERR_FILENAME_TOO_LONG',\n            PCLZIP_ERR_INVALID_ZIP => 'PCLZIP_ERR_INVALID_ZIP',\n            PCLZIP_ERR_BAD_EXTRACTED_FILE => 'PCLZIP_ERR_BAD_EXTRACTED_FILE',\n            PCLZIP_ERR_DIR_CREATE_FAIL => 'PCLZIP_ERR_DIR_CREATE_FAIL',\n            PCLZIP_ERR_BAD_EXTENSION => 'PCLZIP_ERR_BAD_EXTENSION',\n            PCLZIP_ERR_BAD_FORMAT => 'PCLZIP_ERR_BAD_FORMAT',\n            PCLZIP_ERR_DELETE_FILE_FAIL => 'PCLZIP_ERR_DELETE_FILE_FAIL',\n            PCLZIP_ERR_RENAME_FILE_FAIL => 'PCLZIP_ERR_RENAME_FILE_FAIL',\n            PCLZIP_ERR_BAD_CHECKSUM => 'PCLZIP_ERR_BAD_CHECKSUM',\n            PCLZIP_ERR_INVALID_ARCHIVE_ZIP => 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP',\n            PCLZIP_ERR_MISSING_OPTION_VALUE => 'PCLZIP_ERR_MISSING_OPTION_VALUE',\n            PCLZIP_ERR_INVALID_OPTION_VALUE => 'PCLZIP_ERR_INVALID_OPTION_VALUE',\n            PCLZIP_ERR_UNSUPPORTED_COMPRESSION => 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION',\n            PCLZIP_ERR_UNSUPPORTED_ENCRYPTION => 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION',\n            PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE => 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE',\n            PCLZIP_ERR_DIRECTORY_RESTRICTION => 'PCLZIP_ERR_DIRECTORY_RESTRICTION'\n        );\n\n        if (isset($v_name[$this->error_code])) {\n            $v_value = $v_name[$this->error_code];\n        } else {\n            $v_value = 'NoName';\n        }\n\n        if ($p_with_code) {\n            return ($v_value . ' (' . $this->error_code . ')');\n        }\n\n        return ($v_value);\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : errorInfo()\n    // Description :\n    // Parameters :\n    // --------------------------------------------------------------------------------\n    public function errorInfo($p_full = false)\n    {\n        if (PCLZIP_ERROR_EXTERNAL == 1) {\n            return (PclErrorString());\n        }\n\n        if ($p_full) {\n            return ($this->errorName(true) . \" : \" . $this->error_string);\n        }\n\n        return ($this->error_string . \" [code \" . $this->error_code . \"]\");\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS *****\n    // *****                                                        *****\n    // *****       THESES FUNCTIONS MUST NOT BE USED DIRECTLY       *****\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privCheckFormat()\n    // Description :\n    //   This method check that the archive exists and is a valid zip archive.\n    //   Several level of check exists. (futur)\n    // Parameters :\n    //   $p_level : Level of check. Default 0.\n    //              0 : Check the first bytes (magic codes) (default value))\n    //              1 : 0 + Check the central directory (futur)\n    //              2 : 1 + Check each file header (futur)\n    // Return Values :\n    //   true on success,\n    //   false on error, the error code is set.\n    // --------------------------------------------------------------------------------\n    public function privCheckFormat($p_level = 0)\n    {\n        $v_result = true;\n\n        // ----- Reset the file system cache\n        clearstatcache();\n\n        // ----- Reset the error handler\n        $this->privErrorReset();\n\n        // ----- Look if the file exits\n        if (!is_file($this->zipname)) {\n            // ----- Error log\n            PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, \"Missing archive file '\" . $this->zipname . \"'\");\n\n            return (false);\n        }\n\n        // ----- Check that the file is readeable\n        if (!is_readable($this->zipname)) {\n            // ----- Error log\n            PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, \"Unable to read archive '\" . $this->zipname . \"'\");\n\n            return (false);\n        }\n\n        // ----- Check the magic code\n        // TBC\n\n        // ----- Check the central header\n        // TBC\n\n        // ----- Check each file header\n        // TBC\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privParseOptions()\n    // Description :\n    //   This internal methods reads the variable list of arguments ($p_options_list,\n    //   $p_size) and generate an array with the options and values ($v_result_list).\n    //   $v_requested_options contains the options that can be present and those that\n    //   must be present.\n    //   $v_requested_options is an array, with the option value as key, and 'optional',\n    //   or 'mandatory' as value.\n    // Parameters :\n    //   See above.\n    // Return Values :\n    //   1 on success.\n    //   0 on failure.\n    // --------------------------------------------------------------------------------\n    public function privParseOptions(&$p_options_list, $p_size, &$v_result_list, $v_requested_options = false)\n    {\n        $v_result = 1;\n\n        // ----- Read the options\n        $i = 0;\n        while ($i < $p_size) {\n\n            // ----- Check if the option is supported\n            if (!isset($v_requested_options[$p_options_list[$i]])) {\n                // ----- Error log\n                PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, \"Invalid optional parameter '\" . $p_options_list[$i] . \"' for this method\");\n\n                // ----- Return\n                return PclZip::errorCode();\n            }\n\n            // ----- Look for next option\n            switch ($p_options_list[$i]) {\n                // ----- Look for options that request a path value\n                case PCLZIP_OPT_PATH:\n                case PCLZIP_OPT_REMOVE_PATH:\n                case PCLZIP_OPT_ADD_PATH:\n                    // ----- Check the number of parameters\n                    if (($i + 1) >= $p_size) {\n                        // ----- Error log\n                        PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, \"Missing parameter value for option '\" . PclZipUtilOptionText($p_options_list[$i]) . \"'\");\n\n                        // ----- Return\n                        return PclZip::errorCode();\n                    }\n\n                    // ----- Get the value\n                    $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i + 1], false);\n                    $i++;\n                    break;\n\n                case PCLZIP_OPT_TEMP_FILE_THRESHOLD:\n                    // ----- Check the number of parameters\n                    if (($i + 1) >= $p_size) {\n                        PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, \"Missing parameter value for option '\" . PclZipUtilOptionText($p_options_list[$i]) . \"'\");\n\n                        return PclZip::errorCode();\n                    }\n\n                    // ----- Check for incompatible options\n                    if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) {\n                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, \"Option '\" . PclZipUtilOptionText($p_options_list[$i]) . \"' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'\");\n\n                        return PclZip::errorCode();\n                    }\n\n                    // ----- Check the value\n                    $v_value = $p_options_list[$i + 1];\n                    if ((!is_integer($v_value)) || ($v_value < 0)) {\n                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, \"Integer expected for option '\" . PclZipUtilOptionText($p_options_list[$i]) . \"'\");\n\n                        return PclZip::errorCode();\n                    }\n\n                    // ----- Get the value (and convert it in bytes)\n                    $v_result_list[$p_options_list[$i]] = $v_value * 1048576;\n                    $i++;\n                    break;\n\n                case PCLZIP_OPT_TEMP_FILE_ON:\n                    // ----- Check for incompatible options\n                    if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) {\n                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, \"Option '\" . PclZipUtilOptionText($p_options_list[$i]) . \"' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'\");\n\n                        return PclZip::errorCode();\n                    }\n\n                    $v_result_list[$p_options_list[$i]] = true;\n                    break;\n\n                case PCLZIP_OPT_TEMP_FILE_OFF:\n                    // ----- Check for incompatible options\n                    if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_ON])) {\n                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, \"Option '\" . PclZipUtilOptionText($p_options_list[$i]) . \"' can not be used with option 'PCLZIP_OPT_TEMP_FILE_ON'\");\n\n                        return PclZip::errorCode();\n                    }\n                    // ----- Check for incompatible options\n                    if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) {\n                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, \"Option '\" . PclZipUtilOptionText($p_options_list[$i]) . \"' can not be used with option 'PCLZIP_OPT_TEMP_FILE_THRESHOLD'\");\n\n                        return PclZip::errorCode();\n                    }\n\n                    $v_result_list[$p_options_list[$i]] = true;\n                    break;\n\n                case PCLZIP_OPT_EXTRACT_DIR_RESTRICTION:\n                    // ----- Check the number of parameters\n                    if (($i + 1) >= $p_size) {\n                        // ----- Error log\n                        PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, \"Missing parameter value for option '\" . PclZipUtilOptionText($p_options_list[$i]) . \"'\");\n\n                        // ----- Return\n                        return PclZip::errorCode();\n                    }\n\n                    // ----- Get the value\n                    if (is_string($p_options_list[$i + 1]) && ($p_options_list[$i + 1] != '')) {\n                        $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i + 1], false);\n                        $i++;\n                    } else {\n                    }\n                    break;\n\n                // ----- Look for options that request an array of string for value\n                case PCLZIP_OPT_BY_NAME:\n                    // ----- Check the number of parameters\n                    if (($i + 1) >= $p_size) {\n                        // ----- Error log\n                        PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, \"Missing parameter value for option '\" . PclZipUtilOptionText($p_options_list[$i]) . \"'\");\n\n                        // ----- Return\n                        return PclZip::errorCode();\n                    }\n\n                    // ----- Get the value\n                    if (is_string($p_options_list[$i + 1])) {\n                        $v_result_list[$p_options_list[$i]][0] = $p_options_list[$i + 1];\n                    } elseif (is_array($p_options_list[$i + 1])) {\n                        $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1];\n                    } else {\n                        // ----- Error log\n                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, \"Wrong parameter value for option '\" . PclZipUtilOptionText($p_options_list[$i]) . \"'\");\n\n                        // ----- Return\n                        return PclZip::errorCode();\n                    }\n                    $i++;\n                    break;\n\n                // ----- Look for options that request an EREG or PREG expression\n                case PCLZIP_OPT_BY_EREG:\n                    $p_options_list[$i] = PCLZIP_OPT_BY_PREG;\n                    // ereg() is deprecated starting with PHP 5.3. Move PCLZIP_OPT_BY_EREG\n                    // to PCLZIP_OPT_BY_PREG\n                case PCLZIP_OPT_BY_PREG:\n                    //case PCLZIP_OPT_CRYPT :\n                    // ----- Check the number of parameters\n                    if (($i + 1) >= $p_size) {\n                        // ----- Error log\n                        PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, \"Missing parameter value for option '\" . PclZipUtilOptionText($p_options_list[$i]) . \"'\");\n\n                        // ----- Return\n                        return PclZip::errorCode();\n                    }\n\n                    // ----- Get the value\n                    if (is_string($p_options_list[$i + 1])) {\n                        $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1];\n                    } else {\n                        // ----- Error log\n                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, \"Wrong parameter value for option '\" . PclZipUtilOptionText($p_options_list[$i]) . \"'\");\n\n                        // ----- Return\n                        return PclZip::errorCode();\n                    }\n                    $i++;\n                    break;\n\n                // ----- Look for options that takes a string\n                case PCLZIP_OPT_COMMENT:\n                case PCLZIP_OPT_ADD_COMMENT:\n                case PCLZIP_OPT_PREPEND_COMMENT:\n                    // ----- Check the number of parameters\n                    if (($i + 1) >= $p_size) {\n                        // ----- Error log\n                        PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, \"Missing parameter value for option '\" . PclZipUtilOptionText($p_options_list[$i]) . \"'\");\n\n                        // ----- Return\n                        return PclZip::errorCode();\n                    }\n\n                    // ----- Get the value\n                    if (is_string($p_options_list[$i + 1])) {\n                        $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1];\n                    } else {\n                        // ----- Error log\n                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, \"Wrong parameter value for option '\" . PclZipUtilOptionText($p_options_list[$i]) . \"'\");\n\n                        // ----- Return\n                        return PclZip::errorCode();\n                    }\n                    $i++;\n                    break;\n\n                // ----- Look for options that request an array of index\n                case PCLZIP_OPT_BY_INDEX:\n                    // ----- Check the number of parameters\n                    if (($i + 1) >= $p_size) {\n                        // ----- Error log\n                        PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, \"Missing parameter value for option '\" . PclZipUtilOptionText($p_options_list[$i]) . \"'\");\n\n                        // ----- Return\n                        return PclZip::errorCode();\n                    }\n\n                    // ----- Get the value\n                    $v_work_list = array();\n                    if (is_string($p_options_list[$i + 1])) {\n\n                        // ----- Remove spaces\n                        $p_options_list[$i + 1] = str_replace(' ', '', $p_options_list[$i + 1]);\n\n                        // ----- Parse items\n                        $v_work_list = explode(\",\", $p_options_list[$i + 1]);\n                    } elseif (is_integer($p_options_list[$i + 1])) {\n                        $v_work_list[0] = $p_options_list[$i + 1] . '-' . $p_options_list[$i + 1];\n                    } elseif (is_array($p_options_list[$i + 1])) {\n                        $v_work_list = $p_options_list[$i + 1];\n                    } else {\n                        // ----- Error log\n                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, \"Value must be integer, string or array for option '\" . PclZipUtilOptionText($p_options_list[$i]) . \"'\");\n\n                        // ----- Return\n                        return PclZip::errorCode();\n                    }\n\n                    // ----- Reduce the index list\n                    // each index item in the list must be a couple with a start and\n                    // an end value : [0,3], [5-5], [8-10], ...\n                    // ----- Check the format of each item\n                    $v_sort_flag  = false;\n                    $v_sort_value = 0;\n                    for ($j = 0; $j < sizeof($v_work_list); $j++) {\n                        // ----- Explode the item\n                        $v_item_list      = explode(\"-\", $v_work_list[$j]);\n                        $v_size_item_list = sizeof($v_item_list);\n\n                        // ----- TBC : Here we might check that each item is a\n                        // real integer ...\n\n                        // ----- Look for single value\n                        if ($v_size_item_list == 1) {\n                            // ----- Set the option value\n                            $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0];\n                            $v_result_list[$p_options_list[$i]][$j]['end']   = $v_item_list[0];\n                        } elseif ($v_size_item_list == 2) {\n                            // ----- Set the option value\n                            $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0];\n                            $v_result_list[$p_options_list[$i]][$j]['end']   = $v_item_list[1];\n                        } else {\n                            // ----- Error log\n                            PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, \"Too many values in index range for option '\" . PclZipUtilOptionText($p_options_list[$i]) . \"'\");\n\n                            // ----- Return\n                            return PclZip::errorCode();\n                        }\n\n                        // ----- Look for list sort\n                        if ($v_result_list[$p_options_list[$i]][$j]['start'] < $v_sort_value) {\n                            $v_sort_flag = true;\n\n                            // ----- TBC : An automatic sort should be writen ...\n                            // ----- Error log\n                            PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, \"Invalid order of index range for option '\" . PclZipUtilOptionText($p_options_list[$i]) . \"'\");\n\n                            // ----- Return\n                            return PclZip::errorCode();\n                        }\n                        $v_sort_value = $v_result_list[$p_options_list[$i]][$j]['start'];\n                    }\n\n                    // ----- Sort the items\n                    if ($v_sort_flag) {\n                        // TBC : To Be Completed\n                    }\n\n                    // ----- Next option\n                    $i++;\n                    break;\n\n                // ----- Look for options that request no value\n                case PCLZIP_OPT_REMOVE_ALL_PATH:\n                case PCLZIP_OPT_EXTRACT_AS_STRING:\n                case PCLZIP_OPT_NO_COMPRESSION:\n                case PCLZIP_OPT_EXTRACT_IN_OUTPUT:\n                case PCLZIP_OPT_REPLACE_NEWER:\n                case PCLZIP_OPT_STOP_ON_ERROR:\n                    $v_result_list[$p_options_list[$i]] = true;\n                    break;\n\n                // ----- Look for options that request an octal value\n                case PCLZIP_OPT_SET_CHMOD:\n                    // ----- Check the number of parameters\n                    if (($i + 1) >= $p_size) {\n                        // ----- Error log\n                        PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, \"Missing parameter value for option '\" . PclZipUtilOptionText($p_options_list[$i]) . \"'\");\n\n                        // ----- Return\n                        return PclZip::errorCode();\n                    }\n\n                    // ----- Get the value\n                    $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1];\n                    $i++;\n                    break;\n\n                // ----- Look for options that request a call-back\n                case PCLZIP_CB_PRE_EXTRACT:\n                case PCLZIP_CB_POST_EXTRACT:\n                case PCLZIP_CB_PRE_ADD:\n                case PCLZIP_CB_POST_ADD:\n                    /* for futur use\n                    case PCLZIP_CB_PRE_DELETE :\n                    case PCLZIP_CB_POST_DELETE :\n                    case PCLZIP_CB_PRE_LIST :\n                    case PCLZIP_CB_POST_LIST :\n                    */\n                    // ----- Check the number of parameters\n                    if (($i + 1) >= $p_size) {\n                        // ----- Error log\n                        PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, \"Missing parameter value for option '\" . PclZipUtilOptionText($p_options_list[$i]) . \"'\");\n\n                        // ----- Return\n                        return PclZip::errorCode();\n                    }\n\n                    // ----- Get the value\n                    $v_function_name = $p_options_list[$i + 1];\n\n                    // ----- Check that the value is a valid existing function\n                    if (!function_exists($v_function_name)) {\n                        // ----- Error log\n                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, \"Function '\" . $v_function_name . \"()' is not an existing function for option '\" . PclZipUtilOptionText($p_options_list[$i]) . \"'\");\n\n                        // ----- Return\n                        return PclZip::errorCode();\n                    }\n\n                    // ----- Set the attribute\n                    $v_result_list[$p_options_list[$i]] = $v_function_name;\n                    $i++;\n                    break;\n\n                default:\n                    // ----- Error log\n                    PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, \"Unknown parameter '\" . $p_options_list[$i] . \"'\");\n\n                    // ----- Return\n                    return PclZip::errorCode();\n            }\n\n            // ----- Next options\n            $i++;\n        }\n\n        // ----- Look for mandatory options\n        if ($v_requested_options !== false) {\n            for ($key = reset($v_requested_options); $key = key($v_requested_options); $key = next($v_requested_options)) {\n                // ----- Look for mandatory option\n                if ($v_requested_options[$key] == 'mandatory') {\n                    // ----- Look if present\n                    if (!isset($v_result_list[$key])) {\n                        // ----- Error log\n                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, \"Missing mandatory parameter \" . PclZipUtilOptionText($key) . \"(\" . $key . \")\");\n\n                        // ----- Return\n                        return PclZip::errorCode();\n                    }\n                }\n            }\n        }\n\n        // ----- Look for default values\n        if (!isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) {\n\n        }\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privOptionDefaultThreshold()\n    // Description :\n    // Parameters :\n    // Return Values :\n    // --------------------------------------------------------------------------------\n    public function privOptionDefaultThreshold(&$p_options)\n    {\n        $v_result = 1;\n\n        if (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) || isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) {\n            return $v_result;\n        }\n\n        // ----- Get 'memory_limit' configuration value\n        $v_memory_limit = ini_get('memory_limit');\n        $v_memory_limit = trim($v_memory_limit);\n        $last           = strtolower(substr($v_memory_limit, -1));\n        $v_memory_limit = preg_replace('/[^0-9,.]/', '', $v_memory_limit);\n\n        if ($last == 'g') {\n            //$v_memory_limit = $v_memory_limit*1024*1024*1024;\n            $v_memory_limit = $v_memory_limit * 1073741824;\n        }\n        if ($last == 'm') {\n            //$v_memory_limit = $v_memory_limit*1024*1024;\n            $v_memory_limit = $v_memory_limit * 1048576;\n        }\n        if ($last == 'k') {\n            $v_memory_limit = $v_memory_limit * 1024;\n        }\n\n        $p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] = floor($v_memory_limit * PCLZIP_TEMPORARY_FILE_RATIO);\n\n        // ----- Sanity check : No threshold if value lower than 1M\n        if ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] < 1048576) {\n            unset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]);\n        }\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privFileDescrParseAtt()\n    // Description :\n    // Parameters :\n    // Return Values :\n    //   1 on success.\n    //   0 on failure.\n    // --------------------------------------------------------------------------------\n    public function privFileDescrParseAtt(&$p_file_list, &$p_filedescr, $v_options, $v_requested_options = false)\n    {\n        $v_result = 1;\n\n        // ----- For each file in the list check the attributes\n        foreach ($p_file_list as $v_key => $v_value) {\n\n            // ----- Check if the option is supported\n            if (!isset($v_requested_options[$v_key])) {\n                // ----- Error log\n                PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, \"Invalid file attribute '\" . $v_key . \"' for this file\");\n\n                // ----- Return\n                return PclZip::errorCode();\n            }\n\n            // ----- Look for attribute\n            switch ($v_key) {\n                case PCLZIP_ATT_FILE_NAME:\n                    if (!is_string($v_value)) {\n                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, \"Invalid type \" . gettype($v_value) . \". String expected for attribute '\" . PclZipUtilOptionText($v_key) . \"'\");\n\n                        return PclZip::errorCode();\n                    }\n\n                    $p_filedescr['filename'] = PclZipUtilPathReduction($v_value);\n\n                    if ($p_filedescr['filename'] == '') {\n                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, \"Invalid empty filename for attribute '\" . PclZipUtilOptionText($v_key) . \"'\");\n\n                        return PclZip::errorCode();\n                    }\n\n                    break;\n\n                case PCLZIP_ATT_FILE_NEW_SHORT_NAME:\n                    if (!is_string($v_value)) {\n                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, \"Invalid type \" . gettype($v_value) . \". String expected for attribute '\" . PclZipUtilOptionText($v_key) . \"'\");\n\n                        return PclZip::errorCode();\n                    }\n\n                    $p_filedescr['new_short_name'] = PclZipUtilPathReduction($v_value);\n\n                    if ($p_filedescr['new_short_name'] == '') {\n                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, \"Invalid empty short filename for attribute '\" . PclZipUtilOptionText($v_key) . \"'\");\n\n                        return PclZip::errorCode();\n                    }\n                    break;\n\n                case PCLZIP_ATT_FILE_NEW_FULL_NAME:\n                    if (!is_string($v_value)) {\n                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, \"Invalid type \" . gettype($v_value) . \". String expected for attribute '\" . PclZipUtilOptionText($v_key) . \"'\");\n\n                        return PclZip::errorCode();\n                    }\n\n                    $p_filedescr['new_full_name'] = PclZipUtilPathReduction($v_value);\n\n                    if ($p_filedescr['new_full_name'] == '') {\n                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, \"Invalid empty full filename for attribute '\" . PclZipUtilOptionText($v_key) . \"'\");\n\n                        return PclZip::errorCode();\n                    }\n                    break;\n\n                // ----- Look for options that takes a string\n                case PCLZIP_ATT_FILE_COMMENT:\n                    if (!is_string($v_value)) {\n                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, \"Invalid type \" . gettype($v_value) . \". String expected for attribute '\" . PclZipUtilOptionText($v_key) . \"'\");\n\n                        return PclZip::errorCode();\n                    }\n\n                    $p_filedescr['comment'] = $v_value;\n                    break;\n\n                case PCLZIP_ATT_FILE_MTIME:\n                    if (!is_integer($v_value)) {\n                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, \"Invalid type \" . gettype($v_value) . \". Integer expected for attribute '\" . PclZipUtilOptionText($v_key) . \"'\");\n\n                        return PclZip::errorCode();\n                    }\n\n                    $p_filedescr['mtime'] = $v_value;\n                    break;\n\n                case PCLZIP_ATT_FILE_CONTENT:\n                    $p_filedescr['content'] = $v_value;\n                    break;\n\n                default:\n                    // ----- Error log\n                    PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, \"Unknown parameter '\" . $v_key . \"'\");\n\n                    // ----- Return\n                    return PclZip::errorCode();\n            }\n\n            // ----- Look for mandatory options\n            if ($v_requested_options !== false) {\n                for ($key = reset($v_requested_options); $key = key($v_requested_options); $key = next($v_requested_options)) {\n                    // ----- Look for mandatory option\n                    if ($v_requested_options[$key] == 'mandatory') {\n                        // ----- Look if present\n                        if (!isset($p_file_list[$key])) {\n                            PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, \"Missing mandatory parameter \" . PclZipUtilOptionText($key) . \"(\" . $key . \")\");\n\n                            return PclZip::errorCode();\n                        }\n                    }\n                }\n            }\n\n            // end foreach\n        }\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privFileDescrExpand()\n    // Description :\n    //   This method look for each item of the list to see if its a file, a folder\n    //   or a string to be added as file. For any other type of files (link, other)\n    //   just ignore the item.\n    //   Then prepare the information that will be stored for that file.\n    //   When its a folder, expand the folder with all the files that are in that\n    //   folder (recursively).\n    // Parameters :\n    // Return Values :\n    //   1 on success.\n    //   0 on failure.\n    // --------------------------------------------------------------------------------\n    public function privFileDescrExpand(&$p_filedescr_list, &$p_options)\n    {\n        $v_result = 1;\n\n        // ----- Create a result list\n        $v_result_list = array();\n\n        // ----- Look each entry\n        for ($i = 0; $i < sizeof($p_filedescr_list); $i++) {\n\n            // ----- Get filedescr\n            $v_descr = $p_filedescr_list[$i];\n\n            // ----- Reduce the filename\n            $v_descr['filename'] = PclZipUtilTranslateWinPath($v_descr['filename'], false);\n            $v_descr['filename'] = PclZipUtilPathReduction($v_descr['filename']);\n\n            // ----- Look for real file or folder\n            if (file_exists($v_descr['filename'])) {\n                if (@is_file($v_descr['filename'])) {\n                    $v_descr['type'] = 'file';\n                } elseif (@is_dir($v_descr['filename'])) {\n                    $v_descr['type'] = 'folder';\n                } elseif (@is_link($v_descr['filename'])) {\n                    // skip\n                    continue;\n                } else {\n                    // skip\n                    continue;\n                }\n\n            // ----- Look for string added as file\n            } elseif (isset($v_descr['content'])) {\n                $v_descr['type'] = 'virtual_file';\n\n            // ----- Missing file\n            } else {\n                // ----- Error log\n                PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, \"File '\" . $v_descr['filename'] . \"' does not exist\");\n\n                // ----- Return\n                return PclZip::errorCode();\n            }\n\n            // ----- Calculate the stored filename\n            $this->privCalculateStoredFilename($v_descr, $p_options);\n\n            // ----- Add the descriptor in result list\n            $v_result_list[sizeof($v_result_list)] = $v_descr;\n\n            // ----- Look for folder\n            if ($v_descr['type'] == 'folder') {\n                // ----- List of items in folder\n                $v_dirlist_descr = array();\n                $v_dirlist_nb    = 0;\n                if ($v_folder_handler = @opendir($v_descr['filename'])) {\n                    while (($v_item_handler = @readdir($v_folder_handler)) !== false) {\n\n                        // ----- Skip '.' and '..'\n                        if (($v_item_handler == '.') || ($v_item_handler == '..')) {\n                            continue;\n                        }\n\n                        // ----- Compose the full filename\n                        $v_dirlist_descr[$v_dirlist_nb]['filename'] = $v_descr['filename'] . '/' . $v_item_handler;\n\n                        // ----- Look for different stored filename\n                        // Because the name of the folder was changed, the name of the\n                        // files/sub-folders also change\n                        if (($v_descr['stored_filename'] != $v_descr['filename']) && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) {\n                            if ($v_descr['stored_filename'] != '') {\n                                $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_descr['stored_filename'] . '/' . $v_item_handler;\n                            } else {\n                                $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_item_handler;\n                            }\n                        }\n\n                        $v_dirlist_nb++;\n                    }\n\n                    @closedir($v_folder_handler);\n                } else {\n                    // TBC : unable to open folder in read mode\n                }\n\n                // ----- Expand each element of the list\n                if ($v_dirlist_nb != 0) {\n                    // ----- Expand\n                    if (($v_result = $this->privFileDescrExpand($v_dirlist_descr, $p_options)) != 1) {\n                        return $v_result;\n                    }\n\n                    // ----- Concat the resulting list\n                    $v_result_list = array_merge($v_result_list, $v_dirlist_descr);\n                } else {\n                }\n\n                // ----- Free local array\n                unset($v_dirlist_descr);\n            }\n        }\n\n        // ----- Get the result list\n        $p_filedescr_list = $v_result_list;\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privCreate()\n    // Description :\n    // Parameters :\n    // Return Values :\n    // --------------------------------------------------------------------------------\n    public function privCreate($p_filedescr_list, &$p_result_list, &$p_options)\n    {\n        $v_result      = 1;\n        $v_list_detail = array();\n\n        // ----- Magic quotes trick\n        $this->privDisableMagicQuotes();\n\n        // ----- Open the file in write mode\n        if (($v_result = $this->privOpenFd('wb')) != 1) {\n            // ----- Return\n            return $v_result;\n        }\n\n        // ----- Add the list of files\n        $v_result = $this->privAddList($p_filedescr_list, $p_result_list, $p_options);\n\n        // ----- Close\n        $this->privCloseFd();\n\n        // ----- Magic quotes trick\n        $this->privSwapBackMagicQuotes();\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privAdd()\n    // Description :\n    // Parameters :\n    // Return Values :\n    // --------------------------------------------------------------------------------\n    public function privAdd($p_filedescr_list, &$p_result_list, &$p_options)\n    {\n        $v_result      = 1;\n        $v_list_detail = array();\n\n        // ----- Look if the archive exists or is empty\n        if ((!is_file($this->zipname)) || (filesize($this->zipname) == 0)) {\n\n            // ----- Do a create\n            $v_result = $this->privCreate($p_filedescr_list, $p_result_list, $p_options);\n\n            // ----- Return\n            return $v_result;\n        }\n        // ----- Magic quotes trick\n        $this->privDisableMagicQuotes();\n\n        // ----- Open the zip file\n        if (($v_result = $this->privOpenFd('rb')) != 1) {\n            // ----- Magic quotes trick\n            $this->privSwapBackMagicQuotes();\n\n            // ----- Return\n            return $v_result;\n        }\n\n        // ----- Read the central directory informations\n        $v_central_dir = array();\n        if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) {\n            $this->privCloseFd();\n            $this->privSwapBackMagicQuotes();\n\n            return $v_result;\n        }\n\n        // ----- Go to beginning of File\n        @rewind($this->zip_fd);\n\n        // ----- Creates a temporay file\n        $v_zip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.tmp';\n\n        // ----- Open the temporary file in write mode\n        if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) {\n            $this->privCloseFd();\n            $this->privSwapBackMagicQuotes();\n\n            PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \\'' . $v_zip_temp_name . '\\' in binary write mode');\n\n            // ----- Return\n            return PclZip::errorCode();\n        }\n\n        // ----- Copy the files from the archive to the temporary file\n        // TBC : Here I should better append the file and go back to erase the central dir\n        $v_size = $v_central_dir['offset'];\n        while ($v_size != 0) {\n            $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);\n            $v_buffer    = fread($this->zip_fd, $v_read_size);\n            @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);\n            $v_size -= $v_read_size;\n        }\n\n        // ----- Swap the file descriptor\n        // Here is a trick : I swap the temporary fd with the zip fd, in order to use\n        // the following methods on the temporary fil and not the real archive\n        $v_swap        = $this->zip_fd;\n        $this->zip_fd  = $v_zip_temp_fd;\n        $v_zip_temp_fd = $v_swap;\n\n        // ----- Add the files\n        $v_header_list = array();\n        if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) {\n            fclose($v_zip_temp_fd);\n            $this->privCloseFd();\n            @unlink($v_zip_temp_name);\n            $this->privSwapBackMagicQuotes();\n\n            // ----- Return\n            return $v_result;\n        }\n\n        // ----- Store the offset of the central dir\n        $v_offset = @ftell($this->zip_fd);\n\n        // ----- Copy the block of file headers from the old archive\n        $v_size = $v_central_dir['size'];\n        while ($v_size != 0) {\n            $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);\n            $v_buffer    = @fread($v_zip_temp_fd, $v_read_size);\n            @fwrite($this->zip_fd, $v_buffer, $v_read_size);\n            $v_size -= $v_read_size;\n        }\n\n        // ----- Create the Central Dir files header\n        for ($i = 0, $v_count = 0; $i < sizeof($v_header_list); $i++) {\n            // ----- Create the file header\n            if ($v_header_list[$i]['status'] == 'ok') {\n                if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) {\n                    fclose($v_zip_temp_fd);\n                    $this->privCloseFd();\n                    @unlink($v_zip_temp_name);\n                    $this->privSwapBackMagicQuotes();\n\n                    // ----- Return\n                    return $v_result;\n                }\n                $v_count++;\n            }\n\n            // ----- Transform the header to a 'usable' info\n            $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);\n        }\n\n        // ----- Zip file comment\n        $v_comment = $v_central_dir['comment'];\n        if (isset($p_options[PCLZIP_OPT_COMMENT])) {\n            $v_comment = $p_options[PCLZIP_OPT_COMMENT];\n        }\n        if (isset($p_options[PCLZIP_OPT_ADD_COMMENT])) {\n            $v_comment = $v_comment . $p_options[PCLZIP_OPT_ADD_COMMENT];\n        }\n        if (isset($p_options[PCLZIP_OPT_PREPEND_COMMENT])) {\n            $v_comment = $p_options[PCLZIP_OPT_PREPEND_COMMENT] . $v_comment;\n        }\n\n        // ----- Calculate the size of the central header\n        $v_size = @ftell($this->zip_fd) - $v_offset;\n\n        // ----- Create the central dir footer\n        if (($v_result = $this->privWriteCentralHeader($v_count + $v_central_dir['entries'], $v_size, $v_offset, $v_comment)) != 1) {\n            // ----- Reset the file list\n            unset($v_header_list);\n            $this->privSwapBackMagicQuotes();\n\n            // ----- Return\n            return $v_result;\n        }\n\n        // ----- Swap back the file descriptor\n        $v_swap        = $this->zip_fd;\n        $this->zip_fd  = $v_zip_temp_fd;\n        $v_zip_temp_fd = $v_swap;\n\n        // ----- Close\n        $this->privCloseFd();\n\n        // ----- Close the temporary file\n        @fclose($v_zip_temp_fd);\n\n        // ----- Magic quotes trick\n        $this->privSwapBackMagicQuotes();\n\n        // ----- Delete the zip file\n        // TBC : I should test the result ...\n        @unlink($this->zipname);\n\n        // ----- Rename the temporary file\n        // TBC : I should test the result ...\n        //@rename($v_zip_temp_name, $this->zipname);\n        PclZipUtilRename($v_zip_temp_name, $this->zipname);\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privOpenFd()\n    // Description :\n    // Parameters :\n    // --------------------------------------------------------------------------------\n    public function privOpenFd($p_mode)\n    {\n        $v_result = 1;\n\n        // ----- Look if already open\n        if ($this->zip_fd != 0) {\n            // ----- Error log\n            PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Zip file \\'' . $this->zipname . '\\' already open');\n\n            // ----- Return\n            return PclZip::errorCode();\n        }\n\n        // ----- Open the zip file\n        if (($this->zip_fd = @fopen($this->zipname, $p_mode)) == 0) {\n            // ----- Error log\n            PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \\'' . $this->zipname . '\\' in ' . $p_mode . ' mode');\n\n            // ----- Return\n            return PclZip::errorCode();\n        }\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privCloseFd()\n    // Description :\n    // Parameters :\n    // --------------------------------------------------------------------------------\n    public function privCloseFd()\n    {\n        $v_result = 1;\n\n        if ($this->zip_fd != 0) {\n            @fclose($this->zip_fd);\n        }\n        $this->zip_fd = 0;\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privAddList()\n    // Description :\n    //   $p_add_dir and $p_remove_dir will give the ability to memorize a path which is\n    //   different from the real path of the file. This is usefull if you want to have PclTar\n    //   running in any directory, and memorize relative path from an other directory.\n    // Parameters :\n    //   $p_list : An array containing the file or directory names to add in the tar\n    //   $p_result_list : list of added files with their properties (specially the status field)\n    //   $p_add_dir : Path to add in the filename path archived\n    //   $p_remove_dir : Path to remove in the filename path archived\n    // Return Values :\n    // --------------------------------------------------------------------------------\n    //  function privAddList($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_options)\n    public function privAddList($p_filedescr_list, &$p_result_list, &$p_options)\n    {\n        $v_result = 1;\n\n        // ----- Add the files\n        $v_header_list = array();\n        if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) {\n            // ----- Return\n            return $v_result;\n        }\n\n        // ----- Store the offset of the central dir\n        $v_offset = @ftell($this->zip_fd);\n\n        // ----- Create the Central Dir files header\n        for ($i = 0, $v_count = 0; $i < sizeof($v_header_list); $i++) {\n            // ----- Create the file header\n            if ($v_header_list[$i]['status'] == 'ok') {\n                if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) {\n                    // ----- Return\n                    return $v_result;\n                }\n                $v_count++;\n            }\n\n            // ----- Transform the header to a 'usable' info\n            $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);\n        }\n\n        // ----- Zip file comment\n        $v_comment = '';\n        if (isset($p_options[PCLZIP_OPT_COMMENT])) {\n            $v_comment = $p_options[PCLZIP_OPT_COMMENT];\n        }\n\n        // ----- Calculate the size of the central header\n        $v_size = @ftell($this->zip_fd) - $v_offset;\n\n        // ----- Create the central dir footer\n        if (($v_result = $this->privWriteCentralHeader($v_count, $v_size, $v_offset, $v_comment)) != 1) {\n            // ----- Reset the file list\n            unset($v_header_list);\n\n            // ----- Return\n            return $v_result;\n        }\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privAddFileList()\n    // Description :\n    // Parameters :\n    //   $p_filedescr_list : An array containing the file description\n    //                      or directory names to add in the zip\n    //   $p_result_list : list of added files with their properties (specially the status field)\n    // Return Values :\n    // --------------------------------------------------------------------------------\n    public function privAddFileList($p_filedescr_list, &$p_result_list, &$p_options)\n    {\n        $v_result = 1;\n        $v_header = array();\n\n        // ----- Recuperate the current number of elt in list\n        $v_nb = sizeof($p_result_list);\n\n        // ----- Loop on the files\n        for ($j = 0; ($j < sizeof($p_filedescr_list)) && ($v_result == 1); $j++) {\n            // ----- Format the filename\n            $p_filedescr_list[$j]['filename'] = PclZipUtilTranslateWinPath($p_filedescr_list[$j]['filename'], false);\n\n            // ----- Skip empty file names\n            // TBC : Can this be possible ? not checked in DescrParseAtt ?\n            if ($p_filedescr_list[$j]['filename'] == \"\") {\n                continue;\n            }\n\n            // ----- Check the filename\n            if (($p_filedescr_list[$j]['type'] != 'virtual_file') && (!file_exists($p_filedescr_list[$j]['filename']))) {\n                PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, \"File '\" . $p_filedescr_list[$j]['filename'] . \"' does not exist\");\n\n                return PclZip::errorCode();\n            }\n\n            // ----- Look if it is a file or a dir with no all path remove option\n            // or a dir with all its path removed\n            //      if (   (is_file($p_filedescr_list[$j]['filename']))\n            //          || (   is_dir($p_filedescr_list[$j]['filename'])\n            if (($p_filedescr_list[$j]['type'] == 'file') || ($p_filedescr_list[$j]['type'] == 'virtual_file') || (($p_filedescr_list[$j]['type'] == 'folder') && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]) || !$p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) {\n\n                // ----- Add the file\n                $v_result = $this->privAddFile($p_filedescr_list[$j], $v_header, $p_options);\n                if ($v_result != 1) {\n                    return $v_result;\n                }\n\n                // ----- Store the file infos\n                $p_result_list[$v_nb++] = $v_header;\n            }\n        }\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privAddFile()\n    // Description :\n    // Parameters :\n    // Return Values :\n    // --------------------------------------------------------------------------------\n    public function privAddFile($p_filedescr, &$p_header, &$p_options)\n    {\n        $v_result = 1;\n\n        // ----- Working variable\n        $p_filename = $p_filedescr['filename'];\n\n        // TBC : Already done in the fileAtt check ... ?\n        if ($p_filename == \"\") {\n            // ----- Error log\n            PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, \"Invalid file list parameter (invalid or empty list)\");\n\n            // ----- Return\n            return PclZip::errorCode();\n        }\n\n        // ----- Look for a stored different filename\n        /* TBC : Removed\n        if (isset($p_filedescr['stored_filename'])) {\n        $v_stored_filename = $p_filedescr['stored_filename'];\n        } else {\n        $v_stored_filename = $p_filedescr['stored_filename'];\n        }\n        */\n\n        // ----- Set the file properties\n        clearstatcache();\n        $p_header['version']           = 20;\n        $p_header['version_extracted'] = 10;\n        $p_header['flag']              = 0;\n        $p_header['compression']       = 0;\n        $p_header['crc']               = 0;\n        $p_header['compressed_size']   = 0;\n        $p_header['filename_len']      = strlen($p_filename);\n        $p_header['extra_len']         = 0;\n        $p_header['disk']              = 0;\n        $p_header['internal']          = 0;\n        $p_header['offset']            = 0;\n        $p_header['filename']          = $p_filename;\n        // TBC : Removed    $p_header['stored_filename'] = $v_stored_filename;\n        $p_header['stored_filename']   = $p_filedescr['stored_filename'];\n        $p_header['extra']             = '';\n        $p_header['status']            = 'ok';\n        $p_header['index']             = -1;\n\n        // ----- Look for regular file\n        if ($p_filedescr['type'] == 'file') {\n            $p_header['external'] = 0x00000000;\n            $p_header['size']     = filesize($p_filename);\n\n        // ----- Look for regular folder\n        } elseif ($p_filedescr['type'] == 'folder') {\n            $p_header['external'] = 0x00000010;\n            $p_header['mtime']    = filemtime($p_filename);\n            $p_header['size']     = filesize($p_filename);\n\n        // ----- Look for virtual file\n        } elseif ($p_filedescr['type'] == 'virtual_file') {\n            $p_header['external'] = 0x00000000;\n            $p_header['size']     = strlen($p_filedescr['content']);\n        }\n\n        // ----- Look for filetime\n        if (isset($p_filedescr['mtime'])) {\n            $p_header['mtime'] = $p_filedescr['mtime'];\n        } elseif ($p_filedescr['type'] == 'virtual_file') {\n            $p_header['mtime'] = time();\n        } else {\n            $p_header['mtime'] = filemtime($p_filename);\n        }\n\n        // ------ Look for file comment\n        if (isset($p_filedescr['comment'])) {\n            $p_header['comment_len'] = strlen($p_filedescr['comment']);\n            $p_header['comment']     = $p_filedescr['comment'];\n        } else {\n            $p_header['comment_len'] = 0;\n            $p_header['comment']     = '';\n        }\n\n        // ----- Look for pre-add callback\n        if (isset($p_options[PCLZIP_CB_PRE_ADD])) {\n\n            // ----- Generate a local information\n            $v_local_header = array();\n            $this->privConvertHeader2FileInfo($p_header, $v_local_header);\n\n            // ----- Call the callback\n            // Here I do not use call_user_func() because I need to send a reference to the\n            // header.\n            //      eval('$v_result = '.$p_options[PCLZIP_CB_PRE_ADD].'(PCLZIP_CB_PRE_ADD, $v_local_header);');\n            $v_result = $p_options[PCLZIP_CB_PRE_ADD](PCLZIP_CB_PRE_ADD, $v_local_header);\n            if ($v_result == 0) {\n                // ----- Change the file status\n                $p_header['status'] = \"skipped\";\n                $v_result           = 1;\n            }\n\n            // ----- Update the informations\n            // Only some fields can be modified\n            if ($p_header['stored_filename'] != $v_local_header['stored_filename']) {\n                $p_header['stored_filename'] = PclZipUtilPathReduction($v_local_header['stored_filename']);\n            }\n        }\n\n        // ----- Look for empty stored filename\n        if ($p_header['stored_filename'] == \"\") {\n            $p_header['status'] = \"filtered\";\n        }\n\n        // ----- Check the path length\n        if (strlen($p_header['stored_filename']) > 0xFF) {\n            $p_header['status'] = 'filename_too_long';\n        }\n\n        // ----- Look if no error, or file not skipped\n        if ($p_header['status'] == 'ok') {\n\n            // ----- Look for a file\n            if ($p_filedescr['type'] == 'file') {\n                // ----- Look for using temporary file to zip\n                if ((!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON]) || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_header['size'])))) {\n                    $v_result = $this->privAddFileUsingTempFile($p_filedescr, $p_header, $p_options);\n                    if ($v_result < PCLZIP_ERR_NO_ERROR) {\n                        return $v_result;\n                    }\n\n                // ----- Use \"in memory\" zip algo\n                } else {\n\n                    // ----- Open the source file\n                    if (($v_file = @fopen($p_filename, \"rb\")) == 0) {\n                        PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, \"Unable to open file '$p_filename' in binary read mode\");\n\n                        return PclZip::errorCode();\n                    }\n\n                    // ----- Read the file content\n                    $v_content = @fread($v_file, $p_header['size']);\n\n                    // ----- Close the file\n                    @fclose($v_file);\n\n                    // ----- Calculate the CRC\n                    $p_header['crc'] = @crc32($v_content);\n\n                    // ----- Look for no compression\n                    if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) {\n                        // ----- Set header parameters\n                        $p_header['compressed_size'] = $p_header['size'];\n                        $p_header['compression']     = 0;\n\n                    // ----- Look for normal compression\n                    } else {\n                        // ----- Compress the content\n                        $v_content = @gzdeflate($v_content);\n\n                        // ----- Set header parameters\n                        $p_header['compressed_size'] = strlen($v_content);\n                        $p_header['compression']     = 8;\n                    }\n\n                    // ----- Call the header generation\n                    if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {\n                        @fclose($v_file);\n\n                        return $v_result;\n                    }\n\n                    // ----- Write the compressed (or not) content\n                    @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']);\n\n                }\n\n            // ----- Look for a virtual file (a file from string)\n            } elseif ($p_filedescr['type'] == 'virtual_file') {\n\n                $v_content = $p_filedescr['content'];\n\n                // ----- Calculate the CRC\n                $p_header['crc'] = @crc32($v_content);\n\n                // ----- Look for no compression\n                if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) {\n                    // ----- Set header parameters\n                    $p_header['compressed_size'] = $p_header['size'];\n                    $p_header['compression']     = 0;\n\n                // ----- Look for normal compression\n                } else {\n                    // ----- Compress the content\n                    $v_content = @gzdeflate($v_content);\n\n                    // ----- Set header parameters\n                    $p_header['compressed_size'] = strlen($v_content);\n                    $p_header['compression']     = 8;\n                }\n\n                // ----- Call the header generation\n                if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {\n                    @fclose($v_file);\n\n                    return $v_result;\n                }\n\n                // ----- Write the compressed (or not) content\n                @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']);\n\n            // ----- Look for a directory\n            } elseif ($p_filedescr['type'] == 'folder') {\n                // ----- Look for directory last '/'\n                if (@substr($p_header['stored_filename'], -1) != '/') {\n                    $p_header['stored_filename'] .= '/';\n                }\n\n                // ----- Set the file properties\n                $p_header['size']     = 0;\n                //$p_header['external'] = 0x41FF0010;   // Value for a folder : to be checked\n                $p_header['external'] = 0x00000010; // Value for a folder : to be checked\n\n                // ----- Call the header generation\n                if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {\n                    return $v_result;\n                }\n            }\n        }\n\n        // ----- Look for post-add callback\n        if (isset($p_options[PCLZIP_CB_POST_ADD])) {\n\n            // ----- Generate a local information\n            $v_local_header = array();\n            $this->privConvertHeader2FileInfo($p_header, $v_local_header);\n\n            // ----- Call the callback\n            // Here I do not use call_user_func() because I need to send a reference to the\n            // header.\n            //      eval('$v_result = '.$p_options[PCLZIP_CB_POST_ADD].'(PCLZIP_CB_POST_ADD, $v_local_header);');\n            $v_result = $p_options[PCLZIP_CB_POST_ADD](PCLZIP_CB_POST_ADD, $v_local_header);\n            if ($v_result == 0) {\n                // ----- Ignored\n                $v_result = 1;\n            }\n\n            // ----- Update the informations\n            // Nothing can be modified\n        }\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privAddFileUsingTempFile()\n    // Description :\n    // Parameters :\n    // Return Values :\n    // --------------------------------------------------------------------------------\n    public function privAddFileUsingTempFile($p_filedescr, &$p_header, &$p_options)\n    {\n        $v_result = PCLZIP_ERR_NO_ERROR;\n\n        // ----- Working variable\n        $p_filename = $p_filedescr['filename'];\n\n        // ----- Open the source file\n        if (($v_file = @fopen($p_filename, \"rb\")) == 0) {\n            PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, \"Unable to open file '$p_filename' in binary read mode\");\n\n            return PclZip::errorCode();\n        }\n\n        // ----- Creates a compressed temporary file\n        $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.gz';\n        if (($v_file_compressed = @gzopen($v_gzip_temp_name, \"wb\")) == 0) {\n            fclose($v_file);\n            PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \\'' . $v_gzip_temp_name . '\\' in binary write mode');\n\n            return PclZip::errorCode();\n        }\n\n        // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks\n        $v_size = filesize($p_filename);\n        while ($v_size != 0) {\n            $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);\n            $v_buffer    = @fread($v_file, $v_read_size);\n            //$v_binary_data = pack('a'.$v_read_size, $v_buffer);\n            @gzputs($v_file_compressed, $v_buffer, $v_read_size);\n            $v_size -= $v_read_size;\n        }\n\n        // ----- Close the file\n        @fclose($v_file);\n        @gzclose($v_file_compressed);\n\n        // ----- Check the minimum file size\n        if (filesize($v_gzip_temp_name) < 18) {\n            PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'gzip temporary file \\'' . $v_gzip_temp_name . '\\' has invalid filesize - should be minimum 18 bytes');\n\n            return PclZip::errorCode();\n        }\n\n        // ----- Extract the compressed attributes\n        if (($v_file_compressed = @fopen($v_gzip_temp_name, \"rb\")) == 0) {\n            PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \\'' . $v_gzip_temp_name . '\\' in binary read mode');\n\n            return PclZip::errorCode();\n        }\n\n        // ----- Read the gzip file header\n        $v_binary_data = @fread($v_file_compressed, 10);\n        $v_data_header = unpack('a1id1/a1id2/a1cm/a1flag/Vmtime/a1xfl/a1os', $v_binary_data);\n\n        // ----- Check some parameters\n        $v_data_header['os'] = bin2hex($v_data_header['os']);\n\n        // ----- Read the gzip file footer\n        @fseek($v_file_compressed, filesize($v_gzip_temp_name) - 8);\n        $v_binary_data = @fread($v_file_compressed, 8);\n        $v_data_footer = unpack('Vcrc/Vcompressed_size', $v_binary_data);\n\n        // ----- Set the attributes\n        $p_header['compression']     = ord($v_data_header['cm']);\n        //$p_header['mtime'] = $v_data_header['mtime'];\n        $p_header['crc']             = $v_data_footer['crc'];\n        $p_header['compressed_size'] = filesize($v_gzip_temp_name) - 18;\n\n        // ----- Close the file\n        @fclose($v_file_compressed);\n\n        // ----- Call the header generation\n        if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {\n            return $v_result;\n        }\n\n        // ----- Add the compressed data\n        if (($v_file_compressed = @fopen($v_gzip_temp_name, \"rb\")) == 0) {\n            PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \\'' . $v_gzip_temp_name . '\\' in binary read mode');\n\n            return PclZip::errorCode();\n        }\n\n        // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks\n        fseek($v_file_compressed, 10);\n        $v_size = $p_header['compressed_size'];\n        while ($v_size != 0) {\n            $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);\n            $v_buffer    = @fread($v_file_compressed, $v_read_size);\n            //$v_binary_data = pack('a'.$v_read_size, $v_buffer);\n            @fwrite($this->zip_fd, $v_buffer, $v_read_size);\n            $v_size -= $v_read_size;\n        }\n\n        // ----- Close the file\n        @fclose($v_file_compressed);\n\n        // ----- Unlink the temporary file\n        @unlink($v_gzip_temp_name);\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privCalculateStoredFilename()\n    // Description :\n    //   Based on file descriptor properties and global options, this method\n    //   calculate the filename that will be stored in the archive.\n    // Parameters :\n    // Return Values :\n    // --------------------------------------------------------------------------------\n    public function privCalculateStoredFilename(&$p_filedescr, &$p_options)\n    {\n        $v_result = 1;\n\n        // ----- Working variables\n        $p_filename = $p_filedescr['filename'];\n        if (isset($p_options[PCLZIP_OPT_ADD_PATH])) {\n            $p_add_dir = $p_options[PCLZIP_OPT_ADD_PATH];\n        } else {\n            $p_add_dir = '';\n        }\n        if (isset($p_options[PCLZIP_OPT_REMOVE_PATH])) {\n            $p_remove_dir = $p_options[PCLZIP_OPT_REMOVE_PATH];\n        } else {\n            $p_remove_dir = '';\n        }\n        if (isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {\n            $p_remove_all_dir = $p_options[PCLZIP_OPT_REMOVE_ALL_PATH];\n        } else {\n            $p_remove_all_dir = 0;\n        }\n\n        // ----- Look for full name change\n        if (isset($p_filedescr['new_full_name'])) {\n            // ----- Remove drive letter if any\n            $v_stored_filename = PclZipUtilTranslateWinPath($p_filedescr['new_full_name']);\n\n        // ----- Look for path and/or short name change\n        } else {\n\n            // ----- Look for short name change\n            // Its when we cahnge just the filename but not the path\n            if (isset($p_filedescr['new_short_name'])) {\n                $v_path_info = pathinfo($p_filename);\n                $v_dir       = '';\n                if ($v_path_info['dirname'] != '') {\n                    $v_dir = $v_path_info['dirname'] . '/';\n                }\n                $v_stored_filename = $v_dir . $p_filedescr['new_short_name'];\n            } else {\n                // ----- Calculate the stored filename\n                $v_stored_filename = $p_filename;\n            }\n\n            // ----- Look for all path to remove\n            if ($p_remove_all_dir) {\n                $v_stored_filename = basename($p_filename);\n\n            // ----- Look for partial path remove\n            } elseif ($p_remove_dir != \"\") {\n                if (substr($p_remove_dir, -1) != '/') {\n                    $p_remove_dir .= \"/\";\n                }\n\n                if ((substr($p_filename, 0, 2) == \"./\") || (substr($p_remove_dir, 0, 2) == \"./\")) {\n\n                    if ((substr($p_filename, 0, 2) == \"./\") && (substr($p_remove_dir, 0, 2) != \"./\")) {\n                        $p_remove_dir = \"./\" . $p_remove_dir;\n                    }\n                    if ((substr($p_filename, 0, 2) != \"./\") && (substr($p_remove_dir, 0, 2) == \"./\")) {\n                        $p_remove_dir = substr($p_remove_dir, 2);\n                    }\n                }\n\n                $v_compare = PclZipUtilPathInclusion($p_remove_dir, $v_stored_filename);\n                if ($v_compare > 0) {\n                    if ($v_compare == 2) {\n                        $v_stored_filename = \"\";\n                    } else {\n                        $v_stored_filename = substr($v_stored_filename, strlen($p_remove_dir));\n                    }\n                }\n            }\n\n            // ----- Remove drive letter if any\n            $v_stored_filename = PclZipUtilTranslateWinPath($v_stored_filename);\n\n            // ----- Look for path to add\n            if ($p_add_dir != \"\") {\n                if (substr($p_add_dir, -1) == \"/\") {\n                    $v_stored_filename = $p_add_dir . $v_stored_filename;\n                } else {\n                    $v_stored_filename = $p_add_dir . \"/\" . $v_stored_filename;\n                }\n            }\n        }\n\n        // ----- Filename (reduce the path of stored name)\n        $v_stored_filename              = PclZipUtilPathReduction($v_stored_filename);\n        $p_filedescr['stored_filename'] = $v_stored_filename;\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privWriteFileHeader()\n    // Description :\n    // Parameters :\n    // Return Values :\n    // --------------------------------------------------------------------------------\n    public function privWriteFileHeader(&$p_header)\n    {\n        $v_result = 1;\n\n        // ----- Store the offset position of the file\n        $p_header['offset'] = ftell($this->zip_fd);\n\n        // ----- Transform UNIX mtime to DOS format mdate/mtime\n        $v_date  = getdate($p_header['mtime']);\n        $v_mtime = ($v_date['hours'] << 11) + ($v_date['minutes'] << 5) + $v_date['seconds'] / 2;\n        $v_mdate = (($v_date['year'] - 1980) << 9) + ($v_date['mon'] << 5) + $v_date['mday'];\n\n        // ----- Packed data\n        $v_binary_data = pack(\"VvvvvvVVVvv\", 0x04034b50, $p_header['version_extracted'], $p_header['flag'], $p_header['compression'], $v_mtime, $v_mdate, $p_header['crc'], $p_header['compressed_size'], $p_header['size'], strlen($p_header['stored_filename']), $p_header['extra_len']);\n\n        // ----- Write the first 148 bytes of the header in the archive\n        fputs($this->zip_fd, $v_binary_data, 30);\n\n        // ----- Write the variable fields\n        if (strlen($p_header['stored_filename']) != 0) {\n            fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename']));\n        }\n        if ($p_header['extra_len'] != 0) {\n            fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']);\n        }\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privWriteCentralFileHeader()\n    // Description :\n    // Parameters :\n    // Return Values :\n    // --------------------------------------------------------------------------------\n    public function privWriteCentralFileHeader(&$p_header)\n    {\n        $v_result = 1;\n\n        // TBC\n        //for (reset($p_header); $key = key($p_header); next($p_header)) {\n        //}\n\n        // ----- Transform UNIX mtime to DOS format mdate/mtime\n        $v_date  = getdate($p_header['mtime']);\n        $v_mtime = ($v_date['hours'] << 11) + ($v_date['minutes'] << 5) + $v_date['seconds'] / 2;\n        $v_mdate = (($v_date['year'] - 1980) << 9) + ($v_date['mon'] << 5) + $v_date['mday'];\n\n        // ----- Packed data\n        $v_binary_data = pack(\"VvvvvvvVVVvvvvvVV\", 0x02014b50, $p_header['version'], $p_header['version_extracted'], $p_header['flag'], $p_header['compression'], $v_mtime, $v_mdate, $p_header['crc'], $p_header['compressed_size'], $p_header['size'], strlen($p_header['stored_filename']), $p_header['extra_len'], $p_header['comment_len'], $p_header['disk'], $p_header['internal'], $p_header['external'], $p_header['offset']);\n\n        // ----- Write the 42 bytes of the header in the zip file\n        fputs($this->zip_fd, $v_binary_data, 46);\n\n        // ----- Write the variable fields\n        if (strlen($p_header['stored_filename']) != 0) {\n            fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename']));\n        }\n        if ($p_header['extra_len'] != 0) {\n            fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']);\n        }\n        if ($p_header['comment_len'] != 0) {\n            fputs($this->zip_fd, $p_header['comment'], $p_header['comment_len']);\n        }\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privWriteCentralHeader()\n    // Description :\n    // Parameters :\n    // Return Values :\n    // --------------------------------------------------------------------------------\n    public function privWriteCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment)\n    {\n        $v_result = 1;\n\n        // ----- Packed data\n        $v_binary_data = pack(\"VvvvvVVv\", 0x06054b50, 0, 0, $p_nb_entries, $p_nb_entries, $p_size, $p_offset, strlen($p_comment));\n\n        // ----- Write the 22 bytes of the header in the zip file\n        fputs($this->zip_fd, $v_binary_data, 22);\n\n        // ----- Write the variable fields\n        if (strlen($p_comment) != 0) {\n            fputs($this->zip_fd, $p_comment, strlen($p_comment));\n        }\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privList()\n    // Description :\n    // Parameters :\n    // Return Values :\n    // --------------------------------------------------------------------------------\n    public function privList(&$p_list)\n    {\n        $v_result = 1;\n\n        // ----- Magic quotes trick\n        $this->privDisableMagicQuotes();\n\n        // ----- Open the zip file\n        if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) {\n            // ----- Magic quotes trick\n            $this->privSwapBackMagicQuotes();\n\n            // ----- Error log\n            PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \\'' . $this->zipname . '\\' in binary read mode');\n\n            // ----- Return\n            return PclZip::errorCode();\n        }\n\n        // ----- Read the central directory informations\n        $v_central_dir = array();\n        if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) {\n            $this->privSwapBackMagicQuotes();\n\n            return $v_result;\n        }\n\n        // ----- Go to beginning of Central Dir\n        @rewind($this->zip_fd);\n        if (@fseek($this->zip_fd, $v_central_dir['offset'])) {\n            $this->privSwapBackMagicQuotes();\n\n            // ----- Error log\n            PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');\n\n            // ----- Return\n            return PclZip::errorCode();\n        }\n\n        // ----- Read each entry\n        for ($i = 0; $i < $v_central_dir['entries']; $i++) {\n            // ----- Read the file header\n            if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) {\n                $this->privSwapBackMagicQuotes();\n\n                return $v_result;\n            }\n            $v_header['index'] = $i;\n\n            // ----- Get the only interesting attributes\n            $this->privConvertHeader2FileInfo($v_header, $p_list[$i]);\n            unset($v_header);\n        }\n\n        // ----- Close the zip file\n        $this->privCloseFd();\n\n        // ----- Magic quotes trick\n        $this->privSwapBackMagicQuotes();\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privConvertHeader2FileInfo()\n    // Description :\n    //   This function takes the file informations from the central directory\n    //   entries and extract the interesting parameters that will be given back.\n    //   The resulting file infos are set in the array $p_info\n    //     $p_info['filename'] : Filename with full path. Given by user (add),\n    //                           extracted in the filesystem (extract).\n    //     $p_info['stored_filename'] : Stored filename in the archive.\n    //     $p_info['size'] = Size of the file.\n    //     $p_info['compressed_size'] = Compressed size of the file.\n    //     $p_info['mtime'] = Last modification date of the file.\n    //     $p_info['comment'] = Comment associated with the file.\n    //     $p_info['folder'] = true/false : indicates if the entry is a folder or not.\n    //     $p_info['status'] = status of the action on the file.\n    //     $p_info['crc'] = CRC of the file content.\n    // Parameters :\n    // Return Values :\n    // --------------------------------------------------------------------------------\n    public function privConvertHeader2FileInfo($p_header, &$p_info)\n    {\n        $v_result = 1;\n\n        // ----- Get the interesting attributes\n        $v_temp_path               = PclZipUtilPathReduction($p_header['filename']);\n        $p_info['filename']        = $v_temp_path;\n        $v_temp_path               = PclZipUtilPathReduction($p_header['stored_filename']);\n        $p_info['stored_filename'] = $v_temp_path;\n        $p_info['size']            = $p_header['size'];\n        $p_info['compressed_size'] = $p_header['compressed_size'];\n        $p_info['mtime']           = $p_header['mtime'];\n        $p_info['comment']         = $p_header['comment'];\n        $p_info['folder']          = (($p_header['external'] & 0x00000010) == 0x00000010);\n        $p_info['index']           = $p_header['index'];\n        $p_info['status']          = $p_header['status'];\n        $p_info['crc']             = $p_header['crc'];\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privExtractByRule()\n    // Description :\n    //   Extract a file or directory depending of rules (by index, by name, ...)\n    // Parameters :\n    //   $p_file_list : An array where will be placed the properties of each\n    //                  extracted file\n    //   $p_path : Path to add while writing the extracted files\n    //   $p_remove_path : Path to remove (from the file memorized path) while writing the\n    //                    extracted files. If the path does not match the file path,\n    //                    the file is extracted with its memorized path.\n    //                    $p_remove_path does not apply to 'list' mode.\n    //                    $p_path and $p_remove_path are commulative.\n    // Return Values :\n    //   1 on success,0 or less on error (see error code list)\n    // --------------------------------------------------------------------------------\n    public function privExtractByRule(&$p_file_list, $p_path, $p_remove_path, $p_remove_all_path, &$p_options)\n    {\n        $v_result = 1;\n\n        // ----- Magic quotes trick\n        $this->privDisableMagicQuotes();\n\n        // ----- Check the path\n        if (($p_path == \"\") || ((substr($p_path, 0, 1) != \"/\") && (substr($p_path, 0, 3) != \"../\") && (substr($p_path, 1, 2) != \":/\"))) {\n            $p_path = \"./\" . $p_path;\n        }\n\n        // ----- Reduce the path last (and duplicated) '/'\n        if (($p_path != \"./\") && ($p_path != \"/\")) {\n            // ----- Look for the path end '/'\n            while (substr($p_path, -1) == \"/\") {\n                $p_path = substr($p_path, 0, strlen($p_path) - 1);\n            }\n        }\n\n        // ----- Look for path to remove format (should end by /)\n        if (($p_remove_path != \"\") && (substr($p_remove_path, -1) != '/')) {\n            $p_remove_path .= '/';\n        }\n        $p_remove_path_size = strlen($p_remove_path);\n\n        // ----- Open the zip file\n        if (($v_result = $this->privOpenFd('rb')) != 1) {\n            $this->privSwapBackMagicQuotes();\n\n            return $v_result;\n        }\n\n        // ----- Read the central directory informations\n        $v_central_dir = array();\n        if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) {\n            // ----- Close the zip file\n            $this->privCloseFd();\n            $this->privSwapBackMagicQuotes();\n\n            return $v_result;\n        }\n\n        // ----- Start at beginning of Central Dir\n        $v_pos_entry = $v_central_dir['offset'];\n\n        // ----- Read each entry\n        $j_start = 0;\n        for ($i = 0, $v_nb_extracted = 0; $i < $v_central_dir['entries']; $i++) {\n\n            // ----- Read next Central dir entry\n            @rewind($this->zip_fd);\n            if (@fseek($this->zip_fd, $v_pos_entry)) {\n                // ----- Close the zip file\n                $this->privCloseFd();\n                $this->privSwapBackMagicQuotes();\n\n                // ----- Error log\n                PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');\n\n                // ----- Return\n                return PclZip::errorCode();\n            }\n\n            // ----- Read the file header\n            $v_header = array();\n            if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) {\n                // ----- Close the zip file\n                $this->privCloseFd();\n                $this->privSwapBackMagicQuotes();\n\n                return $v_result;\n            }\n\n            // ----- Store the index\n            $v_header['index'] = $i;\n\n            // ----- Store the file position\n            $v_pos_entry = ftell($this->zip_fd);\n\n            // ----- Look for the specific extract rules\n            $v_extract = false;\n\n            // ----- Look for extract by name rule\n            if ((isset($p_options[PCLZIP_OPT_BY_NAME])) && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) {\n\n                // ----- Look if the filename is in the list\n                for ($j = 0; ($j < sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_extract); $j++) {\n\n                    // ----- Look for a directory\n                    if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == \"/\") {\n\n                        // ----- Look if the directory is in the filename path\n                        if ((strlen($v_header['stored_filename']) > strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) && (substr($v_header['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) {\n                            $v_extract = true;\n                        }\n\n                    // ----- Look for a filename\n                    } elseif ($v_header['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) {\n                        $v_extract = true;\n                    }\n                }\n\n            // ----- Look for extract by preg rule\n            } elseif ((isset($p_options[PCLZIP_OPT_BY_PREG])) && ($p_options[PCLZIP_OPT_BY_PREG] != \"\")) {\n\n                if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header['stored_filename'])) {\n                    $v_extract = true;\n                }\n\n            // ----- Look for extract by index rule\n            } elseif ((isset($p_options[PCLZIP_OPT_BY_INDEX])) && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) {\n\n                // ----- Look if the index is in the list\n                for ($j = $j_start; ($j < sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_extract); $j++) {\n\n                    if (($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i <= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) {\n                        $v_extract = true;\n                    }\n                    if ($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) {\n                        $j_start = $j + 1;\n                    }\n\n                    if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start'] > $i) {\n                        break;\n                    }\n                }\n\n            // ----- Look for no rule, which means extract all the archive\n            } else {\n                $v_extract = true;\n            }\n\n            // ----- Check compression method\n            if (($v_extract) && (($v_header['compression'] != 8) && ($v_header['compression'] != 0))) {\n                $v_header['status'] = 'unsupported_compression';\n\n                // ----- Look for PCLZIP_OPT_STOP_ON_ERROR\n                if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) {\n\n                    $this->privSwapBackMagicQuotes();\n\n                    PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_COMPRESSION, \"Filename '\" . $v_header['stored_filename'] . \"' is \" . \"compressed by an unsupported compression \" . \"method (\" . $v_header['compression'] . \") \");\n\n                    return PclZip::errorCode();\n                }\n            }\n\n            // ----- Check encrypted files\n            if (($v_extract) && (($v_header['flag'] & 1) == 1)) {\n                $v_header['status'] = 'unsupported_encryption';\n\n                // ----- Look for PCLZIP_OPT_STOP_ON_ERROR\n                if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) {\n\n                    $this->privSwapBackMagicQuotes();\n\n                    PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, \"Unsupported encryption for \" . \" filename '\" . $v_header['stored_filename'] . \"'\");\n\n                    return PclZip::errorCode();\n                }\n            }\n\n            // ----- Look for real extraction\n            if (($v_extract) && ($v_header['status'] != 'ok')) {\n                $v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++]);\n                if ($v_result != 1) {\n                    $this->privCloseFd();\n                    $this->privSwapBackMagicQuotes();\n\n                    return $v_result;\n                }\n\n                $v_extract = false;\n            }\n\n            // ----- Look for real extraction\n            if ($v_extract) {\n\n                // ----- Go to the file position\n                @rewind($this->zip_fd);\n                if (@fseek($this->zip_fd, $v_header['offset'])) {\n                    // ----- Close the zip file\n                    $this->privCloseFd();\n\n                    $this->privSwapBackMagicQuotes();\n\n                    // ----- Error log\n                    PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');\n\n                    // ----- Return\n                    return PclZip::errorCode();\n                }\n\n                // ----- Look for extraction as string\n                if ($p_options[PCLZIP_OPT_EXTRACT_AS_STRING]) {\n\n                    $v_string = '';\n\n                    // ----- Extracting the file\n                    $v_result1 = $this->privExtractFileAsString($v_header, $v_string, $p_options);\n                    if ($v_result1 < 1) {\n                        $this->privCloseFd();\n                        $this->privSwapBackMagicQuotes();\n\n                        return $v_result1;\n                    }\n\n                    // ----- Get the only interesting attributes\n                    if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted])) != 1) {\n                        // ----- Close the zip file\n                        $this->privCloseFd();\n                        $this->privSwapBackMagicQuotes();\n\n                        return $v_result;\n                    }\n\n                    // ----- Set the file content\n                    $p_file_list[$v_nb_extracted]['content'] = $v_string;\n\n                    // ----- Next extracted file\n                    $v_nb_extracted++;\n\n                    // ----- Look for user callback abort\n                    if ($v_result1 == 2) {\n                        break;\n                    }\n\n                // ----- Look for extraction in standard output\n                } elseif ((isset($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) && ($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) {\n                    // ----- Extracting the file in standard output\n                    $v_result1 = $this->privExtractFileInOutput($v_header, $p_options);\n                    if ($v_result1 < 1) {\n                        $this->privCloseFd();\n                        $this->privSwapBackMagicQuotes();\n\n                        return $v_result1;\n                    }\n\n                    // ----- Get the only interesting attributes\n                    if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) {\n                        $this->privCloseFd();\n                        $this->privSwapBackMagicQuotes();\n\n                        return $v_result;\n                    }\n\n                    // ----- Look for user callback abort\n                    if ($v_result1 == 2) {\n                        break;\n                    }\n\n                // ----- Look for normal extraction\n                } else {\n                    // ----- Extracting the file\n                    $v_result1 = $this->privExtractFile($v_header, $p_path, $p_remove_path, $p_remove_all_path, $p_options);\n                    if ($v_result1 < 1) {\n                        $this->privCloseFd();\n                        $this->privSwapBackMagicQuotes();\n\n                        return $v_result1;\n                    }\n\n                    // ----- Get the only interesting attributes\n                    if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) {\n                        // ----- Close the zip file\n                        $this->privCloseFd();\n                        $this->privSwapBackMagicQuotes();\n\n                        return $v_result;\n                    }\n\n                    // ----- Look for user callback abort\n                    if ($v_result1 == 2) {\n                        break;\n                    }\n                }\n            }\n        }\n\n        // ----- Close the zip file\n        $this->privCloseFd();\n        $this->privSwapBackMagicQuotes();\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privExtractFile()\n    // Description :\n    // Parameters :\n    // Return Values :\n    //\n    // 1 : ... ?\n    // PCLZIP_ERR_USER_ABORTED(2) : User ask for extraction stop in callback\n    // --------------------------------------------------------------------------------\n    public function privExtractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_options)\n    {\n        $v_result = 1;\n\n        // ----- Read the file header\n        if (($v_result = $this->privReadFileHeader($v_header)) != 1) {\n            // ----- Return\n            return $v_result;\n        }\n\n        // ----- Check that the file header is coherent with $p_entry info\n        if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {\n            // TBC\n        }\n\n        // ----- Look for all path to remove\n        if ($p_remove_all_path == true) {\n            // ----- Look for folder entry that not need to be extracted\n            if (($p_entry['external'] & 0x00000010) == 0x00000010) {\n\n                $p_entry['status'] = \"filtered\";\n\n                return $v_result;\n            }\n\n            // ----- Get the basename of the path\n            $p_entry['filename'] = basename($p_entry['filename']);\n\n        // ----- Look for path to remove\n        } elseif ($p_remove_path != \"\") {\n            if (PclZipUtilPathInclusion($p_remove_path, $p_entry['filename']) == 2) {\n\n                // ----- Change the file status\n                $p_entry['status'] = \"filtered\";\n\n                // ----- Return\n                return $v_result;\n            }\n\n            $p_remove_path_size = strlen($p_remove_path);\n            if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path) {\n\n                // ----- Remove the path\n                $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size);\n\n            }\n        }\n\n        // ----- Add the path\n        if ($p_path != '') {\n            $p_entry['filename'] = $p_path . \"/\" . $p_entry['filename'];\n        }\n\n        // ----- Check a base_dir_restriction\n        if (isset($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION])) {\n            $v_inclusion = PclZipUtilPathInclusion($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION], $p_entry['filename']);\n            if ($v_inclusion == 0) {\n\n                PclZip::privErrorLog(PCLZIP_ERR_DIRECTORY_RESTRICTION, \"Filename '\" . $p_entry['filename'] . \"' is \" . \"outside PCLZIP_OPT_EXTRACT_DIR_RESTRICTION\");\n\n                return PclZip::errorCode();\n            }\n        }\n\n        // ----- Look for pre-extract callback\n        if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {\n\n            // ----- Generate a local information\n            $v_local_header = array();\n            $this->privConvertHeader2FileInfo($p_entry, $v_local_header);\n\n            // ----- Call the callback\n            // Here I do not use call_user_func() because I need to send a reference to the\n            // header.\n            //      eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');\n            $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);\n            if ($v_result == 0) {\n                // ----- Change the file status\n                $p_entry['status'] = \"skipped\";\n                $v_result          = 1;\n            }\n\n            // ----- Look for abort result\n            if ($v_result == 2) {\n                // ----- This status is internal and will be changed in 'skipped'\n                $p_entry['status'] = \"aborted\";\n                $v_result          = PCLZIP_ERR_USER_ABORTED;\n            }\n\n            // ----- Update the informations\n            // Only some fields can be modified\n            $p_entry['filename'] = $v_local_header['filename'];\n        }\n\n        // ----- Look if extraction should be done\n        if ($p_entry['status'] == 'ok') {\n\n            // ----- Look for specific actions while the file exist\n            if (file_exists($p_entry['filename'])) {\n\n                // ----- Look if file is a directory\n                if (is_dir($p_entry['filename'])) {\n\n                    // ----- Change the file status\n                    $p_entry['status'] = \"already_a_directory\";\n\n                    // ----- Look for PCLZIP_OPT_STOP_ON_ERROR\n                    // For historical reason first PclZip implementation does not stop\n                    // when this kind of error occurs.\n                    if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) {\n\n                        PclZip::privErrorLog(PCLZIP_ERR_ALREADY_A_DIRECTORY, \"Filename '\" . $p_entry['filename'] . \"' is \" . \"already used by an existing directory\");\n\n                        return PclZip::errorCode();\n                    }\n\n                // ----- Look if file is write protected\n                } elseif (!is_writeable($p_entry['filename'])) {\n\n                    // ----- Change the file status\n                    $p_entry['status'] = \"write_protected\";\n\n                    // ----- Look for PCLZIP_OPT_STOP_ON_ERROR\n                    // For historical reason first PclZip implementation does not stop\n                    // when this kind of error occurs.\n                    if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) {\n\n                        PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, \"Filename '\" . $p_entry['filename'] . \"' exists \" . \"and is write protected\");\n\n                        return PclZip::errorCode();\n                    }\n\n                // ----- Look if the extracted file is older\n                } elseif (filemtime($p_entry['filename']) > $p_entry['mtime']) {\n                    // ----- Change the file status\n                    if ((isset($p_options[PCLZIP_OPT_REPLACE_NEWER])) && ($p_options[PCLZIP_OPT_REPLACE_NEWER] === true)) {\n                    } else {\n                        $p_entry['status'] = \"newer_exist\";\n\n                        // ----- Look for PCLZIP_OPT_STOP_ON_ERROR\n                        // For historical reason first PclZip implementation does not stop\n                        // when this kind of error occurs.\n                        if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) {\n\n                            PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, \"Newer version of '\" . $p_entry['filename'] . \"' exists \" . \"and option PCLZIP_OPT_REPLACE_NEWER is not selected\");\n\n                            return PclZip::errorCode();\n                        }\n                    }\n                } else {\n                }\n\n            // ----- Check the directory availability and create it if necessary\n            } else {\n                if ((($p_entry['external'] & 0x00000010) == 0x00000010) || (substr($p_entry['filename'], -1) == '/')) {\n                    $v_dir_to_check = $p_entry['filename'];\n                } elseif (!strstr($p_entry['filename'], \"/\")) {\n                    $v_dir_to_check = \"\";\n                } else {\n                    $v_dir_to_check = dirname($p_entry['filename']);\n                }\n\n                if (($v_result = $this->privDirCheck($v_dir_to_check, (($p_entry['external'] & 0x00000010) == 0x00000010))) != 1) {\n\n                    // ----- Change the file status\n                    $p_entry['status'] = \"path_creation_fail\";\n\n                    // ----- Return\n                    //return $v_result;\n                    $v_result = 1;\n                }\n            }\n        }\n\n        // ----- Look if extraction should be done\n        if ($p_entry['status'] == 'ok') {\n\n            // ----- Do the extraction (if not a folder)\n            if (!(($p_entry['external'] & 0x00000010) == 0x00000010)) {\n                // ----- Look for not compressed file\n                if ($p_entry['compression'] == 0) {\n\n                    // ----- Opening destination file\n                    if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {\n\n                        // ----- Change the file status\n                        $p_entry['status'] = \"write_error\";\n\n                        // ----- Return\n                        return $v_result;\n                    }\n\n                    // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks\n                    $v_size = $p_entry['compressed_size'];\n                    while ($v_size != 0) {\n                        $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);\n                        $v_buffer    = @fread($this->zip_fd, $v_read_size);\n                        /* Try to speed up the code\n                        $v_binary_data = pack('a'.$v_read_size, $v_buffer);\n                        @fwrite($v_dest_file, $v_binary_data, $v_read_size);\n                        */\n                        @fwrite($v_dest_file, $v_buffer, $v_read_size);\n                        $v_size -= $v_read_size;\n                    }\n\n                    // ----- Closing the destination file\n                    fclose($v_dest_file);\n\n                    // ----- Change the file mtime\n                    touch($p_entry['filename'], $p_entry['mtime']);\n\n                } else {\n                    // ----- TBC\n                    // Need to be finished\n                    if (($p_entry['flag'] & 1) == 1) {\n                        PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, 'File \\'' . $p_entry['filename'] . '\\' is encrypted. Encrypted files are not supported.');\n\n                        return PclZip::errorCode();\n                    }\n\n                    // ----- Look for using temporary file to unzip\n                    if ((!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON]) || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_entry['size'])))) {\n                        $v_result = $this->privExtractFileUsingTempFile($p_entry, $p_options);\n                        if ($v_result < PCLZIP_ERR_NO_ERROR) {\n                            return $v_result;\n                        }\n\n                    // ----- Look for extract in memory\n                    } else {\n\n                        // ----- Read the compressed file in a buffer (one shot)\n                        $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);\n\n                        // ----- Decompress the file\n                        $v_file_content = @gzinflate($v_buffer);\n                        unset($v_buffer);\n                        if ($v_file_content === false) {\n\n                            // ----- Change the file status\n                            // TBC\n                            $p_entry['status'] = \"error\";\n\n                            return $v_result;\n                        }\n\n                        // ----- Opening destination file\n                        if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {\n\n                            // ----- Change the file status\n                            $p_entry['status'] = \"write_error\";\n\n                            return $v_result;\n                        }\n\n                        // ----- Write the uncompressed data\n                        @fwrite($v_dest_file, $v_file_content, $p_entry['size']);\n                        unset($v_file_content);\n\n                        // ----- Closing the destination file\n                        @fclose($v_dest_file);\n\n                    }\n\n                    // ----- Change the file mtime\n                    @touch($p_entry['filename'], $p_entry['mtime']);\n                }\n\n                // ----- Look for chmod option\n                if (isset($p_options[PCLZIP_OPT_SET_CHMOD])) {\n\n                    // ----- Change the mode of the file\n                    @chmod($p_entry['filename'], $p_options[PCLZIP_OPT_SET_CHMOD]);\n                }\n\n            }\n        }\n\n        // ----- Change abort status\n        if ($p_entry['status'] == \"aborted\") {\n            $p_entry['status'] = \"skipped\";\n\n        // ----- Look for post-extract callback\n        } elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {\n\n            // ----- Generate a local information\n            $v_local_header = array();\n            $this->privConvertHeader2FileInfo($p_entry, $v_local_header);\n\n            // ----- Call the callback\n            // Here I do not use call_user_func() because I need to send a reference to the\n            // header.\n            //      eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');\n            $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);\n\n            // ----- Look for abort result\n            if ($v_result == 2) {\n                $v_result = PCLZIP_ERR_USER_ABORTED;\n            }\n        }\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privExtractFileUsingTempFile()\n    // Description :\n    // Parameters :\n    // Return Values :\n    // --------------------------------------------------------------------------------\n    public function privExtractFileUsingTempFile(&$p_entry, &$p_options)\n    {\n        $v_result = 1;\n\n        // ----- Creates a temporary file\n        $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.gz';\n        if (($v_dest_file = @fopen($v_gzip_temp_name, \"wb\")) == 0) {\n            fclose($v_file);\n            PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \\'' . $v_gzip_temp_name . '\\' in binary write mode');\n\n            return PclZip::errorCode();\n        }\n\n        // ----- Write gz file format header\n        $v_binary_data = pack('va1a1Va1a1', 0x8b1f, chr($p_entry['compression']), chr(0x00), time(), chr(0x00), chr(3));\n        @fwrite($v_dest_file, $v_binary_data, 10);\n\n        // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks\n        $v_size = $p_entry['compressed_size'];\n        while ($v_size != 0) {\n            $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);\n            $v_buffer    = @fread($this->zip_fd, $v_read_size);\n            //$v_binary_data = pack('a'.$v_read_size, $v_buffer);\n            @fwrite($v_dest_file, $v_buffer, $v_read_size);\n            $v_size -= $v_read_size;\n        }\n\n        // ----- Write gz file format footer\n        $v_binary_data = pack('VV', $p_entry['crc'], $p_entry['size']);\n        @fwrite($v_dest_file, $v_binary_data, 8);\n\n        // ----- Close the temporary file\n        @fclose($v_dest_file);\n\n        // ----- Opening destination file\n        if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {\n            $p_entry['status'] = \"write_error\";\n\n            return $v_result;\n        }\n\n        // ----- Open the temporary gz file\n        if (($v_src_file = @gzopen($v_gzip_temp_name, 'rb')) == 0) {\n            @fclose($v_dest_file);\n            $p_entry['status'] = \"read_error\";\n            PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \\'' . $v_gzip_temp_name . '\\' in binary read mode');\n\n            return PclZip::errorCode();\n        }\n\n        // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks\n        $v_size = $p_entry['size'];\n        while ($v_size != 0) {\n            $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);\n            $v_buffer    = @gzread($v_src_file, $v_read_size);\n            //$v_binary_data = pack('a'.$v_read_size, $v_buffer);\n            @fwrite($v_dest_file, $v_buffer, $v_read_size);\n            $v_size -= $v_read_size;\n        }\n        @fclose($v_dest_file);\n        @gzclose($v_src_file);\n\n        // ----- Delete the temporary file\n        @unlink($v_gzip_temp_name);\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privExtractFileInOutput()\n    // Description :\n    // Parameters :\n    // Return Values :\n    // --------------------------------------------------------------------------------\n    public function privExtractFileInOutput(&$p_entry, &$p_options)\n    {\n        $v_result = 1;\n\n        // ----- Read the file header\n        if (($v_result = $this->privReadFileHeader($v_header)) != 1) {\n            return $v_result;\n        }\n\n        // ----- Check that the file header is coherent with $p_entry info\n        if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {\n            // TBC\n        }\n\n        // ----- Look for pre-extract callback\n        if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {\n\n            // ----- Generate a local information\n            $v_local_header = array();\n            $this->privConvertHeader2FileInfo($p_entry, $v_local_header);\n\n            // ----- Call the callback\n            // Here I do not use call_user_func() because I need to send a reference to the\n            // header.\n            //      eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');\n            $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);\n            if ($v_result == 0) {\n                // ----- Change the file status\n                $p_entry['status'] = \"skipped\";\n                $v_result          = 1;\n            }\n\n            // ----- Look for abort result\n            if ($v_result == 2) {\n                // ----- This status is internal and will be changed in 'skipped'\n                $p_entry['status'] = \"aborted\";\n                $v_result          = PCLZIP_ERR_USER_ABORTED;\n            }\n\n            // ----- Update the informations\n            // Only some fields can be modified\n            $p_entry['filename'] = $v_local_header['filename'];\n        }\n\n        // ----- Trace\n\n        // ----- Look if extraction should be done\n        if ($p_entry['status'] == 'ok') {\n\n            // ----- Do the extraction (if not a folder)\n            if (!(($p_entry['external'] & 0x00000010) == 0x00000010)) {\n                // ----- Look for not compressed file\n                if ($p_entry['compressed_size'] == $p_entry['size']) {\n\n                    // ----- Read the file in a buffer (one shot)\n                    $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);\n\n                    // ----- Send the file to the output\n                    echo $v_buffer;\n                    unset($v_buffer);\n                } else {\n\n                    // ----- Read the compressed file in a buffer (one shot)\n                    $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);\n\n                    // ----- Decompress the file\n                    $v_file_content = gzinflate($v_buffer);\n                    unset($v_buffer);\n\n                    // ----- Send the file to the output\n                    echo $v_file_content;\n                    unset($v_file_content);\n                }\n            }\n        }\n\n        // ----- Change abort status\n        if ($p_entry['status'] == \"aborted\") {\n            $p_entry['status'] = \"skipped\";\n\n        // ----- Look for post-extract callback\n        } elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {\n\n            // ----- Generate a local information\n            $v_local_header = array();\n            $this->privConvertHeader2FileInfo($p_entry, $v_local_header);\n\n            // ----- Call the callback\n            // Here I do not use call_user_func() because I need to send a reference to the\n            // header.\n            //      eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');\n            $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);\n\n            // ----- Look for abort result\n            if ($v_result == 2) {\n                $v_result = PCLZIP_ERR_USER_ABORTED;\n            }\n        }\n\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privExtractFileAsString()\n    // Description :\n    // Parameters :\n    // Return Values :\n    // --------------------------------------------------------------------------------\n    public function privExtractFileAsString(&$p_entry, &$p_string, &$p_options)\n    {\n        $v_result = 1;\n\n        // ----- Read the file header\n        $v_header = array();\n        if (($v_result = $this->privReadFileHeader($v_header)) != 1) {\n            // ----- Return\n            return $v_result;\n        }\n\n        // ----- Check that the file header is coherent with $p_entry info\n        if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {\n            // TBC\n        }\n\n        // ----- Look for pre-extract callback\n        if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {\n\n            // ----- Generate a local information\n            $v_local_header = array();\n            $this->privConvertHeader2FileInfo($p_entry, $v_local_header);\n\n            // ----- Call the callback\n            // Here I do not use call_user_func() because I need to send a reference to the\n            // header.\n            //      eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');\n            $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);\n            if ($v_result == 0) {\n                // ----- Change the file status\n                $p_entry['status'] = \"skipped\";\n                $v_result          = 1;\n            }\n\n            // ----- Look for abort result\n            if ($v_result == 2) {\n                // ----- This status is internal and will be changed in 'skipped'\n                $p_entry['status'] = \"aborted\";\n                $v_result          = PCLZIP_ERR_USER_ABORTED;\n            }\n\n            // ----- Update the informations\n            // Only some fields can be modified\n            $p_entry['filename'] = $v_local_header['filename'];\n        }\n\n        // ----- Look if extraction should be done\n        if ($p_entry['status'] == 'ok') {\n\n            // ----- Do the extraction (if not a folder)\n            if (!(($p_entry['external'] & 0x00000010) == 0x00000010)) {\n                // ----- Look for not compressed file\n                //      if ($p_entry['compressed_size'] == $p_entry['size'])\n                if ($p_entry['compression'] == 0) {\n\n                    // ----- Reading the file\n                    $p_string = @fread($this->zip_fd, $p_entry['compressed_size']);\n                } else {\n\n                    // ----- Reading the file\n                    $v_data = @fread($this->zip_fd, $p_entry['compressed_size']);\n\n                    // ----- Decompress the file\n                    if (($p_string = @gzinflate($v_data)) === false) {\n                        // TBC\n                    }\n                }\n\n                // ----- Trace\n            } else {\n                // TBC : error : can not extract a folder in a string\n            }\n\n        }\n\n        // ----- Change abort status\n        if ($p_entry['status'] == \"aborted\") {\n            $p_entry['status'] = \"skipped\";\n\n        // ----- Look for post-extract callback\n        } elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {\n\n            // ----- Generate a local information\n            $v_local_header = array();\n            $this->privConvertHeader2FileInfo($p_entry, $v_local_header);\n\n            // ----- Swap the content to header\n            $v_local_header['content'] = $p_string;\n            $p_string                  = '';\n\n            // ----- Call the callback\n            // Here I do not use call_user_func() because I need to send a reference to the\n            // header.\n            //      eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');\n            $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);\n\n            // ----- Swap back the content to header\n            $p_string = $v_local_header['content'];\n            unset($v_local_header['content']);\n\n            // ----- Look for abort result\n            if ($v_result == 2) {\n                $v_result = PCLZIP_ERR_USER_ABORTED;\n            }\n        }\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privReadFileHeader()\n    // Description :\n    // Parameters :\n    // Return Values :\n    // --------------------------------------------------------------------------------\n    public function privReadFileHeader(&$p_header)\n    {\n        $v_result = 1;\n\n        // ----- Read the 4 bytes signature\n        $v_binary_data = @fread($this->zip_fd, 4);\n        $v_data        = unpack('Vid', $v_binary_data);\n\n        // ----- Check signature\n        if ($v_data['id'] != 0x04034b50) {\n\n            // ----- Error log\n            PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure');\n\n            // ----- Return\n            return PclZip::errorCode();\n        }\n\n        // ----- Read the first 42 bytes of the header\n        $v_binary_data = fread($this->zip_fd, 26);\n\n        // ----- Look for invalid block size\n        if (strlen($v_binary_data) != 26) {\n            $p_header['filename'] = \"\";\n            $p_header['status']   = \"invalid_header\";\n\n            // ----- Error log\n            PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, \"Invalid block size : \" . strlen($v_binary_data));\n\n            // ----- Return\n            return PclZip::errorCode();\n        }\n\n        // ----- Extract the values\n        $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data);\n\n        // ----- Get filename\n        $p_header['filename'] = fread($this->zip_fd, $v_data['filename_len']);\n\n        // ----- Get extra_fields\n        if ($v_data['extra_len'] != 0) {\n            $p_header['extra'] = fread($this->zip_fd, $v_data['extra_len']);\n        } else {\n            $p_header['extra'] = '';\n        }\n\n        // ----- Extract properties\n        $p_header['version_extracted'] = $v_data['version'];\n        $p_header['compression']       = $v_data['compression'];\n        $p_header['size']              = $v_data['size'];\n        $p_header['compressed_size']   = $v_data['compressed_size'];\n        $p_header['crc']               = $v_data['crc'];\n        $p_header['flag']              = $v_data['flag'];\n        $p_header['filename_len']      = $v_data['filename_len'];\n\n        // ----- Recuperate date in UNIX format\n        $p_header['mdate'] = $v_data['mdate'];\n        $p_header['mtime'] = $v_data['mtime'];\n        if ($p_header['mdate'] && $p_header['mtime']) {\n            // ----- Extract time\n            $v_hour    = ($p_header['mtime'] & 0xF800) >> 11;\n            $v_minute  = ($p_header['mtime'] & 0x07E0) >> 5;\n            $v_seconde = ($p_header['mtime'] & 0x001F) * 2;\n\n            // ----- Extract date\n            $v_year  = (($p_header['mdate'] & 0xFE00) >> 9) + 1980;\n            $v_month = ($p_header['mdate'] & 0x01E0) >> 5;\n            $v_day   = $p_header['mdate'] & 0x001F;\n\n            // ----- Get UNIX date format\n            $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year);\n\n        } else {\n            $p_header['mtime'] = time();\n        }\n\n        // TBC\n        //for (reset($v_data); $key = key($v_data); next($v_data)) {\n        //}\n\n        // ----- Set the stored filename\n        $p_header['stored_filename'] = $p_header['filename'];\n\n        // ----- Set the status field\n        $p_header['status'] = \"ok\";\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privReadCentralFileHeader()\n    // Description :\n    // Parameters :\n    // Return Values :\n    // --------------------------------------------------------------------------------\n    public function privReadCentralFileHeader(&$p_header)\n    {\n        $v_result = 1;\n\n        // ----- Read the 4 bytes signature\n        $v_binary_data = @fread($this->zip_fd, 4);\n        $v_data        = unpack('Vid', $v_binary_data);\n\n        // ----- Check signature\n        if ($v_data['id'] != 0x02014b50) {\n\n            // ----- Error log\n            PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure');\n\n            // ----- Return\n            return PclZip::errorCode();\n        }\n\n        // ----- Read the first 42 bytes of the header\n        $v_binary_data = fread($this->zip_fd, 42);\n\n        // ----- Look for invalid block size\n        if (strlen($v_binary_data) != 42) {\n            $p_header['filename'] = \"\";\n            $p_header['status']   = \"invalid_header\";\n\n            // ----- Error log\n            PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, \"Invalid block size : \" . strlen($v_binary_data));\n\n            // ----- Return\n            return PclZip::errorCode();\n        }\n\n        // ----- Extract the values\n        $p_header = unpack('vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $v_binary_data);\n\n        // ----- Get filename\n        if ($p_header['filename_len'] != 0) {\n            $p_header['filename'] = fread($this->zip_fd, $p_header['filename_len']);\n        } else {\n            $p_header['filename'] = '';\n        }\n\n        // ----- Get extra\n        if ($p_header['extra_len'] != 0) {\n            $p_header['extra'] = fread($this->zip_fd, $p_header['extra_len']);\n        } else {\n            $p_header['extra'] = '';\n        }\n\n        // ----- Get comment\n        if ($p_header['comment_len'] != 0) {\n            $p_header['comment'] = fread($this->zip_fd, $p_header['comment_len']);\n        } else {\n            $p_header['comment'] = '';\n        }\n\n        // ----- Extract properties\n\n        // ----- Recuperate date in UNIX format\n        //if ($p_header['mdate'] && $p_header['mtime'])\n        // TBC : bug : this was ignoring time with 0/0/0\n        if (1) {\n            // ----- Extract time\n            $v_hour    = ($p_header['mtime'] & 0xF800) >> 11;\n            $v_minute  = ($p_header['mtime'] & 0x07E0) >> 5;\n            $v_seconde = ($p_header['mtime'] & 0x001F) * 2;\n\n            // ----- Extract date\n            $v_year  = (($p_header['mdate'] & 0xFE00) >> 9) + 1980;\n            $v_month = ($p_header['mdate'] & 0x01E0) >> 5;\n            $v_day   = $p_header['mdate'] & 0x001F;\n\n            // ----- Get UNIX date format\n            $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year);\n\n        } else {\n            $p_header['mtime'] = time();\n        }\n\n        // ----- Set the stored filename\n        $p_header['stored_filename'] = $p_header['filename'];\n\n        // ----- Set default status to ok\n        $p_header['status'] = 'ok';\n\n        // ----- Look if it is a directory\n        if (substr($p_header['filename'], -1) == '/') {\n            //$p_header['external'] = 0x41FF0010;\n            $p_header['external'] = 0x00000010;\n        }\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privCheckFileHeaders()\n    // Description :\n    // Parameters :\n    // Return Values :\n    //   1 on success,\n    //   0 on error;\n    // --------------------------------------------------------------------------------\n    public function privCheckFileHeaders(&$p_local_header, &$p_central_header)\n    {\n        $v_result = 1;\n\n        // ----- Check the static values\n        // TBC\n        if ($p_local_header['filename'] != $p_central_header['filename']) {\n        }\n        if ($p_local_header['version_extracted'] != $p_central_header['version_extracted']) {\n        }\n        if ($p_local_header['flag'] != $p_central_header['flag']) {\n        }\n        if ($p_local_header['compression'] != $p_central_header['compression']) {\n        }\n        if ($p_local_header['mtime'] != $p_central_header['mtime']) {\n        }\n        if ($p_local_header['filename_len'] != $p_central_header['filename_len']) {\n        }\n\n        // ----- Look for flag bit 3\n        if (($p_local_header['flag'] & 8) == 8) {\n            $p_local_header['size']            = $p_central_header['size'];\n            $p_local_header['compressed_size'] = $p_central_header['compressed_size'];\n            $p_local_header['crc']             = $p_central_header['crc'];\n        }\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privReadEndCentralDir()\n    // Description :\n    // Parameters :\n    // Return Values :\n    // --------------------------------------------------------------------------------\n    public function privReadEndCentralDir(&$p_central_dir)\n    {\n        $v_result = 1;\n\n        // ----- Go to the end of the zip file\n        $v_size = filesize($this->zipname);\n        @fseek($this->zip_fd, $v_size);\n        if (@ftell($this->zip_fd) != $v_size) {\n            // ----- Error log\n            PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to go to the end of the archive \\'' . $this->zipname . '\\'');\n\n            // ----- Return\n            return PclZip::errorCode();\n        }\n\n        // ----- First try : look if this is an archive with no commentaries (most of the time)\n        // in this case the end of central dir is at 22 bytes of the file end\n        $v_found = 0;\n        if ($v_size > 26) {\n            @fseek($this->zip_fd, $v_size - 22);\n            if (($v_pos = @ftell($this->zip_fd)) != ($v_size - 22)) {\n                // ----- Error log\n                PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \\'' . $this->zipname . '\\'');\n\n                // ----- Return\n                return PclZip::errorCode();\n            }\n\n            // ----- Read for bytes\n            $v_binary_data = @fread($this->zip_fd, 4);\n            $v_data        = @unpack('Vid', $v_binary_data);\n\n            // ----- Check signature\n            if ($v_data['id'] == 0x06054b50) {\n                $v_found = 1;\n            }\n\n            $v_pos = ftell($this->zip_fd);\n        }\n\n        // ----- Go back to the maximum possible size of the Central Dir End Record\n        if (!$v_found) {\n            $v_maximum_size = 65557; // 0xFFFF + 22;\n            if ($v_maximum_size > $v_size) {\n                $v_maximum_size = $v_size;\n            }\n            @fseek($this->zip_fd, $v_size - $v_maximum_size);\n            if (@ftell($this->zip_fd) != ($v_size - $v_maximum_size)) {\n                // ----- Error log\n                PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \\'' . $this->zipname . '\\'');\n\n                // ----- Return\n                return PclZip::errorCode();\n            }\n\n            // ----- Read byte per byte in order to find the signature\n            $v_pos   = ftell($this->zip_fd);\n            $v_bytes = 0x00000000;\n            while ($v_pos < $v_size) {\n                // ----- Read a byte\n                $v_byte = @fread($this->zip_fd, 1);\n\n                // -----  Add the byte\n                //$v_bytes = ($v_bytes << 8) | Ord($v_byte);\n                // Note we mask the old value down such that once shifted we can never end up with more than a 32bit number\n                // Otherwise on systems where we have 64bit integers the check below for the magic number will fail.\n                $v_bytes = (($v_bytes & 0xFFFFFF) << 8) | ord($v_byte);\n\n                // ----- Compare the bytes\n                if ($v_bytes == 0x504b0506) {\n                    $v_pos++;\n                    break;\n                }\n\n                $v_pos++;\n            }\n\n            // ----- Look if not found end of central dir\n            if ($v_pos == $v_size) {\n\n                // ----- Error log\n                PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, \"Unable to find End of Central Dir Record signature\");\n\n                // ----- Return\n                return PclZip::errorCode();\n            }\n        }\n\n        // ----- Read the first 18 bytes of the header\n        $v_binary_data = fread($this->zip_fd, 18);\n\n        // ----- Look for invalid block size\n        if (strlen($v_binary_data) != 18) {\n\n            // ----- Error log\n            PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, \"Invalid End of Central Dir Record size : \" . strlen($v_binary_data));\n\n            // ----- Return\n            return PclZip::errorCode();\n        }\n\n        // ----- Extract the values\n        $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data);\n\n        // ----- Check the global size\n        if (($v_pos + $v_data['comment_size'] + 18) != $v_size) {\n\n            // ----- Removed in release 2.2 see readme file\n            // The check of the file size is a little too strict.\n            // Some bugs where found when a zip is encrypted/decrypted with 'crypt'.\n            // While decrypted, zip has training 0 bytes\n            if (0) {\n                // ----- Error log\n                PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'The central dir is not at the end of the archive.' . ' Some trailing bytes exists after the archive.');\n\n                // ----- Return\n                return PclZip::errorCode();\n            }\n        }\n\n        // ----- Get comment\n        if ($v_data['comment_size'] != 0) {\n            $p_central_dir['comment'] = fread($this->zip_fd, $v_data['comment_size']);\n        } else {\n            $p_central_dir['comment'] = '';\n        }\n\n        $p_central_dir['entries']      = $v_data['entries'];\n        $p_central_dir['disk_entries'] = $v_data['disk_entries'];\n        $p_central_dir['offset']       = $v_data['offset'];\n        $p_central_dir['size']         = $v_data['size'];\n        $p_central_dir['disk']         = $v_data['disk'];\n        $p_central_dir['disk_start']   = $v_data['disk_start'];\n\n        // TBC\n        //for (reset($p_central_dir); $key = key($p_central_dir); next($p_central_dir)) {\n        //}\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privDeleteByRule()\n    // Description :\n    // Parameters :\n    // Return Values :\n    // --------------------------------------------------------------------------------\n    public function privDeleteByRule(&$p_result_list, &$p_options)\n    {\n        $v_result      = 1;\n        $v_list_detail = array();\n\n        // ----- Open the zip file\n        if (($v_result = $this->privOpenFd('rb')) != 1) {\n            // ----- Return\n            return $v_result;\n        }\n\n        // ----- Read the central directory informations\n        $v_central_dir = array();\n        if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) {\n            $this->privCloseFd();\n\n            return $v_result;\n        }\n\n        // ----- Go to beginning of File\n        @rewind($this->zip_fd);\n\n        // ----- Scan all the files\n        // ----- Start at beginning of Central Dir\n        $v_pos_entry = $v_central_dir['offset'];\n        @rewind($this->zip_fd);\n        if (@fseek($this->zip_fd, $v_pos_entry)) {\n            // ----- Close the zip file\n            $this->privCloseFd();\n\n            // ----- Error log\n            PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');\n\n            // ----- Return\n            return PclZip::errorCode();\n        }\n\n        // ----- Read each entry\n        $v_header_list = array();\n        $j_start       = 0;\n        for ($i = 0, $v_nb_extracted = 0; $i < $v_central_dir['entries']; $i++) {\n\n            // ----- Read the file header\n            $v_header_list[$v_nb_extracted] = array();\n            if (($v_result = $this->privReadCentralFileHeader($v_header_list[$v_nb_extracted])) != 1) {\n                // ----- Close the zip file\n                $this->privCloseFd();\n\n                return $v_result;\n            }\n\n            // ----- Store the index\n            $v_header_list[$v_nb_extracted]['index'] = $i;\n\n            // ----- Look for the specific extract rules\n            $v_found = false;\n\n            // ----- Look for extract by name rule\n            if ((isset($p_options[PCLZIP_OPT_BY_NAME])) && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) {\n\n                // ----- Look if the filename is in the list\n                for ($j = 0; ($j < sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_found); $j++) {\n\n                    // ----- Look for a directory\n                    if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == \"/\") {\n\n                        // ----- Look if the directory is in the filename path\n                        if ((strlen($v_header_list[$v_nb_extracted]['stored_filename']) > strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) && (substr($v_header_list[$v_nb_extracted]['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) {\n                            $v_found = true;\n                        } elseif ((($v_header_list[$v_nb_extracted]['external'] & 0x00000010) == 0x00000010) /* Indicates a folder */ && ($v_header_list[$v_nb_extracted]['stored_filename'] . '/' == $p_options[PCLZIP_OPT_BY_NAME][$j])) {\n                            $v_found = true;\n                        }\n\n                    // ----- Look for a filename\n                    } elseif ($v_header_list[$v_nb_extracted]['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) {\n                        $v_found = true;\n                    }\n                }\n\n            // ----- Look for extract by preg rule\n            } elseif ((isset($p_options[PCLZIP_OPT_BY_PREG])) && ($p_options[PCLZIP_OPT_BY_PREG] != \"\")) {\n\n                if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header_list[$v_nb_extracted]['stored_filename'])) {\n                    $v_found = true;\n                }\n\n            // ----- Look for extract by index rule\n            } elseif ((isset($p_options[PCLZIP_OPT_BY_INDEX])) && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) {\n\n                // ----- Look if the index is in the list\n                for ($j = $j_start; ($j < sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_found); $j++) {\n\n                    if (($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i <= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) {\n                        $v_found = true;\n                    }\n                    if ($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) {\n                        $j_start = $j + 1;\n                    }\n\n                    if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start'] > $i) {\n                        break;\n                    }\n                }\n            } else {\n                $v_found = true;\n            }\n\n            // ----- Look for deletion\n            if ($v_found) {\n                unset($v_header_list[$v_nb_extracted]);\n            } else {\n                $v_nb_extracted++;\n            }\n        }\n\n        // ----- Look if something need to be deleted\n        if ($v_nb_extracted > 0) {\n\n            // ----- Creates a temporay file\n            $v_zip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.tmp';\n\n            // ----- Creates a temporary zip archive\n            $v_temp_zip = new PclZip($v_zip_temp_name);\n\n            // ----- Open the temporary zip file in write mode\n            if (($v_result = $v_temp_zip->privOpenFd('wb')) != 1) {\n                $this->privCloseFd();\n\n                // ----- Return\n                return $v_result;\n            }\n\n            // ----- Look which file need to be kept\n            for ($i = 0; $i < sizeof($v_header_list); $i++) {\n\n                // ----- Calculate the position of the header\n                @rewind($this->zip_fd);\n                if (@fseek($this->zip_fd, $v_header_list[$i]['offset'])) {\n                    // ----- Close the zip file\n                    $this->privCloseFd();\n                    $v_temp_zip->privCloseFd();\n                    @unlink($v_zip_temp_name);\n\n                    // ----- Error log\n                    PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');\n\n                    // ----- Return\n                    return PclZip::errorCode();\n                }\n\n                // ----- Read the file header\n                $v_local_header = array();\n                if (($v_result = $this->privReadFileHeader($v_local_header)) != 1) {\n                    // ----- Close the zip file\n                    $this->privCloseFd();\n                    $v_temp_zip->privCloseFd();\n                    @unlink($v_zip_temp_name);\n\n                    // ----- Return\n                    return $v_result;\n                }\n\n                // ----- Check that local file header is same as central file header\n                if ($this->privCheckFileHeaders($v_local_header, $v_header_list[$i]) != 1) {\n                    // TBC\n                }\n                unset($v_local_header);\n\n                // ----- Write the file header\n                if (($v_result = $v_temp_zip->privWriteFileHeader($v_header_list[$i])) != 1) {\n                    // ----- Close the zip file\n                    $this->privCloseFd();\n                    $v_temp_zip->privCloseFd();\n                    @unlink($v_zip_temp_name);\n\n                    // ----- Return\n                    return $v_result;\n                }\n\n                // ----- Read/write the data block\n                if (($v_result = PclZipUtilCopyBlock($this->zip_fd, $v_temp_zip->zip_fd, $v_header_list[$i]['compressed_size'])) != 1) {\n                    // ----- Close the zip file\n                    $this->privCloseFd();\n                    $v_temp_zip->privCloseFd();\n                    @unlink($v_zip_temp_name);\n\n                    // ----- Return\n                    return $v_result;\n                }\n            }\n\n            // ----- Store the offset of the central dir\n            $v_offset = @ftell($v_temp_zip->zip_fd);\n\n            // ----- Re-Create the Central Dir files header\n            for ($i = 0; $i < sizeof($v_header_list); $i++) {\n                // ----- Create the file header\n                if (($v_result = $v_temp_zip->privWriteCentralFileHeader($v_header_list[$i])) != 1) {\n                    $v_temp_zip->privCloseFd();\n                    $this->privCloseFd();\n                    @unlink($v_zip_temp_name);\n\n                    // ----- Return\n                    return $v_result;\n                }\n\n                // ----- Transform the header to a 'usable' info\n                $v_temp_zip->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);\n            }\n\n            // ----- Zip file comment\n            $v_comment = '';\n            if (isset($p_options[PCLZIP_OPT_COMMENT])) {\n                $v_comment = $p_options[PCLZIP_OPT_COMMENT];\n            }\n\n            // ----- Calculate the size of the central header\n            $v_size = @ftell($v_temp_zip->zip_fd) - $v_offset;\n\n            // ----- Create the central dir footer\n            if (($v_result = $v_temp_zip->privWriteCentralHeader(sizeof($v_header_list), $v_size, $v_offset, $v_comment)) != 1) {\n                // ----- Reset the file list\n                unset($v_header_list);\n                $v_temp_zip->privCloseFd();\n                $this->privCloseFd();\n                @unlink($v_zip_temp_name);\n\n                // ----- Return\n                return $v_result;\n            }\n\n            // ----- Close\n            $v_temp_zip->privCloseFd();\n            $this->privCloseFd();\n\n            // ----- Delete the zip file\n            // TBC : I should test the result ...\n            @unlink($this->zipname);\n\n            // ----- Rename the temporary file\n            // TBC : I should test the result ...\n            //@rename($v_zip_temp_name, $this->zipname);\n            PclZipUtilRename($v_zip_temp_name, $this->zipname);\n\n            // ----- Destroy the temporary archive\n            unset($v_temp_zip);\n\n        // ----- Remove every files : reset the file\n        } elseif ($v_central_dir['entries'] != 0) {\n            $this->privCloseFd();\n\n            if (($v_result = $this->privOpenFd('wb')) != 1) {\n                return $v_result;\n            }\n\n            if (($v_result = $this->privWriteCentralHeader(0, 0, 0, '')) != 1) {\n                return $v_result;\n            }\n\n            $this->privCloseFd();\n        }\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privDirCheck()\n    // Description :\n    //   Check if a directory exists, if not it creates it and all the parents directory\n    //   which may be useful.\n    // Parameters :\n    //   $p_dir : Directory path to check.\n    // Return Values :\n    //    1 : OK\n    //   -1 : Unable to create directory\n    // --------------------------------------------------------------------------------\n    public function privDirCheck($p_dir, $p_is_dir = false)\n    {\n        $v_result = 1;\n\n        // ----- Remove the final '/'\n        if (($p_is_dir) && (substr($p_dir, -1) == '/')) {\n            $p_dir = substr($p_dir, 0, strlen($p_dir) - 1);\n        }\n\n        // ----- Check the directory availability\n        if ((is_dir($p_dir)) || ($p_dir == \"\")) {\n            return 1;\n        }\n\n        // ----- Extract parent directory\n        $p_parent_dir = dirname($p_dir);\n\n        // ----- Just a check\n        if ($p_parent_dir != $p_dir) {\n            // ----- Look for parent directory\n            if ($p_parent_dir != \"\") {\n                if (($v_result = $this->privDirCheck($p_parent_dir)) != 1) {\n                    return $v_result;\n                }\n            }\n        }\n\n        // ----- Create the directory\n        if (!@mkdir($p_dir, 0777)) {\n            // ----- Error log\n            PclZip::privErrorLog(PCLZIP_ERR_DIR_CREATE_FAIL, \"Unable to create directory '$p_dir'\");\n\n            // ----- Return\n            return PclZip::errorCode();\n        }\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privMerge()\n    // Description :\n    //   If $p_archive_to_add does not exist, the function exit with a success result.\n    // Parameters :\n    // Return Values :\n    // --------------------------------------------------------------------------------\n    public function privMerge(&$p_archive_to_add)\n    {\n        $v_result = 1;\n\n        // ----- Look if the archive_to_add exists\n        if (!is_file($p_archive_to_add->zipname)) {\n\n            // ----- Nothing to merge, so merge is a success\n            $v_result = 1;\n\n            // ----- Return\n            return $v_result;\n        }\n\n        // ----- Look if the archive exists\n        if (!is_file($this->zipname)) {\n\n            // ----- Do a duplicate\n            $v_result = $this->privDuplicate($p_archive_to_add->zipname);\n\n            // ----- Return\n            return $v_result;\n        }\n\n        // ----- Open the zip file\n        if (($v_result = $this->privOpenFd('rb')) != 1) {\n            // ----- Return\n            return $v_result;\n        }\n\n        // ----- Read the central directory informations\n        $v_central_dir = array();\n        if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) {\n            $this->privCloseFd();\n\n            return $v_result;\n        }\n\n        // ----- Go to beginning of File\n        @rewind($this->zip_fd);\n\n        // ----- Open the archive_to_add file\n        if (($v_result = $p_archive_to_add->privOpenFd('rb')) != 1) {\n            $this->privCloseFd();\n\n            // ----- Return\n            return $v_result;\n        }\n\n        // ----- Read the central directory informations\n        $v_central_dir_to_add = array();\n        if (($v_result = $p_archive_to_add->privReadEndCentralDir($v_central_dir_to_add)) != 1) {\n            $this->privCloseFd();\n            $p_archive_to_add->privCloseFd();\n\n            return $v_result;\n        }\n\n        // ----- Go to beginning of File\n        @rewind($p_archive_to_add->zip_fd);\n\n        // ----- Creates a temporay file\n        $v_zip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.tmp';\n\n        // ----- Open the temporary file in write mode\n        if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) {\n            $this->privCloseFd();\n            $p_archive_to_add->privCloseFd();\n\n            PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \\'' . $v_zip_temp_name . '\\' in binary write mode');\n\n            // ----- Return\n            return PclZip::errorCode();\n        }\n\n        // ----- Copy the files from the archive to the temporary file\n        // TBC : Here I should better append the file and go back to erase the central dir\n        $v_size = $v_central_dir['offset'];\n        while ($v_size != 0) {\n            $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);\n            $v_buffer    = fread($this->zip_fd, $v_read_size);\n            @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);\n            $v_size -= $v_read_size;\n        }\n\n        // ----- Copy the files from the archive_to_add into the temporary file\n        $v_size = $v_central_dir_to_add['offset'];\n        while ($v_size != 0) {\n            $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);\n            $v_buffer    = fread($p_archive_to_add->zip_fd, $v_read_size);\n            @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);\n            $v_size -= $v_read_size;\n        }\n\n        // ----- Store the offset of the central dir\n        $v_offset = @ftell($v_zip_temp_fd);\n\n        // ----- Copy the block of file headers from the old archive\n        $v_size = $v_central_dir['size'];\n        while ($v_size != 0) {\n            $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);\n            $v_buffer    = @fread($this->zip_fd, $v_read_size);\n            @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);\n            $v_size -= $v_read_size;\n        }\n\n        // ----- Copy the block of file headers from the archive_to_add\n        $v_size = $v_central_dir_to_add['size'];\n        while ($v_size != 0) {\n            $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);\n            $v_buffer    = @fread($p_archive_to_add->zip_fd, $v_read_size);\n            @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);\n            $v_size -= $v_read_size;\n        }\n\n        // ----- Merge the file comments\n        $v_comment = $v_central_dir['comment'] . ' ' . $v_central_dir_to_add['comment'];\n\n        // ----- Calculate the size of the (new) central header\n        $v_size = @ftell($v_zip_temp_fd) - $v_offset;\n\n        // ----- Swap the file descriptor\n        // Here is a trick : I swap the temporary fd with the zip fd, in order to use\n        // the following methods on the temporary fil and not the real archive fd\n        $v_swap        = $this->zip_fd;\n        $this->zip_fd  = $v_zip_temp_fd;\n        $v_zip_temp_fd = $v_swap;\n\n        // ----- Create the central dir footer\n        if (($v_result = $this->privWriteCentralHeader($v_central_dir['entries'] + $v_central_dir_to_add['entries'], $v_size, $v_offset, $v_comment)) != 1) {\n            $this->privCloseFd();\n            $p_archive_to_add->privCloseFd();\n            @fclose($v_zip_temp_fd);\n            $this->zip_fd = null;\n\n            // ----- Reset the file list\n            unset($v_header_list);\n\n            // ----- Return\n            return $v_result;\n        }\n\n        // ----- Swap back the file descriptor\n        $v_swap        = $this->zip_fd;\n        $this->zip_fd  = $v_zip_temp_fd;\n        $v_zip_temp_fd = $v_swap;\n\n        // ----- Close\n        $this->privCloseFd();\n        $p_archive_to_add->privCloseFd();\n\n        // ----- Close the temporary file\n        @fclose($v_zip_temp_fd);\n\n        // ----- Delete the zip file\n        // TBC : I should test the result ...\n        @unlink($this->zipname);\n\n        // ----- Rename the temporary file\n        // TBC : I should test the result ...\n        //@rename($v_zip_temp_name, $this->zipname);\n        PclZipUtilRename($v_zip_temp_name, $this->zipname);\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privDuplicate()\n    // Description :\n    // Parameters :\n    // Return Values :\n    // --------------------------------------------------------------------------------\n    public function privDuplicate($p_archive_filename)\n    {\n        $v_result = 1;\n\n        // ----- Look if the $p_archive_filename exists\n        if (!is_file($p_archive_filename)) {\n\n            // ----- Nothing to duplicate, so duplicate is a success.\n            $v_result = 1;\n\n            // ----- Return\n            return $v_result;\n        }\n\n        // ----- Open the zip file\n        if (($v_result = $this->privOpenFd('wb')) != 1) {\n            // ----- Return\n            return $v_result;\n        }\n\n        // ----- Open the temporary file in write mode\n        if (($v_zip_temp_fd = @fopen($p_archive_filename, 'rb')) == 0) {\n            $this->privCloseFd();\n\n            PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive file \\'' . $p_archive_filename . '\\' in binary write mode');\n\n            // ----- Return\n            return PclZip::errorCode();\n        }\n\n        // ----- Copy the files from the archive to the temporary file\n        // TBC : Here I should better append the file and go back to erase the central dir\n        $v_size = filesize($p_archive_filename);\n        while ($v_size != 0) {\n            $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);\n            $v_buffer    = fread($v_zip_temp_fd, $v_read_size);\n            @fwrite($this->zip_fd, $v_buffer, $v_read_size);\n            $v_size -= $v_read_size;\n        }\n\n        // ----- Close\n        $this->privCloseFd();\n\n        // ----- Close the temporary file\n        @fclose($v_zip_temp_fd);\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privErrorLog()\n    // Description :\n    // Parameters :\n    // --------------------------------------------------------------------------------\n    public function privErrorLog($p_error_code = 0, $p_error_string = '')\n    {\n        if (PCLZIP_ERROR_EXTERNAL == 1) {\n            PclError($p_error_code, $p_error_string);\n        } else {\n            $this->error_code   = $p_error_code;\n            $this->error_string = $p_error_string;\n        }\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privErrorReset()\n    // Description :\n    // Parameters :\n    // --------------------------------------------------------------------------------\n    public function privErrorReset()\n    {\n        if (PCLZIP_ERROR_EXTERNAL == 1) {\n            PclErrorReset();\n        } else {\n            $this->error_code   = 0;\n            $this->error_string = '';\n        }\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privDisableMagicQuotes()\n    // Description :\n    // Parameters :\n    // Return Values :\n    // --------------------------------------------------------------------------------\n    public function privDisableMagicQuotes()\n    {\n        $v_result = 1;\n\n        // ----- Look if function exists\n        if ((!function_exists(\"get_magic_quotes_runtime\")) || (!function_exists(\"set_magic_quotes_runtime\"))) {\n            return $v_result;\n        }\n\n        // ----- Look if already done\n        if ($this->magic_quotes_status != -1) {\n            return $v_result;\n        }\n\n        // ----- Get and memorize the magic_quote value\n        $this->magic_quotes_status = @get_magic_quotes_runtime();\n\n        // ----- Disable magic_quotes\n        if ($this->magic_quotes_status == 1) {\n            @set_magic_quotes_runtime(0);\n        }\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n\n    // --------------------------------------------------------------------------------\n    // Function : privSwapBackMagicQuotes()\n    // Description :\n    // Parameters :\n    // Return Values :\n    // --------------------------------------------------------------------------------\n    public function privSwapBackMagicQuotes()\n    {\n        $v_result = 1;\n\n        // ----- Look if function exists\n        if ((!function_exists(\"get_magic_quotes_runtime\")) || (!function_exists(\"set_magic_quotes_runtime\"))) {\n            return $v_result;\n        }\n\n        // ----- Look if something to do\n        if ($this->magic_quotes_status != -1) {\n            return $v_result;\n        }\n\n        // ----- Swap back magic_quotes\n        if ($this->magic_quotes_status == 1) {\n            @set_magic_quotes_runtime($this->magic_quotes_status);\n        }\n\n        // ----- Return\n        return $v_result;\n    }\n    // --------------------------------------------------------------------------------\n}\n\n// End of class\n// --------------------------------------------------------------------------------\n\n// --------------------------------------------------------------------------------\n// Function : PclZipUtilPathReduction()\n// Description :\n// Parameters :\n// Return Values :\n// --------------------------------------------------------------------------------\nfunction PclZipUtilPathReduction($p_dir)\n{\n    $v_result = \"\";\n\n    // ----- Look for not empty path\n    if ($p_dir != \"\") {\n        // ----- Explode path by directory names\n        $v_list = explode(\"/\", $p_dir);\n\n        // ----- Study directories from last to first\n        $v_skip = 0;\n        for ($i = sizeof($v_list) - 1; $i >= 0; $i--) {\n            // ----- Look for current path\n            if ($v_list[$i] == \".\") {\n                // ----- Ignore this directory\n                // Should be the first $i=0, but no check is done\n            } elseif ($v_list[$i] == \"..\") {\n                $v_skip++;\n            } elseif ($v_list[$i] == \"\") {\n                // ----- First '/' i.e. root slash\n                if ($i == 0) {\n                    $v_result = \"/\" . $v_result;\n                    if ($v_skip > 0) {\n                        // ----- It is an invalid path, so the path is not modified\n                        // TBC\n                        $v_result = $p_dir;\n                        $v_skip   = 0;\n                    }\n\n                // ----- Last '/' i.e. indicates a directory\n                } elseif ($i == (sizeof($v_list) - 1)) {\n                    $v_result = $v_list[$i];\n\n                // ----- Double '/' inside the path\n                } else {\n                    // ----- Ignore only the double '//' in path,\n                    // but not the first and last '/'\n                }\n            } else {\n                // ----- Look for item to skip\n                if ($v_skip > 0) {\n                    $v_skip--;\n                } else {\n                    $v_result = $v_list[$i] . ($i != (sizeof($v_list) - 1) ? \"/\" . $v_result : \"\");\n                }\n            }\n        }\n\n        // ----- Look for skip\n        if ($v_skip > 0) {\n            while ($v_skip > 0) {\n                $v_result = '../' . $v_result;\n                $v_skip--;\n            }\n        }\n    }\n\n    // ----- Return\n    return $v_result;\n}\n// --------------------------------------------------------------------------------\n\n// --------------------------------------------------------------------------------\n// Function : PclZipUtilPathInclusion()\n// Description :\n//   This function indicates if the path $p_path is under the $p_dir tree. Or,\n//   said in an other way, if the file or sub-dir $p_path is inside the dir\n//   $p_dir.\n//   The function indicates also if the path is exactly the same as the dir.\n//   This function supports path with duplicated '/' like '//', but does not\n//   support '.' or '..' statements.\n// Parameters :\n// Return Values :\n//   0 if $p_path is not inside directory $p_dir\n//   1 if $p_path is inside directory $p_dir\n//   2 if $p_path is exactly the same as $p_dir\n// --------------------------------------------------------------------------------\nfunction PclZipUtilPathInclusion($p_dir, $p_path)\n{\n    $v_result = 1;\n\n    // ----- Look for path beginning by ./\n    if (($p_dir == '.') || ((strlen($p_dir) >= 2) && (substr($p_dir, 0, 2) == './'))) {\n        $p_dir = PclZipUtilTranslateWinPath(getcwd(), false) . '/' . substr($p_dir, 1);\n    }\n    if (($p_path == '.') || ((strlen($p_path) >= 2) && (substr($p_path, 0, 2) == './'))) {\n        $p_path = PclZipUtilTranslateWinPath(getcwd(), false) . '/' . substr($p_path, 1);\n    }\n\n    // ----- Explode dir and path by directory separator\n    $v_list_dir       = explode(\"/\", $p_dir);\n    $v_list_dir_size  = sizeof($v_list_dir);\n    $v_list_path      = explode(\"/\", $p_path);\n    $v_list_path_size = sizeof($v_list_path);\n\n    // ----- Study directories paths\n    $i = 0;\n    $j = 0;\n    while (($i < $v_list_dir_size) && ($j < $v_list_path_size) && ($v_result)) {\n\n        // ----- Look for empty dir (path reduction)\n        if ($v_list_dir[$i] == '') {\n            $i++;\n            continue;\n        }\n        if ($v_list_path[$j] == '') {\n            $j++;\n            continue;\n        }\n\n        // ----- Compare the items\n        if (($v_list_dir[$i] != $v_list_path[$j]) && ($v_list_dir[$i] != '') && ($v_list_path[$j] != '')) {\n            $v_result = 0;\n        }\n\n        // ----- Next items\n        $i++;\n        $j++;\n    }\n\n    // ----- Look if everything seems to be the same\n    if ($v_result) {\n        // ----- Skip all the empty items\n        while (($j < $v_list_path_size) && ($v_list_path[$j] == '')) {\n            $j++;\n        }\n        while (($i < $v_list_dir_size) && ($v_list_dir[$i] == '')) {\n            $i++;\n        }\n\n        if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) {\n            // ----- There are exactly the same\n            $v_result = 2;\n        } elseif ($i < $v_list_dir_size) {\n            // ----- The path is shorter than the dir\n            $v_result = 0;\n        }\n    }\n\n    // ----- Return\n    return $v_result;\n}\n// --------------------------------------------------------------------------------\n\n// --------------------------------------------------------------------------------\n// Function : PclZipUtilCopyBlock()\n// Description :\n// Parameters :\n//   $p_mode : read/write compression mode\n//             0 : src & dest normal\n//             1 : src gzip, dest normal\n//             2 : src normal, dest gzip\n//             3 : src & dest gzip\n// Return Values :\n// --------------------------------------------------------------------------------\nfunction PclZipUtilCopyBlock($p_src, $p_dest, $p_size, $p_mode = 0)\n{\n    $v_result = 1;\n\n    if ($p_mode == 0) {\n        while ($p_size != 0) {\n            $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);\n            $v_buffer    = @fread($p_src, $v_read_size);\n            @fwrite($p_dest, $v_buffer, $v_read_size);\n            $p_size -= $v_read_size;\n        }\n    } elseif ($p_mode == 1) {\n        while ($p_size != 0) {\n            $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);\n            $v_buffer    = @gzread($p_src, $v_read_size);\n            @fwrite($p_dest, $v_buffer, $v_read_size);\n            $p_size -= $v_read_size;\n        }\n    } elseif ($p_mode == 2) {\n        while ($p_size != 0) {\n            $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);\n            $v_buffer    = @fread($p_src, $v_read_size);\n            @gzwrite($p_dest, $v_buffer, $v_read_size);\n            $p_size -= $v_read_size;\n        }\n    } elseif ($p_mode == 3) {\n        while ($p_size != 0) {\n            $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE);\n            $v_buffer    = @gzread($p_src, $v_read_size);\n            @gzwrite($p_dest, $v_buffer, $v_read_size);\n            $p_size -= $v_read_size;\n        }\n    }\n\n    // ----- Return\n    return $v_result;\n}\n// --------------------------------------------------------------------------------\n\n// --------------------------------------------------------------------------------\n// Function : PclZipUtilRename()\n// Description :\n//   This function tries to do a simple rename() function. If it fails, it\n//   tries to copy the $p_src file in a new $p_dest file and then unlink the\n//   first one.\n// Parameters :\n//   $p_src : Old filename\n//   $p_dest : New filename\n// Return Values :\n//   1 on success, 0 on failure.\n// --------------------------------------------------------------------------------\nfunction PclZipUtilRename($p_src, $p_dest)\n{\n    $v_result = 1;\n\n    // ----- Try to rename the files\n    if (!@rename($p_src, $p_dest)) {\n\n        // ----- Try to copy & unlink the src\n        if (!@copy($p_src, $p_dest)) {\n            $v_result = 0;\n        } elseif (!@unlink($p_src)) {\n            $v_result = 0;\n        }\n    }\n\n    // ----- Return\n    return $v_result;\n}\n// --------------------------------------------------------------------------------\n\n// --------------------------------------------------------------------------------\n// Function : PclZipUtilOptionText()\n// Description :\n//   Translate option value in text. Mainly for debug purpose.\n// Parameters :\n//   $p_option : the option value.\n// Return Values :\n//   The option text value.\n// --------------------------------------------------------------------------------\nfunction PclZipUtilOptionText($p_option)\n{\n\n    $v_list = get_defined_constants();\n    for (reset($v_list); $v_key = key($v_list); next($v_list)) {\n        $v_prefix = substr($v_key, 0, 10);\n        if ((($v_prefix == 'PCLZIP_OPT') || ($v_prefix == 'PCLZIP_CB_') || ($v_prefix == 'PCLZIP_ATT')) && ($v_list[$v_key] == $p_option)) {\n            return $v_key;\n        }\n    }\n\n    $v_result = 'Unknown';\n\n    return $v_result;\n}\n// --------------------------------------------------------------------------------\n\n// --------------------------------------------------------------------------------\n// Function : PclZipUtilTranslateWinPath()\n// Description :\n//   Translate windows path by replacing '\\' by '/' and optionally removing\n//   drive letter.\n// Parameters :\n//   $p_path : path to translate.\n//   $p_remove_disk_letter : true | false\n// Return Values :\n//   The path translated.\n// --------------------------------------------------------------------------------\nfunction PclZipUtilTranslateWinPath($p_path, $p_remove_disk_letter = true)\n{\n    if (stristr(php_uname(), 'windows')) {\n        // ----- Look for potential disk letter\n        if (($p_remove_disk_letter) && (($v_position = strpos($p_path, ':')) != false)) {\n            $p_path = substr($p_path, $v_position + 1);\n        }\n        // ----- Change potential windows directory separator\n        if ((strpos($p_path, '\\\\') > 0) || (substr($p_path, 0, 1) == '\\\\')) {\n            $p_path = strtr($p_path, '\\\\', '/');\n        }\n    }\n\n    return $p_path;\n}\n// --------------------------------------------------------------------------------\n"
  },
  {
    "path": "src/PhpWord/Shared/Text.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Shared;\n\nuse PhpOffice\\PhpWord\\Exception\\Exception;\n\n/**\n * Text.\n */\nclass Text\n{\n    /**\n     * Control characters array.\n     *\n     * @var string[]\n     */\n    private static $controlCharacters = [];\n\n    /**\n     * Build control characters array.\n     */\n    private static function buildControlCharacters(): void\n    {\n        for ($i = 0; $i <= 19; ++$i) {\n            if ($i != 9 && $i != 10 && $i != 13) {\n                $find = '_x' . sprintf('%04s', strtoupper(dechex($i))) . '_';\n                $replace = chr($i);\n                self::$controlCharacters[$find] = $replace;\n            }\n        }\n    }\n\n    /**\n     * Convert from PHP control character to OpenXML escaped control character.\n     *\n     * Excel 2007 team:\n     * ----------------\n     * That's correct, control characters are stored directly in the shared-strings table.\n     * We do encode characters that cannot be represented in XML using the following escape sequence:\n     * _xHHHH_ where H represents a hexadecimal character in the character's value...\n     * So you could end up with something like _x0008_ in a string (either in a cell value (<v>)\n     * element or in the shared string <t> element.\n     *\n     * @param  string $value Value to escape\n     *\n     * @return string\n     */\n    public static function controlCharacterPHP2OOXML($value = '')\n    {\n        if (empty(self::$controlCharacters)) {\n            self::buildControlCharacters();\n        }\n\n        return str_replace(array_values(self::$controlCharacters), array_keys(self::$controlCharacters), $value);\n    }\n\n    /**\n     * Return a number formatted for being integrated in xml files.\n     *\n     * @param float $number\n     * @param int $decimals\n     *\n     * @return string\n     */\n    public static function numberFormat($number, $decimals)\n    {\n        return number_format($number, $decimals, '.', '');\n    }\n\n    /**\n     * @param int $dec\n     *\n     * @see http://stackoverflow.com/a/7153133/2235790\n     *\n     * @author velcrow\n     *\n     * @return string\n     */\n    public static function chr($dec)\n    {\n        if ($dec <= 0x7F) {\n            return chr($dec);\n        }\n        if ($dec <= 0x7FF) {\n            return chr(($dec >> 6) + 192) . chr(($dec & 63) + 128);\n        }\n        if ($dec <= 0xFFFF) {\n            return chr(($dec >> 12) + 224) . chr((($dec >> 6) & 63) + 128) . chr(($dec & 63) + 128);\n        }\n        if ($dec <= 0x1FFFFF) {\n            return chr(($dec >> 18) + 240) . chr((($dec >> 12) & 63) + 128) . chr((($dec >> 6) & 63) + 128) . chr(($dec & 63) + 128);\n        }\n\n        return '';\n    }\n\n    /**\n     * Convert from OpenXML escaped control character to PHP control character.\n     *\n     * @param string $value Value to unescape\n     *\n     * @return string\n     */\n    public static function controlCharacterOOXML2PHP($value = '')\n    {\n        if (empty(self::$controlCharacters)) {\n            self::buildControlCharacters();\n        }\n\n        return str_replace(array_keys(self::$controlCharacters), array_values(self::$controlCharacters), $value);\n    }\n\n    /**\n     * Check if a string contains UTF-8 data.\n     *\n     * @param string $value\n     *\n     * @return bool\n     */\n    public static function isUTF8($value = '')\n    {\n        return is_string($value) && ($value === '' || preg_match('/^./su', $value) == 1);\n    }\n\n    /**\n     * Return UTF8 encoded value.\n     *\n     * @param null|string $value\n     *\n     * @return ?string\n     */\n    public static function toUTF8($value = '')\n    {\n        if (null !== $value && !self::isUTF8($value)) {\n            // PHP8.2 : utf8_encode is deprecated, but mb_convert_encoding always usable\n            $value = (function_exists('mb_convert_encoding')) ? mb_convert_encoding($value, 'UTF-8', 'ISO-8859-1') : utf8_encode($value);\n            if ($value === false) {\n                throw new Exception('Unable to convert text to UTF-8');\n            }\n        }\n\n        return $value;\n    }\n\n    /**\n     * Returns unicode from UTF8 text.\n     *\n     * The function is splitted to reduce cyclomatic complexity\n     *\n     * @param string $text UTF8 text\n     *\n     * @return string Unicode text\n     *\n     * @since 0.11.0\n     */\n    public static function toUnicode($text)\n    {\n        return self::unicodeToEntities(self::utf8ToUnicode($text));\n    }\n\n    /**\n     * Returns unicode array from UTF8 text.\n     *\n     * @param string $text UTF8 text\n     *\n     * @return array\n     *\n     * @since 0.11.0\n     * @see http://www.randomchaos.com/documents/?source=php_and_unicode\n     */\n    public static function utf8ToUnicode($text)\n    {\n        $unicode = [];\n        $values = [];\n        $lookingFor = 1;\n\n        // Gets unicode for each character\n        for ($i = 0; $i < strlen($text); ++$i) {\n            $thisValue = ord($text[$i]);\n            if ($thisValue < 128) {\n                $unicode[] = $thisValue;\n            } else {\n                if (count($values) == 0) {\n                    $lookingFor = $thisValue < 224 ? 2 : 3;\n                }\n                $values[] = $thisValue;\n                if (count($values) == $lookingFor) {\n                    if ($lookingFor == 3) {\n                        $number = (($values[0] % 16) * 4096) + (($values[1] % 64) * 64) + ($values[2] % 64);\n                    } else {\n                        $number = (($values[0] % 32) * 64) + ($values[1] % 64);\n                    }\n                    $unicode[] = $number;\n                    $values = [];\n                    $lookingFor = 1;\n                }\n            }\n        }\n\n        return $unicode;\n    }\n\n    /**\n     * Returns entites from unicode array.\n     *\n     * @param array $unicode\n     *\n     * @return string\n     *\n     * @since 0.11.0\n     * @see http://www.randomchaos.com/documents/?source=php_and_unicode\n     */\n    private static function unicodeToEntities($unicode)\n    {\n        $entities = '';\n\n        foreach ($unicode as $value) {\n            if ($value != 65279) {\n                $entities .= $value > 127 ? '\\uc0{\\u' . $value . '}' : chr($value);\n            }\n        }\n\n        return $entities;\n    }\n\n    /**\n     * Return name without underscore for < 0.10.0 variable name compatibility.\n     *\n     * @param string $value\n     *\n     * @return string\n     */\n    public static function removeUnderscorePrefix($value)\n    {\n        if (null !== $value) {\n            if (substr($value, 0, 1) == '_') {\n                $value = substr($value, 1);\n            }\n        }\n\n        return $value;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Shared/Validate.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\ndeclare(strict_types=1);\n\nnamespace PhpOffice\\PhpWord\\Shared;\n\nclass Validate\n{\n    public const CSS_WHITESPACE = [\n        'pre-wrap',\n        'normal',\n        'nowrap',\n        'pre',\n        'pre-line',\n        'initial',\n        'inherit',\n    ];\n\n    public const CSS_GENERICFONT = [\n        'serif',\n        'sans-serif',\n        'monospace',\n        'cursive',\n        'fantasy',\n        'system-ui',\n        'math',\n        'emoji',\n        'fangsong',\n    ];\n\n    /**\n     * Validate html css white-space value. It is expected that only pre-wrap and normal (default) are useful.\n     *\n     * @param string $value CSS White space\n     *\n     * @return string value if valid, empty string if not\n     */\n    public static function validateCSSWhiteSpace(?string $value): string\n    {\n        if (in_array($value, self::CSS_WHITESPACE)) {\n            return $value;\n        }\n\n        return '';\n    }\n\n    /**\n     * Validate generic font for fallback for html.\n     *\n     * @param string $value Generic font name\n     *\n     * @return string Value if legitimate, empty string if not\n     */\n    public static function validateCSSGenericFont(?string $value): string\n    {\n        if (in_array($value, self::CSS_GENERICFONT)) {\n            return $value;\n        }\n\n        return '';\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Shared/XMLReader.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Shared;\n\nuse DOMDocument;\nuse DOMElement;\nuse DOMNodeList;\nuse DOMXpath;\nuse Exception;\nuse InvalidArgumentException;\nuse ZipArchive;\n\n/**\n * XML Reader wrapper.\n *\n * @since   0.2.1\n */\nclass XMLReader\n{\n    /**\n     * DOMDocument object.\n     *\n     * @var DOMDocument\n     */\n    private $dom;\n\n    /**\n     * DOMXpath object.\n     *\n     * @var DOMXpath\n     */\n    private $xpath;\n\n    /**\n     * Get DOMDocument from ZipArchive.\n     *\n     * @param string $zipFile\n     * @param string $xmlFile\n     *\n     * @return DOMDocument|false\n     */\n    public function getDomFromZip($zipFile, $xmlFile)\n    {\n        if (file_exists($zipFile) === false) {\n            throw new Exception('Cannot find archive file.');\n        }\n\n        $zip = new ZipArchive();\n        $openStatus = $zip->open($zipFile);\n        if ($openStatus !== true) {\n            /**\n             * Throw an exception since making further calls on the ZipArchive would cause a fatal error.\n             * This prevents fatal errors on corrupt archives and attempts to open old \"doc\" files.\n             */\n            throw new Exception(\"The archive failed to load with the following error code: $openStatus\");\n        }\n\n        $content = $zip->getFromName(ltrim($xmlFile, '/'));\n        $zip->close();\n\n        if ($content === false) {\n            return false;\n        }\n\n        return $this->getDomFromString($content);\n    }\n\n    /**\n     * Get DOMDocument from content string.\n     *\n     * @param string $content\n     *\n     * @return DOMDocument\n     */\n    public function getDomFromString($content)\n    {\n        if (\\PHP_VERSION_ID < 80000) {\n            $originalLibXMLEntityValue = libxml_disable_entity_loader(true);\n        }\n        $this->dom = new DOMDocument();\n        $this->dom->loadXML($content);\n        if (\\PHP_VERSION_ID < 80000) {\n            libxml_disable_entity_loader($originalLibXMLEntityValue);\n        }\n\n        return $this->dom;\n    }\n\n    /**\n     * Get elements.\n     *\n     * @param string $path\n     *\n     * @return DOMNodeList<DOMElement>\n     */\n    public function getElements($path, ?DOMElement $contextNode = null)\n    {\n        if ($this->dom === null) {\n            return new DOMNodeList(); // @phpstan-ignore-line\n        }\n        if ($this->xpath === null) {\n            $this->xpath = new DOMXpath($this->dom);\n        }\n\n        $result = @$this->xpath->query($path, $contextNode);\n\n        return empty($result) ? new DOMNodeList() : $result; // @phpstan-ignore-line\n    }\n\n    /**\n     * Registers the namespace with the DOMXPath object.\n     *\n     * @param string $prefix The prefix\n     * @param string $namespaceURI The URI of the namespace\n     *\n     * @return bool true on success or false on failure\n     */\n    public function registerNamespace($prefix, $namespaceURI)\n    {\n        if ($this->dom === null) {\n            throw new InvalidArgumentException('Dom needs to be loaded before registering a namespace');\n        }\n        if ($this->xpath === null) {\n            $this->xpath = new DOMXpath($this->dom);\n        }\n\n        return $this->xpath->registerNamespace($prefix, $namespaceURI);\n    }\n\n    /**\n     * Get element.\n     *\n     * @param string $path\n     *\n     * @return null|DOMElement\n     */\n    public function getElement($path, ?DOMElement $contextNode = null)\n    {\n        $elements = $this->getElements($path, $contextNode);\n        if ($elements->length > 0) {\n            return $elements->item(0);\n        }\n\n        return null;\n    }\n\n    /**\n     * Get element attribute.\n     *\n     * @param string $attribute\n     * @param string $path\n     *\n     * @return null|string\n     */\n    public function getAttribute($attribute, ?DOMElement $contextNode = null, $path = null)\n    {\n        $return = null;\n        if ($path !== null) {\n            $elements = $this->getElements($path, $contextNode);\n            if ($elements->length > 0) {\n                /** @var DOMElement $node Type hint */\n                $node = $elements->item(0);\n                $return = $node->getAttribute($attribute);\n            }\n        } else {\n            if ($contextNode !== null) {\n                $return = $contextNode->getAttribute($attribute);\n            }\n        }\n\n        return ($return == '') ? null : $return;\n    }\n\n    /**\n     * Get element value.\n     *\n     * @param string $path\n     *\n     * @return null|string\n     */\n    public function getValue($path, ?DOMElement $contextNode = null)\n    {\n        $elements = $this->getElements($path, $contextNode);\n        if ($elements->length > 0) {\n            return $elements->item(0)->nodeValue;\n        }\n\n        return null;\n    }\n\n    /**\n     * Count elements.\n     *\n     * @param string $path\n     *\n     * @return int\n     */\n    public function countElements($path, ?DOMElement $contextNode = null)\n    {\n        $elements = $this->getElements($path, $contextNode);\n\n        return $elements->length;\n    }\n\n    /**\n     * Element exists.\n     *\n     * @param string $path\n     *\n     * @return bool\n     */\n    public function elementExists($path, ?DOMElement $contextNode = null)\n    {\n        return $this->getElements($path, $contextNode)->length > 0;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Shared/XMLWriter.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Shared;\n\nuse Exception;\n\n/**\n * XMLWriter.\n *\n * @method bool endElement()\n * @method mixed flush(bool $empty = null)\n * @method bool openMemory()\n * @method string outputMemory(bool $flush = null)\n * @method bool setIndent(bool $indent)\n * @method bool startDocument(string $version = 1.0, string $encoding = null, string $standalone = null)\n * @method bool startElement(string $name)\n * @method bool text(string $content)\n * @method bool writeCData(string $content)\n * @method bool writeComment(string $content)\n * @method bool writeElement(string $name, string $content = null)\n * @method bool writeRaw(string $content)\n */\nclass XMLWriter extends \\XMLWriter\n{\n    /** Temporary storage method */\n    const STORAGE_MEMORY = 1;\n    const STORAGE_DISK = 2;\n\n    /**\n     * Temporary filename.\n     *\n     * @var string\n     */\n    private $tempFileName = '';\n\n    /**\n     * Create a new \\PhpOffice\\PhpWord\\Shared\\XMLWriter instance.\n     *\n     * @param int $pTemporaryStorage Temporary storage location\n     * @param string $pTemporaryStorageDir Temporary storage folder\n     * @param bool $compatibility\n     */\n    public function __construct($pTemporaryStorage = self::STORAGE_MEMORY, $pTemporaryStorageDir = null, $compatibility = false)\n    {\n        // Open temporary storage\n        if ($pTemporaryStorage == self::STORAGE_MEMORY) {\n            $this->openMemory();\n        } else {\n            if (!$pTemporaryStorageDir || !is_dir($pTemporaryStorageDir)) {\n                $pTemporaryStorageDir = sys_get_temp_dir();\n            }\n            // Create temporary filename\n            $this->tempFileName = @tempnam($pTemporaryStorageDir, 'xml');\n\n            // Open storage\n            $this->openUri($this->tempFileName);\n        }\n\n        if ($compatibility) {\n            $this->setIndent(false);\n            $this->setIndentString('');\n        } else {\n            $this->setIndent(true);\n            $this->setIndentString('  ');\n        }\n    }\n\n    /**\n     * Destructor.\n     */\n    public function __destruct()\n    {\n        // Unlink temporary files\n        if (empty($this->tempFileName)) {\n            return;\n        }\n        if (PHP_OS != 'WINNT' && @unlink($this->tempFileName) === false) {\n            throw new Exception('The file ' . $this->tempFileName . ' could not be deleted.');\n        }\n    }\n\n    /**\n     * Get written data.\n     *\n     * @return string\n     */\n    public function getData()\n    {\n        if ($this->tempFileName == '') {\n            return $this->outputMemory(true);\n        }\n\n        $this->flush();\n\n        return file_get_contents($this->tempFileName);\n    }\n\n    /**\n     * Write simple element and attribute(s) block.\n     *\n     * There are two options:\n     * 1. If the `$attributes` is an array, then it's an associative array of attributes\n     * 2. If not, then it's a simple attribute-value pair\n     *\n     * @param string $element\n     * @param array|string $attributes\n     * @param string $value\n     */\n    public function writeElementBlock($element, $attributes, $value = null): void\n    {\n        $this->startElement($element);\n        if (!is_array($attributes)) {\n            $attributes = [$attributes => $value];\n        }\n        foreach ($attributes as $attribute => $value) {\n            $this->writeAttribute($attribute, $value);\n        }\n        $this->endElement();\n    }\n\n    /**\n     * Write element if ...\n     *\n     * @param bool $condition\n     * @param string $element\n     * @param string $attribute\n     * @param mixed $value\n     */\n    public function writeElementIf($condition, $element, $attribute = null, $value = null): void\n    {\n        if ($condition == true) {\n            if (null === $attribute) {\n                $this->writeElement($element, $value);\n            } else {\n                $this->startElement($element);\n                $this->writeAttribute($attribute, $value);\n                $this->endElement();\n            }\n        }\n    }\n\n    /**\n     * Write attribute if ...\n     *\n     * @param bool $condition\n     * @param string $attribute\n     * @param mixed $value\n     */\n    public function writeAttributeIf($condition, $attribute, $value): void\n    {\n        if ($condition == true) {\n            $this->writeAttribute($attribute, $value);\n        }\n    }\n\n    /**\n     * @param string $name\n     * @param mixed $value\n     */\n    public function writeAttribute($name, $value): bool\n    {\n        if (is_float($value)) {\n            $value = json_encode($value);\n        }\n\n        return parent::writeAttribute($name, $value ?? '');\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Shared/ZipArchive.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Shared;\n\nuse PclZip;\nuse PhpOffice\\PhpWord\\Exception\\Exception;\nuse PhpOffice\\PhpWord\\Settings;\nuse Throwable;\n\n/**\n * ZipArchive wrapper.\n *\n * Wraps zip archive functionality of PHP ZipArchive and PCLZip. PHP ZipArchive\n * properties and methods are bypassed and used as the model for the PCLZip\n * emulation. Only needed PHP ZipArchive features are implemented.\n *\n * @method  bool addFile(string $filename, string $localname = null)\n * @method  bool addFromString(string $localname, string $contents)\n * @method  false|string getNameIndex(int $index)\n * @method  false|int locateName(string $name)\n *\n * @since   0.10.0\n */\nclass ZipArchive\n{\n    /** @const int Flags for open method */\n    const CREATE = 1; // Emulate \\ZipArchive::CREATE\n    const OVERWRITE = 8; // Emulate \\ZipArchive::OVERWRITE\n\n    /**\n     * Number of files (emulate ZipArchive::$numFiles).\n     *\n     * @var int\n     */\n    public $numFiles = 0;\n\n    /**\n     * Archive filename (emulate ZipArchive::$filename).\n     *\n     * @var string\n     */\n    public $filename;\n\n    /**\n     * Temporary storage directory.\n     *\n     * @var string\n     */\n    private $tempDir;\n\n    /**\n     * Internal zip archive object.\n     *\n     * @var PclZip|\\ZipArchive\n     */\n    private $zip;\n\n    /**\n     * Use PCLZip (default behaviour).\n     *\n     * @var bool\n     */\n    private $usePclzip = true;\n\n    /**\n     * Create new instance.\n     */\n    public function __construct()\n    {\n        $this->usePclzip = (Settings::getZipClass() != 'ZipArchive');\n        if ($this->usePclzip) {\n            if (!defined('PCLZIP_TEMPORARY_DIR')) {\n                define('PCLZIP_TEMPORARY_DIR', Settings::getTempDir() . '/');\n            }\n            require_once 'PCLZip/pclzip.lib.php';\n        }\n    }\n\n    /**\n     * Catch function calls: pass to ZipArchive or PCLZip.\n     *\n     * `call_user_func_array` can only used for public function, hence the `public` in all `pcl...` methods\n     *\n     * @param mixed $function\n     * @param mixed $args\n     *\n     * @return mixed\n     */\n    public function __call($function, $args)\n    {\n        // Set object and function\n        $zipFunction = $function;\n        if (!$this->usePclzip) {\n            $zipObject = $this->zip;\n        } else {\n            $zipObject = $this;\n            $zipFunction = \"pclzip{$zipFunction}\";\n        }\n\n        // Run function\n        $result = false;\n        if (method_exists($zipObject, $zipFunction)) {\n            $result = @call_user_func_array([$zipObject, $zipFunction], $args);\n        }\n\n        return $result;\n    }\n\n    /**\n     * Open a new zip archive.\n     *\n     * @param string $filename The file name of the ZIP archive to open\n     * @param int $flags The mode to use to open the archive\n     *\n     * @return bool\n     */\n    public function open($filename, $flags = null)\n    {\n        $result = true;\n        $this->filename = $filename;\n        $this->tempDir = Settings::getTempDir();\n\n        if (!$this->usePclzip) {\n            $zip = new \\ZipArchive();\n\n            // PHP 8.1 compat - passing null as second arg to \\ZipArchive::open() is deprecated\n            // passing 0 achieves the same behaviour\n            if ($flags === null) {\n                $flags = 0;\n            }\n\n            $result = $zip->open($this->filename, $flags);\n\n            // Scrutizer will report the property numFiles does not exist\n            // See https://github.com/scrutinizer-ci/php-analyzer/issues/190\n            $this->numFiles = $zip->numFiles;\n        } else {\n            $zip = new PclZip($this->filename);\n            $zipContent = $zip->listContent();\n            $this->numFiles = is_array($zipContent) ? count($zipContent) : 0;\n        }\n        $this->zip = $zip;\n\n        return $result;\n    }\n\n    /**\n     * Close the active archive.\n     *\n     * @return bool\n     */\n    public function close()\n    {\n        if (!$this->usePclzip) {\n            try {\n                $result = @$this->zip->close();\n            } catch (Throwable $e) {\n                $result = false;\n            }\n            if ($result === false) {\n                throw new Exception(\"Could not close zip file {$this->filename}: \");\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * Extract the archive contents (emulate \\ZipArchive).\n     *\n     * @param string $destination\n     * @param array|string $entries\n     *\n     * @return bool\n     *\n     * @since 0.10.0\n     */\n    public function extractTo($destination, $entries = null)\n    {\n        if (!is_dir($destination)) {\n            return false;\n        }\n\n        if (!$this->usePclzip) {\n            return $this->zip->extractTo($destination, $entries);\n        }\n\n        return $this->pclzipExtractTo($destination, $entries);\n    }\n\n    /**\n     * Extract file from archive by given file name (emulate \\ZipArchive).\n     *\n     * @param  string $filename Filename for the file in zip archive\n     *\n     * @return bool|string $contents File string contents\n     */\n    public function getFromName($filename)\n    {\n        if (!$this->usePclzip) {\n            $contents = $this->zip->getFromName($filename);\n            if ($contents === false) {\n                $filename = substr($filename, 1);\n                $contents = $this->zip->getFromName($filename);\n            }\n        } else {\n            $contents = $this->pclzipGetFromName($filename);\n        }\n\n        return $contents;\n    }\n\n    /**\n     * Add a new file to the zip archive (emulate \\ZipArchive).\n     *\n     * @param string $filename Directory/Name of the file to add to the zip archive\n     * @param string $localname Directory/Name of the file added to the zip\n     *\n     * @return bool\n     */\n    public function pclzipAddFile($filename, $localname = null)\n    {\n        /** @var PclZip $zip Type hint */\n        $zip = $this->zip;\n\n        // Bugfix GH-261 https://github.com/PHPOffice/PHPWord/pull/261\n        $realpathFilename = realpath($filename);\n        if ($realpathFilename !== false) {\n            $filename = $realpathFilename;\n        }\n\n        $filenamePartsBaseName = pathinfo($filename, PATHINFO_BASENAME);\n        $filenamePartsDirName = pathinfo($filename, PATHINFO_DIRNAME);\n        $localnamePartsBaseName = pathinfo($localname, PATHINFO_BASENAME);\n        $localnamePartsDirName = pathinfo($localname, PATHINFO_DIRNAME);\n\n        // To Rename the file while adding it to the zip we\n        //   need to create a temp file with the correct name\n        $tempFile = false;\n        if ($filenamePartsBaseName != $localnamePartsBaseName) {\n            $tempFile = true; // temp file created\n            $temppath = $this->tempDir . DIRECTORY_SEPARATOR . $localnamePartsBaseName;\n            copy($filename, $temppath);\n            $filename = $temppath;\n            $filenamePartsDirName = pathinfo($temppath, PATHINFO_DIRNAME);\n        }\n\n        $pathRemoved = $filenamePartsDirName;\n        $pathAdded = $localnamePartsDirName;\n\n        if (!$this->usePclzip) {\n            $pathAdded = $pathAdded . '/' . ltrim(str_replace('\\\\', '/', substr($filename, strlen($pathRemoved))), '/');\n            //$res = $zip->addFile($filename, $pathAdded);\n            $res = $zip->addFromString($pathAdded, file_get_contents($filename));       // addFile can't use subfolders in some cases\n        } else {\n            $res = $zip->add($filename, PCLZIP_OPT_REMOVE_PATH, $pathRemoved, PCLZIP_OPT_ADD_PATH, $pathAdded);\n        }\n\n        if ($tempFile) {\n            // Remove temp file, if created\n            unlink($this->tempDir . DIRECTORY_SEPARATOR . $localnamePartsBaseName);\n        }\n\n        return $res != 0;\n    }\n\n    /**\n     * Add a new file to the zip archive from a string of raw data (emulate \\ZipArchive).\n     *\n     * @param string $localname Directory/Name of the file to add to the zip archive\n     * @param string $contents String of data to add to the zip archive\n     *\n     * @return bool\n     */\n    public function pclzipAddFromString($localname, $contents)\n    {\n        /** @var PclZip $zip Type hint */\n        $zip = $this->zip;\n        $filenamePartsBaseName = pathinfo($localname, PATHINFO_BASENAME);\n        $filenamePartsDirName = pathinfo($localname, PATHINFO_DIRNAME);\n\n        // Write $contents to a temp file\n        $handle = fopen($this->tempDir . DIRECTORY_SEPARATOR . $filenamePartsBaseName, 'wb');\n        if ($handle) {\n            fwrite($handle, $contents);\n            fclose($handle);\n        }\n\n        // Add temp file to zip\n        $filename = $this->tempDir . DIRECTORY_SEPARATOR . $filenamePartsBaseName;\n        $pathRemoved = $this->tempDir;\n        $pathAdded = $filenamePartsDirName;\n\n        $res = $zip->add($filename, PCLZIP_OPT_REMOVE_PATH, $pathRemoved, PCLZIP_OPT_ADD_PATH, $pathAdded);\n\n        // Remove temp file\n        @unlink($this->tempDir . DIRECTORY_SEPARATOR . $filenamePartsBaseName);\n\n        return $res != 0;\n    }\n\n    /**\n     * Extract the archive contents (emulate \\ZipArchive).\n     *\n     * @param string $destination\n     * @param array|string $entries\n     *\n     * @return bool\n     *\n     * @since 0.10.0\n     */\n    public function pclzipExtractTo($destination, $entries = null)\n    {\n        /** @var PclZip $zip Type hint */\n        $zip = $this->zip;\n\n        // Extract all files\n        if (null === $entries) {\n            $result = $zip->extract(PCLZIP_OPT_PATH, $destination);\n\n            return $result > 0;\n        }\n\n        // Extract by entries\n        if (!is_array($entries)) {\n            $entries = [$entries];\n        }\n        foreach ($entries as $entry) {\n            $entryIndex = $this->locateName($entry);\n            $result = $zip->extractByIndex($entryIndex, PCLZIP_OPT_PATH, $destination);\n            if ($result <= 0) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * Extract file from archive by given file name (emulate \\ZipArchive).\n     *\n     * @param  string $filename Filename for the file in zip archive\n     *\n     * @return string $contents File string contents\n     */\n    public function pclzipGetFromName($filename)\n    {\n        /** @var PclZip $zip Type hint */\n        $zip = $this->zip;\n        $listIndex = $this->pclzipLocateName($filename);\n        $contents = false;\n\n        if ($listIndex !== false) {\n            $extracted = $zip->extractByIndex($listIndex, PCLZIP_OPT_EXTRACT_AS_STRING);\n        } else {\n            $filename = substr($filename, 1);\n            $listIndex = $this->pclzipLocateName($filename);\n            $extracted = $zip->extractByIndex($listIndex, PCLZIP_OPT_EXTRACT_AS_STRING);\n        }\n        if (is_array($extracted) && count($extracted) != 0) {\n            $contents = $extracted[0]['content'];\n        }\n\n        return $contents;\n    }\n\n    /**\n     * Returns the name of an entry using its index (emulate \\ZipArchive).\n     *\n     * @param int $index\n     *\n     * @return bool|string\n     *\n     * @since 0.10.0\n     */\n    public function pclzipGetNameIndex($index)\n    {\n        /** @var PclZip $zip Type hint */\n        $zip = $this->zip;\n        $list = $zip->listContent();\n        if (isset($list[$index])) {\n            return $list[$index]['filename'];\n        }\n\n        return false;\n    }\n\n    /**\n     * Returns the index of the entry in the archive (emulate \\ZipArchive).\n     *\n     * @param string $filename Filename for the file in zip archive\n     *\n     * @return false|int\n     */\n    public function pclzipLocateName($filename)\n    {\n        /** @var PclZip $zip Type hint */\n        $zip = $this->zip;\n        $list = $zip->listContent();\n        $listCount = count($list);\n        $listIndex = -1;\n        for ($i = 0; $i < $listCount; ++$i) {\n            if (strtolower($list[$i]['filename']) == strtolower($filename) ||\n                strtolower($list[$i]['stored_filename']) == strtolower($filename)) {\n                $listIndex = $i;\n\n                break;\n            }\n        }\n\n        return ($listIndex > -1) ? $listIndex : false;\n    }\n\n    /**\n     * Add an empty directory to the zip archive (emulate \\ZipArchive).\n     *\n     * @param string $dirname Directory name to add to the zip archive\n     */\n    public function addEmptyDir(string $dirname): bool\n    {\n        // Create a directory entry by adding an empty file with trailing slash\n        return $this->addFromString(rtrim($dirname, '/') . '/', '');\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/SimpleType/Border.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\SimpleType;\n\nuse PhpOffice\\PhpWord\\Shared\\AbstractEnum;\n\n/**\n * Border Styles.\n *\n * @since 0.18.0\n * @see  http://www.datypic.com/sc/ooxml/t-w_ST_Border.html\n */\nfinal class Border extends AbstractEnum\n{\n    const SINGLE = 'single'; //A single line\n    const DASH_DOT_STROKED = 'dashDotStroked'; //A line with a series of alternating thin and thick strokes\n    const DASHED = 'dashed'; //A dashed line\n    const DASH_SMALL_GAP = 'dashSmallGap'; //A dashed line with small gaps\n    const DOT_DASH = 'dotDash'; //A line with alternating dots and dashes\n    const DOT_DOT_DASH = 'dotDotDash'; //A line with a repeating dot - dot - dash sequence\n    const DOTTED = 'dotted'; //A dotted line\n    const DOUBLE = 'double'; //A double line\n    const DOUBLE_WAVE = 'doubleWave'; //A double wavy line\n    const INSET = 'inset'; //An inset set of lines\n    const NIL = 'nil'; //No border\n    const NONE = 'none'; //No border\n    const OUTSET = 'outset'; //An outset set of lines\n    const THICK = 'thick'; //A single line\n    const THICK_THIN_LARGE_GAP = 'thickThinLargeGap'; //A thick line contained within a thin line with a large-sized intermediate gap\n    const THICK_THIN_MEDIUM_GAP = 'thickThinMediumGap'; //A thick line contained within a thin line with a medium-sized intermediate gap\n    const THICK_THIN_SMALL_GAP = 'thickThinSmallGap'; //A thick line contained within a thin line with a small intermediate gap\n    const THIN_THICK_LARGE_GAP = 'thinThickLargeGap'; //A thin line contained within a thick line with a large-sized intermediate gap\n    const THIN_THICK_MEDIUM_GAP = 'thinThickMediumGap'; //A thick line contained within a thin line with a medium-sized intermediate gap\n    const THIN_THICK_SMALL_GAP = 'thinThickSmallGap'; //A thick line contained within a thin line with a small intermediate gap\n    const THIN_THICK_THINLARGE_GAP = 'thinThickThinLargeGap'; //A thin-thick-thin line with a large gap\n    const THIN_THICK_THIN_MEDIUM_GAP = 'thinThickThinMediumGap'; //A thin-thick-thin line with a medium gap\n    const THIN_THICK_THIN_SMALL_GAP = 'thinThickThinSmallGap'; //A thin-thick-thin line with a small gap\n    const THREE_D_EMBOSS = 'threeDEmboss'; //A three-staged gradient line, getting darker towards the paragraph\n    const THREE_D_ENGRAVE = 'threeDEngrave'; //A three-staged gradient like, getting darker away from the paragraph\n    const TRIPLE = 'triple'; //A triple line\n    const WAVE = 'wave'; //A wavy line\n}\n"
  },
  {
    "path": "src/PhpWord/SimpleType/DocProtect.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\SimpleType;\n\nuse PhpOffice\\PhpWord\\Shared\\AbstractEnum;\n\n/**\n * Document Protection Types.\n *\n * @since 0.14.0\n * @see http://www.datypic.com/sc/ooxml/t-w_ST_DocProtect.html\n */\nfinal class DocProtect extends AbstractEnum\n{\n    /**\n     * No Editing Restrictions.\n     */\n    const NONE = 'none';\n\n    /**\n     * Allow No Editing.\n     */\n    const READ_ONLY = 'readOnly';\n\n    /**\n     * Allow Editing of Comments.\n     */\n    const COMMENTS = 'comments';\n\n    /**\n     * Allow Editing With Revision Tracking.\n     */\n    const TRACKED_CHANGES = 'trackedChanges';\n\n    /**\n     * Allow Editing of Form Fields.\n     */\n    const FORMS = 'forms';\n}\n"
  },
  {
    "path": "src/PhpWord/SimpleType/Jc.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\SimpleType;\n\nuse PhpOffice\\PhpWord\\Shared\\AbstractEnum;\n\n/**\n * Horizontal Alignment Type.\n *\n * Introduced in 1st Edition of ECMA-376. Initially it was intended to align paragraphs and tables.\n * Since ISO/IEC-29500:2008 the type must not be used for table alignment.\n *\n * @since 0.13.0\n * @see JcTable For table alignment modes available since ISO/IEC-29500:2008.\n * @see  http://www.datypic.com/sc/ooxml/t-w_ST_Jc.html\n */\nfinal class Jc extends AbstractEnum\n{\n    const START = 'start';\n    const CENTER = 'center';\n    const END = 'end';\n    const BOTH = 'both';\n    const MEDIUM_KASHIDA = 'mediumKashida';\n    const DISTRIBUTE = 'distribute';\n    const NUM_TAB = 'numTab';\n    const HIGH_KASHIDA = 'highKashida';\n    const LOW_KASHIDA = 'lowKashida';\n    const THAI_DISTRIBUTE = 'thaiDistribute';\n\n    /**\n     * Kept for compatibility with 1st edition of ECMA-376 standard.\n     * Microsoft Word 2007 and WPS Writer 2016 still rely on it.\n     *\n     * @deprecated 0.13.0 For documents based on ISO/IEC 29500:2008 and later use `START` instead.\n     */\n    const LEFT = 'left';\n    /**\n     * Kept for compatibility with 1st edition of ECMA-376 standard.\n     * Microsoft Word 2007 and WPS Writer 2016 still rely on it.\n     *\n     * @deprecated 0.13.0 For documents based on ISO/IEC 29500:2008 and later use `END` instead.\n     */\n    const RIGHT = 'right';\n    /**\n     * Kept for compatibility with 1st edition of ECMA-376 standard.\n     * Microsoft Word 2007 and WPS Writer 2016 still rely on it.\n     *\n     * @deprecated 0.13.0 For documents based on ISO/IEC 29500:2008 and later use `BOTH` instead.\n     */\n    const JUSTIFY = 'justify';\n}\n"
  },
  {
    "path": "src/PhpWord/SimpleType/JcTable.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\SimpleType;\n\nuse PhpOffice\\PhpWord\\Shared\\AbstractEnum;\n\n/**\n * Table Alignment Type.\n *\n * Introduced in ISO/IEC-29500:2008.\n *\n * @since 0.13.0\n */\nfinal class JcTable extends AbstractEnum\n{\n    const START = 'start';\n    const CENTER = 'center';\n    const END = 'end';\n}\n"
  },
  {
    "path": "src/PhpWord/SimpleType/LineSpacingRule.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\SimpleType;\n\nuse PhpOffice\\PhpWord\\Shared\\AbstractEnum;\n\n/**\n * Line Spacing Rule.\n *\n * @since 0.14.0\n * @see http://www.datypic.com/sc/ooxml/t-w_ST_LineSpacingRule.html\n */\nfinal class LineSpacingRule extends AbstractEnum\n{\n    /**\n     * Automatically Determined Line Height.\n     */\n    const AUTO = 'auto';\n\n    /**\n     * Exact Line Height.\n     */\n    const EXACT = 'exact';\n\n    /**\n     * Minimum Line Height.\n     */\n    const AT_LEAST = 'atLeast';\n}\n"
  },
  {
    "path": "src/PhpWord/SimpleType/NumberFormat.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\SimpleType;\n\nuse PhpOffice\\PhpWord\\Shared\\AbstractEnum;\n\n/**\n * Numbering Format.\n *\n * @since 0.14.0\n * @see http://www.datypic.com/sc/ooxml/t-w_ST_NumberFormat.html.\n */\nfinal class NumberFormat extends AbstractEnum\n{\n    //Decimal Numbers\n    const DECIMAL = 'decimal';\n    //Uppercase Roman Numerals\n    const UPPER_ROMAN = 'upperRoman';\n    //Lowercase Roman Numerals\n    const LOWER_ROMAN = 'lowerRoman';\n    //Uppercase Latin Alphabet\n    const UPPER_LETTER = 'upperLetter';\n    //Lowercase Latin Alphabet\n    const LOWER_LETTER = 'lowerLetter';\n    //Ordinal\n    const ORDINAL = 'ordinal';\n    //Cardinal Text\n    const CARDINAL_TEXT = 'cardinalText';\n    //Ordinal Text\n    const ORDINAL_TEXT = 'ordinalText';\n    //Hexadecimal Numbering\n    const HEX = 'hex';\n    //Chicago Manual of Style\n    const CHICAGO = 'chicago';\n    //Ideographs\n    const IDEOGRAPH_DIGITAL = 'ideographDigital';\n    //Japanese Counting System\n    const JAPANESE_COUNTING = 'japaneseCounting';\n    //AIUEO Order Hiragana\n    const AIUEO = 'aiueo';\n    //Iroha Ordered Katakana\n    const IROHA = 'iroha';\n    //Double Byte Arabic Numerals\n    const DECIMAL_FULL_WIDTH = 'decimalFullWidth';\n    //Single Byte Arabic Numerals\n    const DECIMAL_HALF_WIDTH = 'decimalHalfWidth';\n    //Japanese Legal Numbering\n    const JAPANESE_LEGAL = 'japaneseLegal';\n    //Japanese Digital Ten Thousand Counting System\n    const JAPANESE_DIGITAL_TEN_THOUSAND = 'japaneseDigitalTenThousand';\n    //Decimal Numbers Enclosed in a Circle\n    const DECIMAL_ENCLOSED_CIRCLE = 'decimalEnclosedCircle';\n    //Double Byte Arabic Numerals Alternate\n    const DECIMAL_FULL_WIDTH2 = 'decimalFullWidth2';\n    //Full-Width AIUEO Order Hiragana\n    const AIUEO_FULL_WIDTH = 'aiueoFullWidth';\n    //Full-Width Iroha Ordered Katakana\n    const IROHA_FULL_WIDTH = 'irohaFullWidth';\n    //Initial Zero Arabic Numerals\n    const DECIMAL_ZERO = 'decimalZero';\n    //Bullet\n    const BULLET = 'bullet';\n    //Korean Ganada Numbering\n    const GANADA = 'ganada';\n    //Korean Chosung Numbering\n    const CHOSUNG = 'chosung';\n    //Decimal Numbers Followed by a Period\n    const DECIMAL_ENCLOSED_FULL_STOP = 'decimalEnclosedFullstop';\n    //Decimal Numbers Enclosed in Parenthesis\n    const DECIMAL_ENCLOSED_PAREN = 'decimalEnclosedParen';\n    //Decimal Numbers Enclosed in a Circle\n    const DECIMAL_ENCLOSED_CIRCLE_CHINESE = 'decimalEnclosedCircleChinese';\n    //Ideographs Enclosed in a Circle\n    const IDEOGRAPHENCLOSEDCIRCLE = 'ideographEnclosedCircle';\n    //Traditional Ideograph Format\n    const IDEOGRAPH_TRADITIONAL = 'ideographTraditional';\n    //Zodiac Ideograph Format\n    const IDEOGRAPH_ZODIAC = 'ideographZodiac';\n    //Traditional Zodiac Ideograph Format\n    const IDEOGRAPH_ZODIAC_TRADITIONAL = 'ideographZodiacTraditional';\n    //Taiwanese Counting System\n    const TAIWANESE_COUNTING = 'taiwaneseCounting';\n    //Traditional Legal Ideograph Format\n    const IDEOGRAPH_LEGAL_TRADITIONAL = 'ideographLegalTraditional';\n    //Taiwanese Counting Thousand System\n    const TAIWANESE_COUNTING_THOUSAND = 'taiwaneseCountingThousand';\n    //Taiwanese Digital Counting System\n    const TAIWANESE_DIGITAL = 'taiwaneseDigital';\n    //Chinese Counting System\n    const CHINESE_COUNTING = 'chineseCounting';\n    //Chinese Legal Simplified Format\n    const CHINESE_LEGAL_SIMPLIFIED = 'chineseLegalSimplified';\n    //Chinese Counting Thousand System\n    const CHINESE_COUNTING_THOUSAND = 'chineseCountingThousand';\n    //Korean Digital Counting System\n    const KOREAN_DIGITAL = 'koreanDigital';\n    //Korean Counting System\n    const KOREAN_COUNTING = 'koreanCounting';\n    //Korean Legal Numbering\n    const KOREAN_LEGAL = 'koreanLegal';\n    //Korean Digital Counting System Alternate\n    const KOREAN_DIGITAL2 = 'koreanDigital2';\n    //Vietnamese Numerals\n    const VIETNAMESE_COUNTING = 'vietnameseCounting';\n    //Lowercase Russian Alphabet\n    const RUSSIAN_LOWER = 'russianLower';\n    //Uppercase Russian Alphabet\n    const RUSSIAN_UPPER = 'russianUpper';\n    //No Numbering\n    const NONE = 'none';\n    //Number With Dashes\n    const NUMBER_IN_DASH = 'numberInDash';\n    //Hebrew Numerals\n    const HEBREW1 = 'hebrew1';\n    //Hebrew Alphabet\n    const HEBREW2 = 'hebrew2';\n    //Arabic Alphabet\n    const ARABIC_ALPHA = 'arabicAlpha';\n    //Arabic Abjad Numerals\n    const ARABIC_ABJAD = 'arabicAbjad';\n    //Hindi Vowels\n    const HINDI_VOWELS = 'hindiVowels';\n    //Hindi Consonants\n    const HINDI_CONSONANTS = 'hindiConsonants';\n    //Hindi Numbers\n    const HINDI_NUMBERS = 'hindiNumbers';\n    //Hindi Counting System\n    const HINDI_COUNTING = 'hindiCounting';\n    //Thai Letters\n    const THAI_LETTERS = 'thaiLetters';\n    //Thai Numerals\n    const THAI_NUMBERS = 'thaiNumbers';\n    //Thai Counting System\n    const THAI_COUNTING = 'thaiCounting';\n}\n"
  },
  {
    "path": "src/PhpWord/SimpleType/TblWidth.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\SimpleType;\n\nuse PhpOffice\\PhpWord\\Shared\\AbstractEnum;\n\n/**\n * Table Width Units.\n *\n * @since 0.15.0\n * @see http://www.datypic.com/sc/ooxml/t-w_ST_TblWidth.html\n */\nfinal class TblWidth extends AbstractEnum\n{\n    //No Width\n    const NIL = 'nil';\n\n    //Automatically Determined Width\n    const AUTO = 'auto';\n\n    //Width in Fiftieths of a Percent\n    const PERCENT = 'pct';\n\n    //Width in Twentieths of a Point\n    const TWIP = 'dxa';\n}\n"
  },
  {
    "path": "src/PhpWord/SimpleType/TextAlignment.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\SimpleType;\n\nuse PhpOffice\\PhpWord\\Shared\\AbstractEnum;\n\n/**\n * Magnification Preset Values.\n *\n * @since 0.14.0\n * @see http://www.datypic.com/sc/ooxml/t-w_ST_TextAlignment.html\n */\nfinal class TextAlignment extends AbstractEnum\n{\n    //Align Text at Top\n    const TOP = 'top';\n\n    //Align Text at Center\n    const CENTER = 'center';\n\n    //Align Text at Baseline\n    const BASELINE = 'baseline';\n\n    //Align Text at Bottom\n    const BOTTOM = 'bottom';\n\n    //Automatically Determine Alignment\n    const AUTO = 'auto';\n}\n"
  },
  {
    "path": "src/PhpWord/SimpleType/VerticalJc.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\SimpleType;\n\nuse PhpOffice\\PhpWord\\Shared\\AbstractEnum;\n\n/**\n * Vertical Alignment Type.\n *\n * Introduced in ISO/IEC-29500:2008.\n *\n * @see http://www.datypic.com/sc/ooxml/t-w_ST_VerticalJc.html\n * @since 0.17.0\n */\nfinal class VerticalJc extends AbstractEnum\n{\n    const TOP = 'top';\n    const CENTER = 'center';\n    const BOTH = 'both';\n    const BOTTOM = 'bottom';\n}\n"
  },
  {
    "path": "src/PhpWord/SimpleType/Zoom.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\SimpleType;\n\nuse PhpOffice\\PhpWord\\Shared\\AbstractEnum;\n\n/**\n * Magnification Preset Values.\n *\n * @since 0.14.0\n * @see http://www.datypic.com/sc/ooxml/t-w_ST_Zoom.html\n */\nfinal class Zoom extends AbstractEnum\n{\n    //No Preset Magnification\n    const NONE = 'none';\n\n    //Display One Full Page\n    const FULL_PAGE = 'fullPage';\n\n    //Display Page Width\n    const BEST_FIT = 'bestFit';\n\n    //Display Text Width\n    const TEXT_FIT = 'textFit';\n}\n"
  },
  {
    "path": "src/PhpWord/Style/AbstractStyle.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Style;\n\nuse InvalidArgumentException;\nuse PhpOffice\\PhpWord\\Shared\\Text;\n\n/**\n * Abstract style class.\n *\n * @since 0.10.0\n */\nabstract class AbstractStyle\n{\n    /**\n     * Style name.\n     *\n     * @var ?string\n     */\n    protected $styleName;\n\n    /**\n     * Index number in Style collection for named style.\n     *\n     * This number starts from one and defined in Style::setStyleValues()\n     *\n     * @var null|int\n     */\n    protected $index;\n\n    /**\n     * Aliases.\n     *\n     * @var array\n     */\n    protected $aliases = [];\n\n    /**\n     * Is this an automatic style? (Used primarily in OpenDocument driver).\n     *\n     * @var bool\n     *\n     * @since 0.11.0\n     */\n    private $isAuto = false;\n\n    /**\n     * Get style name.\n     *\n     * @return ?string\n     */\n    public function getStyleName()\n    {\n        return $this->styleName;\n    }\n\n    /**\n     * Set style name.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setStyleName($value)\n    {\n        $this->styleName = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get index number.\n     *\n     * @return null|int\n     */\n    public function getIndex()\n    {\n        return $this->index;\n    }\n\n    /**\n     * Set index number.\n     *\n     * @param null|int $value\n     *\n     * @return self\n     */\n    public function setIndex($value = null)\n    {\n        $this->index = $this->setIntVal($value, $this->index);\n\n        return $this;\n    }\n\n    /**\n     * Get is automatic style flag.\n     *\n     * @return bool\n     */\n    public function isAuto()\n    {\n        return $this->isAuto;\n    }\n\n    /**\n     * Set is automatic style flag.\n     *\n     * @param bool $value\n     *\n     * @return self\n     */\n    public function setAuto($value = true)\n    {\n        $this->isAuto = $this->setBoolVal($value, $this->isAuto);\n\n        return $this;\n    }\n\n    /**\n     * Return style value of child style object, e.g. `left` from `Indentation` child style of `Paragraph`.\n     *\n     * @param AbstractStyle $substyleObject\n     * @param string $substyleProperty\n     *\n     * @return mixed\n     *\n     * @since 0.12.0\n     */\n    public function getChildStyleValue($substyleObject, $substyleProperty)\n    {\n        if ($substyleObject !== null) {\n            $method = \"get{$substyleProperty}\";\n\n            return $substyleObject->$method();\n        }\n\n        return null;\n    }\n\n    /**\n     * Set style value template method.\n     *\n     * Some child classes have their own specific overrides.\n     * Backward compability check for versions < 0.10.0 which use underscore\n     * prefix for their private properties.\n     * Check if the set method is exists. Throws an exception?\n     *\n     * @param string $key\n     * @param array|int|string $value\n     *\n     * @return self\n     */\n    public function setStyleValue($key, $value)\n    {\n        if (isset($this->aliases[$key])) {\n            $key = $this->aliases[$key];\n        }\n\n        if ($key === 'align') {\n            $key = 'alignment';\n        }\n\n        $method = 'set' . Text::removeUnderscorePrefix($key);\n        if (method_exists($this, $method)) {\n            $this->$method($value);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Set style by using associative array.\n     *\n     * @param array $values\n     *\n     * @return self\n     */\n    public function setStyleByArray($values = [])\n    {\n        foreach ($values as $key => $value) {\n            $this->setStyleValue($key, $value);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Set default for null and empty value.\n     *\n     * @param ?string $value\n     * @param string $default\n     *\n     * @return string\n     */\n    protected function setNonEmptyVal($value, $default)\n    {\n        if ($value === null || $value == '') {\n            $value = $default;\n        }\n\n        return $value;\n    }\n\n    /**\n     * Set bool value.\n     *\n     * @param bool $value\n     * @param bool $default\n     *\n     * @return bool\n     */\n    protected function setBoolVal($value, $default)\n    {\n        if (!is_bool($value)) {\n            $value = $default;\n        }\n\n        return $value;\n    }\n\n    /**\n     * Set numeric value.\n     *\n     * @param mixed $value\n     * @param null|float|int $default\n     *\n     * @return null|float|int\n     */\n    protected function setNumericVal($value, $default = null)\n    {\n        if (!is_numeric($value)) {\n            $value = $default;\n        }\n\n        return $value;\n    }\n\n    /**\n     * Set integer value: Convert string that contains only numeric into integer.\n     *\n     * @param null|float|int|string $value\n     * @param null|int $default\n     *\n     * @return null|int\n     */\n    protected function setIntVal($value, $default = null)\n    {\n        if (is_string($value) && (preg_match('/[^\\d]/', $value) == 0)) {\n            $value = (int) $value;\n        }\n        if (!is_numeric($value)) {\n            $value = $default;\n        } else {\n            $value = (int) $value;\n        }\n\n        return $value;\n    }\n\n    /**\n     * Set float value: Convert string that contains only numeric into float.\n     *\n     * @param mixed $value\n     * @param null|float $default\n     *\n     * @return null|float\n     */\n    protected function setFloatVal($value, $default = null)\n    {\n        if (is_string($value) && (preg_match('/[^\\d\\.\\,]/', $value) == 0)) {\n            $value = (float) $value;\n        }\n        if (!is_numeric($value)) {\n            $value = $default;\n        }\n\n        return $value;\n    }\n\n    /**\n     * Set enum value.\n     *\n     * @param mixed $value\n     * @param array $enum\n     * @param mixed $default\n     *\n     * @return mixed\n     */\n    protected function setEnumVal($value = null, $enum = [], $default = null)\n    {\n        if ($value != null && trim($value) != '' && !empty($enum) && !in_array($value, $enum)) {\n            throw new InvalidArgumentException(\"Invalid style value: {$value} Options:\" . implode(',', $enum));\n        } elseif ($value === null || trim($value) == '') {\n            $value = $default;\n        }\n\n        return $value;\n    }\n\n    /**\n     * Set object value.\n     *\n     * @param mixed $value\n     * @param mixed &$style\n     *\n     * @return mixed\n     */\n    protected function setObjectVal($value, string $styleName, &$style)\n    {\n        $styleClass = substr(static::class, 0, (int) strrpos(static::class, '\\\\')) . '\\\\' . $styleName;\n        if (is_array($value)) {\n            /** @var AbstractStyle $style Type hint */\n            if (!$style instanceof $styleClass) {\n                $style = new $styleClass();\n            }\n            $style->setStyleByArray($value);\n        } else {\n            $style = $value;\n        }\n\n        return $style;\n    }\n\n    /**\n     * Set $property value and set $pairProperty = false when $value = true.\n     *\n     * @param bool &$property\n     * @param bool &$pairProperty\n     * @param bool $value\n     *\n     * @return self\n     */\n    protected function setPairedVal(&$property, &$pairProperty, $value)\n    {\n        $property = $this->setBoolVal($value, $property);\n        if ($value === true) {\n            $pairProperty = false;\n        }\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Style/Border.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Style;\n\n/**\n * Border style.\n */\nclass Border extends AbstractStyle\n{\n    const DEFAULT_MARGIN = 1440;           // In twips.\n\n    /**\n     * Border Top Size.\n     *\n     * @var float|int\n     */\n    protected $borderTopSize;\n\n    /**\n     * Border Top Color.\n     *\n     * @var null|string\n     */\n    protected $borderTopColor;\n\n    /**\n     * Border Top Style.\n     *\n     * @var string\n     */\n    protected $borderTopStyle;\n\n    /**\n     * Border Left Size.\n     *\n     * @var float|int\n     */\n    protected $borderLeftSize;\n\n    /**\n     * Border Left Color.\n     *\n     * @var null|string\n     */\n    protected $borderLeftColor;\n\n    /**\n     * Border Left Style.\n     *\n     * @var string\n     */\n    protected $borderLeftStyle;\n\n    /**\n     * Border Right Size.\n     *\n     * @var float|int\n     */\n    protected $borderRightSize;\n\n    /**\n     * Border Right Color.\n     *\n     * @var null|string\n     */\n    protected $borderRightColor;\n\n    /**\n     * Border Right Style.\n     *\n     * @var string\n     */\n    protected $borderRightStyle;\n\n    /**\n     * Border Bottom Size.\n     *\n     * @var float|int\n     */\n    protected $borderBottomSize;\n\n    /**\n     * Border Bottom Color.\n     *\n     * @var null|string\n     */\n    protected $borderBottomColor;\n\n    /**\n     * Border Bottom Style.\n     *\n     * @var string\n     */\n    protected $borderBottomStyle;\n\n    /**\n     * Top margin spacing.\n     *\n     * @var float|int\n     */\n    protected $marginTop = self::DEFAULT_MARGIN;\n\n    /**\n     * Left margin spacing.\n     *\n     * @var float|int\n     */\n    protected $marginLeft = self::DEFAULT_MARGIN;\n\n    /**\n     * Right margin spacing.\n     *\n     * @var float|int\n     */\n    protected $marginRight = self::DEFAULT_MARGIN;\n\n    /**\n     * Bottom margin spacing.\n     *\n     * @var float|int\n     */\n    protected $marginBottom = self::DEFAULT_MARGIN;\n\n    /**\n     * Get border size.\n     *\n     * @return int[]\n     */\n    public function getBorderSize()\n    {\n        return [\n            $this->getBorderTopSize(),\n            $this->getBorderLeftSize(),\n            $this->getBorderRightSize(),\n            $this->getBorderBottomSize(),\n        ];\n    }\n\n    /**\n     * Set border size.\n     *\n     * @param float|int $value\n     *\n     * @return self\n     */\n    public function setBorderSize($value = null)\n    {\n        $this->setBorderTopSize($value);\n        $this->setBorderLeftSize($value);\n        $this->setBorderRightSize($value);\n        $this->setBorderBottomSize($value);\n\n        return $this;\n    }\n\n    /**\n     * Get border color.\n     *\n     * @return array<null|string>\n     */\n    public function getBorderColor()\n    {\n        return [\n            $this->getBorderTopColor(),\n            $this->getBorderLeftColor(),\n            $this->getBorderRightColor(),\n            $this->getBorderBottomColor(),\n        ];\n    }\n\n    /**\n     * Set border color.\n     *\n     * @param null|string $value\n     *\n     * @return self\n     */\n    public function setBorderColor($value = null)\n    {\n        $this->setBorderTopColor($value);\n        $this->setBorderLeftColor($value);\n        $this->setBorderRightColor($value);\n        $this->setBorderBottomColor($value);\n\n        return $this;\n    }\n\n    /**\n     * Get border style.\n     *\n     * @return string[]\n     */\n    public function getBorderStyle()\n    {\n        return [\n            $this->getBorderTopStyle(),\n            $this->getBorderLeftStyle(),\n            $this->getBorderRightStyle(),\n            $this->getBorderBottomStyle(),\n        ];\n    }\n\n    /**\n     * Set border style.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setBorderStyle($value = null)\n    {\n        $this->setBorderTopStyle($value);\n        $this->setBorderLeftStyle($value);\n        $this->setBorderRightStyle($value);\n        $this->setBorderBottomStyle($value);\n\n        return $this;\n    }\n\n    /**\n     * Get border top size.\n     *\n     * @return float|int\n     */\n    public function getBorderTopSize()\n    {\n        return $this->borderTopSize;\n    }\n\n    /**\n     * Set border top size.\n     *\n     * @param float|int $value\n     *\n     * @return self\n     */\n    public function setBorderTopSize($value = null)\n    {\n        $this->borderTopSize = $this->setNumericVal($value, $this->borderTopSize);\n\n        return $this;\n    }\n\n    /**\n     * Get border top color.\n     *\n     * @return null|string\n     */\n    public function getBorderTopColor()\n    {\n        return $this->borderTopColor;\n    }\n\n    /**\n     * Set border top color.\n     *\n     * @param null|string $value\n     *\n     * @return self\n     */\n    public function setBorderTopColor($value = null)\n    {\n        $this->borderTopColor = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get border top style.\n     *\n     * @return string\n     */\n    public function getBorderTopStyle()\n    {\n        return $this->borderTopStyle;\n    }\n\n    /**\n     * Set border top Style.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setBorderTopStyle($value = null)\n    {\n        $this->borderTopStyle = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get border left size.\n     *\n     * @return float|int\n     */\n    public function getBorderLeftSize()\n    {\n        return $this->borderLeftSize;\n    }\n\n    /**\n     * Set border left size.\n     *\n     * @param float|int $value\n     *\n     * @return self\n     */\n    public function setBorderLeftSize($value = null)\n    {\n        $this->borderLeftSize = $this->setNumericVal($value, $this->borderLeftSize);\n\n        return $this;\n    }\n\n    /**\n     * Get border left color.\n     *\n     * @return null|string\n     */\n    public function getBorderLeftColor()\n    {\n        return $this->borderLeftColor;\n    }\n\n    /**\n     * Set border left color.\n     *\n     * @param null|string $value\n     *\n     * @return self\n     */\n    public function setBorderLeftColor($value = null)\n    {\n        $this->borderLeftColor = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get border left style.\n     *\n     * @return string\n     */\n    public function getBorderLeftStyle()\n    {\n        return $this->borderLeftStyle;\n    }\n\n    /**\n     * Set border left style.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setBorderLeftStyle($value = null)\n    {\n        $this->borderLeftStyle = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get border right size.\n     *\n     * @return float|int\n     */\n    public function getBorderRightSize()\n    {\n        return $this->borderRightSize;\n    }\n\n    /**\n     * Set border right size.\n     *\n     * @param float|int $value\n     *\n     * @return self\n     */\n    public function setBorderRightSize($value = null)\n    {\n        $this->borderRightSize = $this->setNumericVal($value, $this->borderRightSize);\n\n        return $this;\n    }\n\n    /**\n     * Get border right color.\n     *\n     * @return null|string\n     */\n    public function getBorderRightColor()\n    {\n        return $this->borderRightColor;\n    }\n\n    /**\n     * Set border right color.\n     *\n     * @param null|string $value\n     *\n     * @return self\n     */\n    public function setBorderRightColor($value = null)\n    {\n        $this->borderRightColor = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get border right style.\n     *\n     * @return string\n     */\n    public function getBorderRightStyle()\n    {\n        return $this->borderRightStyle;\n    }\n\n    /**\n     * Set border right style.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setBorderRightStyle($value = null)\n    {\n        $this->borderRightStyle = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get border bottom size.\n     *\n     * @return float|int\n     */\n    public function getBorderBottomSize()\n    {\n        return $this->borderBottomSize;\n    }\n\n    /**\n     * Set border bottom size.\n     *\n     * @param float|int $value\n     *\n     * @return self\n     */\n    public function setBorderBottomSize($value = null)\n    {\n        $this->borderBottomSize = $this->setNumericVal($value, $this->borderBottomSize);\n\n        return $this;\n    }\n\n    /**\n     * Get border bottom color.\n     *\n     * @return null|string\n     */\n    public function getBorderBottomColor()\n    {\n        return $this->borderBottomColor;\n    }\n\n    /**\n     * Set border bottom color.\n     *\n     * @param null|string $value\n     *\n     * @return self\n     */\n    public function setBorderBottomColor($value = null)\n    {\n        $this->borderBottomColor = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get border bottom style.\n     *\n     * @return string\n     */\n    public function getBorderBottomStyle()\n    {\n        return $this->borderBottomStyle;\n    }\n\n    /**\n     * Set border bottom style.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setBorderBottomStyle($value = null)\n    {\n        $this->borderBottomStyle = $value;\n\n        return $this;\n    }\n\n    /**\n     * Check if any of the border is not null.\n     *\n     * @return bool\n     */\n    public function hasBorder()\n    {\n        $borders = $this->getBorderSize();\n\n        return $borders !== array_filter($borders, 'is_null');\n    }\n\n    /**\n     * Get Margin Top.\n     *\n     * @return float|int\n     */\n    public function getMarginTop()\n    {\n        return $this->marginTop;\n    }\n\n    /**\n     * Set Margin Top.\n     *\n     * @param float|int $value\n     *\n     * @return self\n     */\n    public function setMarginTop($value = null)\n    {\n        $this->marginTop = $this->setNumericVal($value, self::DEFAULT_MARGIN);\n\n        return $this;\n    }\n\n    /**\n     * Get Margin Left.\n     *\n     * @return float|int\n     */\n    public function getMarginLeft()\n    {\n        return $this->marginLeft;\n    }\n\n    /**\n     * Set Margin Left.\n     *\n     * @param float|int $value\n     *\n     * @return self\n     */\n    public function setMarginLeft($value = null)\n    {\n        $this->marginLeft = $this->setNumericVal($value, self::DEFAULT_MARGIN);\n\n        return $this;\n    }\n\n    /**\n     * Get Margin Right.\n     *\n     * @return float|int\n     */\n    public function getMarginRight()\n    {\n        return $this->marginRight;\n    }\n\n    /**\n     * Set Margin Right.\n     *\n     * @param float|int $value\n     *\n     * @return self\n     */\n    public function setMarginRight($value = null)\n    {\n        $this->marginRight = $this->setNumericVal($value, self::DEFAULT_MARGIN);\n\n        return $this;\n    }\n\n    /**\n     * Get Margin Bottom.\n     *\n     * @return float|int\n     */\n    public function getMarginBottom()\n    {\n        return $this->marginBottom;\n    }\n\n    /**\n     * Set Margin Bottom.\n     *\n     * @param float|int $value\n     *\n     * @return self\n     */\n    public function setMarginBottom($value = null)\n    {\n        $this->marginBottom = $this->setNumericVal($value, self::DEFAULT_MARGIN);\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Style/Cell.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Style;\n\nuse PhpOffice\\PhpWord\\SimpleType\\TblWidth;\nuse PhpOffice\\PhpWord\\SimpleType\\VerticalJc;\n\n/**\n * Table cell style.\n */\nclass Cell extends Border\n{\n    //Text direction constants\n    /**\n     * Left to Right, Top to Bottom.\n     */\n    const TEXT_DIR_LRTB = 'lrTb';\n    /**\n     * Top to Bottom, Right to Left.\n     */\n    const TEXT_DIR_TBRL = 'tbRl';\n    /**\n     * Bottom to Top, Left to Right.\n     */\n    const TEXT_DIR_BTLR = 'btLr';\n    /**\n     * Left to Right, Top to Bottom Rotated.\n     */\n    const TEXT_DIR_LRTBV = 'lrTbV';\n    /**\n     * Top to Bottom, Right to Left Rotated.\n     */\n    const TEXT_DIR_TBRLV = 'tbRlV';\n    /**\n     * Top to Bottom, Left to Right Rotated.\n     */\n    const TEXT_DIR_TBLRV = 'tbLrV';\n\n    /**\n     * Vertical merge (rowspan) constants.\n     *\n     * @const string\n     */\n    const VMERGE_RESTART = 'restart';\n    const VMERGE_CONTINUE = 'continue';\n\n    /**\n     * Default border color.\n     *\n     * @const string\n     */\n    const DEFAULT_BORDER_COLOR = '000000';\n\n    /**\n     * Vertical align (top, center, both, bottom).\n     *\n     * @var null|string\n     */\n    private $vAlign;\n\n    /**\n     * @var null|int\n     */\n    private $paddingTop;\n\n    /**\n     * @var null|int\n     */\n    private $paddingBottom;\n\n    /**\n     * @var null|int\n     */\n    private $paddingLeft;\n\n    /**\n     * @var null|int\n     */\n    private $paddingRight;\n\n    /**\n     * Text Direction.\n     *\n     * @var string\n     */\n    private $textDirection;\n\n    /**\n     * colspan.\n     *\n     * @var int\n     */\n    private $gridSpan;\n\n    /**\n     * rowspan (restart, continue).\n     *\n     * - restart: Start/restart merged region\n     * - continue: Continue merged region\n     *\n     * @var null|string\n     */\n    private $vMerge;\n\n    /**\n     * Shading.\n     *\n     * @var Shading\n     */\n    private $shading;\n\n    /**\n     * Width.\n     *\n     * @var ?int\n     */\n    private $width;\n\n    /**\n     * Width unit.\n     *\n     * @var string\n     */\n    private $unit = TblWidth::TWIP;\n\n    /**\n     * Prevent text from wrapping in the cell.\n     *\n     * @var bool\n     */\n    private $noWrap = true;\n\n    /**\n     * Get vertical align.\n     *\n     * @return null|string\n     */\n    public function getVAlign()\n    {\n        return $this->vAlign;\n    }\n\n    /**\n     * Set vertical align.\n     *\n     * @param null|string $value\n     *\n     * @return self\n     */\n    public function setVAlign($value = null)\n    {\n        if ($value === null) {\n            $this->vAlign = null;\n\n            return $this;\n        }\n\n        VerticalJc::validate($value);\n        $this->vAlign = $this->setEnumVal($value, VerticalJc::values(), $this->vAlign);\n\n        return $this;\n    }\n\n    /**\n     * Get text direction.\n     *\n     * @return string\n     */\n    public function getTextDirection()\n    {\n        return $this->textDirection;\n    }\n\n    /**\n     * Set text direction.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setTextDirection($value = null)\n    {\n        $enum = [\n            self::TEXT_DIR_BTLR,\n            self::TEXT_DIR_TBRL,\n            self::TEXT_DIR_LRTB,\n            self::TEXT_DIR_LRTBV,\n            self::TEXT_DIR_TBRLV,\n            self::TEXT_DIR_TBLRV,\n        ];\n        $this->textDirection = $this->setEnumVal($value, $enum, $this->textDirection);\n\n        return $this;\n    }\n\n    /**\n     * Get background.\n     *\n     * @return string\n     */\n    public function getBgColor()\n    {\n        if ($this->shading !== null) {\n            return $this->shading->getFill();\n        }\n\n        return null;\n    }\n\n    /**\n     * Set background.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setBgColor($value = null)\n    {\n        return $this->setShading(['fill' => $value]);\n    }\n\n    /**\n     * Get grid span (colspan).\n     *\n     * @return int\n     */\n    public function getGridSpan()\n    {\n        return $this->gridSpan;\n    }\n\n    /**\n     * Set grid span (colspan).\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setGridSpan($value = null)\n    {\n        $this->gridSpan = $this->setIntVal($value, $this->gridSpan);\n\n        return $this;\n    }\n\n    /**\n     * Get vertical merge (rowspan).\n     *\n     * @return null|string\n     */\n    public function getVMerge()\n    {\n        return $this->vMerge;\n    }\n\n    /**\n     * Set vertical merge (rowspan).\n     *\n     * @param null|string $value\n     *\n     * @return self\n     */\n    public function setVMerge($value = null)\n    {\n        if ($value === null) {\n            $this->vMerge = null;\n\n            return $this;\n        }\n\n        $enum = [self::VMERGE_RESTART, self::VMERGE_CONTINUE];\n        $this->vMerge = $this->setEnumVal($value, $enum, $this->vMerge);\n\n        return $this;\n    }\n\n    /**\n     * Get shading.\n     *\n     * @return Shading\n     */\n    public function getShading()\n    {\n        return $this->shading;\n    }\n\n    /**\n     * Set shading.\n     *\n     * @param mixed $value\n     *\n     * @return self\n     */\n    public function setShading($value = null)\n    {\n        $this->setObjectVal($value, 'Shading', $this->shading);\n\n        return $this;\n    }\n\n    /**\n     * Get cell width.\n     *\n     * @return ?int\n     */\n    public function getWidth()\n    {\n        return $this->width;\n    }\n\n    /**\n     * Set cell width.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setWidth($value)\n    {\n        $this->width = $this->setIntVal($value);\n\n        return $this;\n    }\n\n    /**\n     * Get width unit.\n     *\n     * @return string\n     */\n    public function getUnit()\n    {\n        return $this->unit;\n    }\n\n    /**\n     * Set width unit.\n     *\n     * @param string $value\n     */\n    public function setUnit($value)\n    {\n        $this->unit = $this->setEnumVal($value, [TblWidth::AUTO, TblWidth::PERCENT, TblWidth::TWIP], TblWidth::TWIP);\n\n        return $this;\n    }\n\n    /**\n     * Set noWrap.\n     */\n    public function setNoWrap(bool $value): self\n    {\n        $this->noWrap = $this->setBoolVal($value, true);\n\n        return $this;\n    }\n\n    /**\n     * Get noWrap.\n     */\n    public function getNoWrap(): bool\n    {\n        return $this->noWrap;\n    }\n\n    /**\n     * Get style padding-top.\n     */\n    public function getPaddingTop(): ?int\n    {\n        return $this->paddingTop;\n    }\n\n    /**\n     * Set style padding-top.\n     *\n     * @return $this\n     */\n    public function setPaddingTop(int $value): self\n    {\n        $this->paddingTop = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get style padding-bottom.\n     */\n    public function getPaddingBottom(): ?int\n    {\n        return $this->paddingBottom;\n    }\n\n    /**\n     * Set style padding-bottom.\n     *\n     * @return $this\n     */\n    public function setPaddingBottom(int $value): self\n    {\n        $this->paddingBottom = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get style padding-left.\n     */\n    public function getPaddingLeft(): ?int\n    {\n        return $this->paddingLeft;\n    }\n\n    /**\n     * Set style padding-left.\n     *\n     * @return $this\n     */\n    public function setPaddingLeft(int $value): self\n    {\n        $this->paddingLeft = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get style padding-right.\n     */\n    public function getPaddingRight(): ?int\n    {\n        return $this->paddingRight;\n    }\n\n    /**\n     * Set style padding-right.\n     *\n     * @return $this\n     */\n    public function setPaddingRight(int $value): self\n    {\n        $this->paddingRight = $value;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Style/Chart.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Style;\n\n/**\n * Chart style.\n *\n * @since 0.12.0\n */\nclass Chart extends AbstractStyle\n{\n    /**\n     * Width (in EMU).\n     *\n     * @var int\n     */\n    private $width = 1000000;\n\n    /**\n     * Height (in EMU).\n     *\n     * @var int\n     */\n    private $height = 1000000;\n\n    /**\n     * Is 3D; applies to pie, bar, line, area.\n     *\n     * @var bool\n     */\n    private $is3d = false;\n\n    /**\n     * A list of colors to use in the chart.\n     *\n     * @var array\n     */\n    private $colors = [];\n\n    /**\n     * Chart title.\n     *\n     * @var string\n     */\n    private $title;\n\n    /**\n     * Chart legend visibility.\n     *\n     * @var bool\n     */\n    private $showLegend = false;\n\n    /**\n     * Chart legend Position.\n     * Possible values are 'r', 't', 'b', 'l', 'tr'.\n     *\n     * @var string\n     */\n    private $legendPosition = 'r';\n\n    /**\n     * A list of display options for data labels.\n     *\n     * @var array\n     */\n    private $dataLabelOptions = [\n        'showVal' => true, // value\n        'showCatName' => true, // category name\n        'showLegendKey' => false, //show the cart legend\n        'showSerName' => false, // series name\n        'showPercent' => false,\n        'showLeaderLines' => false,\n        'showBubbleSize' => false,\n    ];\n\n    /**\n     * A string that tells the writer where to write chart labels or to skip\n     * \"nextTo\" - sets labels next to the axis (bar graphs on the left) (default)\n     * \"low\" - labels on the left side of the graph\n     * \"high\" - labels on the right side of the graph.\n     *\n     * @var string\n     */\n    private $categoryLabelPosition = 'nextTo';\n\n    /**\n     * A string that tells the writer where to write chart labels or to skip\n     * \"nextTo\" - sets labels next to the axis (bar graphs on the bottom) (default)\n     * \"low\" - labels are below the graph\n     * \"high\" - labels above the graph.\n     *\n     * @var string\n     */\n    private $valueLabelPosition = 'nextTo';\n\n    /**\n     * @var string\n     */\n    private $categoryAxisTitle;\n\n    /**\n     * @var string\n     */\n    private $valueAxisTitle;\n\n    /**\n     * The position for major tick marks\n     * Possible values are 'in', 'out', 'cross', 'none'.\n     *\n     * @var string\n     */\n    private $majorTickMarkPos = 'none';\n\n    /**\n     * Show labels for axis.\n     *\n     * @var bool\n     */\n    private $showAxisLabels = false;\n\n    /**\n     * Show Gridlines for Y-Axis.\n     *\n     * @var bool\n     */\n    private $gridY = false;\n\n    /**\n     * Show Gridlines for X-Axis.\n     *\n     * @var bool\n     */\n    private $gridX = false;\n\n    /**\n     * Create a new instance.\n     *\n     * @param array $style\n     */\n    public function __construct($style = [])\n    {\n        $this->setStyleByArray($style);\n    }\n\n    /**\n     * Get width.\n     *\n     * @return int\n     */\n    public function getWidth()\n    {\n        return $this->width;\n    }\n\n    /**\n     * Set width.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setWidth($value = null)\n    {\n        $this->width = $this->setIntVal($value, $this->width);\n\n        return $this;\n    }\n\n    /**\n     * Get height.\n     *\n     * @return int\n     */\n    public function getHeight()\n    {\n        return $this->height;\n    }\n\n    /**\n     * Set height.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setHeight($value = null)\n    {\n        $this->height = $this->setIntVal($value, $this->height);\n\n        return $this;\n    }\n\n    /**\n     * Is 3D.\n     *\n     * @return bool\n     */\n    public function is3d()\n    {\n        return $this->is3d;\n    }\n\n    /**\n     * Set 3D.\n     *\n     * @param bool $value\n     *\n     * @return self\n     */\n    public function set3d($value = true)\n    {\n        $this->is3d = $this->setBoolVal($value, $this->is3d);\n\n        return $this;\n    }\n\n    /**\n     * Get the list of colors to use in a chart.\n     *\n     * @return array\n     */\n    public function getColors()\n    {\n        return $this->colors;\n    }\n\n    /**\n     * Set the colors to use in a chart.\n     *\n     * @param array $value a list of colors to use in the chart\n     *\n     * @return self\n     */\n    public function setColors($value = [])\n    {\n        $this->colors = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get the chart title.\n     *\n     * @return string\n     */\n    public function getTitle()\n    {\n        return $this->title;\n    }\n\n    /**\n     * Set the chart title.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setTitle($value = null)\n    {\n        $this->title = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get chart legend visibility.\n     *\n     * @return bool\n     */\n    public function isShowLegend()\n    {\n        return $this->showLegend;\n    }\n\n    /**\n     * Set chart legend visibility.\n     *\n     * @param bool $value\n     *\n     * @return self\n     */\n    public function setShowLegend($value = false)\n    {\n        $this->showLegend = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get chart legend position.\n     *\n     * @return string\n     */\n    public function getLegendPosition()\n    {\n        return $this->legendPosition;\n    }\n\n    /**\n     * Set chart legend position. choices:\n     * \"r\" - right of chart\n     * \"b\" - bottom of chart\n     * \"t\" - top of chart\n     * \"l\" - left of chart\n     * \"tr\" - top right of chart.\n     *\n     * default: right\n     *\n     * @param string $legendPosition\n     *\n     * @return self\n     */\n    public function setLegendPosition($legendPosition = 'r')\n    {\n        $enum = ['r', 'b', 't', 'l', 'tr'];\n        $this->legendPosition = $this->setEnumVal($legendPosition, $enum, $this->legendPosition);\n\n        return $this;\n    }\n\n    /*\n     * Show labels for axis\n     *\n     * @return bool\n     */\n    public function showAxisLabels()\n    {\n        return $this->showAxisLabels;\n    }\n\n    /**\n     * Set show Gridlines for Y-Axis.\n     *\n     * @param bool $value\n     *\n     * @return self\n     */\n    public function setShowAxisLabels($value = true)\n    {\n        $this->showAxisLabels = $this->setBoolVal($value, $this->showAxisLabels);\n\n        return $this;\n    }\n\n    /**\n     * get the list of options for data labels.\n     *\n     * @return array\n     */\n    public function getDataLabelOptions()\n    {\n        return $this->dataLabelOptions;\n    }\n\n    /**\n     * Set values for data label options.\n     * This will only change values for options defined in $this->dataLabelOptions, and cannot create new ones.\n     *\n     * @param array $values [description]\n     */\n    public function setDataLabelOptions($values = []): void\n    {\n        foreach (array_keys($this->dataLabelOptions) as $option) {\n            if (isset($values[$option])) {\n                $this->dataLabelOptions[$option] = $this->setBoolVal(\n                    $values[$option],\n                    $this->dataLabelOptions[$option]\n                );\n            }\n        }\n    }\n\n    /*\n     * Show Gridlines for Y-Axis\n     *\n     * @return bool\n     */\n    public function showGridY()\n    {\n        return $this->gridY;\n    }\n\n    /**\n     * Set show Gridlines for Y-Axis.\n     *\n     * @param bool $value\n     *\n     * @return self\n     */\n    public function setShowGridY($value = true)\n    {\n        $this->gridY = $this->setBoolVal($value, $this->gridY);\n\n        return $this;\n    }\n\n    /**\n     * Get the categoryLabelPosition setting.\n     *\n     * @return string\n     */\n    public function getCategoryLabelPosition()\n    {\n        return $this->categoryLabelPosition;\n    }\n\n    /**\n     * Set the categoryLabelPosition setting\n     * \"none\" - skips writing  labels\n     * \"nextTo\" - sets labels next to the  (bar graphs on the left)\n     * \"low\" - labels on the left side of the graph\n     * \"high\" - labels on the right side of the graph.\n     *\n     * @param mixed $labelPosition\n     *\n     * @return self\n     */\n    public function setCategoryLabelPosition($labelPosition)\n    {\n        $enum = ['nextTo', 'low', 'high'];\n        $this->categoryLabelPosition = $this->setEnumVal($labelPosition, $enum, $this->categoryLabelPosition);\n\n        return $this;\n    }\n\n    /**\n     * Get the valueAxisLabelPosition setting.\n     *\n     * @return string\n     */\n    public function getValueLabelPosition()\n    {\n        return $this->valueLabelPosition;\n    }\n\n    /**\n     * Set the valueLabelPosition setting\n     * \"none\" - skips writing labels\n     * \"nextTo\" - sets labels next to the value\n     * \"low\" - sets labels are below the graph\n     * \"high\" - sets labels above the graph.\n     */\n    public function setValueLabelPosition(string $labelPosition)\n    {\n        $enum = ['nextTo', 'low', 'high'];\n        $this->valueLabelPosition = $this->setEnumVal($labelPosition, $enum, $this->valueLabelPosition);\n\n        return $this;\n    }\n\n    /**\n     * Get the categoryAxisTitle.\n     *\n     * @return string\n     */\n    public function getCategoryAxisTitle()\n    {\n        return $this->categoryAxisTitle;\n    }\n\n    /**\n     * Set the title that appears on the category side of the chart.\n     *\n     * @param string $axisTitle\n     */\n    public function setCategoryAxisTitle($axisTitle)\n    {\n        $this->categoryAxisTitle = $axisTitle;\n\n        return $this;\n    }\n\n    /**\n     * Get the valueAxisTitle.\n     *\n     * @return string\n     */\n    public function getValueAxisTitle()\n    {\n        return $this->valueAxisTitle;\n    }\n\n    /**\n     * Set the title that appears on the value side of the chart.\n     *\n     * @param string $axisTitle\n     */\n    public function setValueAxisTitle($axisTitle)\n    {\n        $this->valueAxisTitle = $axisTitle;\n\n        return $this;\n    }\n\n    public function getMajorTickPosition()\n    {\n        return $this->majorTickMarkPos;\n    }\n\n    /**\n     * Set the position for major tick marks.\n     *\n     * @param string $position\n     */\n    public function setMajorTickPosition($position): void\n    {\n        $enum = ['in', 'out', 'cross', 'none'];\n        $this->majorTickMarkPos = $this->setEnumVal($position, $enum, $this->majorTickMarkPos);\n    }\n\n    /**\n     * Show Gridlines for X-Axis.\n     *\n     * @return bool\n     */\n    public function showGridX()\n    {\n        return $this->gridX;\n    }\n\n    /**\n     * Set show Gridlines for X-Axis.\n     *\n     * @param bool $value\n     *\n     * @return self\n     */\n    public function setShowGridX($value = true)\n    {\n        $this->gridX = $this->setBoolVal($value, $this->gridX);\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Style/Extrusion.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Style;\n\n/**\n * 3D extrusion style.\n *\n * @see  http://www.schemacentral.com/sc/ooxml/t-o_CT_Extrusion.html\n * @since 0.12.0\n */\nclass Extrusion extends AbstractStyle\n{\n    /**\n     * Type constants.\n     *\n     * @const string\n     */\n    const EXTRUSION_PARALLEL = 'parallel';\n    const EXTRUSION_PERSPECTIVE = 'perspective';\n\n    /**\n     * Type: parallel|perspective.\n     *\n     * @var string\n     */\n    private $type;\n\n    /**\n     * Color.\n     *\n     * @var string\n     */\n    private $color;\n\n    /**\n     * Create a new instance.\n     *\n     * @param array $style\n     */\n    public function __construct($style = [])\n    {\n        $this->setStyleByArray($style);\n    }\n\n    /**\n     * Get type.\n     *\n     * @return string\n     */\n    public function getType()\n    {\n        return $this->type;\n    }\n\n    /**\n     * Set pattern.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setType($value = null)\n    {\n        $enum = [self::EXTRUSION_PARALLEL, self::EXTRUSION_PERSPECTIVE];\n        $this->type = $this->setEnumVal($value, $enum, null);\n\n        return $this;\n    }\n\n    /**\n     * Get color.\n     *\n     * @return string\n     */\n    public function getColor()\n    {\n        return $this->color;\n    }\n\n    /**\n     * Set color.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setColor($value = null)\n    {\n        $this->color = $value;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Style/Fill.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Style;\n\n/**\n * Fill style.\n *\n * There are still lot of interesting things for this style that can be added, including gradient. See @see .\n *\n * @see  http://www.schemacentral.com/sc/ooxml/t-v_CT_Fill.html\n * @since 0.12.0\n */\nclass Fill extends AbstractStyle\n{\n    /**\n     * Color.\n     *\n     * @var string\n     */\n    private $color;\n\n    /**\n     * Create a new instance.\n     *\n     * @param array $style\n     */\n    public function __construct($style = [])\n    {\n        $this->setStyleByArray($style);\n    }\n\n    /**\n     * Get color.\n     *\n     * @return string\n     */\n    public function getColor()\n    {\n        return $this->color;\n    }\n\n    /**\n     * Set color.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setColor($value = null)\n    {\n        $this->color = $value;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Style/Font.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Style;\n\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Shared\\Validate;\n\n/**\n * Font style.\n */\nclass Font extends AbstractStyle\n{\n    /**\n     * Underline types.\n     *\n     * @const string\n     */\n    const UNDERLINE_NONE = 'none';\n    const UNDERLINE_DASH = 'dash';\n    const UNDERLINE_DASHHEAVY = 'dashHeavy';\n    const UNDERLINE_DASHLONG = 'dashLong';\n    const UNDERLINE_DASHLONGHEAVY = 'dashLongHeavy';\n    const UNDERLINE_DOUBLE = 'dbl';\n    const UNDERLINE_DOTDASH = 'dotDash';\n    const UNDERLINE_DOTDASHHEAVY = 'dotDashHeavy';\n    const UNDERLINE_DOTDOTDASH = 'dotDotDash';\n    const UNDERLINE_DOTDOTDASHHEAVY = 'dotDotDashHeavy';\n    const UNDERLINE_DOTTED = 'dotted';\n    const UNDERLINE_DOTTEDHEAVY = 'dottedHeavy';\n    const UNDERLINE_HEAVY = 'heavy';\n    const UNDERLINE_SINGLE = 'single';\n    const UNDERLINE_WAVY = 'wavy';\n    const UNDERLINE_WAVYDOUBLE = 'wavyDbl';\n    const UNDERLINE_WAVYHEAVY = 'wavyHeavy';\n    const UNDERLINE_WORDS = 'words';\n\n    /**\n     * Foreground colors.\n     *\n     * @const string\n     */\n    const FGCOLOR_YELLOW = 'yellow';\n    const FGCOLOR_LIGHTGREEN = 'green';\n    const FGCOLOR_CYAN = 'cyan';\n    const FGCOLOR_MAGENTA = 'magenta';\n    const FGCOLOR_BLUE = 'blue';\n    const FGCOLOR_RED = 'red';\n    const FGCOLOR_DARKBLUE = 'darkBlue';\n    const FGCOLOR_DARKCYAN = 'darkCyan';\n    const FGCOLOR_DARKGREEN = 'darkGreen';\n    const FGCOLOR_DARKMAGENTA = 'darkMagenta';\n    const FGCOLOR_DARKRED = 'darkRed';\n    const FGCOLOR_DARKYELLOW = 'darkYellow';\n    const FGCOLOR_DARKGRAY = 'darkGray';\n    const FGCOLOR_LIGHTGRAY = 'lightGray';\n    const FGCOLOR_BLACK = 'black';\n\n    /**\n     * Aliases.\n     *\n     * @var array\n     */\n    protected $aliases = ['line-height' => 'lineHeight', 'letter-spacing' => 'spacing'];\n\n    /**\n     * Font style type.\n     *\n     * @var string\n     */\n    private $type;\n\n    /**\n     * Font name.\n     *\n     * @var string\n     */\n    private $name;\n\n    /**\n     * Font Content Type.\n     *\n     * @var string\n     */\n    private $hint;\n\n    /**\n     * Font size.\n     *\n     * @var float|int\n     */\n    private $size;\n\n    /**\n     * Font color.\n     *\n     * @var null|string\n     */\n    private $color;\n\n    /**\n     * Bold.\n     *\n     * @var bool\n     */\n    private $bold;\n\n    /**\n     * Italic.\n     *\n     * @var bool\n     */\n    private $italic;\n\n    /**\n     * Undeline.\n     *\n     * @var string\n     */\n    private $underline = self::UNDERLINE_NONE;\n\n    /**\n     * Superscript.\n     *\n     * @var bool\n     */\n    private $superScript = false;\n\n    /**\n     * Subscript.\n     *\n     * @var bool\n     */\n    private $subScript = false;\n\n    /**\n     * Strikethrough.\n     *\n     * @var bool\n     */\n    private $strikethrough;\n\n    /**\n     * Double strikethrough.\n     *\n     * @var bool\n     */\n    private $doubleStrikethrough;\n\n    /**\n     * Small caps.\n     *\n     * @var bool\n     *\n     * @see  http://www.schemacentral.com/sc/ooxml/e-w_smallCaps-1.html\n     */\n    private $smallCaps;\n\n    /**\n     * All caps.\n     *\n     * @var bool\n     *\n     * @see  http://www.schemacentral.com/sc/ooxml/e-w_caps-1.html\n     */\n    private $allCaps;\n\n    /**\n     * Foreground/highlight.\n     *\n     * @var string\n     */\n    private $fgColor;\n\n    /**\n     * Expanded/compressed text: 0-600 (percent).\n     *\n     * @var int\n     *\n     * @since 0.12.0\n     * @see  http://www.schemacentral.com/sc/ooxml/e-w_w-1.html\n     */\n    private $scale;\n\n    /**\n     * Character spacing adjustment: twip.\n     *\n     * @var float|int\n     *\n     * @since 0.12.0\n     * @see  http://www.schemacentral.com/sc/ooxml/e-w_spacing-2.html\n     */\n    private $spacing;\n\n    /**\n     * Font kerning: halfpoint.\n     *\n     * @var float|int\n     *\n     * @since 0.12.0\n     * @see  http://www.schemacentral.com/sc/ooxml/e-w_kern-1.html\n     */\n    private $kerning;\n\n    /**\n     * Paragraph style.\n     *\n     * @var Paragraph\n     */\n    private $paragraph;\n\n    /**\n     * Shading.\n     *\n     * @var Shading\n     */\n    private $shading;\n\n    /**\n     * Right to left languages.\n     *\n     * @var ?bool\n     */\n    private $rtl;\n\n    /**\n     * noProof (disables AutoCorrect).\n     *\n     * @var bool\n     * http://www.datypic.com/sc/ooxml/e-w_noProof-1.html\n     */\n    private $noProof;\n\n    /**\n     * Languages.\n     *\n     * @var null|Language\n     */\n    private $lang;\n\n    /**\n     * Hidden text.\n     *\n     * @var bool\n     *\n     * @see  http://www.datypic.com/sc/ooxml/e-w_vanish-1.html\n     */\n    private $hidden;\n\n    /**\n     * Vertically Raised or Lowered Text.\n     *\n     * @var int Signed Half-Point Measurement\n     *\n     * @see http://www.datypic.com/sc/ooxml/e-w_position-1.html\n     */\n    private $position;\n\n    /**\n     * Preservation of white space in html.\n     *\n     * @var string Value used for css white-space\n     */\n    private $whiteSpace = '';\n\n    /**\n     * Generic font as fallback for html.\n     *\n     * @var string generic font name\n     */\n    private $fallbackFont = '';\n\n    /**\n     * Create new font style.\n     *\n     * @param string $type Type of font\n     * @param AbstractStyle|array|string $paragraph Paragraph styles definition\n     */\n    public function __construct($type = 'text', $paragraph = null)\n    {\n        $this->type = $type;\n        $this->setParagraph($paragraph);\n    }\n\n    /**\n     * Get style values.\n     *\n     * @return array\n     *\n     * @since 0.12.0\n     */\n    public function getStyleValues()\n    {\n        return [\n            'name' => $this->getStyleName(),\n            'basic' => [\n                'name' => $this->getName(),\n                'size' => $this->getSize(),\n                'color' => $this->getColor(),\n                'hint' => $this->getHint(),\n            ],\n            'style' => [\n                'bold' => $this->isBold(),\n                'italic' => $this->isItalic(),\n                'underline' => $this->getUnderline(),\n                'strike' => $this->isStrikethrough(),\n                'dStrike' => $this->isDoubleStrikethrough(),\n                'super' => $this->isSuperScript(),\n                'sub' => $this->isSubScript(),\n                'smallCaps' => $this->isSmallCaps(),\n                'allCaps' => $this->isAllCaps(),\n                'fgColor' => $this->getFgColor(),\n                'hidden' => $this->isHidden(),\n            ],\n            'spacing' => [\n                'scale' => $this->getScale(),\n                'spacing' => $this->getSpacing(),\n                'kerning' => $this->getKerning(),\n                'position' => $this->getPosition(),\n            ],\n            'paragraph' => $this->getParagraph(),\n            'rtl' => $this->isRTL(),\n            'shading' => $this->getShading(),\n            'lang' => $this->getLang(),\n            'whiteSpace' => $this->getWhiteSpace(),\n            'fallbackFont' => $this->getFallbackFont(),\n        ];\n    }\n\n    /**\n     * Get style type.\n     *\n     * @return string\n     */\n    public function getStyleType()\n    {\n        return $this->type;\n    }\n\n    /**\n     * Get font name.\n     *\n     * @return string\n     */\n    public function getName()\n    {\n        return $this->name;\n    }\n\n    /**\n     * Set font name.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setName($value = null)\n    {\n        $this->name = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get Font Content Type.\n     *\n     * @return string\n     */\n    public function getHint()\n    {\n        return $this->hint;\n    }\n\n    /**\n     * Set Font Content Type.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setHint($value = null)\n    {\n        $this->hint = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get font size.\n     *\n     * @return float|int\n     */\n    public function getSize()\n    {\n        return $this->size;\n    }\n\n    /**\n     * Set font size.\n     *\n     * @param float|int $value\n     *\n     * @return self\n     */\n    public function setSize($value = null)\n    {\n        $this->size = $this->setNumericVal($value, $this->size);\n\n        return $this;\n    }\n\n    /**\n     * Get font color.\n     */\n    public function getColor(): ?string\n    {\n        return $this->color;\n    }\n\n    /**\n     * Set font color.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setColor($value = null)\n    {\n        $this->color = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get bold.\n     *\n     * @return bool\n     */\n    public function isBold()\n    {\n        return $this->bold;\n    }\n\n    /**\n     * Set bold.\n     *\n     * @param bool $value\n     *\n     * @return self\n     */\n    public function setBold($value = true)\n    {\n        $this->bold = $this->setBoolVal($value, $this->bold);\n\n        return $this;\n    }\n\n    /**\n     * Get italic.\n     *\n     * @return bool\n     */\n    public function isItalic()\n    {\n        return $this->italic;\n    }\n\n    /**\n     * Set italic.\n     *\n     * @param bool $value\n     *\n     * @return self\n     */\n    public function setItalic($value = true)\n    {\n        $this->italic = $this->setBoolVal($value, $this->italic);\n\n        return $this;\n    }\n\n    /**\n     * Get underline.\n     *\n     * @return string\n     */\n    public function getUnderline()\n    {\n        return $this->underline;\n    }\n\n    /**\n     * Set underline.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setUnderline($value = self::UNDERLINE_NONE)\n    {\n        $this->underline = $this->setNonEmptyVal($value, self::UNDERLINE_NONE);\n\n        return $this;\n    }\n\n    /**\n     * Get superscript.\n     *\n     * @return bool\n     */\n    public function isSuperScript()\n    {\n        return $this->superScript;\n    }\n\n    /**\n     * Set superscript.\n     *\n     * @param bool $value\n     *\n     * @return self\n     */\n    public function setSuperScript($value = true)\n    {\n        return $this->setPairedVal($this->superScript, $this->subScript, $value);\n    }\n\n    /**\n     * Get subscript.\n     *\n     * @return bool\n     */\n    public function isSubScript()\n    {\n        return $this->subScript;\n    }\n\n    /**\n     * Set subscript.\n     *\n     * @param bool $value\n     *\n     * @return self\n     */\n    public function setSubScript($value = true)\n    {\n        return $this->setPairedVal($this->subScript, $this->superScript, $value);\n    }\n\n    /**\n     * Get strikethrough.\n     */\n    public function isStrikethrough(): ?bool\n    {\n        return $this->strikethrough;\n    }\n\n    /**\n     * Set strikethrough.\n     *\n     * @param bool $value\n     */\n    public function setStrikethrough($value = true): self\n    {\n        return $this->setPairedVal($this->strikethrough, $this->doubleStrikethrough, $value);\n    }\n\n    /**\n     * Get double strikethrough.\n     */\n    public function isDoubleStrikethrough(): ?bool\n    {\n        return $this->doubleStrikethrough;\n    }\n\n    /**\n     * Set double strikethrough.\n     *\n     * @param bool $value\n     */\n    public function setDoubleStrikethrough($value = true): self\n    {\n        return $this->setPairedVal($this->doubleStrikethrough, $this->strikethrough, $value);\n    }\n\n    /**\n     * Get small caps.\n     *\n     * @return bool\n     */\n    public function isSmallCaps()\n    {\n        return $this->smallCaps;\n    }\n\n    /**\n     * Set small caps.\n     *\n     * @param bool $value\n     *\n     * @return self\n     */\n    public function setSmallCaps($value = true)\n    {\n        return $this->setPairedVal($this->smallCaps, $this->allCaps, $value);\n    }\n\n    /**\n     * Get all caps.\n     *\n     * @return bool\n     */\n    public function isAllCaps()\n    {\n        return $this->allCaps;\n    }\n\n    /**\n     * Set all caps.\n     *\n     * @param bool $value\n     *\n     * @return self\n     */\n    public function setAllCaps($value = true)\n    {\n        return $this->setPairedVal($this->allCaps, $this->smallCaps, $value);\n    }\n\n    /**\n     * Get foreground/highlight color.\n     *\n     * @return string\n     */\n    public function getFgColor()\n    {\n        return $this->fgColor;\n    }\n\n    /**\n     * Set foreground/highlight color.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setFgColor($value = null)\n    {\n        $this->fgColor = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get background.\n     *\n     * @return string\n     */\n    public function getBgColor()\n    {\n        return $this->getChildStyleValue($this->shading, 'fill');\n    }\n\n    /**\n     * Set background.\n     *\n     * @param string $value\n     *\n     * @return Table\n     */\n    public function setBgColor($value = null)\n    {\n        $this->setShading(['fill' => $value]);\n    }\n\n    /**\n     * Get scale.\n     *\n     * @return int\n     */\n    public function getScale()\n    {\n        return $this->scale;\n    }\n\n    /**\n     * Set scale.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setScale($value = null)\n    {\n        $this->scale = $this->setIntVal($value, null);\n\n        return $this;\n    }\n\n    /**\n     * Get font spacing.\n     *\n     * @return float|int\n     */\n    public function getSpacing()\n    {\n        return $this->spacing;\n    }\n\n    /**\n     * Set font spacing.\n     *\n     * @param float|int $value\n     *\n     * @return self\n     */\n    public function setSpacing($value = null)\n    {\n        $this->spacing = $this->setNumericVal($value, null);\n\n        return $this;\n    }\n\n    /**\n     * Get font kerning.\n     *\n     * @return float|int\n     */\n    public function getKerning()\n    {\n        return $this->kerning;\n    }\n\n    /**\n     * Set font kerning.\n     *\n     * @param float|int $value\n     *\n     * @return self\n     */\n    public function setKerning($value = null)\n    {\n        $this->kerning = $this->setNumericVal($value, null);\n\n        return $this;\n    }\n\n    /**\n     * Get noProof (disables autocorrect).\n     *\n     * @return bool\n     */\n    public function isNoProof()\n    {\n        return $this->noProof;\n    }\n\n    /**\n     * Set noProof (disables autocorrect).\n     *\n     * @param bool $value\n     *\n     * @return $this\n     */\n    public function setNoProof($value = false)\n    {\n        $this->noProof = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get line height.\n     *\n     * @return float|int\n     */\n    public function getLineHeight()\n    {\n        return $this->getParagraph()->getLineHeight();\n    }\n\n    /**\n     * Set lineheight.\n     *\n     * @param float|int|string $value\n     *\n     * @return self\n     */\n    public function setLineHeight($value)\n    {\n        $this->setParagraph(['lineHeight' => $value]);\n\n        return $this;\n    }\n\n    /**\n     * Get paragraph style.\n     *\n     * @return Paragraph\n     */\n    public function getParagraph()\n    {\n        return $this->paragraph;\n    }\n\n    /**\n     * Set Paragraph.\n     *\n     * @param mixed $value\n     *\n     * @return self\n     */\n    public function setParagraph($value = null)\n    {\n        $this->setObjectVal($value, 'Paragraph', $this->paragraph);\n\n        return $this;\n    }\n\n    /**\n     * Get rtl.\n     *\n     * @return ?bool\n     */\n    public function isRTL()\n    {\n        return $this->rtl ?? Settings::isDefaultRtl();\n    }\n\n    /**\n     * Set rtl.\n     *\n     * @param ?bool $value\n     *\n     * @return self\n     */\n    public function setRTL($value = true)\n    {\n        $this->rtl = $this->setBoolVal($value, $this->rtl);\n\n        return $this;\n    }\n\n    /**\n     * Get shading.\n     *\n     * @return Shading\n     */\n    public function getShading()\n    {\n        return $this->shading;\n    }\n\n    /**\n     * Set shading.\n     *\n     * @param mixed $value\n     *\n     * @return self\n     */\n    public function setShading($value = null)\n    {\n        $this->setObjectVal($value, 'Shading', $this->shading);\n\n        return $this;\n    }\n\n    /**\n     * Get language.\n     *\n     * @return null|Language\n     */\n    public function getLang()\n    {\n        return $this->lang;\n    }\n\n    /**\n     * Set language.\n     *\n     * @param mixed $value\n     *\n     * @return self\n     */\n    public function setLang($value = null)\n    {\n        if (is_string($value) && $value != '') {\n            $value = new Language($value);\n        }\n        $this->setObjectVal($value, 'Language', $this->lang);\n\n        return $this;\n    }\n\n    /**\n     * Get hidden text.\n     *\n     * @return bool\n     */\n    public function isHidden()\n    {\n        return $this->hidden;\n    }\n\n    /**\n     * Set hidden text.\n     *\n     * @param bool $value\n     *\n     * @return self\n     */\n    public function setHidden($value = true)\n    {\n        $this->hidden = $this->setBoolVal($value, $this->hidden);\n\n        return $this;\n    }\n\n    /**\n     * Get position.\n     *\n     * @return int\n     */\n    public function getPosition()\n    {\n        return $this->position;\n    }\n\n    /**\n     * Set position.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setPosition($value = null)\n    {\n        $this->position = $this->setIntVal($value, null);\n\n        return $this;\n    }\n\n    /**\n     * Set html css white-space value. It is expected that only pre-wrap and normal (default) are useful.\n     *\n     * @param null|string $value Should be one of pre-wrap, normal, nowrap, pre, pre-line, initial, inherit\n     */\n    public function setWhiteSpace(?string $value): self\n    {\n        $this->whiteSpace = Validate::validateCSSWhiteSpace($value);\n\n        return $this;\n    }\n\n    /**\n     * Get html css white-space value.\n     */\n    public function getWhiteSpace(): string\n    {\n        return $this->whiteSpace;\n    }\n\n    /**\n     * Set generic font for fallback for html.\n     *\n     * @param string $value generic font name\n     */\n    public function setFallbackFont(?string $value): self\n    {\n        $this->fallbackFont = Validate::validateCSSGenericFont($value);\n\n        return $this;\n    }\n\n    /**\n     * Get html fallback generic font.\n     */\n    public function getFallbackFont(): string\n    {\n        return $this->fallbackFont;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Style/Frame.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Style;\n\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\n\n/**\n * Frame defines the size and position of an object.\n *\n * Width, height, left/hpos, top/vpos, hrel, vrel, wrap, zindex\n *\n * @since 0.12.0\n *\n * @todo Make existing style (image, textbox, etc) use this style\n */\nclass Frame extends AbstractStyle\n{\n    /**\n     * Length unit.\n     *\n     * @const string\n     */\n    const UNIT_PT = 'pt'; // Mostly for shapes\n    const UNIT_PX = 'px'; // Mostly for images\n\n    /**\n     * General positioning options.\n     *\n     * @const string\n     */\n    const POS_ABSOLUTE = 'absolute';\n    const POS_RELATIVE = 'relative';\n\n    /**\n     * Horizontal/vertical value.\n     *\n     * @const string\n     */\n    const POS_CENTER = 'center';\n    const POS_LEFT = 'left';\n    const POS_RIGHT = 'right';\n    const POS_TOP = 'top';\n    const POS_BOTTOM = 'bottom';\n    const POS_INSIDE = 'inside';\n    const POS_OUTSIDE = 'outside';\n\n    /**\n     * Position relative to.\n     *\n     * @const string\n     */\n    const POS_RELTO_MARGIN = 'margin';\n    const POS_RELTO_PAGE = 'page';\n    const POS_RELTO_COLUMN = 'column'; // horizontal only\n    const POS_RELTO_CHAR = 'char'; // horizontal only\n    const POS_RELTO_TEXT = 'text'; // vertical only\n    const POS_RELTO_LINE = 'line'; // vertical only\n    const POS_RELTO_LMARGIN = 'left-margin-area'; // horizontal only\n    const POS_RELTO_RMARGIN = 'right-margin-area'; // horizontal only\n    const POS_RELTO_TMARGIN = 'top-margin-area'; // vertical only\n    const POS_RELTO_BMARGIN = 'bottom-margin-area'; // vertical only\n    const POS_RELTO_IMARGIN = 'inner-margin-area';\n    const POS_RELTO_OMARGIN = 'outer-margin-area';\n\n    /**\n     * Wrap type.\n     *\n     * @const string\n     */\n    const WRAP_INLINE = 'inline';\n    const WRAP_SQUARE = 'square';\n    const WRAP_TIGHT = 'tight';\n    const WRAP_THROUGH = 'through';\n    const WRAP_TOPBOTTOM = 'topAndBottom';\n    const WRAP_BEHIND = 'behind';\n    const WRAP_INFRONT = 'infront';\n\n    /**\n     * @var string\n     */\n    private $alignment = '';\n\n    /**\n     * Unit.\n     *\n     * @var string\n     */\n    private $unit = 'pt';\n\n    /**\n     * Width.\n     *\n     * @var float|int\n     */\n    private $width;\n\n    /**\n     * Height.\n     *\n     * @var float|int\n     */\n    private $height;\n\n    /**\n     * Leftmost (horizontal) position.\n     *\n     * @var float|int\n     */\n    private $left = 0;\n\n    /**\n     * Topmost (vertical) position.\n     *\n     * @var float|int\n     */\n    private $top = 0;\n\n    /**\n     * Position type: absolute|relative.\n     *\n     * @var string\n     */\n    private $pos;\n\n    /**\n     * Horizontal position.\n     *\n     * @var string\n     */\n    private $hPos;\n\n    /**\n     * Horizontal position relative to.\n     *\n     * @var string\n     */\n    private $hPosRelTo;\n\n    /**\n     * Vertical position.\n     *\n     * @var string\n     */\n    private $vPos;\n\n    /**\n     * Vertical position relative to.\n     *\n     * @var string\n     */\n    private $vPosRelTo;\n\n    /**\n     * Wrap type.\n     *\n     * @var string\n     */\n    private $wrap;\n\n    /**\n     * Top wrap distance.\n     *\n     * @var float\n     */\n    private $wrapDistanceTop;\n\n    /**\n     * Bottom wrap distance.\n     *\n     * @var float\n     */\n    private $wrapDistanceBottom;\n\n    /**\n     * Left wrap distance.\n     *\n     * @var float\n     */\n    private $wrapDistanceLeft;\n\n    /**\n     * Right wrap distance.\n     *\n     * @var float\n     */\n    private $wrapDistanceRight;\n\n    /**\n     * Vertically raised or lowered text.\n     *\n     * @var int\n     *\n     * @see http://www.datypic.com/sc/ooxml/e-w_position-1.html\n     */\n    private $position;\n\n    /**\n     * Create a new instance.\n     *\n     * @param array $style\n     */\n    public function __construct($style = [])\n    {\n        $this->setStyleByArray($style);\n    }\n\n    /**\n     * @since 0.13.0\n     *\n     * @return string\n     */\n    public function getAlignment()\n    {\n        return $this->alignment;\n    }\n\n    /**\n     * @since 0.13.0\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setAlignment($value)\n    {\n        if (Jc::isValid($value)) {\n            $this->alignment = $value;\n        }\n\n        return $this;\n    }\n\n    /**\n     * Get unit.\n     *\n     * @return string\n     */\n    public function getUnit()\n    {\n        return $this->unit;\n    }\n\n    /**\n     * Set unit.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setUnit($value)\n    {\n        $this->unit = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get width.\n     *\n     * @return float|int\n     */\n    public function getWidth()\n    {\n        return $this->width;\n    }\n\n    /**\n     * Set width.\n     *\n     * @param float|int $value\n     *\n     * @return self\n     */\n    public function setWidth($value = null)\n    {\n        $this->width = $this->setNumericVal($value, null);\n\n        return $this;\n    }\n\n    /**\n     * Get height.\n     *\n     * @return float|int\n     */\n    public function getHeight()\n    {\n        return $this->height;\n    }\n\n    /**\n     * Set height.\n     *\n     * @param float|int $value\n     *\n     * @return self\n     */\n    public function setHeight($value = null)\n    {\n        $this->height = $this->setNumericVal($value, null);\n\n        return $this;\n    }\n\n    /**\n     * Get left.\n     *\n     * @return float|int\n     */\n    public function getLeft()\n    {\n        return $this->left;\n    }\n\n    /**\n     * Set left.\n     *\n     * @param float|int $value\n     *\n     * @return self\n     */\n    public function setLeft($value = 0)\n    {\n        $this->left = $this->setNumericVal($value, 0);\n\n        return $this;\n    }\n\n    /**\n     * Get topmost position.\n     *\n     * @return float|int\n     */\n    public function getTop()\n    {\n        return $this->top;\n    }\n\n    /**\n     * Set topmost position.\n     *\n     * @param float|int $value\n     *\n     * @return self\n     */\n    public function setTop($value = 0)\n    {\n        $this->top = $this->setNumericVal($value, 0);\n\n        return $this;\n    }\n\n    /**\n     * Get position type.\n     *\n     * @return string\n     */\n    public function getPos()\n    {\n        return $this->pos;\n    }\n\n    /**\n     * Set position type.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setPos($value)\n    {\n        $enum = [\n            self::POS_ABSOLUTE,\n            self::POS_RELATIVE,\n        ];\n        $this->pos = $this->setEnumVal($value, $enum, $this->pos);\n\n        return $this;\n    }\n\n    /**\n     * Get horizontal position.\n     *\n     * @return string\n     */\n    public function getHPos()\n    {\n        return $this->hPos;\n    }\n\n    /**\n     * Set horizontal position.\n     *\n     * @since 0.12.0 \"absolute\" option is available.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setHPos($value)\n    {\n        $enum = [\n            self::POS_ABSOLUTE,\n            self::POS_LEFT,\n            self::POS_CENTER,\n            self::POS_RIGHT,\n            self::POS_INSIDE,\n            self::POS_OUTSIDE,\n        ];\n        $this->hPos = $this->setEnumVal($value, $enum, $this->hPos);\n\n        return $this;\n    }\n\n    /**\n     * Get vertical position.\n     *\n     * @return string\n     */\n    public function getVPos()\n    {\n        return $this->vPos;\n    }\n\n    /**\n     * Set vertical position.\n     *\n     * @since 0.12.0 \"absolute\" option is available.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setVPos($value)\n    {\n        $enum = [\n            self::POS_ABSOLUTE,\n            self::POS_TOP,\n            self::POS_CENTER,\n            self::POS_BOTTOM,\n            self::POS_INSIDE,\n            self::POS_OUTSIDE,\n        ];\n        $this->vPos = $this->setEnumVal($value, $enum, $this->vPos);\n\n        return $this;\n    }\n\n    /**\n     * Get horizontal position relative to.\n     *\n     * @return string\n     */\n    public function getHPosRelTo()\n    {\n        return $this->hPosRelTo;\n    }\n\n    /**\n     * Set horizontal position relative to.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setHPosRelTo($value)\n    {\n        $enum = [\n            self::POS_RELTO_MARGIN,\n            self::POS_RELTO_PAGE,\n            self::POS_RELTO_COLUMN,\n            self::POS_RELTO_CHAR,\n            self::POS_RELTO_LMARGIN,\n            self::POS_RELTO_RMARGIN,\n            self::POS_RELTO_IMARGIN,\n            self::POS_RELTO_OMARGIN,\n        ];\n        $this->hPosRelTo = $this->setEnumVal($value, $enum, $this->hPosRelTo);\n\n        return $this;\n    }\n\n    /**\n     * Get vertical position relative to.\n     *\n     * @return string\n     */\n    public function getVPosRelTo()\n    {\n        return $this->vPosRelTo;\n    }\n\n    /**\n     * Set vertical position relative to.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setVPosRelTo($value)\n    {\n        $enum = [\n            self::POS_RELTO_MARGIN,\n            self::POS_RELTO_PAGE,\n            self::POS_RELTO_TEXT,\n            self::POS_RELTO_LINE,\n            self::POS_RELTO_TMARGIN,\n            self::POS_RELTO_BMARGIN,\n            self::POS_RELTO_IMARGIN,\n            self::POS_RELTO_OMARGIN,\n        ];\n        $this->vPosRelTo = $this->setEnumVal($value, $enum, $this->vPosRelTo);\n\n        return $this;\n    }\n\n    /**\n     * Get wrap type.\n     *\n     * @return string\n     */\n    public function getWrap()\n    {\n        return $this->wrap;\n    }\n\n    /**\n     * Set wrap type.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setWrap($value)\n    {\n        $enum = [\n            self::WRAP_INLINE,\n            self::WRAP_SQUARE,\n            self::WRAP_TIGHT,\n            self::WRAP_THROUGH,\n            self::WRAP_TOPBOTTOM,\n            self::WRAP_BEHIND,\n            self::WRAP_INFRONT,\n        ];\n        $this->wrap = $this->setEnumVal($value, $enum, $this->wrap);\n\n        return $this;\n    }\n\n    /**\n     * Get top distance from text wrap.\n     *\n     * @return float\n     */\n    public function getWrapDistanceTop()\n    {\n        return $this->wrapDistanceTop;\n    }\n\n    /**\n     * Set top distance from text wrap.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setWrapDistanceTop($value = null)\n    {\n        $this->wrapDistanceTop = $this->setFloatVal($value, null);\n\n        return $this;\n    }\n\n    /**\n     * Get bottom distance from text wrap.\n     *\n     * @return float\n     */\n    public function getWrapDistanceBottom()\n    {\n        return $this->wrapDistanceBottom;\n    }\n\n    /**\n     * Set bottom distance from text wrap.\n     *\n     * @param float $value\n     *\n     * @return self\n     */\n    public function setWrapDistanceBottom($value = null)\n    {\n        $this->wrapDistanceBottom = $this->setFloatVal($value, null);\n\n        return $this;\n    }\n\n    /**\n     * Get left distance from text wrap.\n     *\n     * @return float\n     */\n    public function getWrapDistanceLeft()\n    {\n        return $this->wrapDistanceLeft;\n    }\n\n    /**\n     * Set left distance from text wrap.\n     *\n     * @param float $value\n     *\n     * @return self\n     */\n    public function setWrapDistanceLeft($value = null)\n    {\n        $this->wrapDistanceLeft = $this->setFloatVal($value, null);\n\n        return $this;\n    }\n\n    /**\n     * Get right distance from text wrap.\n     *\n     * @return float\n     */\n    public function getWrapDistanceRight()\n    {\n        return $this->wrapDistanceRight;\n    }\n\n    /**\n     * Set right distance from text wrap.\n     *\n     * @param float $value\n     *\n     * @return self\n     */\n    public function setWrapDistanceRight($value = null)\n    {\n        $this->wrapDistanceRight = $this->setFloatVal($value, null);\n\n        return $this;\n    }\n\n    /**\n     * Get position.\n     *\n     * @return int\n     */\n    public function getPosition()\n    {\n        return $this->position;\n    }\n\n    /**\n     * Set position.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setPosition($value = null)\n    {\n        $this->position = $this->setIntVal($value, null);\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Style/Image.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Style;\n\n/**\n * Image and memory image style.\n */\nclass Image extends Frame\n{\n    /**\n     * Backward compatibility constants.\n     *\n     * @const string\n     */\n    const WRAPPING_STYLE_INLINE = self::WRAP_INLINE;\n    const WRAPPING_STYLE_SQUARE = self::WRAP_SQUARE;\n    const WRAPPING_STYLE_TIGHT = self::WRAP_TIGHT;\n    const WRAPPING_STYLE_BEHIND = self::WRAP_BEHIND;\n    const WRAPPING_STYLE_INFRONT = self::WRAP_INFRONT;\n    const POSITION_HORIZONTAL_LEFT = self::POS_LEFT;\n    const POSITION_HORIZONTAL_CENTER = self::POS_CENTER;\n    const POSITION_HORIZONTAL_RIGHT = self::POS_RIGHT;\n    const POSITION_VERTICAL_TOP = self::POS_TOP;\n    const POSITION_VERTICAL_CENTER = self::POS_CENTER;\n    const POSITION_VERTICAL_BOTTOM = self::POS_BOTTOM;\n    const POSITION_VERTICAL_INSIDE = self::POS_INSIDE;\n    const POSITION_VERTICAL_OUTSIDE = self::POS_OUTSIDE;\n    const POSITION_RELATIVE_TO_MARGIN = self::POS_RELTO_MARGIN;\n    const POSITION_RELATIVE_TO_PAGE = self::POS_RELTO_PAGE;\n    const POSITION_RELATIVE_TO_COLUMN = self::POS_RELTO_COLUMN;\n    const POSITION_RELATIVE_TO_CHAR = self::POS_RELTO_CHAR;\n    const POSITION_RELATIVE_TO_TEXT = self::POS_RELTO_TEXT;\n    const POSITION_RELATIVE_TO_LINE = self::POS_RELTO_LINE;\n    const POSITION_RELATIVE_TO_LMARGIN = self::POS_RELTO_LMARGIN;\n    const POSITION_RELATIVE_TO_RMARGIN = self::POS_RELTO_RMARGIN;\n    const POSITION_RELATIVE_TO_TMARGIN = self::POS_RELTO_TMARGIN;\n    const POSITION_RELATIVE_TO_BMARGIN = self::POS_RELTO_BMARGIN;\n    const POSITION_RELATIVE_TO_IMARGIN = self::POS_RELTO_IMARGIN;\n    const POSITION_RELATIVE_TO_OMARGIN = self::POS_RELTO_OMARGIN;\n    const POSITION_ABSOLUTE = self::POS_ABSOLUTE;\n    const POSITION_RELATIVE = self::POS_RELATIVE;\n\n    /**\n     * Create new instance.\n     */\n    public function __construct()\n    {\n        parent::__construct();\n        $this->setUnit(self::UNIT_PT);\n\n        // Backward compatibility setting\n        // @todo Remove on 1.0.0\n        $this->setWrap(self::WRAPPING_STYLE_INLINE);\n        $this->setHPos(self::POSITION_HORIZONTAL_LEFT);\n        $this->setHPosRelTo(self::POSITION_RELATIVE_TO_CHAR);\n        $this->setVPos(self::POSITION_VERTICAL_TOP);\n        $this->setVPosRelTo(self::POSITION_RELATIVE_TO_LINE);\n    }\n\n    /**\n     * Get margin top.\n     *\n     * @return float|int\n     */\n    public function getMarginTop()\n    {\n        return $this->getTop();\n    }\n\n    /**\n     * Set margin top.\n     *\n     * @ignoreScrutinizerPatch\n     *\n     * @param float|int $value\n     *\n     * @return self\n     */\n    public function setMarginTop($value = 0)\n    {\n        $this->setTop($value);\n\n        return $this;\n    }\n\n    /**\n     * Get margin left.\n     *\n     * @return float|int\n     */\n    public function getMarginLeft()\n    {\n        return $this->getLeft();\n    }\n\n    /**\n     * Set margin left.\n     *\n     * @ignoreScrutinizerPatch\n     *\n     * @param float|int $value\n     *\n     * @return self\n     */\n    public function setMarginLeft($value = 0)\n    {\n        $this->setLeft($value);\n\n        return $this;\n    }\n\n    /**\n     * Get wrapping style.\n     *\n     * @return string\n     */\n    public function getWrappingStyle()\n    {\n        return $this->getWrap();\n    }\n\n    /**\n     * Set wrapping style.\n     *\n     * @param string $wrappingStyle\n     *\n     * @return self\n     */\n    public function setWrappingStyle($wrappingStyle)\n    {\n        $this->setWrap($wrappingStyle);\n\n        return $this;\n    }\n\n    /**\n     * Get positioning type.\n     *\n     * @return string\n     */\n    public function getPositioning()\n    {\n        return $this->getPos();\n    }\n\n    /**\n     * Set positioning type.\n     *\n     * @param string $positioning\n     *\n     * @return self\n     */\n    public function setPositioning($positioning)\n    {\n        $this->setPos($positioning);\n\n        return $this;\n    }\n\n    /**\n     * Get horizontal alignment.\n     *\n     * @return string\n     */\n    public function getPosHorizontal()\n    {\n        return $this->getHPos();\n    }\n\n    /**\n     * Set horizontal alignment.\n     *\n     * @param string $alignment\n     *\n     * @return self\n     */\n    public function setPosHorizontal($alignment)\n    {\n        $this->setHPos($alignment);\n\n        return $this;\n    }\n\n    /**\n     * Get vertical alignment.\n     *\n     * @return string\n     */\n    public function getPosVertical()\n    {\n        return $this->getVPos();\n    }\n\n    /**\n     * Set vertical alignment.\n     *\n     * @param string $alignment\n     *\n     * @return self\n     */\n    public function setPosVertical($alignment)\n    {\n        $this->setVPos($alignment);\n\n        return $this;\n    }\n\n    /**\n     * Get horizontal relation.\n     *\n     * @return string\n     */\n    public function getPosHorizontalRel()\n    {\n        return $this->getHPosRelTo();\n    }\n\n    /**\n     * Set horizontal relation.\n     *\n     * @param string $relto\n     *\n     * @return self\n     */\n    public function setPosHorizontalRel($relto)\n    {\n        $this->setHPosRelTo($relto);\n\n        return $this;\n    }\n\n    /**\n     * Get vertical relation.\n     *\n     * @return string\n     */\n    public function getPosVerticalRel()\n    {\n        return $this->getVPosRelTo();\n    }\n\n    /**\n     * Set vertical relation.\n     *\n     * @param string $relto\n     *\n     * @return self\n     */\n    public function setPosVerticalRel($relto)\n    {\n        $this->setVPosRelTo($relto);\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Style/Indentation.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Style;\n\n/**\n * Paragraph indentation style.\n *\n * @see  http://www.schemacentral.com/sc/ooxml/t-w_CT_Ind.html\n * @since 0.10.0\n */\nclass Indentation extends AbstractStyle\n{\n    /**\n     * Left indentation (twip).\n     *\n     * @var null|float\n     */\n    private $left = 0;\n\n    /**\n     * Right indentation (twip).\n     *\n     * @var null|float\n     */\n    private $right = 0;\n\n    /**\n     * Additional first line indentation (twip).\n     *\n     * @var null|float\n     */\n    private $firstLine = 0;\n\n    /**\n     * Additional first line chars indentation (twip).\n     *\n     * @var int\n     */\n    private $firstLineChars = 0;\n\n    /**\n     * Indentation removed from first line (twip).\n     *\n     * @var null|float\n     */\n    private $hanging = 0;\n\n    /**\n     * Create a new instance.\n     *\n     * @param array $style\n     */\n    public function __construct($style = [])\n    {\n        $this->setStyleByArray($style);\n    }\n\n    /**\n     * Get left.\n     */\n    public function getLeft(): ?float\n    {\n        return $this->left;\n    }\n\n    /**\n     * Set left.\n     */\n    public function setLeft(?float $value): self\n    {\n        $this->left = $this->setNumericVal($value);\n\n        return $this;\n    }\n\n    /**\n     * Get right.\n     */\n    public function getRight(): ?float\n    {\n        return $this->right;\n    }\n\n    /**\n     * Set right.\n     */\n    public function setRight(?float $value): self\n    {\n        $this->right = $this->setNumericVal($value);\n\n        return $this;\n    }\n\n    /**\n     * Get first line.\n     */\n    public function getFirstLine(): ?float\n    {\n        return $this->firstLine;\n    }\n\n    /**\n     * Set first line.\n     */\n    public function setFirstLine(?float $value): self\n    {\n        $this->firstLine = $this->setNumericVal($value);\n\n        return $this;\n    }\n\n    /**\n     * Get first line chars.\n     */\n    public function getFirstLineChars(): int\n    {\n        return $this->firstLineChars;\n    }\n\n    /**\n     * Set first line chars.\n     */\n    public function setFirstLineChars(int $value): self\n    {\n        $this->firstLineChars = $this->setIntVal($value, $this->firstLineChars);\n\n        return $this;\n    }\n\n    /**\n     * Get hanging.\n     */\n    public function getHanging(): ?float\n    {\n        return $this->hanging;\n    }\n\n    /**\n     * Set hanging.\n     */\n    public function setHanging(?float $value = null): self\n    {\n        $this->hanging = $this->setNumericVal($value);\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Style/Language.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Style;\n\nuse InvalidArgumentException;\n\n/**\n * Language\n * A couple of predefined values are defined here, see the websites below for more values.\n *\n * @see http://www.datypic.com/sc/ooxml/t-w_CT_Language.html\n * @see https://technet.microsoft.com/en-us/library/cc287874(v=office.12).aspx\n */\nfinal class Language extends AbstractStyle\n{\n    const EN_US = 'en-US';\n    const EN_US_ID = 1033;\n\n    const EN_GB = 'en-GB';\n    const EN_GB_ID = 2057;\n\n    const FR_FR = 'fr-FR';\n    const FR_FR_ID = 1036;\n\n    const FR_BE = 'fr-BE';\n    const FR_BE_ID = 2060;\n\n    const FR_CH = 'fr-CH';\n    const FR_CH_ID = 4108;\n\n    const ES_ES = 'es-ES';\n    const ES_ES_ID = 3082;\n\n    const DE_DE = 'de-DE';\n    const DE_DE_ID = 1031;\n\n    const DE_CH = 'de-CH';\n    const DE_CH_ID = 2055;\n\n    const HE_IL = 'he-IL';\n    const HE_IL_ID = 1037;\n\n    const IT_IT = 'it-IT';\n    const IT_IT_ID = 1040;\n\n    const IT_CH = 'it-CH';\n    const IT_CH_ID = 2064;\n\n    const JA_JP = 'ja-JP';\n    const JA_JP_ID = 1041;\n\n    const KO_KR = 'ko-KR';\n    const KO_KR_ID = 1042;\n\n    const ZH_CN = 'zh-CN';\n    const ZH_CN_ID = 2052;\n\n    const HI_IN = 'hi-IN';\n    const HI_IN_ID = 1081;\n\n    const PT_BR = 'pt-BR';\n    const PT_BR_ID = 1046;\n\n    const NL_NL = 'nl-NL';\n    const NL_NL_ID = 1043;\n\n    const SV_SE = 'sv-SE';\n    const SV_SE_ID = 1053;\n\n    const UK_UA = 'uk-UA';\n    const UK_UA_ID = 1058;\n\n    const RU_RU = 'ru-RU';\n    const RU_RU_ID = 1049;\n\n    /**\n     * Language ID, used for RTF document generation.\n     *\n     * @var int\n     *\n     * @see https://technet.microsoft.com/en-us/library/cc179219.aspx\n     */\n    private $langId;\n\n    /**\n     * Latin Language.\n     *\n     * @var null|string\n     */\n    private $latin;\n\n    /**\n     * East Asian Language.\n     *\n     * @var null|string\n     */\n    private $eastAsia;\n\n    /**\n     * Complex Script Language.\n     *\n     * @var null|string\n     */\n    private $bidirectional;\n\n    /**\n     * Constructor.\n     */\n    public function __construct(?string $latin = null, ?string $eastAsia = null, ?string $bidirectional = null)\n    {\n        if (!empty($latin)) {\n            $this->setLatin($latin);\n        }\n        if (!empty($eastAsia)) {\n            $this->setEastAsia($eastAsia);\n        }\n        if (!empty($bidirectional)) {\n            $this->setBidirectional($bidirectional);\n        }\n    }\n\n    /**\n     * Set the Latin Language.\n     *\n     * @param string $latin\n     *            The value for the latin language\n     */\n    public function setLatin(?string $latin): self\n    {\n        $this->latin = $this->validateLocale($latin);\n\n        return $this;\n    }\n\n    /**\n     * Get the Latin Language.\n     */\n    public function getLatin(): ?string\n    {\n        return $this->latin;\n    }\n\n    /**\n     * Set the Language ID.\n     *\n     * @param int $langId\n     *            The value for the language ID\n     *\n     * @return self\n     *\n     * @see https://technet.microsoft.com/en-us/library/cc287874(v=office.12).aspx\n     */\n    public function setLangId($langId)\n    {\n        $this->langId = $langId;\n\n        return $this;\n    }\n\n    /**\n     * Get the Language ID.\n     *\n     * @return int\n     */\n    public function getLangId()\n    {\n        return $this->langId;\n    }\n\n    /**\n     * Set the East Asian Language.\n     *\n     * @param string $eastAsia\n     *            The value for the east asian language\n     *\n     * @return self\n     */\n    public function setEastAsia($eastAsia)\n    {\n        $this->eastAsia = $this->validateLocale($eastAsia);\n\n        return $this;\n    }\n\n    /**\n     * Get the East Asian Language.\n     *\n     * @return null|string\n     */\n    public function getEastAsia()\n    {\n        return $this->eastAsia;\n    }\n\n    /**\n     * Set the Complex Script Language.\n     *\n     * @param string $bidirectional\n     *            The value for the complex script language\n     *\n     * @return self\n     */\n    public function setBidirectional($bidirectional)\n    {\n        $this->bidirectional = $this->validateLocale($bidirectional);\n\n        return $this;\n    }\n\n    /**\n     * Get the Complex Script Language.\n     *\n     * @return null|string\n     */\n    public function getBidirectional()\n    {\n        return $this->bidirectional;\n    }\n\n    /**\n     * Validates that the language passed is in the format xx-xx.\n     *\n     * @param string $locale\n     *\n     * @return string\n     */\n    private function validateLocale($locale)\n    {\n        if ($locale !== null) {\n            $locale = str_replace('_', '-', $locale);\n        }\n\n        if ($locale !== null && strlen($locale) === 2) {\n            return strtolower($locale) . '-' . strtoupper($locale);\n        }\n        if ($locale === 'und') {\n            return 'en-EN';\n        }\n        if ($locale !== null && $locale !== 'zxx' && strstr($locale, '-') === false) {\n            throw new InvalidArgumentException($locale . ' is not a valid language code');\n        }\n\n        return $locale;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Style/Line.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Style;\n\n/**\n * Line style.\n */\nclass Line extends Image\n{\n    /**\n     * Connector types.\n     *\n     * @const string\n     */\n    const CONNECTOR_TYPE_STRAIGHT = 'straight';\n\n    /**\n     * Arrow styles.\n     *\n     * @const string\n     */\n    const ARROW_STYLE_BLOCK = 'block';\n    const ARROW_STYLE_OPEN = 'open';\n    const ARROW_STYLE_CLASSIC = 'classic';\n    const ARROW_STYLE_DIAMOND = 'diamond';\n    const ARROW_STYLE_OVAL = 'oval';\n\n    /**\n     * Dash styles.\n     *\n     * @const string\n     */\n    const DASH_STYLE_DASH = 'dash';\n    const DASH_STYLE_ROUND_DOT = 'rounddot';\n    const DASH_STYLE_SQUARE_DOT = 'squaredot';\n    const DASH_STYLE_DASH_DOT = 'dashdot';\n    const DASH_STYLE_LONG_DASH = 'longdash';\n    const DASH_STYLE_LONG_DASH_DOT = 'longdashdot';\n    const DASH_STYLE_LONG_DASH_DOT_DOT = 'longdashdotdot';\n\n    /**\n     * flip Line.\n     *\n     * @var bool\n     */\n    private $flip = false;\n\n    /**\n     * connectorType.\n     *\n     * @var string\n     */\n    private $connectorType = self::CONNECTOR_TYPE_STRAIGHT;\n\n    /**\n     * Line Weight.\n     *\n     * @var int\n     */\n    private $weight;\n\n    /**\n     * Line color.\n     *\n     * @var string\n     */\n    private $color;\n\n    /**\n     * Dash style.\n     *\n     * @var string\n     */\n    private $dash;\n\n    /**\n     * Begin arrow.\n     *\n     * @var string\n     */\n    private $beginArrow;\n\n    /**\n     * End arrow.\n     *\n     * @var string\n     */\n    private $endArrow;\n\n    /**\n     * Get flip.\n     *\n     * @return bool\n     */\n    public function isFlip()\n    {\n        return $this->flip;\n    }\n\n    /**\n     * Set flip.\n     *\n     * @param bool $value\n     *\n     * @return self\n     */\n    public function setFlip($value = false)\n    {\n        $this->flip = $this->setBoolVal($value, $this->flip);\n\n        return $this;\n    }\n\n    /**\n     * Get connectorType.\n     *\n     * @return string\n     */\n    public function getConnectorType()\n    {\n        return $this->connectorType;\n    }\n\n    /**\n     * Set connectorType.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setConnectorType($value = null)\n    {\n        $enum = [\n            self::CONNECTOR_TYPE_STRAIGHT,\n        ];\n        $this->connectorType = $this->setEnumVal($value, $enum, $this->connectorType);\n\n        return $this;\n    }\n\n    /**\n     * Get weight.\n     *\n     * @return int\n     */\n    public function getWeight()\n    {\n        return $this->weight;\n    }\n\n    /**\n     * Set weight.\n     *\n     * @param int $value Weight in points\n     *\n     * @return self\n     */\n    public function setWeight($value = null)\n    {\n        $this->weight = $this->setNumericVal($value, $this->weight);\n\n        return $this;\n    }\n\n    /**\n     * Get color.\n     *\n     * @return string\n     */\n    public function getColor()\n    {\n        return $this->color;\n    }\n\n    /**\n     * Set color.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setColor($value = null)\n    {\n        $this->color = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get beginArrow.\n     *\n     * @return string\n     */\n    public function getBeginArrow()\n    {\n        return $this->beginArrow;\n    }\n\n    /**\n     * Set beginArrow.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setBeginArrow($value = null)\n    {\n        $enum = [\n            self::ARROW_STYLE_BLOCK, self::ARROW_STYLE_CLASSIC, self::ARROW_STYLE_DIAMOND,\n            self::ARROW_STYLE_OPEN, self::ARROW_STYLE_OVAL,\n        ];\n        $this->beginArrow = $this->setEnumVal($value, $enum, $this->beginArrow);\n\n        return $this;\n    }\n\n    /**\n     * Get endArrow.\n     *\n     * @return string\n     */\n    public function getEndArrow()\n    {\n        return $this->endArrow;\n    }\n\n    /**\n     * Set endArrow.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setEndArrow($value = null)\n    {\n        $enum = [\n            self::ARROW_STYLE_BLOCK, self::ARROW_STYLE_CLASSIC, self::ARROW_STYLE_DIAMOND,\n            self::ARROW_STYLE_OPEN, self::ARROW_STYLE_OVAL,\n        ];\n        $this->endArrow = $this->setEnumVal($value, $enum, $this->endArrow);\n\n        return $this;\n    }\n\n    /**\n     * Get Dash.\n     *\n     * @return string\n     */\n    public function getDash()\n    {\n        return $this->dash;\n    }\n\n    /**\n     * Set Dash.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setDash($value = null)\n    {\n        $enum = [\n            self::DASH_STYLE_DASH, self::DASH_STYLE_DASH_DOT, self::DASH_STYLE_LONG_DASH,\n            self::DASH_STYLE_LONG_DASH_DOT, self::DASH_STYLE_LONG_DASH_DOT_DOT, self::DASH_STYLE_ROUND_DOT,\n            self::DASH_STYLE_SQUARE_DOT,\n        ];\n        $this->dash = $this->setEnumVal($value, $enum, $this->dash);\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Style/LineNumbering.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Style;\n\n/**\n * Line numbering style.\n *\n * @see  http://www.schemacentral.com/sc/ooxml/t-w_CT_LineNumber.html\n * @since 0.10.0\n */\nclass LineNumbering extends AbstractStyle\n{\n    /** @const string Line numbering restart setting http://www.schemacentral.com/sc/ooxml/a-w_restart-1.html */\n    const LINE_NUMBERING_CONTINUOUS = 'continuous';\n    const LINE_NUMBERING_NEW_PAGE = 'newPage';\n    const LINE_NUMBERING_NEW_SECTION = 'newSection';\n\n    /**\n     * Line numbering starting value.\n     *\n     * @var int\n     */\n    private $start = 1;\n\n    /**\n     * Line number increments.\n     *\n     * @var int\n     */\n    private $increment = 1;\n\n    /**\n     * Distance between text and line numbering in twip.\n     *\n     * @var float|int\n     */\n    private $distance;\n\n    /**\n     * Line numbering restart setting continuous|newPage|newSection.\n     *\n     * @var string\n     *\n     * @see  http://www.schemacentral.com/sc/ooxml/a-w_restart-1.html\n     */\n    private $restart;\n\n    /**\n     * Create a new instance.\n     *\n     * @param array $style\n     */\n    public function __construct($style = [])\n    {\n        $this->setStyleByArray($style);\n    }\n\n    /**\n     * Get start.\n     *\n     * @return int\n     */\n    public function getStart()\n    {\n        return $this->start;\n    }\n\n    /**\n     * Set start.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setStart($value = null)\n    {\n        $this->start = $this->setIntVal($value, $this->start);\n\n        return $this;\n    }\n\n    /**\n     * Get increment.\n     *\n     * @return int\n     */\n    public function getIncrement()\n    {\n        return $this->increment;\n    }\n\n    /**\n     * Set increment.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setIncrement($value = null)\n    {\n        $this->increment = $this->setIntVal($value, $this->increment);\n\n        return $this;\n    }\n\n    /**\n     * Get distance.\n     *\n     * @return float|int\n     */\n    public function getDistance()\n    {\n        return $this->distance;\n    }\n\n    /**\n     * Set distance.\n     *\n     * @param float|int $value\n     *\n     * @return self\n     */\n    public function setDistance($value = null)\n    {\n        $this->distance = $this->setNumericVal($value, $this->distance);\n\n        return $this;\n    }\n\n    /**\n     * Get restart.\n     *\n     * @return string\n     */\n    public function getRestart()\n    {\n        return $this->restart;\n    }\n\n    /**\n     * Set distance.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setRestart($value = null)\n    {\n        $enum = [self::LINE_NUMBERING_CONTINUOUS, self::LINE_NUMBERING_NEW_PAGE, self::LINE_NUMBERING_NEW_SECTION];\n        $this->restart = $this->setEnumVal($value, $enum, $this->restart);\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Style/ListItem.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Style;\n\nuse PhpOffice\\PhpWord\\Style;\n\n/**\n * List item style.\n *\n * Before version 0.10.0, numbering style is defined statically with $listType.\n * After version 0.10.0, numbering style is defined by using Numbering and\n * recorded by $numStyle. $listStyle is maintained for backward compatility\n */\nclass ListItem extends AbstractStyle\n{\n    const TYPE_SQUARE_FILLED = 1;\n    const TYPE_BULLET_FILLED = 3; // default\n    const TYPE_BULLET_EMPTY = 5;\n    const TYPE_NUMBER = 7;\n    const TYPE_NUMBER_NESTED = 8;\n    const TYPE_ALPHANUM = 9;\n\n    /**\n     * Legacy list type.\n     *\n     * @var int\n     */\n    private $listType;\n\n    /**\n     * Numbering style name.\n     *\n     * @var string\n     *\n     * @since 0.10.0\n     */\n    private $numStyle;\n\n    /**\n     * Numbering definition instance ID.\n     *\n     * @var int\n     *\n     * @since 0.10.0\n     */\n    private $numId;\n\n    /**\n     * Create new instance.\n     *\n     * @param string $numStyle\n     */\n    public function __construct($numStyle = null)\n    {\n        if ($numStyle !== null) {\n            $this->setNumStyle($numStyle);\n        } else {\n            $this->setListType();\n        }\n    }\n\n    /**\n     * Get List Type.\n     *\n     * @return int\n     */\n    public function getListType()\n    {\n        return $this->listType;\n    }\n\n    /**\n     * Set legacy list type for version < 0.10.0.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setListType($value = self::TYPE_BULLET_FILLED)\n    {\n        $enum = [\n            self::TYPE_SQUARE_FILLED, self::TYPE_BULLET_FILLED,\n            self::TYPE_BULLET_EMPTY, self::TYPE_NUMBER,\n            self::TYPE_NUMBER_NESTED, self::TYPE_ALPHANUM,\n        ];\n        $this->listType = $this->setEnumVal($value, $enum, $this->listType);\n        $this->getListTypeStyle();\n\n        return $this;\n    }\n\n    /**\n     * Get numbering style name.\n     *\n     * @return string\n     */\n    public function getNumStyle()\n    {\n        return $this->numStyle;\n    }\n\n    /**\n     * Set numbering style name.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setNumStyle($value)\n    {\n        $this->numStyle = $value;\n        $numStyleObject = Style::getStyle($this->numStyle);\n        if ($numStyleObject instanceof Numbering) {\n            $this->numId = $numStyleObject->getIndex();\n            $numStyleObject->setNumId($this->numId);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Get numbering Id.\n     *\n     * @return int\n     */\n    public function getNumId()\n    {\n        return $this->numId;\n    }\n\n    /**\n     * Set numbering Id. Same numId means same list.\n     *\n     * @param mixed $numInt\n     */\n    public function setNumId($numInt): void\n    {\n        $this->numId = $numInt;\n        $this->getListTypeStyle();\n    }\n\n    /**\n     * Get legacy numbering definition.\n     *\n     * @return array\n     *\n     * @since 0.10.0\n     */\n    private function getListTypeStyle()\n    {\n        // Check if legacy style already registered in global Style collection\n        $numStyle = 'PHPWordListType' . $this->listType;\n\n        if ($this->numId) {\n            $numStyle .= 'NumId' . $this->numId;\n        }\n\n        if (Style::getStyle($numStyle) !== null) {\n            $this->setNumStyle($numStyle);\n\n            return;\n        }\n\n        // Property mapping for numbering level information\n        $properties = ['start', 'format', 'text', 'alignment', 'tabPos', 'left', 'hanging', 'font', 'hint'];\n\n        // Legacy level information\n        $listTypeStyles = [\n            self::TYPE_SQUARE_FILLED => [\n                'type' => 'hybridMultilevel',\n                'levels' => [\n                    0 => '1, bullet, , left, 720, 720, 360, Wingdings, default',\n                    1 => '1, bullet, o, left, 1440, 1440, 360, Courier New, default',\n                    2 => '1, bullet, , left, 2160, 2160, 360, Wingdings, default',\n                    3 => '1, bullet, , left, 2880, 2880, 360, Symbol, default',\n                    4 => '1, bullet, o, left, 3600, 3600, 360, Courier New, default',\n                    5 => '1, bullet, , left, 4320, 4320, 360, Wingdings, default',\n                    6 => '1, bullet, , left, 5040, 5040, 360, Symbol, default',\n                    7 => '1, bullet, o, left, 5760, 5760, 360, Courier New, default',\n                    8 => '1, bullet, , left, 6480, 6480, 360, Wingdings, default',\n                ],\n            ],\n            self::TYPE_BULLET_FILLED => [\n                'type' => 'hybridMultilevel',\n                'levels' => [\n                    0 => '1, bullet, , left, 720, 720, 360, Symbol, default',\n                    1 => '1, bullet, o, left, 1440, 1440, 360, Courier New, default',\n                    2 => '1, bullet, , left, 2160, 2160, 360, Wingdings, default',\n                    3 => '1, bullet, , left, 2880, 2880, 360, Symbol, default',\n                    4 => '1, bullet, o, left, 3600, 3600, 360, Courier New, default',\n                    5 => '1, bullet, , left, 4320, 4320, 360, Wingdings, default',\n                    6 => '1, bullet, , left, 5040, 5040, 360, Symbol, default',\n                    7 => '1, bullet, o, left, 5760, 5760, 360, Courier New, default',\n                    8 => '1, bullet, , left, 6480, 6480, 360, Wingdings, default',\n                ],\n            ],\n            self::TYPE_BULLET_EMPTY => [\n                'type' => 'hybridMultilevel',\n                'levels' => [\n                    0 => '1, bullet, o, left, 720, 720, 360, Courier New, default',\n                    1 => '1, bullet, o, left, 1440, 1440, 360, Courier New, default',\n                    2 => '1, bullet, , left, 2160, 2160, 360, Wingdings, default',\n                    3 => '1, bullet, , left, 2880, 2880, 360, Symbol, default',\n                    4 => '1, bullet, o, left, 3600, 3600, 360, Courier New, default',\n                    5 => '1, bullet, , left, 4320, 4320, 360, Wingdings, default',\n                    6 => '1, bullet, , left, 5040, 5040, 360, Symbol, default',\n                    7 => '1, bullet, o, left, 5760, 5760, 360, Courier New, default',\n                    8 => '1, bullet, , left, 6480, 6480, 360, Wingdings, default',\n                ],\n            ],\n            self::TYPE_NUMBER => [\n                'type' => 'hybridMultilevel',\n                'levels' => [\n                    0 => '1, decimal, %1., left, 720, 720, 360, , default',\n                    1 => '1, bullet, o, left, 1440, 1440, 360, Courier New, default',\n                    2 => '1, bullet, , left, 2160, 2160, 360, Wingdings, default',\n                    3 => '1, bullet, , left, 2880, 2880, 360, Symbol, default',\n                    4 => '1, bullet, o, left, 3600, 3600, 360, Courier New, default',\n                    5 => '1, bullet, , left, 4320, 4320, 360, Wingdings, default',\n                    6 => '1, bullet, , left, 5040, 5040, 360, Symbol, default',\n                    7 => '1, bullet, o, left, 5760, 5760, 360, Courier New, default',\n                    8 => '1, bullet, , left, 6480, 6480, 360, Wingdings, default',\n                ],\n            ],\n            self::TYPE_NUMBER_NESTED => [\n                'type' => 'multilevel',\n                'levels' => [\n                    0 => '1, decimal, %1., left, 360, 360, 360, , ',\n                    1 => '1, decimal, %1.%2., left, 792, 792, 432, , ',\n                    2 => '1, decimal, %1.%2.%3., left, 1224, 1224, 504, , ',\n                    3 => '1, decimal, %1.%2.%3.%4., left, 1800, 1728, 648, , ',\n                    4 => '1, decimal, %1.%2.%3.%4.%5., left, 2520, 2232, 792, , ',\n                    5 => '1, decimal, %1.%2.%3.%4.%5.%6., left, 2880, 2736, 936, , ',\n                    6 => '1, decimal, %1.%2.%3.%4.%5.%6.%7., left, 3600, 3240, 1080, , ',\n                    7 => '1, decimal, %1.%2.%3.%4.%5.%6.%7.%8., left, 3960, 3744, 1224, , ',\n                    8 => '1, decimal, %1.%2.%3.%4.%5.%6.%7.%8.%9., left, 4680, 4320, 1440, , ',\n                ],\n            ],\n            self::TYPE_ALPHANUM => [\n                'type' => 'multilevel',\n                'levels' => [\n                    0 => '1, decimal, %1., left, 720, 720, 360, , ',\n                    1 => '1, lowerLetter, %2., left, 1440, 1440, 360, , ',\n                    2 => '1, lowerRoman, %3., right, 2160, 2160, 180, , ',\n                    3 => '1, decimal, %4., left, 2880, 2880, 360, , ',\n                    4 => '1, lowerLetter, %5., left, 3600, 3600, 360, , ',\n                    5 => '1, lowerRoman, %6., right, 4320, 4320, 180, , ',\n                    6 => '1, decimal, %7., left, 5040, 5040, 360, , ',\n                    7 => '1, lowerLetter, %8., left, 5760, 5760, 360, , ',\n                    8 => '1, lowerRoman, %9., right, 6480, 6480, 180, , ',\n                ],\n            ],\n        ];\n\n        // Populate style and register to global Style register\n        $style = $listTypeStyles[$this->listType];\n        $numProperties = count($properties);\n        foreach ($style['levels'] as $key => $value) {\n            $level = [];\n            $levelProperties = explode(', ', $value);\n            $level['level'] = $key;\n            for ($i = 0; $i < $numProperties; ++$i) {\n                $property = $properties[$i];\n                $level[$property] = $levelProperties[$i];\n            }\n            $style['levels'][$key] = $level;\n        }\n        Style::addNumberingStyle($numStyle, $style);\n        $this->setNumStyle($numStyle);\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Style/Numbering.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Style;\n\n/**\n * Numbering style.\n *\n * @see  http://www.schemacentral.com/sc/ooxml/e-w_numbering.html\n * @see  http://www.schemacentral.com/sc/ooxml/e-w_abstractNum-1.html\n * @see  http://www.schemacentral.com/sc/ooxml/e-w_num-1.html\n * @since 0.10.0\n */\nclass Numbering extends AbstractStyle\n{\n    /**\n     * Numbering definition instance ID.\n     *\n     * @var int\n     *\n     * @see  http://www.schemacentral.com/sc/ooxml/e-w_num-1.html\n     */\n    private $numId;\n\n    /**\n     * Multilevel type singleLevel|multilevel|hybridMultilevel.\n     *\n     * @var string\n     *\n     * @see  http://www.schemacentral.com/sc/ooxml/a-w_val-67.html\n     */\n    private $type;\n\n    /**\n     * Numbering levels.\n     *\n     * @var NumberingLevel[]\n     */\n    private $levels = [];\n\n    /**\n     * Get Id.\n     */\n    public function getNumId(): ?int\n    {\n        return $this->numId;\n    }\n\n    /**\n     * Set Id.\n     */\n    public function setNumId(int $value): self\n    {\n        $this->numId = $this->setIntVal($value, $this->numId);\n\n        return $this;\n    }\n\n    /**\n     * Get multilevel type.\n     */\n    public function getType(): ?string\n    {\n        return $this->type;\n    }\n\n    /**\n     * Set multilevel type.\n     */\n    public function setType(string $value): self\n    {\n        $enum = ['singleLevel', 'multilevel', 'hybridMultilevel'];\n        $this->type = $this->setEnumVal($value, $enum, $this->type);\n\n        return $this;\n    }\n\n    /**\n     * Get levels.\n     *\n     * @return NumberingLevel[]\n     */\n    public function getLevels(): array\n    {\n        return $this->levels;\n    }\n\n    /**\n     * Set multilevel type.\n     */\n    public function setLevels(array $values): self\n    {\n        foreach ($values as $key => $value) {\n            $numberingLevel = new NumberingLevel();\n            if (is_array($value)) {\n                $numberingLevel->setStyleByArray($value);\n                $numberingLevel->setLevel($key);\n            }\n            $this->levels[$key] = $numberingLevel;\n        }\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Style/NumberingLevel.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Style;\n\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\nuse PhpOffice\\PhpWord\\SimpleType\\NumberFormat;\n\n/**\n * Numbering level definition.\n *\n * @see  http://www.schemacentral.com/sc/ooxml/e-w_lvl-1.html\n * @since 0.10.0\n */\nclass NumberingLevel extends AbstractStyle\n{\n    /**\n     * Level number, 0 to 8 (total 9 levels).\n     *\n     * @var int\n     */\n    private $level = 0;\n\n    /**\n     * Starting value w:start.\n     *\n     * @var int\n     *\n     * @see  http://www.schemacentral.com/sc/ooxml/e-w_start-1.html\n     */\n    private $start = 1;\n\n    /**\n     * Numbering format w:numFmt, one of PhpOffice\\PhpWord\\SimpleType\\NumberFormat.\n     *\n     * @var string\n     *\n     * @see  http://www.schemacentral.com/sc/ooxml/t-w_ST_NumberFormat.html\n     */\n    private $format;\n\n    /**\n     * Restart numbering level symbol w:lvlRestart.\n     *\n     * @var int\n     *\n     * @see  http://www.schemacentral.com/sc/ooxml/e-w_lvlRestart-1.html\n     */\n    private $restart;\n\n    /**\n     * Related paragraph style.\n     *\n     * @var string\n     *\n     * @see  http://www.schemacentral.com/sc/ooxml/e-w_pStyle-2.html\n     */\n    private $pStyle;\n\n    /**\n     * Content between numbering symbol and paragraph text w:suff.\n     *\n     * @var string tab|space|nothing\n     *\n     * @see  http://www.schemacentral.com/sc/ooxml/e-w_suff-1.html\n     */\n    private $suffix = 'tab';\n\n    /**\n     * Numbering level text e.g. %1 for nonbullet or bullet character.\n     *\n     * @var string\n     *\n     * @see  http://www.schemacentral.com/sc/ooxml/e-w_lvlText-1.html\n     */\n    private $text;\n\n    /**\n     * Justification, w:lvlJc.\n     *\n     * @var string one of PhpOffice\\PhpWord\\SimpleType\\Jc\n     */\n    private $alignment = '';\n\n    /**\n     * Left.\n     *\n     * @var int\n     */\n    private $left;\n\n    /**\n     * Hanging.\n     *\n     * @var int\n     */\n    private $hanging;\n\n    /**\n     * Tab position.\n     *\n     * @var int\n     */\n    private $tabPos;\n\n    /**\n     * Font family.\n     *\n     * @var string\n     */\n    private $font;\n\n    /**\n     * Hint default|eastAsia|cs.\n     *\n     * @var string\n     *\n     * @see  http://www.schemacentral.com/sc/ooxml/a-w_hint-1.html\n     */\n    private $hint;\n\n    /**\n     * Get level.\n     *\n     * @return int\n     */\n    public function getLevel()\n    {\n        return $this->level;\n    }\n\n    /**\n     * Set level.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setLevel($value)\n    {\n        $this->level = $this->setIntVal($value, $this->level);\n\n        return $this;\n    }\n\n    /**\n     * Get start.\n     *\n     * @return int\n     */\n    public function getStart()\n    {\n        return $this->start;\n    }\n\n    /**\n     * Set start.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setStart($value)\n    {\n        $this->start = $this->setIntVal($value, $this->start);\n\n        return $this;\n    }\n\n    /**\n     * Get format.\n     *\n     * @return string\n     */\n    public function getFormat()\n    {\n        return $this->format;\n    }\n\n    /**\n     * Set format.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setFormat($value)\n    {\n        $this->format = $this->setEnumVal($value, NumberFormat::values(), $this->format);\n\n        return $this;\n    }\n\n    /**\n     * Get restart.\n     *\n     * @return int\n     */\n    public function getRestart()\n    {\n        return $this->restart;\n    }\n\n    /**\n     * Set restart.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setRestart($value)\n    {\n        $this->restart = $this->setIntVal($value, $this->restart);\n\n        return $this;\n    }\n\n    /**\n     * Get related paragraph style.\n     *\n     * @return string\n     */\n    public function getPStyle()\n    {\n        return $this->pStyle;\n    }\n\n    /**\n     * Set  related paragraph style.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setPStyle($value)\n    {\n        $this->pStyle = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get suffix.\n     *\n     * @return string\n     */\n    public function getSuffix()\n    {\n        return $this->suffix;\n    }\n\n    /**\n     * Set suffix.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setSuffix($value)\n    {\n        $enum = ['tab', 'space', 'nothing'];\n        $this->suffix = $this->setEnumVal($value, $enum, $this->suffix);\n\n        return $this;\n    }\n\n    /**\n     * Get text.\n     *\n     * @return string\n     */\n    public function getText()\n    {\n        return $this->text;\n    }\n\n    /**\n     * Set text.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setText($value)\n    {\n        $this->text = $value;\n\n        return $this;\n    }\n\n    /**\n     * @since 0.13.0\n     *\n     * @return string\n     */\n    public function getAlignment()\n    {\n        return $this->alignment;\n    }\n\n    /**\n     * @since 0.13.0\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setAlignment($value)\n    {\n        if (Jc::isValid($value)) {\n            $this->alignment = $value;\n        }\n\n        return $this;\n    }\n\n    /**\n     * Get left.\n     *\n     * @return int\n     */\n    public function getLeft()\n    {\n        return $this->left;\n    }\n\n    /**\n     * Set left.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setLeft($value)\n    {\n        $this->left = $this->setIntVal($value, $this->left);\n\n        return $this;\n    }\n\n    /**\n     * Get hanging.\n     *\n     * @return int\n     */\n    public function getHanging()\n    {\n        return $this->hanging;\n    }\n\n    /**\n     * Set hanging.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setHanging($value)\n    {\n        $this->hanging = $this->setIntVal($value, $this->hanging);\n\n        return $this;\n    }\n\n    /**\n     * Get tab.\n     *\n     * @return int\n     */\n    public function getTabPos()\n    {\n        return $this->tabPos;\n    }\n\n    /**\n     * Set tab.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setTabPos($value)\n    {\n        $this->tabPos = $this->setIntVal($value, $this->tabPos);\n\n        return $this;\n    }\n\n    /**\n     * Get font.\n     *\n     * @return string\n     */\n    public function getFont()\n    {\n        return $this->font;\n    }\n\n    /**\n     * Set font.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setFont($value)\n    {\n        $this->font = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get hint.\n     *\n     * @return string\n     */\n    public function getHint()\n    {\n        return $this->hint;\n    }\n\n    /**\n     * Set hint.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setHint($value = null)\n    {\n        $enum = ['default', 'eastAsia', 'cs'];\n        $this->hint = $this->setEnumVal($value, $enum, $this->hint);\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Style/Outline.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Style;\n\n/**\n * Outline defines the line/border of the object.\n *\n * @see  http://www.schemacentral.com/sc/ooxml/t-v_CT_Stroke.html\n * @see  http://www.w3.org/TR/1998/NOTE-VML-19980513#_Toc416858395\n * @since 0.12.0\n */\nclass Outline extends AbstractStyle\n{\n    /**\n     * Line style constants.\n     *\n     * @see  http://www.schemacentral.com/sc/ooxml/t-v_ST_StrokeLineStyle.html\n     *\n     * @const string\n     */\n    const LINE_SINGLE = 'single';\n    const LINE_THIN_THIN = 'thinThin';\n    const LINE_THIN_THICK = 'thinThick';\n    const LINE_THICK_THIN = 'thickThin';\n    const LINE_THICK_BETWEEN_THIN = 'thickBetweenThin';\n\n    /**\n     * Line style constants.\n     *\n     * @see  http://www.schemacentral.com/sc/ooxml/t-v_ST_StrokeEndCap.html\n     *\n     * @const string\n     */\n    const ENDCAP_FLAT = 'flat';\n    const ENDCAP_SQUARE = 'square';\n    const ENDCAP_ROUND = 'round';\n\n    /**\n     * Arrowhead type constants.\n     *\n     * @see  http://www.schemacentral.com/sc/ooxml/t-v_ST_StrokeArrowType.html\n     *\n     * @const string\n     */\n    const ARROW_NONE = 'none';\n    const ARROW_BLOCK = 'block';\n    const ARROW_CLASSIC = 'classic';\n    const ARROW_OVAL = 'oval';\n    const ARROW_DIAMOND = 'diamond';\n    const ARROW_OPEN = 'open';\n\n    /**\n     * Unit; No set method for now.\n     *\n     * @var string\n     */\n    private $unit = 'pt';\n\n    /**\n     * Outline weight.\n     *\n     * @var float|int\n     */\n    private $weight;\n\n    /**\n     * Outline color.\n     *\n     * @var string\n     */\n    private $color;\n\n    /**\n     * Dash type.\n     *\n     * @var string\n     */\n    private $dash;\n\n    /**\n     * Line style.\n     *\n     * @var string\n     */\n    private $line;\n\n    /**\n     * End cap.\n     *\n     * @var string\n     *\n     * @see  http://www.schemacentral.com/sc/ooxml/t-v_ST_StrokeEndCap.html\n     */\n    private $endCap;\n\n    /**\n     * Start arrow type.\n     *\n     * @var string\n     */\n    private $startArrow;\n\n    /**\n     * End arrow type.\n     *\n     * @var string\n     */\n    private $endArrow;\n\n    /**\n     * Create a new instance.\n     *\n     * @param array $style\n     */\n    public function __construct($style = [])\n    {\n        $this->setStyleByArray($style);\n    }\n\n    /**\n     * Get unit.\n     *\n     * @return string\n     */\n    public function getUnit()\n    {\n        return $this->unit;\n    }\n\n    /**\n     * Get weight.\n     *\n     * @return float|int\n     */\n    public function getWeight()\n    {\n        return $this->weight;\n    }\n\n    /**\n     * Set weight.\n     *\n     * @param float|int $value\n     *\n     * @return self\n     */\n    public function setWeight($value = null)\n    {\n        $this->weight = $this->setNumericVal($value, null);\n\n        return $this;\n    }\n\n    /**\n     * Get color.\n     *\n     * @return string\n     */\n    public function getColor()\n    {\n        return $this->color;\n    }\n\n    /**\n     * Set color.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setColor($value = null)\n    {\n        $this->color = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get dash type.\n     *\n     * @return string\n     */\n    public function getDash()\n    {\n        return $this->dash;\n    }\n\n    /**\n     * Set dash type.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setDash($value = null)\n    {\n        $this->dash = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get line style.\n     *\n     * @return string\n     */\n    public function getLine()\n    {\n        return $this->line;\n    }\n\n    /**\n     * Set line style.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setLine($value = null)\n    {\n        $enum = [self::LINE_SINGLE, self::LINE_THIN_THIN, self::LINE_THIN_THICK,\n            self::LINE_THICK_THIN, self::LINE_THICK_BETWEEN_THIN, ];\n        $this->line = $this->setEnumVal($value, $enum, null);\n\n        return $this;\n    }\n\n    /**\n     * Get endCap style.\n     *\n     * @return string\n     */\n    public function getEndCap()\n    {\n        return $this->endCap;\n    }\n\n    /**\n     * Set endCap style.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setEndCap($value = null)\n    {\n        $enum = [self::ENDCAP_FLAT, self::ENDCAP_SQUARE, self::ENDCAP_ROUND];\n        $this->endCap = $this->setEnumVal($value, $enum, null);\n\n        return $this;\n    }\n\n    /**\n     * Get startArrow.\n     *\n     * @return string\n     */\n    public function getStartArrow()\n    {\n        return $this->startArrow;\n    }\n\n    /**\n     * Set pattern.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setStartArrow($value = null)\n    {\n        $enum = [self::ARROW_NONE, self::ARROW_BLOCK, self::ARROW_CLASSIC,\n            self::ARROW_OVAL, self::ARROW_DIAMOND, self::ARROW_OPEN, ];\n        $this->startArrow = $this->setEnumVal($value, $enum, null);\n\n        return $this;\n    }\n\n    /**\n     * Get endArrow.\n     *\n     * @return string\n     */\n    public function getEndArrow()\n    {\n        return $this->endArrow;\n    }\n\n    /**\n     * Set pattern.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setEndArrow($value = null)\n    {\n        $enum = [self::ARROW_NONE, self::ARROW_BLOCK, self::ARROW_CLASSIC,\n            self::ARROW_OVAL, self::ARROW_DIAMOND, self::ARROW_OPEN, ];\n        $this->endArrow = $this->setEnumVal($value, $enum, null);\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Style/Paper.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Style;\n\nuse PhpOffice\\PhpWord\\Shared\\Converter;\n\n/**\n * Paper size from ISO/IEC 29500-1:2012 pg. 1656-1657.\n *\n * 1 = Letter paper (8.5 in. by 11 in.)\n * 2 = Letter small paper (8.5 in. by 11 in.)\n * 3 = Tabloid paper (11 in. by 17 in.)\n * 4 = Ledger paper (17 in. by 11 in.)\n * 5 = Legal paper (8.5 in. by 14 in.)\n * 6 = Statement paper (5.5 in. by 8.5 in.)\n * 7 = Executive paper (7.25 in. by 10.5 in.)\n * 8 = A3 paper (297 mm by 420 mm)\n * 9 = A4 paper (210 mm by 297 mm)\n * 10 = A4 small paper (210 mm by 297 mm)\n * 11 = A5 paper (148 mm by 210 mm)\n * 12 = B4 paper (250 mm by 353 mm)\n * 13 = B5 paper (176 mm by 250 mm)\n * 14 = Folio paper (8.5 in. by 13 in.)\n * 15 = Quarto paper (215 mm by 275 mm)\n * 16 = Standard paper (10 in. by 14 in.)\n * 17 = Standard paper (11 in. by 17 in.)\n * 18 = Note paper (8.5 in. by 11 in.)\n * 19 = #9 envelope (3.875 in. by 8.875 in.)\n * 20 = #10 envelope (4.125 in. by 9.5 in.)\n * 21 = #11 envelope (4.5 in. by 10.375 in.)\n * 22 = #12 envelope (4.75 in. by 11 in.)\n * 23 = #14 envelope (5 in. by 11.5 in.)\n * 24 = C paper (17 in. by 22 in.)\n * 25 = D paper (22 in. by 34 in.)\n * 26 = E paper (34 in. by 44 in.)\n * 27 = DL envelope (110 mm by 220 mm)\n * 28 = C5 envelope (162 mm by 229 mm)\n * 29 = C3 envelope (324 mm by 458 mm)\n * 30 = C4 envelope (229 mm by 324 mm)\n * 31 = C6 envelope (114 mm by 162 mm)\n * 32 = C65 envelope (114 mm by 229 mm)\n * 33 = B4 envelope (250 mm by 353 mm)\n * 34 = B5 envelope (176 mm by 250 mm)\n * 35 = B6 envelope (176 mm by 125 mm)\n * 36 = Italy envelope (110 mm by 230 mm)\n * 37 = Monarch envelope (3.875 in. by 7.5 in.).\n * 38 = 6 3/4 envelope (3.625 in. by 6.5 in.)\n * 39 = US standard fanfold (14.875 in. by 11 in.)\n * 40 = German standard fanfold (8.5 in. by 12 in.)\n * 41 = German legal fanfold (8.5 in. by 13 in.)\n * 42 = ISO B4 (250 mm by 353 mm)\n * 43 = Japanese double postcard (200 mm by 148 mm)\n * 44 = Standard paper (9 in. by 11 in.)\n * 45 = Standard paper (10 in. by 11 in.)\n * 46 = Standard paper (15 in. by 11 in.)\n * 47 = Invite envelope (220 mm by 220 mm)\n * 50 = Letter extra paper (9.275 in. by 12 in.)\n * 51 = Legal extra paper (9.275 in. by 15 in.)\n * 52 = Tabloid extra paper (11.69 in. by 18 in.)\n * 53 = A4 extra paper (236 mm by 322 mm)\n * 54 = Letter transverse paper (8.275 in. by 11 in.)\n * 55 = A4 transverse paper (210 mm by 297 mm)\n * 56 = Letter extra transverse paper (9.275 in. by 12 in.)\n * 57 = SuperA/SuperA/A4 paper (227 mm by 356 mm)\n * 58 = SuperB/SuperB/A3 paper (305 mm by 487 mm)\n * 59 = Letter plus paper (8.5 in. by 12.69 in.)\n * 60 = A4 plus paper (210 mm by 330 mm)\n * 61 = A5 transverse paper (148 mm by 210 mm)\n * 62 = JIS B5 transverse paper (182 mm by 257 mm)\n * 63 = A3 extra paper (322 mm by 445 mm)\n * 64 = A5 extra paper (174 mm by 235 mm)\n * 65 = ISO B5 extra paper (201 mm by 276 mm)\n * 66 = A2 paper (420 mm by 594 mm)\n * 67 = A3 transverse paper (297 mm by 420 mm)\n * 68 = A3 extra transverse paper (322 mm by 445 mm)\n *\n * @since 0.12.0\n */\nclass Paper extends AbstractStyle\n{\n    /**\n     * Paper sizes.\n     *\n     * @var array\n     */\n    private $sizes = [\n        'A3' => [297, 420, 'mm'],\n        'A4' => [210, 297, 'mm'],\n        'A5' => [148, 210, 'mm'],\n        'B5' => [176, 250, 'mm'],\n        'Folio' => [8.5, 13, 'in'],\n        'Legal' => [8.5, 14, 'in'],\n        'Letter' => [8.5, 11, 'in'],\n    ];\n\n    /**\n     * Paper size.\n     *\n     * @var string\n     */\n    private $size = 'A4';\n\n    /**\n     * Width.\n     *\n     * @var float (twip)\n     */\n    private $width;\n\n    /**\n     * Height.\n     *\n     * @var float (twip)\n     */\n    private $height;\n\n    /**\n     * Create a new instance.\n     *\n     * @param string $size\n     */\n    public function __construct($size = 'A4')\n    {\n        $this->setSize($size);\n    }\n\n    /**\n     * Get size.\n     *\n     * @return string\n     */\n    public function getSize()\n    {\n        return $this->size;\n    }\n\n    /**\n     * Set size.\n     *\n     * @param string $size\n     *\n     * @return self\n     */\n    public function setSize($size)\n    {\n        $this->size = $this->setEnumVal($size, array_keys($this->sizes), $this->size);\n\n        [$width, $height, $unit] = $this->sizes[$this->size];\n\n        if ($unit == 'mm') {\n            $this->width = Converter::cmToTwip($width / 10);\n            $this->height = Converter::cmToTwip($height / 10);\n        } else {\n            $this->width = Converter::inchToTwip($width);\n            $this->height = Converter::inchToTwip($height);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Get width.\n     *\n     * @return float\n     */\n    public function getWidth()\n    {\n        return $this->width;\n    }\n\n    /**\n     * Get height.\n     *\n     * @return float\n     */\n    public function getHeight()\n    {\n        return $this->height;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Style/Paragraph.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Style;\n\nuse PhpOffice\\PhpWord\\Exception\\InvalidStyleException;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Shared\\Text;\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\nuse PhpOffice\\PhpWord\\SimpleType\\TextAlignment;\n\n/**\n * Paragraph style.\n *\n * OOXML:\n * - General: alignment, outline level\n * - Indentation: left, right, firstline, hanging\n * - Spacing: before, after, line spacing\n * - Pagination: widow control, keep next, keep line, page break before\n * - Formatting exception: suppress line numbers, don't hyphenate\n * - Textbox options\n * - Tabs\n * - Shading\n * - Borders\n *\n * OpenOffice:\n * - Indents & spacing\n * - Alignment\n * - Text flow\n * - Outline & numbering\n * - Tabs\n * - Dropcaps\n * - Tabs\n * - Borders\n * - Background\n *\n * @see  http://www.schemacentral.com/sc/ooxml/t-w_CT_PPr.html\n */\nclass Paragraph extends Border\n{\n    /**\n     * @const int One line height equals 240 twip\n     */\n    const LINE_HEIGHT = 240;\n\n    /**\n     * Aliases.\n     *\n     * @var array\n     */\n    protected $aliases = ['line-height' => 'lineHeight', 'line-spacing' => 'spacing'];\n\n    /**\n     * Parent style.\n     *\n     * @var string\n     */\n    private $basedOn = 'Normal';\n\n    /**\n     * Style for next paragraph.\n     *\n     * @var string\n     */\n    private $next;\n\n    /**\n     * @var string\n     */\n    private $alignment = '';\n\n    /**\n     * Indentation.\n     *\n     * @var null|Indentation\n     */\n    private $indentation;\n\n    /**\n     * Spacing.\n     *\n     * @var Spacing\n     */\n    private $spacing;\n\n    /**\n     * Text line height.\n     *\n     * @var null|float|int\n     */\n    private $lineHeight;\n\n    /**\n     * Allow first/last line to display on a separate page.\n     *\n     * @var bool\n     */\n    private $widowControl = true;\n\n    /**\n     * Keep paragraph with next paragraph.\n     *\n     * @var bool\n     */\n    private $keepNext = false;\n\n    /**\n     * Keep all lines on one page.\n     *\n     * @var bool\n     */\n    private $keepLines = false;\n\n    /**\n     * Start paragraph on next page.\n     *\n     * @var bool\n     */\n    private $pageBreakBefore = false;\n\n    /**\n     * Numbering style name.\n     *\n     * @var string\n     */\n    private $numStyle;\n\n    /**\n     * Numbering level.\n     *\n     * @var int\n     */\n    private $numLevel = 0;\n\n    /**\n     * Set of Custom Tab Stops.\n     *\n     * @var Tab[]\n     */\n    private $tabs = [];\n\n    /**\n     * Shading.\n     *\n     * @var Shading\n     */\n    private $shading;\n\n    /**\n     * Ignore Spacing Above and Below When Using Identical Styles.\n     *\n     * @var bool\n     */\n    private $contextualSpacing = false;\n\n    /**\n     * Right to Left Paragraph Layout.\n     *\n     * @var ?bool\n     */\n    private $bidi;\n\n    /**\n     * Vertical Character Alignment on Line.\n     *\n     * @var string\n     */\n    private $textAlignment;\n\n    /**\n     * Suppress hyphenation for paragraph.\n     *\n     * @var bool\n     */\n    private $suppressAutoHyphens = false;\n\n    /**\n     * Set Style value.\n     *\n     * @param string $key\n     * @param mixed $value\n     *\n     * @return self\n     */\n    public function setStyleValue($key, $value)\n    {\n        $key = Text::removeUnderscorePrefix($key);\n        if ('indent' == $key || 'hanging' == $key) {\n            $value = $value * 720;  // 720 twips is 0.5 inch\n        }\n\n        return parent::setStyleValue($key, $value);\n    }\n\n    /**\n     * Get style values.\n     *\n     * An experiment to retrieve all style values in one function. This will\n     * reduce function call and increase cohesion between functions. Should be\n     * implemented in all styles.\n     *\n     * @ignoreScrutinizerPatch\n     *\n     * @return array\n     */\n    public function getStyleValues()\n    {\n        $styles = [\n            'name' => $this->getStyleName(),\n            'basedOn' => $this->getBasedOn(),\n            'next' => $this->getNext(),\n            'alignment' => $this->getAlignment(),\n            'indentation' => $this->getIndentation(),\n            'spacing' => $this->getSpace(),\n            'pagination' => [\n                'widowControl' => $this->hasWidowControl(),\n                'keepNext' => $this->isKeepNext(),\n                'keepLines' => $this->isKeepLines(),\n                'pageBreak' => $this->hasPageBreakBefore(),\n            ],\n            'numbering' => [\n                'style' => $this->getNumStyle(),\n                'level' => $this->getNumLevel(),\n            ],\n            'tabs' => $this->getTabs(),\n            'shading' => $this->getShading(),\n            'contextualSpacing' => $this->hasContextualSpacing(),\n            'bidi' => $this->isBidi(),\n            'textAlignment' => $this->getTextAlignment(),\n            'suppressAutoHyphens' => $this->hasSuppressAutoHyphens(),\n        ];\n\n        return $styles;\n    }\n\n    /**\n     * @since 0.13.0\n     *\n     * @return string\n     */\n    public function getAlignment()\n    {\n        return $this->alignment;\n    }\n\n    /**\n     * @since 0.13.0\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setAlignment($value)\n    {\n        if (Jc::isValid($value)) {\n            $this->alignment = $value;\n        }\n\n        return $this;\n    }\n\n    /**\n     * Get parent style ID.\n     *\n     * @return string\n     */\n    public function getBasedOn()\n    {\n        return $this->basedOn;\n    }\n\n    /**\n     * Set parent style ID.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setBasedOn($value = 'Normal')\n    {\n        $this->basedOn = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get style for next paragraph.\n     *\n     * @return string\n     */\n    public function getNext()\n    {\n        return $this->next;\n    }\n\n    /**\n     * Set style for next paragraph.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setNext($value = null)\n    {\n        $this->next = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get hanging.\n     */\n    public function getHanging(): ?float\n    {\n        return $this->getChildStyleValue($this->indentation, 'hanging');\n    }\n\n    /**\n     * Get indentation.\n     *\n     * @deprecated 1.4.0 Use getIndentLeft\n     */\n    public function getIndent(): ?float\n    {\n        return $this->getChildStyleValue($this->indentation, 'left');\n    }\n\n    /**\n     * Get indentation.\n     */\n    public function getIndentation(): ?Indentation\n    {\n        return $this->indentation;\n    }\n\n    /**\n     * Get firstLine.\n     */\n    public function getIndentFirstLine(): ?float\n    {\n        return $this->getChildStyleValue($this->indentation, 'firstLine');\n    }\n\n    /**\n     * Get left indentation.\n     */\n    public function getIndentLeft(): ?float\n    {\n        return $this->getChildStyleValue($this->indentation, 'left');\n    }\n\n    /**\n     * Get right indentation.\n     */\n    public function getIndentRight(): ?float\n    {\n        return $this->getChildStyleValue($this->indentation, 'right');\n    }\n\n    /**\n     * Set hanging.\n     *\n     * @deprecated 1.4.0 Use setIndentHanging\n     */\n    public function setHanging(?float $value = null): self\n    {\n        return $this->setIndentation(['hanging' => $value]);\n    }\n\n    /**\n     * Set indentation.\n     *\n     * @deprecated 1.4.0 Use setIndentLeft\n     */\n    public function setIndent(?float $value = null): self\n    {\n        return $this->setIndentation(['left' => $value]);\n    }\n\n    /**\n     * Set indentation.\n     *\n     * @param array{\n     *     left?:null|float|int|numeric-string,\n     *     right?:null|float|int|numeric-string,\n     *     hanging?:null|float|int|numeric-string,\n     *     firstLine?:null|float|int|numeric-string\n     * } $value\n     */\n    public function setIndentation(array $value = []): self\n    {\n        $value = array_map(function ($indent) {\n            if (is_string($indent) || is_numeric($indent)) {\n                $indent = $this->setFloatVal($indent);\n            }\n\n            return $indent;\n        }, $value);\n        $this->setObjectVal($value, 'Indentation', $this->indentation);\n\n        return $this;\n    }\n\n    /**\n     * Set hanging indentation.\n     */\n    public function setIndentHanging(?float $value = null): self\n    {\n        return $this->setIndentation(['hanging' => $value]);\n    }\n\n    /**\n     * Set firstline indentation.\n     */\n    public function setIndentFirstLine(?float $value = null): self\n    {\n        return $this->setIndentation(['firstLine' => $value]);\n    }\n\n    /**\n     * Set firstlineChars indentation.\n     */\n    public function setIndentFirstLineChars(int $value = 0): self\n    {\n        return $this->setIndentation(['firstLineChars' => $value]);\n    }\n\n    /**\n     * Set left indentation.\n     */\n    public function setIndentLeft(?float $value = null): self\n    {\n        return $this->setIndentation(['left' => $value]);\n    }\n\n    /**\n     * Set right indentation.\n     */\n    public function setIndentRight(?float $value = null): self\n    {\n        return $this->setIndentation(['right' => $value]);\n    }\n\n    /**\n     * Get spacing.\n     *\n     * @return Spacing\n     *\n     * @todo Rename to getSpacing in 1.0\n     */\n    public function getSpace()\n    {\n        return $this->spacing;\n    }\n\n    /**\n     * Set spacing.\n     *\n     * @param mixed $value\n     *\n     * @return self\n     *\n     * @todo Rename to setSpacing in 1.0\n     */\n    public function setSpace($value = null)\n    {\n        $this->setObjectVal($value, 'Spacing', $this->spacing);\n\n        return $this;\n    }\n\n    /**\n     * Get space before paragraph.\n     *\n     * @return null|float|int\n     */\n    public function getSpaceBefore()\n    {\n        return $this->getChildStyleValue($this->spacing, 'before');\n    }\n\n    /**\n     * Set space before paragraph.\n     *\n     * @param null|float|int $value\n     *\n     * @return self\n     */\n    public function setSpaceBefore($value = null)\n    {\n        return $this->setSpace(['before' => $value]);\n    }\n\n    /**\n     * Get space after paragraph.\n     *\n     * @return null|float|int\n     */\n    public function getSpaceAfter()\n    {\n        return $this->getChildStyleValue($this->spacing, 'after');\n    }\n\n    /**\n     * Set space after paragraph.\n     *\n     * @param null|float|int $value\n     *\n     * @return self\n     */\n    public function setSpaceAfter($value = null)\n    {\n        return $this->setSpace(['after' => $value]);\n    }\n\n    /**\n     * Get spacing between lines.\n     *\n     * @return null|float|int\n     */\n    public function getSpacing()\n    {\n        return $this->getChildStyleValue($this->spacing, 'line');\n    }\n\n    /**\n     * Set spacing between lines.\n     *\n     * @param null|float|int $value\n     *\n     * @return self\n     */\n    public function setSpacing($value = null)\n    {\n        return $this->setSpace(['line' => $value]);\n    }\n\n    /**\n     * Get spacing line rule.\n     *\n     * @return string\n     */\n    public function getSpacingLineRule()\n    {\n        return $this->getChildStyleValue($this->spacing, 'lineRule');\n    }\n\n    /**\n     * Set the spacing line rule.\n     *\n     * @param string $value Possible values are defined in LineSpacingRule\n     *\n     * @return Paragraph\n     */\n    public function setSpacingLineRule($value)\n    {\n        return $this->setSpace(['lineRule' => $value]);\n    }\n\n    /**\n     * Get line height.\n     *\n     * @return null|float|int\n     */\n    public function getLineHeight()\n    {\n        return $this->lineHeight;\n    }\n\n    /**\n     * Set the line height.\n     *\n     * @param float|int|string $lineHeight\n     *\n     * @return self\n     */\n    public function setLineHeight($lineHeight)\n    {\n        if (is_string($lineHeight)) {\n            $lineHeight = (float) (preg_replace('/[^0-9\\.\\,]/', '', $lineHeight));\n        }\n\n        if ((!is_int($lineHeight) && !is_float($lineHeight)) || !$lineHeight) {\n            throw new InvalidStyleException('Line height must be a valid number');\n        }\n\n        $this->lineHeight = $lineHeight;\n        $this->setSpacing(($lineHeight - 1) * self::LINE_HEIGHT);\n        $this->setSpacingLineRule(\\PhpOffice\\PhpWord\\SimpleType\\LineSpacingRule::AUTO);\n\n        return $this;\n    }\n\n    /**\n     * Get allow first/last line to display on a separate page setting.\n     *\n     * @return bool\n     */\n    public function hasWidowControl()\n    {\n        return $this->widowControl;\n    }\n\n    /**\n     * Set keep paragraph with next paragraph setting.\n     *\n     * @param bool $value\n     *\n     * @return self\n     */\n    public function setWidowControl($value = true)\n    {\n        $this->widowControl = $this->setBoolVal($value, $this->widowControl);\n\n        return $this;\n    }\n\n    /**\n     * Get keep paragraph with next paragraph setting.\n     *\n     * @return bool\n     */\n    public function isKeepNext()\n    {\n        return $this->keepNext;\n    }\n\n    /**\n     * Set keep paragraph with next paragraph setting.\n     *\n     * @param bool $value\n     *\n     * @return self\n     */\n    public function setKeepNext($value = true)\n    {\n        $this->keepNext = $this->setBoolVal($value, $this->keepNext);\n\n        return $this;\n    }\n\n    /**\n     * Get keep all lines on one page setting.\n     *\n     * @return bool\n     */\n    public function isKeepLines()\n    {\n        return $this->keepLines;\n    }\n\n    /**\n     * Set keep all lines on one page setting.\n     *\n     * @param bool $value\n     *\n     * @return self\n     */\n    public function setKeepLines($value = true)\n    {\n        $this->keepLines = $this->setBoolVal($value, $this->keepLines);\n\n        return $this;\n    }\n\n    /**\n     * Get start paragraph on next page setting.\n     *\n     * @return bool\n     */\n    public function hasPageBreakBefore()\n    {\n        return $this->pageBreakBefore;\n    }\n\n    /**\n     * Set start paragraph on next page setting.\n     *\n     * @param bool $value\n     *\n     * @return self\n     */\n    public function setPageBreakBefore($value = true)\n    {\n        $this->pageBreakBefore = $this->setBoolVal($value, $this->pageBreakBefore);\n\n        return $this;\n    }\n\n    /**\n     * Get numbering style name.\n     *\n     * @return string\n     */\n    public function getNumStyle()\n    {\n        return $this->numStyle;\n    }\n\n    /**\n     * Set numbering style name.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setNumStyle($value)\n    {\n        $this->numStyle = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get numbering level.\n     *\n     * @return int\n     */\n    public function getNumLevel()\n    {\n        return $this->numLevel;\n    }\n\n    /**\n     * Set numbering level.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setNumLevel($value = 0)\n    {\n        $this->numLevel = $this->setIntVal($value, $this->numLevel);\n\n        return $this;\n    }\n\n    /**\n     * Get tabs.\n     *\n     * @return Tab[]\n     */\n    public function getTabs()\n    {\n        return $this->tabs;\n    }\n\n    /**\n     * Set tabs.\n     *\n     * @param array $value\n     *\n     * @return self\n     */\n    public function setTabs($value = null)\n    {\n        if (is_array($value)) {\n            $this->tabs = $value;\n        }\n\n        return $this;\n    }\n\n    /**\n     * Get shading.\n     *\n     * @return Shading\n     */\n    public function getShading()\n    {\n        return $this->shading;\n    }\n\n    /**\n     * Set shading.\n     *\n     * @param mixed $value\n     *\n     * @return self\n     */\n    public function setShading($value = null)\n    {\n        $this->setObjectVal($value, 'Shading', $this->shading);\n\n        return $this;\n    }\n\n    /**\n     * Get contextualSpacing.\n     *\n     * @return bool\n     */\n    public function hasContextualSpacing()\n    {\n        return $this->contextualSpacing;\n    }\n\n    /**\n     * Set contextualSpacing.\n     *\n     * @param bool $contextualSpacing\n     *\n     * @return self\n     */\n    public function setContextualSpacing($contextualSpacing)\n    {\n        $this->contextualSpacing = $contextualSpacing;\n\n        return $this;\n    }\n\n    /**\n     * Get bidirectional.\n     *\n     * @return ?bool\n     */\n    public function isBidi()\n    {\n        return $this->bidi ?? Settings::isDefaultRtl();\n    }\n\n    /**\n     * Set bidi.\n     *\n     * @param ?bool $bidi\n     *            Set to true to write from right to left\n     *\n     * @return self\n     */\n    public function setBidi($bidi)\n    {\n        $this->bidi = $bidi;\n\n        return $this;\n    }\n\n    /**\n     * Get textAlignment.\n     *\n     * @return string\n     */\n    public function getTextAlignment()\n    {\n        return $this->textAlignment;\n    }\n\n    /**\n     * Set textAlignment.\n     *\n     * @param string $textAlignment\n     *\n     * @return self\n     */\n    public function setTextAlignment($textAlignment)\n    {\n        TextAlignment::validate($textAlignment);\n        $this->textAlignment = $textAlignment;\n\n        return $this;\n    }\n\n    /**\n     * @return bool\n     */\n    public function hasSuppressAutoHyphens()\n    {\n        return $this->suppressAutoHyphens;\n    }\n\n    /**\n     * @param bool $suppressAutoHyphens\n     */\n    public function setSuppressAutoHyphens($suppressAutoHyphens): void\n    {\n        $this->suppressAutoHyphens = (bool) $suppressAutoHyphens;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Style/Row.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Style;\n\n/**\n * Table row style.\n *\n * @since 0.8.0\n */\nclass Row extends AbstractStyle\n{\n    /**\n     * Repeat table row on every new page.\n     *\n     * @var bool\n     */\n    private $tblHeader = false;\n\n    /**\n     * Table row cannot break across pages.\n     *\n     * @var bool\n     */\n    private $cantSplit = false;\n\n    /**\n     * Table row exact height.\n     *\n     * @var bool\n     */\n    private $exactHeight = false;\n\n    /**\n     * Create a new row style.\n     */\n    public function __construct()\n    {\n    }\n\n    /**\n     * Is tblHeader.\n     */\n    public function isTblHeader(): bool\n    {\n        return $this->tblHeader;\n    }\n\n    /**\n     * Is tblHeader.\n     */\n    public function setTblHeader(bool $value = true): self\n    {\n        $this->tblHeader = $this->setBoolVal($value, $this->tblHeader);\n\n        return $this;\n    }\n\n    /**\n     * Is cantSplit.\n     */\n    public function isCantSplit(): bool\n    {\n        return $this->cantSplit;\n    }\n\n    /**\n     * Is cantSplit.\n     */\n    public function setCantSplit(bool $value = true): self\n    {\n        $this->cantSplit = $this->setBoolVal($value, $this->cantSplit);\n\n        return $this;\n    }\n\n    /**\n     * Is exactHeight.\n     */\n    public function isExactHeight(): bool\n    {\n        return $this->exactHeight;\n    }\n\n    /**\n     * Set exactHeight.\n     */\n    public function setExactHeight(bool $value = true): self\n    {\n        $this->exactHeight = $this->setBoolVal($value, $this->exactHeight);\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Style/Section.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Style;\n\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\SimpleType\\VerticalJc;\n\n/**\n * Section settings.\n */\nclass Section extends Border\n{\n    /**\n     * Page orientation.\n     *\n     * @const string\n     */\n    const ORIENTATION_PORTRAIT = 'portrait';\n    const ORIENTATION_LANDSCAPE = 'landscape';\n\n    /**\n     * Page default constants.\n     *\n     * @const int|float\n     */\n    const DEFAULT_WIDTH = 11905.511811024; // In twips.\n    const DEFAULT_HEIGHT = 16837.79527559; // In twips.\n    const DEFAULT_GUTTER = 0;              // In twips.\n    const DEFAULT_HEADER_HEIGHT = 720;     // In twips.\n    const DEFAULT_FOOTER_HEIGHT = 720;     // In twips.\n    const DEFAULT_COLUMN_COUNT = 1;\n    const DEFAULT_COLUMN_SPACING = 720;    // In twips.\n\n    /**\n     * Page Orientation.\n     *\n     * @var string\n     *\n     * @see  http://www.schemacentral.com/sc/ooxml/a-w_orient-1.html\n     */\n    private $orientation = self::ORIENTATION_PORTRAIT;\n\n    /**\n     * Paper size.\n     *\n     * @var Paper\n     */\n    private $paper;\n\n    /**\n     * Page Size Width.\n     *\n     * @var float|int\n     */\n    private $pageSizeW = self::DEFAULT_WIDTH;\n\n    /**\n     * Page Size Height.\n     *\n     * @var float|int\n     */\n    private $pageSizeH = self::DEFAULT_HEIGHT;\n\n    /**\n     * Page gutter spacing.\n     *\n     * @var float|int\n     *\n     * @see  http://www.schemacentral.com/sc/ooxml/e-w_pgMar-1.html\n     */\n    private $gutter = self::DEFAULT_GUTTER;\n\n    /**\n     * Header height.\n     *\n     * @var float|int\n     */\n    private $headerHeight = self::DEFAULT_HEADER_HEIGHT;\n\n    /**\n     * Footer height.\n     *\n     * @var float|int\n     */\n    private $footerHeight = self::DEFAULT_FOOTER_HEIGHT;\n\n    /**\n     * Page Numbering Start.\n     *\n     * @var int\n     */\n    private $pageNumberingStart;\n\n    /**\n     * Section columns count.\n     *\n     * @var int\n     */\n    private $colsNum = self::DEFAULT_COLUMN_COUNT;\n\n    /**\n     * Section spacing between columns.\n     *\n     * @var float|int\n     */\n    private $colsSpace = self::DEFAULT_COLUMN_SPACING;\n\n    /**\n     * Section break type.\n     *\n     * Options:\n     * - nextPage: Next page section break\n     * - nextColumn: Column section break\n     * - continuous: Continuous section break\n     * - evenPage: Even page section break\n     * - oddPage: Odd page section break\n     *\n     * @var ?string\n     */\n    private $breakType;\n\n    /**\n     * Line numbering.\n     *\n     * @var LineNumbering\n     *\n     * @see  http://www.schemacentral.com/sc/ooxml/e-w_lnNumType-1.html\n     */\n    private $lineNumbering;\n\n    /**\n     * Vertical Text Alignment on Page\n     * One of \\PhpOffice\\PhpWord\\SimpleType\\VerticalJc.\n     *\n     * @var ?string\n     */\n    private $vAlign;\n\n    /**\n     * Create new instance.\n     */\n    public function __construct()\n    {\n        $this->setPaperSize();\n    }\n\n    /**\n     * Get paper size.\n     *\n     * @return string\n     */\n    public function getPaperSize()\n    {\n        return $this->paper->getSize();\n    }\n\n    /**\n     * Set paper size.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setPaperSize($value = '')\n    {\n        if (!$value) {\n            $value = Settings::getDefaultPaper();\n        }\n        if ($this->paper === null) {\n            $this->paper = new Paper();\n        }\n        $this->paper->setSize($value);\n        $this->pageSizeW = $this->paper->getWidth();\n        $this->pageSizeH = $this->paper->getHeight();\n\n        return $this;\n    }\n\n    /**\n     * Set Setting Value.\n     *\n     * @param string $key\n     * @param array|int|string $value\n     *\n     * @return self\n     */\n    public function setSettingValue($key, $value)\n    {\n        return $this->setStyleValue($key, $value);\n    }\n\n    /**\n     * Set orientation.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setOrientation($value = null)\n    {\n        $enum = [self::ORIENTATION_PORTRAIT, self::ORIENTATION_LANDSCAPE];\n        $this->orientation = $this->setEnumVal($value, $enum, $this->orientation);\n\n        /** @var float|int $longSide Type hint */\n        $longSide = $this->pageSizeW >= $this->pageSizeH ? $this->pageSizeW : $this->pageSizeH;\n\n        /** @var float|int $shortSide Type hint */\n        $shortSide = $this->pageSizeW < $this->pageSizeH ? $this->pageSizeW : $this->pageSizeH;\n\n        if ($this->orientation == self::ORIENTATION_PORTRAIT) {\n            $this->pageSizeW = $shortSide;\n            $this->pageSizeH = $longSide;\n        } else {\n            $this->pageSizeW = $longSide;\n            $this->pageSizeH = $shortSide;\n        }\n\n        return $this;\n    }\n\n    /**\n     * Get Page Orientation.\n     *\n     * @return string\n     */\n    public function getOrientation()\n    {\n        return $this->orientation;\n    }\n\n    /**\n     * Set Portrait Orientation.\n     *\n     * @return self\n     */\n    public function setPortrait()\n    {\n        return $this->setOrientation(self::ORIENTATION_PORTRAIT);\n    }\n\n    /**\n     * Set Landscape Orientation.\n     *\n     * @return self\n     */\n    public function setLandscape()\n    {\n        return $this->setOrientation(self::ORIENTATION_LANDSCAPE);\n    }\n\n    /**\n     * Get Page Size Width.\n     *\n     * @return null|float|int\n     *\n     * @since 0.12.0\n     */\n    public function getPageSizeW()\n    {\n        return $this->pageSizeW;\n    }\n\n    /**\n     * @param null|float|int $value\n     *\n     * @return Section\n     *\n     * @since 0.12.0\n     */\n    public function setPageSizeW($value = null)\n    {\n        $this->pageSizeW = $this->setNumericVal($value, self::DEFAULT_WIDTH);\n\n        return $this;\n    }\n\n    /**\n     * Get Page Size Height.\n     *\n     * @return null|float|int\n     *\n     * @since 0.12.0\n     */\n    public function getPageSizeH()\n    {\n        return $this->pageSizeH;\n    }\n\n    /**\n     * @param null|float|int $value\n     *\n     * @return Section\n     *\n     * @since 0.12.0\n     */\n    public function setPageSizeH($value = null)\n    {\n        $this->pageSizeH = $this->setNumericVal($value, self::DEFAULT_HEIGHT);\n\n        return $this;\n    }\n\n    /**\n     * Get gutter.\n     *\n     * @return float|int\n     */\n    public function getGutter()\n    {\n        return $this->gutter;\n    }\n\n    /**\n     * Set gutter.\n     *\n     * @param float|int $value\n     *\n     * @return self\n     */\n    public function setGutter($value = null)\n    {\n        $this->gutter = $this->setNumericVal($value, self::DEFAULT_GUTTER);\n\n        return $this;\n    }\n\n    /**\n     * Get Header Height.\n     *\n     * @return float|int\n     */\n    public function getHeaderHeight()\n    {\n        return $this->headerHeight;\n    }\n\n    /**\n     * Set Header Height.\n     *\n     * @param float|int $value\n     *\n     * @return self\n     */\n    public function setHeaderHeight($value = null)\n    {\n        $this->headerHeight = $this->setNumericVal($value, self::DEFAULT_HEADER_HEIGHT);\n\n        return $this;\n    }\n\n    /**\n     * Get Footer Height.\n     *\n     * @return float|int\n     */\n    public function getFooterHeight()\n    {\n        return $this->footerHeight;\n    }\n\n    /**\n     * Set Footer Height.\n     *\n     * @param float|int $value\n     *\n     * @return self\n     */\n    public function setFooterHeight($value = null)\n    {\n        $this->footerHeight = $this->setNumericVal($value, self::DEFAULT_FOOTER_HEIGHT);\n\n        return $this;\n    }\n\n    /**\n     * Get page numbering start.\n     *\n     * @return null|int\n     */\n    public function getPageNumberingStart()\n    {\n        return $this->pageNumberingStart;\n    }\n\n    /**\n     * Set page numbering start.\n     *\n     * @param null|int $pageNumberingStart\n     *\n     * @return self\n     */\n    public function setPageNumberingStart($pageNumberingStart = null)\n    {\n        $this->pageNumberingStart = $pageNumberingStart;\n\n        return $this;\n    }\n\n    /**\n     * Get Section Columns Count.\n     *\n     * @return int\n     */\n    public function getColsNum()\n    {\n        return $this->colsNum;\n    }\n\n    /**\n     * Set Section Columns Count.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setColsNum($value = null)\n    {\n        $this->colsNum = $this->setIntVal($value, self::DEFAULT_COLUMN_COUNT);\n\n        return $this;\n    }\n\n    /**\n     * Get Section Space Between Columns.\n     *\n     * @return float|int\n     */\n    public function getColsSpace()\n    {\n        return $this->colsSpace;\n    }\n\n    /**\n     * Set Section Space Between Columns.\n     *\n     * @param float|int $value\n     *\n     * @return self\n     */\n    public function setColsSpace($value = null)\n    {\n        $this->colsSpace = $this->setNumericVal($value, self::DEFAULT_COLUMN_SPACING);\n\n        return $this;\n    }\n\n    /**\n     * Get Break Type.\n     *\n     * @return ?string\n     */\n    public function getBreakType()\n    {\n        return $this->breakType;\n    }\n\n    /**\n     * Set Break Type.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setBreakType($value = null)\n    {\n        $this->breakType = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get line numbering.\n     *\n     * @return LineNumbering\n     */\n    public function getLineNumbering()\n    {\n        return $this->lineNumbering;\n    }\n\n    /**\n     * Set line numbering.\n     *\n     * @param mixed $value\n     *\n     * @return self\n     */\n    public function setLineNumbering($value = null)\n    {\n        $this->setObjectVal($value, 'LineNumbering', $this->lineNumbering);\n\n        return $this;\n    }\n\n    /**\n     * Get vertical alignment.\n     *\n     * @return ?string\n     */\n    public function getVAlign()\n    {\n        return $this->vAlign;\n    }\n\n    /**\n     * Set vertical alignment.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setVAlign($value = null)\n    {\n        VerticalJc::validate($value);\n        $this->vAlign = $value;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Style/Shading.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Style;\n\n/**\n * Shading style.\n *\n * @see  http://www.schemacentral.com/sc/ooxml/t-w_CT_Shd.html\n * @since 0.10.0\n */\nclass Shading extends AbstractStyle\n{\n    /**\n     * Pattern constants (partly).\n     *\n     * @const string\n     *\n     * @see  http://www.schemacentral.com/sc/ooxml/t-w_ST_Shd.html\n     */\n    const PATTERN_CLEAR = 'clear'; // No pattern\n    const PATTERN_SOLID = 'solid'; // 100% fill pattern\n    const PATTERN_HSTRIPE = 'horzStripe'; // Horizontal stripe pattern\n    const PATTERN_VSTRIPE = 'vertStripe'; // Vertical stripe pattern\n    const PATTERN_DSTRIPE = 'diagStripe'; // Diagonal stripe pattern\n    const PATTERN_HCROSS = 'horzCross'; // Horizontal cross pattern\n    const PATTERN_DCROSS = 'diagCross'; // Diagonal cross pattern\n\n    /**\n     * Shading pattern.\n     *\n     * @var string\n     *\n     * @see  http://www.schemacentral.com/sc/ooxml/t-w_ST_Shd.html\n     */\n    private $pattern = self::PATTERN_CLEAR;\n\n    /**\n     * Shading pattern color.\n     *\n     * @var string\n     */\n    private $color;\n\n    /**\n     * Shading background color.\n     *\n     * @var string\n     */\n    private $fill;\n\n    /**\n     * Create a new instance.\n     *\n     * @param array $style\n     */\n    public function __construct($style = [])\n    {\n        $this->setStyleByArray($style);\n    }\n\n    /**\n     * Get pattern.\n     *\n     * @return string\n     */\n    public function getPattern()\n    {\n        return $this->pattern;\n    }\n\n    /**\n     * Set pattern.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setPattern($value = null)\n    {\n        $enum = [\n            self::PATTERN_CLEAR, self::PATTERN_SOLID, self::PATTERN_HSTRIPE,\n            self::PATTERN_VSTRIPE, self::PATTERN_DSTRIPE, self::PATTERN_HCROSS, self::PATTERN_DCROSS,\n        ];\n        $this->pattern = $this->setEnumVal($value, $enum, $this->pattern);\n\n        return $this;\n    }\n\n    /**\n     * Get color.\n     *\n     * @return string\n     */\n    public function getColor()\n    {\n        return $this->color;\n    }\n\n    /**\n     * Set pattern.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setColor($value = null)\n    {\n        $this->color = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get fill.\n     *\n     * @return string\n     */\n    public function getFill()\n    {\n        return $this->fill;\n    }\n\n    /**\n     * Set fill.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setFill($value = null)\n    {\n        $this->fill = $value;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Style/Shadow.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Style;\n\n/**\n * Shadow style.\n *\n * @see  http://www.schemacentral.com/sc/ooxml/t-v_CT_Shadow.html\n * @since 0.12.0\n */\nclass Shadow extends AbstractStyle\n{\n    /**\n     * Color.\n     *\n     * @var string\n     */\n    private $color;\n\n    /**\n     * Offset; Format: 3pt,3pt.\n     *\n     * @var string\n     */\n    private $offset;\n\n    /**\n     * Create a new instance.\n     *\n     * @param array $style\n     */\n    public function __construct($style = [])\n    {\n        $this->setStyleByArray($style);\n    }\n\n    /**\n     * Get color.\n     *\n     * @return string\n     */\n    public function getColor()\n    {\n        return $this->color;\n    }\n\n    /**\n     * Set color.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setColor($value = null)\n    {\n        $this->color = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get offset.\n     *\n     * @return string\n     */\n    public function getOffset()\n    {\n        return $this->offset;\n    }\n\n    /**\n     * Set offset.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setOffset($value = null)\n    {\n        $this->offset = $value;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Style/Shape.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Style;\n\n/**\n * Shape style.\n *\n * @since 0.12.0\n *\n * @todo Skew http://www.schemacentral.com/sc/ooxml/t-o_CT_Skew.html\n */\nclass Shape extends AbstractStyle\n{\n    /**\n     * Points.\n     *\n     * - Arc: startAngle endAngle; 0 = top center, moving clockwise\n     * - Curve: from-x1,from-y1 to-x2,to-y2 control1-x,control1-y control2-x,control2-y\n     * - Line: from-x1,from-y1 to-x2,to-y2\n     * - Polyline: x1,y1 x2,y2 ...\n     * - Rect and oval: Not applicable\n     *\n     * @var string\n     */\n    private $points;\n\n    /**\n     * Roundness measure of corners; 0 = straightest (rectangular); 1 = roundest (circle/oval).\n     *\n     * Only for rect\n     *\n     * @var float|int\n     */\n    private $roundness;\n\n    /**\n     * Frame.\n     *\n     * @var Frame\n     */\n    private $frame;\n\n    /**\n     * Fill.\n     *\n     * @var Fill\n     */\n    private $fill;\n\n    /**\n     * Outline.\n     *\n     * @var Outline\n     */\n    private $outline;\n\n    /**\n     * Shadow.\n     *\n     * @var Shadow\n     */\n    private $shadow;\n\n    /**\n     * 3D extrusion.\n     *\n     * @var Extrusion\n     */\n    private $extrusion;\n\n    /**\n     * Create a new instance.\n     *\n     * @param array $style\n     */\n    public function __construct($style = [])\n    {\n        $this->setStyleByArray($style);\n    }\n\n    /**\n     * Get points.\n     *\n     * @return string\n     */\n    public function getPoints()\n    {\n        return $this->points;\n    }\n\n    /**\n     * Set points.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setPoints($value = null)\n    {\n        $this->points = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get roundness.\n     *\n     * @return float|int\n     */\n    public function getRoundness()\n    {\n        return $this->roundness;\n    }\n\n    /**\n     * Set roundness.\n     *\n     * @param float|int $value\n     *\n     * @return self\n     */\n    public function setRoundness($value = null)\n    {\n        $this->roundness = $this->setNumericVal($value, null);\n\n        return $this;\n    }\n\n    /**\n     * Get frame.\n     *\n     * @return Frame\n     */\n    public function getFrame()\n    {\n        return $this->frame;\n    }\n\n    /**\n     * Set frame.\n     *\n     * @param mixed $value\n     *\n     * @return self\n     */\n    public function setFrame($value = null)\n    {\n        $this->setObjectVal($value, 'Frame', $this->frame);\n\n        return $this;\n    }\n\n    /**\n     * Get fill.\n     *\n     * @return Fill\n     */\n    public function getFill()\n    {\n        return $this->fill;\n    }\n\n    /**\n     * Set fill.\n     *\n     * @param mixed $value\n     *\n     * @return self\n     */\n    public function setFill($value = null)\n    {\n        $this->setObjectVal($value, 'Fill', $this->fill);\n\n        return $this;\n    }\n\n    /**\n     * Get outline.\n     *\n     * @return Outline\n     */\n    public function getOutline()\n    {\n        return $this->outline;\n    }\n\n    /**\n     * Set outline.\n     *\n     * @param mixed $value\n     *\n     * @return self\n     */\n    public function setOutline($value = null)\n    {\n        $this->setObjectVal($value, 'Outline', $this->outline);\n\n        return $this;\n    }\n\n    /**\n     * Get shadow.\n     *\n     * @return Shadow\n     */\n    public function getShadow()\n    {\n        return $this->shadow;\n    }\n\n    /**\n     * Set shadow.\n     *\n     * @param mixed $value\n     *\n     * @return self\n     */\n    public function setShadow($value = null)\n    {\n        $this->setObjectVal($value, 'Shadow', $this->shadow);\n\n        return $this;\n    }\n\n    /**\n     * Get 3D extrusion.\n     *\n     * @return Extrusion\n     */\n    public function getExtrusion()\n    {\n        return $this->extrusion;\n    }\n\n    /**\n     * Set 3D extrusion.\n     *\n     * @param mixed $value\n     *\n     * @return self\n     */\n    public function setExtrusion($value = null)\n    {\n        $this->setObjectVal($value, 'Extrusion', $this->extrusion);\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Style/Spacing.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Style;\n\nuse PhpOffice\\PhpWord\\SimpleType\\LineSpacingRule;\n\n/**\n * Spacing between lines and above/below paragraph style.\n *\n * @see  http://www.datypic.com/sc/ooxml/t-w_CT_Spacing.html\n * @since 0.10.0\n */\nclass Spacing extends AbstractStyle\n{\n    /**\n     * Spacing above paragraph (twip).\n     *\n     * @var null|float|int\n     */\n    private $before;\n\n    /**\n     * Spacing below paragraph (twip).\n     *\n     * @var null|float|int\n     */\n    private $after;\n\n    /**\n     * Spacing between lines in paragraph (twip).\n     *\n     * @var null|float|int\n     */\n    private $line;\n\n    /**\n     * Type of spacing between lines.\n     *\n     * @var string\n     */\n    private $lineRule = LineSpacingRule::AUTO;\n\n    /**\n     * Create a new instance.\n     *\n     * @param array $style\n     */\n    public function __construct($style = [])\n    {\n        $this->setStyleByArray($style);\n    }\n\n    /**\n     * Get before.\n     *\n     * @return null|float|int\n     */\n    public function getBefore()\n    {\n        return $this->before;\n    }\n\n    /**\n     * Set before.\n     *\n     * @param null|float|int $value\n     *\n     * @return self\n     */\n    public function setBefore($value = null)\n    {\n        $this->before = $this->setNumericVal($value, $this->before);\n\n        return $this;\n    }\n\n    /**\n     * Get after.\n     *\n     * @return null|float|int\n     */\n    public function getAfter()\n    {\n        return $this->after;\n    }\n\n    /**\n     * Set after.\n     *\n     * @param null|float|int $value\n     *\n     * @return self\n     */\n    public function setAfter($value = null)\n    {\n        $this->after = $this->setNumericVal($value, $this->after);\n\n        return $this;\n    }\n\n    /**\n     * Get line.\n     *\n     * @return null|float|int\n     */\n    public function getLine()\n    {\n        return $this->line;\n    }\n\n    /**\n     * Set distance.\n     *\n     * @param null|float|int $value\n     *\n     * @return self\n     */\n    public function setLine($value = null)\n    {\n        $this->line = $this->setNumericVal($value, $this->line);\n\n        return $this;\n    }\n\n    /**\n     * Get line rule.\n     *\n     * @return string\n     */\n    public function getLineRule()\n    {\n        return $this->lineRule;\n    }\n\n    /**\n     * Set line rule.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setLineRule($value = null)\n    {\n        LineSpacingRule::validate($value);\n        $this->lineRule = $value;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Style/TOC.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Style;\n\n/**\n * TOC style.\n */\nclass TOC extends Tab\n{\n    /**\n     * Indent.\n     *\n     * @var float|int (twip)\n     */\n    private $indent = 200;\n\n    /**\n     * Create a new TOC Style.\n     */\n    public function __construct()\n    {\n        parent::__construct(self::TAB_STOP_RIGHT, 9062, self::TAB_LEADER_DOT);\n    }\n\n    /**\n     * Get Tab Position.\n     *\n     * @return float|int\n     */\n    public function getTabPos()\n    {\n        return $this->getPosition();\n    }\n\n    /**\n     * Set Tab Position.\n     *\n     * @param float|int $value\n     *\n     * @return self\n     */\n    public function setTabPos($value)\n    {\n        return $this->setPosition($value);\n    }\n\n    /**\n     * Get Tab Leader.\n     *\n     * @return string\n     */\n    public function getTabLeader()\n    {\n        return $this->getLeader();\n    }\n\n    /**\n     * Set Tab Leader.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setTabLeader($value = self::TAB_LEADER_DOT)\n    {\n        return $this->setLeader($value);\n    }\n\n    /**\n     * Get Indent.\n     *\n     * @return float|int\n     */\n    public function getIndent()\n    {\n        return $this->indent;\n    }\n\n    /**\n     * Set Indent.\n     *\n     * @param float|int $value\n     *\n     * @return self\n     */\n    public function setIndent($value)\n    {\n        $this->indent = $this->setNumericVal($value, $this->indent);\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Style/Tab.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Style;\n\n/**\n * Tab style.\n */\nclass Tab extends AbstractStyle\n{\n    /**\n     * Tab stop types.\n     *\n     * @const string\n     */\n    const TAB_STOP_CLEAR = 'clear';\n    const TAB_STOP_LEFT = 'left';\n    const TAB_STOP_CENTER = 'center';\n    const TAB_STOP_RIGHT = 'right';\n    const TAB_STOP_DECIMAL = 'decimal';\n    const TAB_STOP_BAR = 'bar';\n    const TAB_STOP_NUM = 'num';\n\n    /**\n     * Tab leader types.\n     *\n     * @const string\n     */\n    const TAB_LEADER_NONE = 'none';\n    const TAB_LEADER_DOT = 'dot';\n    const TAB_LEADER_HYPHEN = 'hyphen';\n    const TAB_LEADER_UNDERSCORE = 'underscore';\n    const TAB_LEADER_HEAVY = 'heavy';\n    const TAB_LEADER_MIDDLEDOT = 'middleDot';\n\n    /**\n     * Tab stop type.\n     *\n     * @var string\n     */\n    private $type = self::TAB_STOP_CLEAR;\n\n    /**\n     * Tab leader character.\n     *\n     * @var string\n     */\n    private $leader = self::TAB_LEADER_NONE;\n\n    /**\n     * Tab stop position (twip).\n     *\n     * @var float|int\n     */\n    private $position = 0;\n\n    /**\n     * Create a new instance of Tab. Both $type and $leader\n     * must conform to the values put forth in the schema. If they do not\n     * they will be changed to default values.\n     *\n     * @param string $type Defaults to 'clear' if value is not possible\n     * @param int $position Must be numeric; otherwise defaults to 0\n     * @param string $leader Defaults to null if value is not possible\n     */\n    public function __construct($type = null, $position = 0, $leader = null)\n    {\n        $stopTypes = [\n            self::TAB_STOP_CLEAR, self::TAB_STOP_LEFT, self::TAB_STOP_CENTER,\n            self::TAB_STOP_RIGHT, self::TAB_STOP_DECIMAL, self::TAB_STOP_BAR, self::TAB_STOP_NUM,\n        ];\n        $leaderTypes = [\n            self::TAB_LEADER_NONE, self::TAB_LEADER_DOT, self::TAB_LEADER_HYPHEN,\n            self::TAB_LEADER_UNDERSCORE, self::TAB_LEADER_HEAVY, self::TAB_LEADER_MIDDLEDOT,\n        ];\n\n        $this->type = $this->setEnumVal($type, $stopTypes, $this->type);\n        $this->position = $this->setNumericVal($position, $this->position);\n        $this->leader = $this->setEnumVal($leader, $leaderTypes, $this->leader);\n    }\n\n    /**\n     * Get stop type.\n     *\n     * @return string\n     */\n    public function getType()\n    {\n        return $this->type;\n    }\n\n    /**\n     * Set stop type.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setType($value)\n    {\n        $enum = [\n            self::TAB_STOP_CLEAR, self::TAB_STOP_LEFT, self::TAB_STOP_CENTER,\n            self::TAB_STOP_RIGHT, self::TAB_STOP_DECIMAL, self::TAB_STOP_BAR,\n            self::TAB_STOP_NUM,\n        ];\n        $this->type = $this->setEnumVal($value, $enum, $this->type);\n\n        return $this;\n    }\n\n    /**\n     * Get leader.\n     *\n     * @return string\n     */\n    public function getLeader()\n    {\n        return $this->leader;\n    }\n\n    /**\n     * Set leader.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setLeader($value)\n    {\n        $enum = [\n            self::TAB_LEADER_NONE, self::TAB_LEADER_DOT, self::TAB_LEADER_HYPHEN,\n            self::TAB_LEADER_UNDERSCORE, self::TAB_LEADER_HEAVY, self::TAB_LEADER_MIDDLEDOT,\n        ];\n        $this->leader = $this->setEnumVal($value, $enum, $this->leader);\n\n        return $this;\n    }\n\n    /**\n     * Get position.\n     *\n     * @return float|int\n     */\n    public function getPosition()\n    {\n        return $this->position;\n    }\n\n    /**\n     * Set position.\n     *\n     * @param float|int $value\n     *\n     * @return self\n     */\n    public function setPosition($value)\n    {\n        $this->position = $this->setNumericVal($value, $this->position);\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Style/Table.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Style;\n\nuse PhpOffice\\PhpWord\\ComplexType\\TblWidth as TblWidthComplexType;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\nuse PhpOffice\\PhpWord\\SimpleType\\JcTable;\nuse PhpOffice\\PhpWord\\SimpleType\\TblWidth;\n\nclass Table extends Border\n{\n    //values for http://www.datypic.com/sc/ooxml/t-w_ST_TblLayoutType.html\n    /**\n     * AutoFit Table Layout.\n     *\n     * @var string\n     */\n    const LAYOUT_AUTO = 'autofit';\n    /**\n     * Fixed Width Table Layout.\n     *\n     * @var string\n     */\n    const LAYOUT_FIXED = 'fixed';\n\n    /**\n     * Is this a first row style?\n     *\n     * @var bool\n     */\n    private $isFirstRow = false;\n\n    /**\n     * Style for first row.\n     *\n     * @var Table\n     */\n    private $firstRowStyle;\n\n    /**\n     * Cell margin top.\n     *\n     * @var int\n     */\n    private $cellMarginTop;\n\n    /**\n     * Cell margin left.\n     *\n     * @var int\n     */\n    private $cellMarginLeft;\n\n    /**\n     * Cell margin right.\n     *\n     * @var int\n     */\n    private $cellMarginRight;\n\n    /**\n     * Cell margin bottom.\n     *\n     * @var int\n     */\n    private $cellMarginBottom;\n\n    /**\n     * Border size inside horizontal.\n     *\n     * @var int\n     */\n    private $borderInsideHSize;\n\n    /**\n     * Border color inside horizontal.\n     *\n     * @var string\n     */\n    private $borderInsideHColor;\n\n    /**\n     * Border size inside vertical.\n     *\n     * @var int\n     */\n    private $borderInsideVSize;\n\n    /**\n     * Border color inside vertical.\n     *\n     * @var string\n     */\n    private $borderInsideVColor;\n\n    /**\n     * Shading.\n     *\n     * @var Shading\n     */\n    private $shading;\n\n    /**\n     * @var string\n     */\n    private $alignment = '';\n\n    /**\n     * @var float|int Width value\n     */\n    private $width = 0;\n\n    /**\n     * @var string Width unit\n     */\n    private $unit = TblWidth::AUTO;\n\n    /**\n     * @var null|float|int cell spacing value\n     */\n    private $cellSpacing;\n\n    /**\n     * @var string Table Layout\n     */\n    private $layout = self::LAYOUT_AUTO;\n\n    /**\n     * Position.\n     *\n     * @var ?TablePosition\n     */\n    private $position;\n\n    /** @var null|TblWidthComplexType */\n    private $indent;\n\n    /**\n     * The width of each column, computed based on the max cell width of each column.\n     *\n     * @var int[]\n     */\n    private $columnWidths;\n\n    /**\n     * Visually Right to Left Table.\n     *\n     * @see  http://www.datypic.com/sc/ooxml/e-w_bidiVisual-1.html\n     *\n     * @var ?bool\n     */\n    private $bidiVisual;\n\n    /**\n     * Create new table style.\n     */\n    public function __construct(?array $tableStyle = null, ?array $firstRowStyle = null)\n    {\n        // Clone first row from table style, but with certain properties disabled\n        if ($firstRowStyle !== null) {\n            $this->firstRowStyle = clone $this;\n            $this->firstRowStyle->isFirstRow = true;\n            unset(\n                $this->firstRowStyle->firstRowStyle,\n                $this->firstRowStyle->borderInsideHSize,\n                $this->firstRowStyle->borderInsideHColor,\n                $this->firstRowStyle->borderInsideVSize,\n                $this->firstRowStyle->borderInsideVColor,\n                $this->firstRowStyle->cellMarginTop,\n                $this->firstRowStyle->cellMarginLeft,\n                $this->firstRowStyle->cellMarginRight,\n                $this->firstRowStyle->cellMarginBottom,\n                $this->firstRowStyle->cellSpacing\n            );\n            $this->firstRowStyle->setStyleByArray($firstRowStyle);\n        }\n\n        if ($tableStyle !== null) {\n            $this->setStyleByArray($tableStyle);\n        }\n    }\n\n    /**\n     * @param null|float|int $cellSpacing\n     */\n    public function setCellSpacing($cellSpacing = null): self\n    {\n        $this->cellSpacing = $cellSpacing;\n\n        return $this;\n    }\n\n    /**\n     * @return null|float|int\n     */\n    public function getCellSpacing()\n    {\n        return $this->cellSpacing;\n    }\n\n    /**\n     * Set first row.\n     *\n     * @return Table\n     */\n    public function getFirstRow()\n    {\n        return $this->firstRowStyle;\n    }\n\n    /**\n     * Get background.\n     *\n     * @return ?string\n     */\n    public function getBgColor()\n    {\n        if ($this->shading !== null) {\n            return $this->shading->getFill();\n        }\n\n        return null;\n    }\n\n    /**\n     * Set background.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setBgColor($value = null)\n    {\n        $this->setShading(['fill' => $value]);\n\n        return $this;\n    }\n\n    /**\n     * Get TLRBHV Border Size.\n     *\n     * @return int[]\n     */\n    public function getBorderSize()\n    {\n        return [\n            $this->getBorderTopSize(),\n            $this->getBorderLeftSize(),\n            $this->getBorderRightSize(),\n            $this->getBorderBottomSize(),\n            $this->getBorderInsideHSize(),\n            $this->getBorderInsideVSize(),\n        ];\n    }\n\n    /**\n     * Set TLRBHV Border Size.\n     *\n     * @param int $value Border size in eighths of a point (1/8 point)\n     *\n     * @return self\n     */\n    public function setBorderSize($value = null)\n    {\n        $this->setBorderTopSize($value);\n        $this->setBorderLeftSize($value);\n        $this->setBorderRightSize($value);\n        $this->setBorderBottomSize($value);\n        $this->setBorderInsideHSize($value);\n        $this->setBorderInsideVSize($value);\n\n        return $this;\n    }\n\n    /**\n     * Get TLRBHV Border Color.\n     *\n     * @return string[]\n     */\n    public function getBorderColor()\n    {\n        return [\n            $this->getBorderTopColor(),\n            $this->getBorderLeftColor(),\n            $this->getBorderRightColor(),\n            $this->getBorderBottomColor(),\n            $this->getBorderInsideHColor(),\n            $this->getBorderInsideVColor(),\n        ];\n    }\n\n    /**\n     * Set TLRBHV Border Color.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setBorderColor($value = null)\n    {\n        $this->setBorderTopColor($value);\n        $this->setBorderLeftColor($value);\n        $this->setBorderRightColor($value);\n        $this->setBorderBottomColor($value);\n        $this->setBorderInsideHColor($value);\n        $this->setBorderInsideVColor($value);\n\n        return $this;\n    }\n\n    /**\n     * Get border size inside horizontal.\n     *\n     * @return int\n     */\n    public function getBorderInsideHSize()\n    {\n        return $this->getTableOnlyProperty('borderInsideHSize');\n    }\n\n    /**\n     * Set border size inside horizontal.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setBorderInsideHSize($value = null)\n    {\n        return $this->setTableOnlyProperty('borderInsideHSize', $value);\n    }\n\n    /**\n     * Get border color inside horizontal.\n     *\n     * @return string\n     */\n    public function getBorderInsideHColor()\n    {\n        return $this->getTableOnlyProperty('borderInsideHColor');\n    }\n\n    /**\n     * Set border color inside horizontal.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setBorderInsideHColor($value = null)\n    {\n        return $this->setTableOnlyProperty('borderInsideHColor', $value, false);\n    }\n\n    /**\n     * Get border size inside vertical.\n     *\n     * @return int\n     */\n    public function getBorderInsideVSize()\n    {\n        return $this->getTableOnlyProperty('borderInsideVSize');\n    }\n\n    /**\n     * Set border size inside vertical.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setBorderInsideVSize($value = null)\n    {\n        return $this->setTableOnlyProperty('borderInsideVSize', $value);\n    }\n\n    /**\n     * Get border color inside vertical.\n     *\n     * @return string\n     */\n    public function getBorderInsideVColor()\n    {\n        return $this->getTableOnlyProperty('borderInsideVColor');\n    }\n\n    /**\n     * Set border color inside vertical.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setBorderInsideVColor($value = null)\n    {\n        return $this->setTableOnlyProperty('borderInsideVColor', $value, false);\n    }\n\n    /**\n     * Get cell margin top.\n     *\n     * @return int\n     */\n    public function getCellMarginTop()\n    {\n        return $this->getTableOnlyProperty('cellMarginTop');\n    }\n\n    /**\n     * Set cell margin top.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setCellMarginTop($value = null)\n    {\n        return $this->setTableOnlyProperty('cellMarginTop', $value);\n    }\n\n    /**\n     * Get cell margin left.\n     *\n     * @return int\n     */\n    public function getCellMarginLeft()\n    {\n        return $this->getTableOnlyProperty('cellMarginLeft');\n    }\n\n    /**\n     * Set cell margin left.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setCellMarginLeft($value = null)\n    {\n        return $this->setTableOnlyProperty('cellMarginLeft', $value);\n    }\n\n    /**\n     * Get cell margin right.\n     *\n     * @return int\n     */\n    public function getCellMarginRight()\n    {\n        return $this->getTableOnlyProperty('cellMarginRight');\n    }\n\n    /**\n     * Set cell margin right.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setCellMarginRight($value = null)\n    {\n        return $this->setTableOnlyProperty('cellMarginRight', $value);\n    }\n\n    /**\n     * Get cell margin bottom.\n     *\n     * @return int\n     */\n    public function getCellMarginBottom()\n    {\n        return $this->getTableOnlyProperty('cellMarginBottom');\n    }\n\n    /**\n     * Set cell margin bottom.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setCellMarginBottom($value = null)\n    {\n        return $this->setTableOnlyProperty('cellMarginBottom', $value);\n    }\n\n    /**\n     * Get cell margin.\n     *\n     * @return int[]\n     */\n    public function getCellMargin()\n    {\n        return [\n            $this->cellMarginTop,\n            $this->cellMarginLeft,\n            $this->cellMarginRight,\n            $this->cellMarginBottom,\n        ];\n    }\n\n    /**\n     * Set TLRB cell margin.\n     *\n     * @param int $value Margin in twips\n     *\n     * @return self\n     */\n    public function setCellMargin($value = null)\n    {\n        $this->setCellMarginTop($value);\n        $this->setCellMarginLeft($value);\n        $this->setCellMarginRight($value);\n        $this->setCellMarginBottom($value);\n\n        return $this;\n    }\n\n    /**\n     * Check if any of the margin is not null.\n     *\n     * @return bool\n     */\n    public function hasMargin()\n    {\n        $margins = $this->getCellMargin();\n\n        return $margins !== array_filter($margins, 'is_null');\n    }\n\n    /**\n     * Get shading.\n     *\n     * @return Shading\n     */\n    public function getShading()\n    {\n        return $this->shading;\n    }\n\n    /**\n     * Set shading.\n     *\n     * @param mixed $value\n     *\n     * @return self\n     */\n    public function setShading($value = null)\n    {\n        $this->setObjectVal($value, 'Shading', $this->shading);\n\n        return $this;\n    }\n\n    /**\n     * @since 0.13.0\n     *\n     * @return string\n     */\n    public function getAlignment()\n    {\n        return $this->alignment;\n    }\n\n    /**\n     * @since 0.13.0\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setAlignment($value)\n    {\n        if (JcTable::isValid($value) || Jc::isValid($value)) {\n            $this->alignment = $value;\n        }\n\n        return $this;\n    }\n\n    /**\n     * Get width.\n     *\n     * @return float|int\n     */\n    public function getWidth()\n    {\n        return $this->width;\n    }\n\n    /**\n     * Set width.\n     *\n     * @param float|int $value\n     *\n     * @return self\n     */\n    public function setWidth($value = null)\n    {\n        $this->width = $this->setNumericVal($value, $this->width);\n\n        return $this;\n    }\n\n    /**\n     * Get width unit.\n     *\n     * @return string\n     */\n    public function getUnit()\n    {\n        return $this->unit;\n    }\n\n    /**\n     * Set width unit.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setUnit($value = null)\n    {\n        TblWidth::validate($value);\n        $this->unit = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get layout.\n     *\n     * @return string\n     */\n    public function getLayout()\n    {\n        return $this->layout;\n    }\n\n    /**\n     * Set layout.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setLayout($value = null)\n    {\n        $enum = [self::LAYOUT_AUTO, self::LAYOUT_FIXED];\n        $this->layout = $this->setEnumVal($value, $enum, $this->layout);\n\n        return $this;\n    }\n\n    /**\n     * Get table style only property by checking if it's a firstRow.\n     *\n     * This is necessary since firstRow style is cloned from table style but\n     * without certain properties activated, e.g. margins\n     *\n     * @param string $property\n     *\n     * @return null|int|string\n     */\n    private function getTableOnlyProperty($property)\n    {\n        if (false === $this->isFirstRow) {\n            return $this->$property;\n        }\n\n        return null;\n    }\n\n    /**\n     * Set table style only property by checking if it's a firstRow.\n     *\n     * This is necessary since firstRow style is cloned from table style but\n     * without certain properties activated, e.g. margins\n     *\n     * @param string $property\n     * @param int|string $value\n     * @param bool $isNumeric\n     *\n     * @return self\n     */\n    private function setTableOnlyProperty($property, $value, $isNumeric = true)\n    {\n        if (false === $this->isFirstRow) {\n            if (true === $isNumeric) {\n                $this->$property = $this->setNumericVal($value, $this->$property);\n            } else {\n                $this->$property = $value;\n            }\n        }\n\n        return $this;\n    }\n\n    /**\n     * Get position.\n     *\n     * @return ?TablePosition\n     */\n    public function getPosition()\n    {\n        return $this->position;\n    }\n\n    /**\n     * Set position.\n     *\n     * @param mixed $value\n     *\n     * @return self\n     */\n    public function setPosition($value = null)\n    {\n        $this->setObjectVal($value, 'TablePosition', $this->position);\n\n        return $this;\n    }\n\n    /**\n     * @return ?TblWidthComplexType\n     */\n    public function getIndent()\n    {\n        return $this->indent;\n    }\n\n    /**\n     * @return self\n     *\n     * @see http://www.datypic.com/sc/ooxml/e-w_tblInd-1.html\n     */\n    public function setIndent(TblWidthComplexType $indent)\n    {\n        $this->indent = $indent;\n\n        return $this;\n    }\n\n    /**\n     * Get the columnWidths.\n     *\n     * @return null|int[]\n     */\n    public function getColumnWidths()\n    {\n        return $this->columnWidths;\n    }\n\n    /**\n     * The column widths.\n     *\n     * @param int[] $value\n     */\n    public function setColumnWidths(?array $value = null): void\n    {\n        $this->columnWidths = $value;\n    }\n\n    /**\n     * Get bidiVisual.\n     *\n     * @return ?bool\n     */\n    public function isBidiVisual()\n    {\n        return $this->bidiVisual ?? Settings::isDefaultRtl();\n    }\n\n    /**\n     * Set bidiVisual.\n     *\n     * @param ?bool $bidi\n     *            Set to true to visually present table as Right to Left\n     *\n     * @return self\n     */\n    public function setBidiVisual($bidi)\n    {\n        $this->bidiVisual = $bidi;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Style/TablePosition.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Style;\n\n/**\n * TablePosition style.\n *\n * @see http://www.datypic.com/sc/ooxml/e-w_tblpPr-1.html\n */\nclass TablePosition extends AbstractStyle\n{\n    /**\n     * Vertical anchor constants.\n     *\n     * @const string\n     *\n     * @see http://www.datypic.com/sc/ooxml/t-w_ST_VAnchor.html\n     */\n    const VANCHOR_TEXT = 'text'; // Relative to vertical text extents\n    const VANCHOR_MARGIN = 'margin'; // Relative to margin\n    const VANCHOR_PAGE = 'page'; // Relative to page\n\n    /**\n     * Horizontal anchor constants.\n     *\n     * @const string\n     *\n     * @see http://www.datypic.com/sc/ooxml/t-w_ST_HAnchor.html\n     */\n    const HANCHOR_TEXT = 'text'; // Relative to text extents\n    const HANCHOR_MARGIN = 'margin'; // Relative to margin\n    const HANCHOR_PAGE = 'page'; // Relative to page\n\n    /**\n     * Horizontal alignment constants.\n     *\n     * @const string\n     *\n     * @see http://www.datypic.com/sc/ooxml/t-w_ST_XAlign.html\n     */\n    const XALIGN_LEFT = 'left'; // Left aligned horizontally\n    const XALIGN_CENTER = 'center'; // Centered horizontally\n    const XALIGN_RIGHT = 'right'; // Right aligned horizontally\n    const XALIGN_INSIDE = 'inside'; // Inside\n    const XALIGN_OUTSIDE = 'outside'; // Outside\n\n    /**\n     * Vertical alignment constants.\n     *\n     * @const string\n     *\n     * @see http://www.datypic.com/sc/ooxml/t-w_ST_YAlign.html\n     */\n    const YALIGN_INLINE = 'inline'; // In line with text\n    const YALIGN_TOP = 'top'; // Top\n    const YALIGN_CENTER = 'center'; // Centered vertically\n    const YALIGN_BOTTOM = 'bottom'; // Bottom\n    const YALIGN_INSIDE = 'inside'; // Inside Anchor Extents\n    const YALIGN_OUTSIDE = 'outside'; // Centered vertically\n\n    /**\n     * Distance from left of table to text.\n     *\n     * @var int\n     */\n    private $leftFromText;\n\n    /**\n     * Distance from right of table to text.\n     *\n     * @var int\n     */\n    private $rightFromText;\n\n    /**\n     * Distance from top of table to text.\n     *\n     * @var int\n     */\n    private $topFromText;\n\n    /**\n     * Distance from bottom of table to text.\n     *\n     * @var int\n     */\n    private $bottomFromText;\n\n    /**\n     * Table vertical anchor.\n     *\n     * @var string\n     *\n     * @see http://www.datypic.com/sc/ooxml/t-w_ST_VAnchor.html\n     */\n    private $vertAnchor;\n\n    /**\n     * Table horizontal anchor.\n     *\n     * @var string\n     *\n     * @see http://www.datypic.com/sc/ooxml/t-w_ST_HAnchor.html\n     */\n    private $horzAnchor;\n\n    /**\n     * Relative horizontal alignment from anchor.\n     *\n     * @var string\n     *\n     * @see http://www.datypic.com/sc/ooxml/t-w_ST_XAlign.html\n     */\n    private $tblpXSpec;\n\n    /**\n     * Absolute horizontal distance from anchor.\n     *\n     * @var int\n     */\n    private $tblpX;\n\n    /**\n     * Relative vertical alignment from anchor.\n     *\n     * @var string\n     *\n     * @see http://www.datypic.com/sc/ooxml/t-w_ST_YAlign.html\n     */\n    private $tblpYSpec;\n\n    /**\n     * Absolute vertical distance from anchor.\n     *\n     * @var int\n     */\n    private $tblpY;\n\n    /**\n     * Create a new instance.\n     *\n     * @param array $style\n     */\n    public function __construct($style = [])\n    {\n        $this->setStyleByArray($style);\n    }\n\n    /**\n     * Get distance from left of table to text.\n     *\n     * @return int\n     */\n    public function getLeftFromText()\n    {\n        return $this->leftFromText;\n    }\n\n    /**\n     * Set distance from left of table to text.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setLeftFromText($value = null)\n    {\n        $this->leftFromText = $this->setNumericVal($value, $this->leftFromText);\n\n        return $this;\n    }\n\n    /**\n     * Get distance from right of table to text.\n     *\n     * @return int\n     */\n    public function getRightFromText()\n    {\n        return $this->rightFromText;\n    }\n\n    /**\n     * Set distance from right of table to text.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setRightFromText($value = null)\n    {\n        $this->rightFromText = $this->setNumericVal($value, $this->rightFromText);\n\n        return $this;\n    }\n\n    /**\n     * Get distance from top of table to text.\n     *\n     * @return int\n     */\n    public function getTopFromText()\n    {\n        return $this->topFromText;\n    }\n\n    /**\n     * Set distance from top of table to text.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setTopFromText($value = null)\n    {\n        $this->topFromText = $this->setNumericVal($value, $this->topFromText);\n\n        return $this;\n    }\n\n    /**\n     * Get distance from bottom of table to text.\n     *\n     * @return int\n     */\n    public function getBottomFromText()\n    {\n        return $this->bottomFromText;\n    }\n\n    /**\n     * Set distance from bottom of table to text.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setBottomFromText($value = null)\n    {\n        $this->bottomFromText = $this->setNumericVal($value, $this->bottomFromText);\n\n        return $this;\n    }\n\n    /**\n     * Get table vertical anchor.\n     *\n     * @return string\n     */\n    public function getVertAnchor()\n    {\n        return $this->vertAnchor;\n    }\n\n    /**\n     * Set table vertical anchor.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setVertAnchor($value = null)\n    {\n        $enum = [\n            self::VANCHOR_TEXT,\n            self::VANCHOR_MARGIN,\n            self::VANCHOR_PAGE,\n        ];\n        $this->vertAnchor = $this->setEnumVal($value, $enum, $this->vertAnchor);\n\n        return $this;\n    }\n\n    /**\n     * Get table horizontal anchor.\n     *\n     * @return string\n     */\n    public function getHorzAnchor()\n    {\n        return $this->horzAnchor;\n    }\n\n    /**\n     * Set table horizontal anchor.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setHorzAnchor($value = null)\n    {\n        $enum = [\n            self::HANCHOR_TEXT,\n            self::HANCHOR_MARGIN,\n            self::HANCHOR_PAGE,\n        ];\n        $this->horzAnchor = $this->setEnumVal($value, $enum, $this->horzAnchor);\n\n        return $this;\n    }\n\n    /**\n     * Get relative horizontal alignment from anchor.\n     *\n     * @return string\n     */\n    public function getTblpXSpec()\n    {\n        return $this->tblpXSpec;\n    }\n\n    /**\n     * Set relative horizontal alignment from anchor.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setTblpXSpec($value = null)\n    {\n        $enum = [\n            self::XALIGN_LEFT,\n            self::XALIGN_CENTER,\n            self::XALIGN_RIGHT,\n            self::XALIGN_INSIDE,\n            self::XALIGN_OUTSIDE,\n        ];\n        $this->tblpXSpec = $this->setEnumVal($value, $enum, $this->tblpXSpec);\n\n        return $this;\n    }\n\n    /**\n     * Get absolute horizontal distance from anchor.\n     *\n     * @return int\n     */\n    public function getTblpX()\n    {\n        return $this->tblpX;\n    }\n\n    /**\n     * Set absolute horizontal distance from anchor.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setTblpX($value = null)\n    {\n        $this->tblpX = $this->setNumericVal($value, $this->tblpX);\n\n        return $this;\n    }\n\n    /**\n     * Get relative vertical alignment from anchor.\n     *\n     * @return string\n     */\n    public function getTblpYSpec()\n    {\n        return $this->tblpYSpec;\n    }\n\n    /**\n     * Set relative vertical alignment from anchor.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setTblpYSpec($value = null)\n    {\n        $enum = [\n            self::YALIGN_INLINE,\n            self::YALIGN_TOP,\n            self::YALIGN_CENTER,\n            self::YALIGN_BOTTOM,\n            self::YALIGN_INSIDE,\n            self::YALIGN_OUTSIDE,\n        ];\n        $this->tblpYSpec = $this->setEnumVal($value, $enum, $this->tblpYSpec);\n\n        return $this;\n    }\n\n    /**\n     * Get absolute vertical distance from anchor.\n     *\n     * @return int\n     */\n    public function getTblpY()\n    {\n        return $this->tblpY;\n    }\n\n    /**\n     * Set absolute vertical distance from anchor.\n     *\n     * @param int $value\n     *\n     * @return self\n     */\n    public function setTblpY($value = null)\n    {\n        $this->tblpY = $this->setNumericVal($value, $this->tblpY);\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Style/TextBox.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Style;\n\n/**\n * TextBox style.\n *\n * @since 0.11.0\n */\nclass TextBox extends Image\n{\n    /**\n     * margin top.\n     *\n     * @var null|int\n     */\n    private $innerMarginTop;\n\n    /**\n     * margin left.\n     *\n     * @var null|int\n     */\n    private $innerMarginLeft;\n\n    /**\n     * margin right.\n     *\n     * @var null|int\n     */\n    private $innerMarginRight;\n\n    /**\n     * Cell margin bottom.\n     *\n     * @var null|int\n     */\n    private $innerMarginBottom;\n\n    /**\n     * border size.\n     *\n     * @var null|int\n     */\n    private $borderSize;\n\n    /**\n     * border color.\n     *\n     * @var null|string\n     */\n    private $borderColor;\n\n    /**\n     * background color.\n     *\n     * @var null|string\n     */\n    private $bgColor;\n\n    /**\n     * Set background color.\n     */\n    public function setBgColor(?string $value = null): void\n    {\n        $this->bgColor = $value;\n    }\n\n    /**\n     * Get background color.\n     */\n    public function getBgColor(): ?string\n    {\n        return $this->bgColor;\n    }\n\n    /**\n     * Set margin top.\n     */\n    public function setInnerMarginTop(?int $value = null): void\n    {\n        $this->innerMarginTop = $value;\n    }\n\n    /**\n     * Get margin top.\n     */\n    public function getInnerMarginTop(): ?int\n    {\n        return $this->innerMarginTop;\n    }\n\n    /**\n     * Set margin left.\n     */\n    public function setInnerMarginLeft(?int $value = null): void\n    {\n        $this->innerMarginLeft = $value;\n    }\n\n    /**\n     * Get margin left.\n     */\n    public function getInnerMarginLeft(): ?int\n    {\n        return $this->innerMarginLeft;\n    }\n\n    /**\n     * Set margin right.\n     */\n    public function setInnerMarginRight(?int $value = null): void\n    {\n        $this->innerMarginRight = $value;\n    }\n\n    /**\n     * Get margin right.\n     */\n    public function getInnerMarginRight(): ?int\n    {\n        return $this->innerMarginRight;\n    }\n\n    /**\n     * Set margin bottom.\n     */\n    public function setInnerMarginBottom(?int $value = null): void\n    {\n        $this->innerMarginBottom = $value;\n    }\n\n    /**\n     * Get margin bottom.\n     */\n    public function getInnerMarginBottom(): ?int\n    {\n        return $this->innerMarginBottom;\n    }\n\n    /**\n     * Set TLRB cell margin.\n     *\n     * @param null|int $value Margin in twips\n     */\n    public function setInnerMargin(?int $value = null): void\n    {\n        $this->setInnerMarginTop($value);\n        $this->setInnerMarginLeft($value);\n        $this->setInnerMarginRight($value);\n        $this->setInnerMarginBottom($value);\n    }\n\n    /**\n     * Get cell margin.\n     *\n     * @return int[]\n     */\n    public function getInnerMargin(): array\n    {\n        return [$this->innerMarginLeft, $this->innerMarginTop, $this->innerMarginRight, $this->innerMarginBottom];\n    }\n\n    /**\n     * Has inner margin?\n     */\n    public function hasInnerMargins(): bool\n    {\n        $hasInnerMargins = false;\n        $margins = $this->getInnerMargin();\n        $numMargins = count($margins);\n        for ($i = 0; $i < $numMargins; ++$i) {\n            if ($margins[$i] !== null) {\n                $hasInnerMargins = true;\n            }\n        }\n\n        return $hasInnerMargins;\n    }\n\n    /**\n     * Set border size.\n     *\n     * @param null|int $value Size in points\n     */\n    public function setBorderSize(?int $value = null): void\n    {\n        $this->borderSize = $value;\n    }\n\n    /**\n     * Get border size.\n     */\n    public function getBorderSize(): ?int\n    {\n        return $this->borderSize;\n    }\n\n    /**\n     * Set border color.\n     */\n    public function setBorderColor(?string $value = null): void\n    {\n        $this->borderColor = $value;\n    }\n\n    /**\n     * Get border color.\n     */\n    public function getBorderColor(): ?string\n    {\n        return $this->borderColor;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Style.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord;\n\nuse PhpOffice\\PhpWord\\Style\\AbstractStyle;\nuse PhpOffice\\PhpWord\\Style\\Font;\nuse PhpOffice\\PhpWord\\Style\\Numbering;\nuse PhpOffice\\PhpWord\\Style\\Paragraph;\nuse PhpOffice\\PhpWord\\Style\\Table;\n\n/**\n * Style collection.\n */\nclass Style\n{\n    /**\n     * Style register.\n     *\n     * @var array\n     */\n    private static $styles = [];\n\n    /**\n     * Add paragraph style.\n     *\n     * @param string $styleName\n     * @param AbstractStyle|array $styles\n     *\n     * @return Paragraph\n     */\n    public static function addParagraphStyle($styleName, $styles)\n    {\n        return self::setStyleValues($styleName, new Paragraph(), $styles);\n    }\n\n    /**\n     * Add font style.\n     *\n     * @param string $styleName\n     * @param AbstractStyle|array $fontStyle\n     * @param AbstractStyle|array $paragraphStyle\n     *\n     * @return Font\n     */\n    public static function addFontStyle($styleName, $fontStyle, $paragraphStyle = null)\n    {\n        return self::setStyleValues($styleName, new Font('text', $paragraphStyle), $fontStyle);\n    }\n\n    /**\n     * Add link style.\n     *\n     * @param string $styleName\n     * @param AbstractStyle|array $styles\n     *\n     * @return Font\n     */\n    public static function addLinkStyle($styleName, $styles)\n    {\n        return self::setStyleValues($styleName, new Font('link'), $styles);\n    }\n\n    /**\n     * Add numbering style.\n     *\n     * @param string $styleName\n     * @param AbstractStyle|array $styleValues\n     *\n     * @return Numbering\n     *\n     * @since 0.10.0\n     */\n    public static function addNumberingStyle($styleName, $styleValues)\n    {\n        return self::setStyleValues($styleName, new Numbering(), $styleValues);\n    }\n\n    /**\n     * Add title style.\n     *\n     * @param null|int $depth Provide null to set title font\n     * @param AbstractStyle|array $fontStyle\n     * @param AbstractStyle|array $paragraphStyle\n     *\n     * @return Font\n     */\n    public static function addTitleStyle($depth, $fontStyle, $paragraphStyle = null)\n    {\n        if (empty($depth)) {\n            $styleName = 'Title';\n        } else {\n            $styleName = \"Heading_{$depth}\";\n        }\n\n        return self::setStyleValues($styleName, new Font('title', $paragraphStyle), $fontStyle);\n    }\n\n    /**\n     * Add table style.\n     *\n     * @param string $styleName\n     * @param array $styleTable\n     * @param null|array $styleFirstRow\n     *\n     * @return Table\n     */\n    public static function addTableStyle($styleName, $styleTable, $styleFirstRow = null)\n    {\n        return self::setStyleValues($styleName, new Table($styleTable, $styleFirstRow), null);\n    }\n\n    /**\n     * Count styles.\n     *\n     * @return int\n     *\n     * @since 0.10.0\n     */\n    public static function countStyles()\n    {\n        return count(self::$styles);\n    }\n\n    /**\n     * Reset styles.\n     *\n     * @since 0.10.0\n     */\n    public static function resetStyles(): void\n    {\n        self::$styles = [];\n    }\n\n    /**\n     * Set default paragraph style.\n     *\n     * @param AbstractStyle|array $styles Paragraph style definition\n     *\n     * @return Paragraph\n     */\n    public static function setDefaultParagraphStyle($styles)\n    {\n        return self::addParagraphStyle('Normal', $styles);\n    }\n\n    /**\n     * Get all styles.\n     *\n     * @return AbstractStyle[]\n     */\n    public static function getStyles()\n    {\n        return self::$styles;\n    }\n\n    /**\n     * Get style by name.\n     *\n     * @param string $styleName\n     *\n     * @return ?AbstractStyle Paragraph|Font|Table|Numbering\n     */\n    public static function getStyle($styleName)\n    {\n        if (isset(self::$styles[$styleName])) {\n            return self::$styles[$styleName];\n        }\n\n        return null;\n    }\n\n    /**\n     * Set style values and put it to static style collection.\n     *\n     * The $styleValues could be an array or object\n     *\n     * @param string $name\n     * @param AbstractStyle $style\n     * @param AbstractStyle|array $value\n     *\n     * @return AbstractStyle\n     */\n    private static function setStyleValues($name, $style, $value = null)\n    {\n        if (!isset(self::$styles[$name])) {\n            if ($value !== null) {\n                if (is_array($value)) {\n                    $style->setStyleByArray($value);\n                } elseif ($value instanceof AbstractStyle) {\n                    if (get_class($style) == get_class($value)) {\n                        $style = $value;\n                    }\n                }\n            }\n            $style->setStyleName($name);\n            $style->setIndex(self::countStyles() + 1); // One based index\n            self::$styles[$name] = $style;\n        }\n\n        return self::getStyle($name);\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/TemplateProcessor.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord;\n\nuse DOMDocument;\nuse PhpOffice\\PhpWord\\Escaper\\RegExp;\nuse PhpOffice\\PhpWord\\Escaper\\Xml;\nuse PhpOffice\\PhpWord\\Exception\\CopyFileException;\nuse PhpOffice\\PhpWord\\Exception\\CreateTemporaryFileException;\nuse PhpOffice\\PhpWord\\Exception\\Exception;\nuse PhpOffice\\PhpWord\\Shared\\Text;\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\nuse PhpOffice\\PhpWord\\Shared\\ZipArchive;\nuse Throwable;\nuse XSLTProcessor;\n\nclass TemplateProcessor\n{\n    const MAXIMUM_REPLACEMENTS_DEFAULT = -1;\n\n    /**\n     * ZipArchive object.\n     *\n     * @var mixed\n     */\n    protected $zipClass;\n\n    /**\n     * @var string Temporary document filename (with path)\n     */\n    protected $tempDocumentFilename;\n\n    /**\n     * Content of main document part (in XML format) of the temporary document.\n     *\n     * @var string\n     */\n    protected $tempDocumentMainPart;\n\n    /**\n     * Content of settings part (in XML format) of the temporary document.\n     *\n     * @var string\n     */\n    protected $tempDocumentSettingsPart;\n\n    /**\n     * Content of headers (in XML format) of the temporary document.\n     *\n     * @var string[]\n     */\n    protected $tempDocumentHeaders = [];\n\n    /**\n     * Content of footers (in XML format) of the temporary document.\n     *\n     * @var string[]\n     */\n    protected $tempDocumentFooters = [];\n\n    /**\n     * Document relations (in XML format) of the temporary document.\n     *\n     * @var string[]\n     */\n    protected $tempDocumentRelations = [];\n\n    /**\n     * Document content types (in XML format) of the temporary document.\n     *\n     * @var string\n     */\n    protected $tempDocumentContentTypes = '';\n\n    /**\n     * new inserted images list.\n     *\n     * @var string[]\n     */\n    protected $tempDocumentNewImages = [];\n\n    protected static $macroOpeningChars = '${';\n\n    protected static $macroClosingChars = '}';\n\n    /**\n     * @since 0.12.0 Throws CreateTemporaryFileException and CopyFileException instead of Exception\n     *\n     * @param string $documentTemplate The fully qualified template filename\n     */\n    public function __construct($documentTemplate)\n    {\n        // Temporary document filename initialization\n        $this->tempDocumentFilename = tempnam(Settings::getTempDir(), 'PhpWord');\n        if (false === $this->tempDocumentFilename) {\n            throw new CreateTemporaryFileException(); // @codeCoverageIgnore\n        }\n\n        // Template file cloning\n        if (false === copy($documentTemplate, $this->tempDocumentFilename)) {\n            throw new CopyFileException($documentTemplate, $this->tempDocumentFilename); // @codeCoverageIgnore\n        }\n\n        // Temporary document content extraction\n        $this->zipClass = new ZipArchive();\n        $this->zipClass->open($this->tempDocumentFilename);\n        $index = 1;\n        while (false !== $this->zipClass->locateName($this->getHeaderName($index))) {\n            $this->tempDocumentHeaders[$index] = $this->readPartWithRels($this->getHeaderName($index));\n            ++$index;\n        }\n        $index = 1;\n        while (false !== $this->zipClass->locateName($this->getFooterName($index))) {\n            $this->tempDocumentFooters[$index] = $this->readPartWithRels($this->getFooterName($index));\n            ++$index;\n        }\n\n        $this->tempDocumentMainPart = $this->readPartWithRels($this->getMainPartName());\n        $this->tempDocumentSettingsPart = $this->readPartWithRels($this->getSettingsPartName());\n        $tempDocumentContentTypes = $this->zipClass->getFromName($this->getDocumentContentTypesName());\n        if (is_string($tempDocumentContentTypes)) {\n            $this->tempDocumentContentTypes = $tempDocumentContentTypes;\n        }\n    }\n\n    public function __destruct()\n    {\n        // ZipClass\n        if ($this->zipClass) {\n            try {\n                $this->zipClass->close();\n            } catch (Throwable $e) {\n                // Nothing to do here.\n            }\n        }\n    }\n\n    /**\n     * Expose zip class.\n     *\n     * To replace an image: $templateProcessor->zip()->AddFromString(\"word/media/image1.jpg\", file_get_contents($file));<br>\n     * To read a file: $templateProcessor->zip()->getFromName(\"word/media/image1.jpg\");\n     *\n     * @return ZipArchive\n     */\n    public function zip()\n    {\n        return $this->zipClass;\n    }\n\n    /**\n     * @param string $fileName\n     *\n     * @return string\n     */\n    protected function readPartWithRels($fileName)\n    {\n        $relsFileName = $this->getRelationsName($fileName);\n        $partRelations = $this->zipClass->getFromName($relsFileName);\n        if ($partRelations !== false) {\n            $this->tempDocumentRelations[$fileName] = $partRelations;\n        }\n\n        return $this->fixBrokenMacros($this->zipClass->getFromName($fileName));\n    }\n\n    /**\n     * @param string $xml\n     * @param XSLTProcessor $xsltProcessor\n     *\n     * @return string\n     */\n    protected function transformSingleXml($xml, $xsltProcessor)\n    {\n        if (\\PHP_VERSION_ID < 80000) {\n            $orignalLibEntityLoader = libxml_disable_entity_loader(true);\n        }\n        $domDocument = new DOMDocument();\n        if (false === $domDocument->loadXML($xml)) {\n            throw new Exception('Could not load the given XML document.');\n        }\n\n        $transformedXml = $xsltProcessor->transformToXml($domDocument);\n        if (false === $transformedXml) {\n            throw new Exception('Could not transform the given XML document.');\n        }\n        if (\\PHP_VERSION_ID < 80000) {\n            libxml_disable_entity_loader($orignalLibEntityLoader);\n        }\n\n        return $transformedXml;\n    }\n\n    /**\n     * @param mixed $xml\n     * @param XSLTProcessor $xsltProcessor\n     *\n     * @return mixed\n     */\n    protected function transformXml($xml, $xsltProcessor)\n    {\n        if (is_array($xml)) {\n            foreach ($xml as &$item) {\n                $item = $this->transformSingleXml($item, $xsltProcessor);\n            }\n            unset($item);\n        } else {\n            $xml = $this->transformSingleXml($xml, $xsltProcessor);\n        }\n\n        return $xml;\n    }\n\n    /**\n     * Applies XSL style sheet to template's parts.\n     *\n     * Note: since the method doesn't make any guess on logic of the provided XSL style sheet,\n     * make sure that output is correctly escaped. Otherwise you may get broken document.\n     *\n     * @param DOMDocument $xslDomDocument\n     * @param array $xslOptions\n     * @param string $xslOptionsUri\n     */\n    public function applyXslStyleSheet($xslDomDocument, $xslOptions = [], $xslOptionsUri = ''): void\n    {\n        $xsltProcessor = new XSLTProcessor();\n\n        $xsltProcessor->importStylesheet($xslDomDocument);\n        if (false === $xsltProcessor->setParameter($xslOptionsUri, $xslOptions)) {\n            throw new Exception('Could not set values for the given XSL style sheet parameters.');\n        }\n\n        $this->tempDocumentHeaders = $this->transformXml($this->tempDocumentHeaders, $xsltProcessor);\n        $this->tempDocumentMainPart = $this->transformXml($this->tempDocumentMainPart, $xsltProcessor);\n        $this->tempDocumentFooters = $this->transformXml($this->tempDocumentFooters, $xsltProcessor);\n    }\n\n    /**\n     * @param string $macro\n     *\n     * @return string\n     */\n    protected static function ensureMacroCompleted($macro)\n    {\n        if (substr($macro, 0, 2) !== self::$macroOpeningChars && substr($macro, -1) !== self::$macroClosingChars) {\n            $macro = self::$macroOpeningChars . $macro . self::$macroClosingChars;\n        }\n\n        return $macro;\n    }\n\n    /**\n     * @param ?string $subject\n     *\n     * @return string\n     */\n    protected static function ensureUtf8Encoded($subject)\n    {\n        return (null !== $subject) ? Text::toUTF8($subject) : '';\n    }\n\n    /**\n     * @param string $search\n     */\n    public function setComplexValue($search, Element\\AbstractElement $complexType): void\n    {\n        $elementName = substr(get_class($complexType), strrpos(get_class($complexType), '\\\\') + 1);\n        $objectClass = 'PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007\\\\Element\\\\' . $elementName;\n\n        $xmlWriter = new XMLWriter();\n        /** @var Writer\\Word2007\\Element\\AbstractElement $elementWriter */\n        $elementWriter = new $objectClass($xmlWriter, $complexType, true);\n        $elementWriter->write();\n\n        $where = $this->findContainingXmlBlockForMacro($search, 'w:r');\n\n        if ($where === false) {\n            return;\n        }\n\n        $block = $this->getSlice($where['start'], $where['end']);\n        $textParts = $this->splitTextIntoTexts($block);\n        $this->replaceXmlBlock($search, $textParts, 'w:r');\n\n        $search = static::ensureMacroCompleted($search);\n        $this->replaceXmlBlock($search, $xmlWriter->getData(), 'w:r');\n    }\n\n    /**\n     * @param string $search\n     */\n    public function setComplexBlock($search, Element\\AbstractElement $complexType): void\n    {\n        $elementName = substr(get_class($complexType), strrpos(get_class($complexType), '\\\\') + 1);\n        $objectClass = 'PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007\\\\Element\\\\' . $elementName;\n\n        $xmlWriter = new XMLWriter();\n        /** @var Writer\\Word2007\\Element\\AbstractElement $elementWriter */\n        $elementWriter = new $objectClass($xmlWriter, $complexType, false);\n        $elementWriter->write();\n\n        $this->replaceXmlBlock($search, $xmlWriter->getData(), 'w:p');\n    }\n\n    /**\n     * @param array<string>|string $search\n     * @param null|array<string>|bool|float|int|string $replace\n     * @param int $limit\n     */\n    public function setValue($search, $replace, $limit = self::MAXIMUM_REPLACEMENTS_DEFAULT): void\n    {\n        if (is_array($search)) {\n            foreach ($search as &$item) {\n                $item = static::ensureMacroCompleted($item);\n            }\n            unset($item);\n        } else {\n            $search = static::ensureMacroCompleted($search);\n        }\n\n        if (is_array($replace)) {\n            foreach ($replace as &$item) {\n                $item = static::ensureUtf8Encoded($item);\n            }\n            unset($item);\n        } else {\n            $replace = static::ensureUtf8Encoded(null === $replace ? null : (string) $replace);\n        }\n\n        if (Settings::isOutputEscapingEnabled()) {\n            $xmlEscaper = new Xml();\n            $replace = $xmlEscaper->escape($replace);\n        }\n\n        // convert carriage returns\n        if (is_array($replace)) {\n            foreach ($replace as &$item) {\n                $item = $this->replaceCarriageReturns($item);\n            }\n        } else {\n            $replace = $this->replaceCarriageReturns($replace);\n        }\n\n        $this->tempDocumentHeaders = $this->setValueForPart($search, $replace, $this->tempDocumentHeaders, $limit);\n        $this->tempDocumentMainPart = $this->setValueForPart($search, $replace, $this->tempDocumentMainPart, $limit);\n        $this->tempDocumentFooters = $this->setValueForPart($search, $replace, $this->tempDocumentFooters, $limit);\n    }\n\n    /**\n     * Set values from a one-dimensional array of \"variable => value\"-pairs.\n     */\n    public function setValues(array $values, int $limit = self::MAXIMUM_REPLACEMENTS_DEFAULT): void\n    {\n        foreach ($values as $macro => $replace) {\n            $this->setValue($macro, $replace, $limit);\n        }\n    }\n\n    public function setCheckbox(string $search, bool $checked): void\n    {\n        $search = static::ensureMacroCompleted($search);\n        $blockType = 'w:sdt';\n\n        $where = $this->findContainingXmlBlockForMacro($search, $blockType);\n        if (!is_array($where)) {\n            return;\n        }\n\n        $block = $this->getSlice($where['start'], $where['end']);\n\n        $val = $checked ? '1' : '0';\n        $block = preg_replace('/(<w14:checked w14:val=)\".*?\"(\\/>)/', '$1\"' . $val . '\"$2', $block);\n\n        $text = $checked ? '☒' : '☐';\n        $block = preg_replace('/(<w:t>).*?(<\\/w:t>)/', '$1' . $text . '$2', $block);\n\n        $this->replaceXmlBlock($search, $block, $blockType);\n    }\n\n    /**\n     * @param string $search\n     */\n    public function setChart($search, Element\\AbstractElement $chart): void\n    {\n        $elementName = substr(get_class($chart), strrpos(get_class($chart), '\\\\') + 1);\n        $objectClass = 'PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007\\\\Element\\\\' . $elementName;\n\n        // Get the next relation id\n        $rId = $this->getNextRelationsIndex($this->getMainPartName());\n        $chart->setRelationId($rId);\n\n        // Define the chart filename\n        $filename = \"charts/chart{$rId}.xml\";\n\n        // Get the part writer\n        $writerPart = new Writer\\Word2007\\Part\\Chart();\n        $writerPart->setElement($chart);\n\n        // ContentTypes.xml\n        $this->zipClass->addFromString(\"word/{$filename}\", $writerPart->write());\n\n        // add chart to content type\n        $xmlRelationsType = \"<Override PartName=\\\"/word/{$filename}\\\" ContentType=\\\"application/vnd.openxmlformats-officedocument.drawingml.chart+xml\\\"/>\";\n        $this->tempDocumentContentTypes = str_replace('</Types>', $xmlRelationsType, $this->tempDocumentContentTypes) . '</Types>';\n\n        // Add the chart to relations\n        $xmlChartRelation = \"<Relationship Id=\\\"rId{$rId}\\\" Type=\\\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart\\\" Target=\\\"charts/chart{$rId}.xml\\\"/>\";\n        $this->tempDocumentRelations[$this->getMainPartName()] = str_replace('</Relationships>', $xmlChartRelation, $this->tempDocumentRelations[$this->getMainPartName()]) . '</Relationships>';\n\n        // Write the chart\n        $xmlWriter = new XMLWriter();\n        $elementWriter = new $objectClass($xmlWriter, $chart, true);\n        $elementWriter->write();\n\n        // Place it in the template\n        $this->replaceXmlBlock($search, '<w:p>' . $xmlWriter->getData() . '</w:p>', 'w:p');\n    }\n\n    private function getImageArgs($varNameWithArgs)\n    {\n        $varElements = explode(':', $varNameWithArgs);\n        array_shift($varElements); // first element is name of variable => remove it\n\n        $varInlineArgs = [];\n        // size format documentation: https://msdn.microsoft.com/en-us/library/documentformat.openxml.vml.shape%28v=office.14%29.aspx?f=255&MSPPError=-2147217396\n        foreach ($varElements as $argIdx => $varArg) {\n            if (strpos($varArg, '=')) { // arg=value\n                [$argName, $argValue] = explode('=', $varArg, 2);\n                $argName = strtolower($argName);\n                if ($argName == 'size') {\n                    [$varInlineArgs['width'], $varInlineArgs['height']] = explode('x', $argValue, 2);\n                } else {\n                    $varInlineArgs[strtolower($argName)] = $argValue;\n                }\n            } elseif (preg_match('/^([0-9]*[a-z%]{0,2}|auto)x([0-9]*[a-z%]{0,2}|auto)$/i', $varArg)) { // 60x40\n                [$varInlineArgs['width'], $varInlineArgs['height']] = explode('x', $varArg, 2);\n            } else { // :60:40:f\n                switch ($argIdx) {\n                    case 0:\n                        $varInlineArgs['width'] = $varArg;\n\n                        break;\n                    case 1:\n                        $varInlineArgs['height'] = $varArg;\n\n                        break;\n                    case 2:\n                        $varInlineArgs['ratio'] = $varArg;\n\n                        break;\n                }\n            }\n        }\n\n        return $varInlineArgs;\n    }\n\n    private function chooseImageDimension($baseValue, $inlineValue, $defaultValue)\n    {\n        $value = $baseValue;\n        if (null === $value && isset($inlineValue)) {\n            $value = $inlineValue;\n        }\n        if (!preg_match('/^([0-9\\.]*(cm|mm|in|pt|pc|px|%|em|ex|)|auto)$/i', $value ?? '')) {\n            $value = null;\n        }\n        if (null === $value) {\n            $value = $defaultValue;\n        }\n        if (is_numeric($value)) {\n            $value .= 'px';\n        }\n\n        return $value;\n    }\n\n    private function fixImageWidthHeightRatio(&$width, &$height, $actualWidth, $actualHeight): void\n    {\n        $imageRatio = $actualWidth / $actualHeight;\n\n        if (($width === '') && ($height === '')) { // defined size are empty\n            $width = $actualWidth . 'px';\n            $height = $actualHeight . 'px';\n        } elseif ($width === '') { // defined width is empty\n            $heightFloat = (float) $height;\n            $widthFloat = $heightFloat * $imageRatio;\n            $matches = [];\n            preg_match('/\\\\d([a-z%]+)$/', $height, $matches);\n            $width = $widthFloat . (!empty($matches) ? $matches[1] : 'px');\n        } elseif ($height === '') { // defined height is empty\n            $widthFloat = (float) $width;\n            $heightFloat = $widthFloat / $imageRatio;\n            $matches = [];\n            preg_match('/\\\\d([a-z%]+)$/', $width, $matches);\n            $height = $heightFloat . (!empty($matches) ? $matches[1] : 'px');\n        } else { // we have defined size, but we need also check it aspect ratio\n            $widthMatches = [];\n            preg_match('/\\\\d([a-z%]+)$/', $width, $widthMatches);\n            $heightMatches = [];\n            preg_match('/\\\\d([a-z%]+)$/', $height, $heightMatches);\n            // try to fix only if dimensions are same\n            if (!empty($widthMatches)\n                && !empty($heightMatches)\n                && $widthMatches[1] == $heightMatches[1]) {\n                $dimention = $widthMatches[1];\n                $widthFloat = (float) $width;\n                $heightFloat = (float) $height;\n                $definedRatio = $widthFloat / $heightFloat;\n\n                if ($imageRatio > $definedRatio) { // image wider than defined box\n                    $height = ($widthFloat / $imageRatio) . $dimention;\n                } elseif ($imageRatio < $definedRatio) { // image higher than defined box\n                    $width = ($heightFloat * $imageRatio) . $dimention;\n                }\n            }\n        }\n    }\n\n    private function prepareImageAttrs($replaceImage, $varInlineArgs)\n    {\n        // get image path and size\n        $width = null;\n        $height = null;\n        $ratio = null;\n\n        // a closure can be passed as replacement value which after resolving, can contain the replacement info for the image\n        // use case: only when a image if found, the replacement tags can be generated\n        if (is_callable($replaceImage)) {\n            $replaceImage = $replaceImage();\n        }\n\n        if (is_array($replaceImage) && isset($replaceImage['path'])) {\n            $imgPath = $replaceImage['path'];\n            if (isset($replaceImage['width'])) {\n                $width = $replaceImage['width'];\n            }\n            if (isset($replaceImage['height'])) {\n                $height = $replaceImage['height'];\n            }\n            if (isset($replaceImage['ratio'])) {\n                $ratio = $replaceImage['ratio'];\n            }\n        } else {\n            $imgPath = $replaceImage;\n        }\n\n        $width = $this->chooseImageDimension($width, $varInlineArgs['width'] ?? null, 115);\n        $height = $this->chooseImageDimension($height, $varInlineArgs['height'] ?? null, 70);\n\n        $imageData = @getimagesize($imgPath);\n        if (!is_array($imageData)) {\n            throw new Exception(sprintf('Invalid image: %s', $imgPath));\n        }\n        [$actualWidth, $actualHeight, $imageType] = $imageData;\n\n        // fix aspect ratio (by default)\n        if (null === $ratio && isset($varInlineArgs['ratio'])) {\n            $ratio = $varInlineArgs['ratio'];\n        }\n        if (null === $ratio || !in_array(strtolower($ratio), ['', '-', 'f', 'false'])) {\n            $this->fixImageWidthHeightRatio($width, $height, $actualWidth, $actualHeight);\n        }\n\n        $imageAttrs = [\n            'src' => $imgPath,\n            'mime' => image_type_to_mime_type($imageType),\n            'width' => $width,\n            'height' => $height,\n        ];\n\n        return $imageAttrs;\n    }\n\n    private function addImageToRelations($partFileName, $rid, $imgPath, $imageMimeType): void\n    {\n        // define templates\n        $typeTpl = '<Override PartName=\"/word/media/{IMG}\" ContentType=\"image/{EXT}\"/>';\n        $relationTpl = '<Relationship Id=\"{RID}\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image\" Target=\"media/{IMG}\"/>';\n        $newRelationsTpl = '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>' . \"\\n\" . '<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\"></Relationships>';\n        $newRelationsTypeTpl = '<Override PartName=\"/{RELS}\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\"/>';\n        $extTransform = [\n            'image/jpeg' => 'jpeg',\n            'image/png' => 'png',\n            'image/bmp' => 'bmp',\n            'image/gif' => 'gif',\n        ];\n\n        // get image embed name\n        if (isset($this->tempDocumentNewImages[$imgPath])) {\n            $imgName = $this->tempDocumentNewImages[$imgPath];\n        } else {\n            // transform extension\n            if (isset($extTransform[$imageMimeType])) {\n                $imgExt = $extTransform[$imageMimeType];\n            } else {\n                throw new Exception(\"Unsupported image type $imageMimeType\");\n            }\n\n            // add image to document\n            $imgName = 'image_' . $rid . '_' . pathinfo($partFileName, PATHINFO_FILENAME) . '.' . $imgExt;\n            $this->zipClass->pclzipAddFile($imgPath, 'word/media/' . $imgName);\n            $this->tempDocumentNewImages[$imgPath] = $imgName;\n\n            // setup type for image\n            $xmlImageType = str_replace(['{IMG}', '{EXT}'], [$imgName, $imgExt], $typeTpl);\n            $this->tempDocumentContentTypes = str_replace('</Types>', $xmlImageType, $this->tempDocumentContentTypes) . '</Types>';\n        }\n\n        $xmlImageRelation = str_replace(['{RID}', '{IMG}'], [$rid, $imgName], $relationTpl);\n\n        if (!isset($this->tempDocumentRelations[$partFileName])) {\n            // create new relations file\n            $this->tempDocumentRelations[$partFileName] = $newRelationsTpl;\n            // and add it to content types\n            $xmlRelationsType = str_replace('{RELS}', $this->getRelationsName($partFileName), $newRelationsTypeTpl);\n            $this->tempDocumentContentTypes = str_replace('</Types>', $xmlRelationsType, $this->tempDocumentContentTypes) . '</Types>';\n        }\n\n        // add image to relations\n        $this->tempDocumentRelations[$partFileName] = str_replace('</Relationships>', $xmlImageRelation, $this->tempDocumentRelations[$partFileName]) . '</Relationships>';\n    }\n\n    /**\n     * @param mixed $search\n     * @param mixed $replace Path to image, or array(\"path\" => xx, \"width\" => yy, \"height\" => zz)\n     * @param int $limit\n     */\n    public function setImageValue($search, $replace, $limit = self::MAXIMUM_REPLACEMENTS_DEFAULT): void\n    {\n        // prepare $search_replace\n        if (!is_array($search)) {\n            $search = [$search];\n        }\n\n        $replacesList = [];\n        if (!is_array($replace) || isset($replace['path'])) {\n            $replacesList[] = $replace;\n        } else {\n            $replacesList = array_values($replace);\n        }\n\n        $searchReplace = [];\n        foreach ($search as $searchIdx => $searchString) {\n            $searchReplace[$searchString] = $replacesList[$searchIdx] ?? $replacesList[0];\n        }\n\n        // collect document parts\n        $searchParts = [\n            $this->getMainPartName() => &$this->tempDocumentMainPart,\n        ];\n        foreach (array_keys($this->tempDocumentHeaders) as $headerIndex) {\n            $searchParts[$this->getHeaderName($headerIndex)] = &$this->tempDocumentHeaders[$headerIndex];\n        }\n        foreach (array_keys($this->tempDocumentFooters) as $footerIndex) {\n            $searchParts[$this->getFooterName($footerIndex)] = &$this->tempDocumentFooters[$footerIndex];\n        }\n\n        // define templates\n        // result can be verified via \"Open XML SDK 2.5 Productivity Tool\" (http://www.microsoft.com/en-us/download/details.aspx?id=30425)\n        $imgTpl = '<w:pict><v:shape type=\"#_x0000_t75\" style=\"width:{WIDTH};height:{HEIGHT}\" stroked=\"f\" filled=\"f\"><v:imagedata r:id=\"{RID}\" o:title=\"\"/></v:shape></w:pict>';\n\n        $i = 0;\n        foreach ($searchParts as $partFileName => &$partContent) {\n            $partVariables = $this->getVariablesForPart($partContent);\n\n            foreach ($searchReplace as $searchString => $replaceImage) {\n                $varsToReplace = array_filter($partVariables, function ($partVar) use ($searchString) {\n                    return ($partVar == $searchString) || preg_match('/^' . preg_quote($searchString, '/') . ':/', $partVar);\n                });\n\n                foreach ($varsToReplace as $varNameWithArgs) {\n                    $varInlineArgs = $this->getImageArgs($varNameWithArgs);\n                    $preparedImageAttrs = $this->prepareImageAttrs($replaceImage, $varInlineArgs);\n                    $imgPath = $preparedImageAttrs['src'];\n\n                    // get image index\n                    $imgIndex = $this->getNextRelationsIndex($partFileName);\n                    $rid = 'rId' . $imgIndex;\n\n                    // replace preparations\n                    $this->addImageToRelations($partFileName, $rid, $imgPath, $preparedImageAttrs['mime']);\n                    $xmlImage = str_replace(['{RID}', '{WIDTH}', '{HEIGHT}'], [$rid, $preparedImageAttrs['width'], $preparedImageAttrs['height']], $imgTpl);\n\n                    // replace variable\n                    $varNameWithArgsFixed = static::ensureMacroCompleted($varNameWithArgs);\n                    $matches = [];\n                    if (preg_match('/(<[^<]+>)([^<]*)(' . preg_quote($varNameWithArgsFixed, '/') . ')([^>]*)(<[^>]+>)/Uu', $partContent, $matches)) {\n                        $wholeTag = $matches[0];\n                        array_shift($matches);\n                        [$openTag, $prefix, , $postfix, $closeTag] = $matches;\n                        $replaceXml = $openTag . $prefix . $closeTag . $xmlImage . $openTag . $postfix . $closeTag;\n                        // replace on each iteration, because in one tag we can have 2+ inline variables => before proceed next variable we need to change $partContent\n                        $partContent = $this->setValueForPart($wholeTag, $replaceXml, $partContent, $limit);\n                    }\n\n                    if (++$i >= $limit) {\n                        break;\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Returns count of all variables in template.\n     *\n     * @return array\n     */\n    public function getVariableCount()\n    {\n        $variables = $this->getVariablesForPart($this->tempDocumentMainPart);\n\n        foreach ($this->tempDocumentHeaders as $headerXML) {\n            $variables = array_merge(\n                $variables,\n                $this->getVariablesForPart($headerXML)\n            );\n        }\n\n        foreach ($this->tempDocumentFooters as $footerXML) {\n            $variables = array_merge(\n                $variables,\n                $this->getVariablesForPart($footerXML)\n            );\n        }\n\n        return array_count_values($variables);\n    }\n\n    /**\n     * Returns array of all variables in template.\n     *\n     * @return string[]\n     */\n    public function getVariables()\n    {\n        return array_keys($this->getVariableCount());\n    }\n\n    /**\n     * Clone a table row in a template document.\n     *\n     * @param string $search\n     * @param int $numberOfClones\n     */\n    public function cloneRow($search, $numberOfClones): void\n    {\n        $search = static::ensureMacroCompleted($search);\n\n        $tagPos = strpos($this->tempDocumentMainPart, $search);\n        if (!$tagPos) {\n            throw new Exception('Can not clone row, template variable not found or variable contains markup.');\n        }\n\n        $rowStart = $this->findRowStart($tagPos);\n        $rowEnd = $this->findRowEnd($tagPos);\n        $xmlRow = $this->getSlice($rowStart, $rowEnd);\n\n        // Check if there's a cell spanning multiple rows.\n        if (preg_match('#<w:vMerge w:val=\"restart\"/>#', $xmlRow)) {\n            // $extraRowStart = $rowEnd;\n            $extraRowEnd = $rowEnd;\n            while (true) {\n                $extraRowStart = $this->findRowStart($extraRowEnd + 1);\n                $extraRowEnd = $this->findRowEnd($extraRowEnd + 1);\n\n                // If extraRowEnd is lower then 7, there was no next row found.\n                if ($extraRowEnd < 7) {\n                    break;\n                }\n\n                // If tmpXmlRow doesn't contain continue, this row is no longer part of the spanned row.\n                $tmpXmlRow = $this->getSlice($extraRowStart, $extraRowEnd);\n                if (!preg_match('#<w:vMerge/>#', $tmpXmlRow) &&\n                    !preg_match('#<w:vMerge w:val=\"continue\"\\s*/>#', $tmpXmlRow)\n                ) {\n                    break;\n                }\n                // This row was a spanned row, update $rowEnd and search for the next row.\n                $rowEnd = $extraRowEnd;\n            }\n            $xmlRow = $this->getSlice($rowStart, $rowEnd);\n        }\n\n        $result = $this->getSlice(0, $rowStart);\n        $result .= implode('', $this->indexClonedVariables($numberOfClones, $xmlRow));\n        $result .= $this->getSlice($rowEnd);\n\n        $this->tempDocumentMainPart = $result;\n    }\n\n    /**\n     * Delete a table row in a template document.\n     */\n    public function deleteRow(string $search): void\n    {\n        if (self::$macroOpeningChars !== substr($search, 0, 2) && self::$macroClosingChars !== substr($search, -1)) {\n            $search = self::$macroOpeningChars . $search . self::$macroClosingChars;\n        }\n\n        $tagPos = strpos($this->tempDocumentMainPart, $search);\n        if (!$tagPos) {\n            throw new Exception(sprintf('Can not delete row %s, template variable not found or variable contains markup.', $search));\n        }\n\n        $tableStart = $this->findTableStart($tagPos);\n        $tableEnd = $this->findTableEnd($tagPos);\n        $xmlTable = $this->getSlice($tableStart, $tableEnd);\n\n        if (substr_count($xmlTable, '<w:tr') === 1) {\n            $this->tempDocumentMainPart = $this->getSlice(0, $tableStart) . $this->getSlice($tableEnd);\n\n            return;\n        }\n\n        $rowStart = $this->findRowStart($tagPos);\n        $rowEnd = $this->findRowEnd($tagPos);\n        $xmlRow = $this->getSlice($rowStart, $rowEnd);\n\n        $this->tempDocumentMainPart = $this->getSlice(0, $rowStart) . $this->getSlice($rowEnd);\n\n        // Check if there's a cell spanning multiple rows.\n        if (preg_match('#<w:vMerge w:val=\"restart\"/>#', $xmlRow)) {\n            $extraRowStart = $rowStart;\n            while (true) {\n                $extraRowStart = $this->findRowStart($extraRowStart + 1);\n                $extraRowEnd = $this->findRowEnd($extraRowStart + 1);\n\n                // If extraRowEnd is lower then 7, there was no next row found.\n                if ($extraRowEnd < 7) {\n                    break;\n                }\n\n                // If tmpXmlRow doesn't contain continue, this row is no longer part of the spanned row.\n                $tmpXmlRow = $this->getSlice($extraRowStart, $extraRowEnd);\n                if (!preg_match('#<w:vMerge/>#', $tmpXmlRow) &&\n                    !preg_match('#<w:vMerge w:val=\"continue\" />#', $tmpXmlRow)\n                ) {\n                    break;\n                }\n\n                $tableStart = $this->findTableStart($extraRowEnd + 1);\n                $tableEnd = $this->findTableEnd($extraRowEnd + 1);\n                $xmlTable = $this->getSlice($tableStart, $tableEnd);\n                if (substr_count($xmlTable, '<w:tr') === 1) {\n                    $this->tempDocumentMainPart = $this->getSlice(0, $tableStart) . $this->getSlice($tableEnd);\n\n                    return;\n                }\n\n                $this->tempDocumentMainPart = $this->getSlice(0, $extraRowStart) . $this->getSlice($extraRowEnd);\n            }\n        }\n    }\n\n    /**\n     * Clones a table row and populates it's values from a two-dimensional array in a template document.\n     *\n     * @param string $search\n     * @param array $values\n     */\n    public function cloneRowAndSetValues($search, $values): void\n    {\n        $this->cloneRow($search, count($values));\n\n        foreach ($values as $rowKey => $rowData) {\n            $rowNumber = $rowKey + 1;\n            foreach ($rowData as $macro => $replace) {\n                $this->setValue($macro . '#' . $rowNumber, $replace);\n            }\n        }\n    }\n\n    /**\n     * Clone a block.\n     *\n     * @param string $blockname\n     * @param int $clones How many time the block should be cloned\n     * @param bool $replace\n     * @param bool $indexVariables If true, any variables inside the block will be indexed (postfixed with #1, #2, ...)\n     * @param array $variableReplacements Array containing replacements for macros found inside the block to clone\n     *\n     * @return null|string\n     */\n    public function cloneBlock($blockname, $clones = 1, $replace = true, $indexVariables = false, $variableReplacements = null)\n    {\n        $xmlBlock = null;\n        $matches = [];\n        $escapedMacroOpeningChars = self::$macroOpeningChars;\n        $escapedMacroClosingChars = self::$macroClosingChars;\n        preg_match(\n            //'/(.*((?s)<w:p\\b(?:(?!<w:p\\b).)*?\\{{' . $blockname . '}<\\/w:.*?p>))(.*)((?s)<w:p\\b(?:(?!<w:p\\b).)[^$]*?\\{{\\/' . $blockname . '}<\\/w:.*?p>)/is',\n            '/(.*((?s)<w:p\\b(?:(?!<w:p\\b).)*?\\\\' . $escapedMacroOpeningChars . $blockname . $escapedMacroClosingChars . '<\\/w:.*?p>))(.*)((?s)<w:p\\b(?:(?!<w:p\\b).)[^$]*?\\\\' . $escapedMacroOpeningChars . '\\/' . $blockname . $escapedMacroClosingChars . '<\\/w:.*?p>)/is',\n            //'/(.*((?s)<w:p\\b(?:(?!<w:p\\b).)*?\\\\'. $escapedMacroOpeningChars . $blockname . '}<\\/w:.*?p>))(.*)((?s)<w:p\\b(?:(?!<w:p\\b).)[^$]*?\\\\'.$escapedMacroOpeningChars.'\\/' . $blockname . '}<\\/w:.*?p>)/is',\n            $this->tempDocumentMainPart,\n            $matches\n        );\n\n        if (isset($matches[3])) {\n            $xmlBlock = $matches[3];\n            if ($indexVariables) {\n                $cloned = $this->indexClonedVariables($clones, $xmlBlock);\n            } elseif ($variableReplacements !== null && is_array($variableReplacements)) {\n                $cloned = $this->replaceClonedVariables($variableReplacements, $xmlBlock);\n            } else {\n                $cloned = [];\n                for ($i = 1; $i <= $clones; ++$i) {\n                    $cloned[] = $xmlBlock;\n                }\n            }\n\n            if ($replace) {\n                $this->tempDocumentMainPart = str_replace(\n                    $matches[2] . $matches[3] . $matches[4],\n                    implode('', $cloned),\n                    $this->tempDocumentMainPart\n                );\n            }\n        }\n\n        return $xmlBlock;\n    }\n\n    /**\n     * Replace a block.\n     *\n     * @param string $blockname\n     * @param string $replacement\n     */\n    public function replaceBlock($blockname, $replacement): void\n    {\n        $matches = [];\n        $escapedMacroOpeningChars = preg_quote(self::$macroOpeningChars);\n        $escapedMacroClosingChars = preg_quote(self::$macroClosingChars);\n        preg_match(\n            '/(<\\?xml.*)(<w:p.*>' . $escapedMacroOpeningChars . $blockname . $escapedMacroClosingChars . '<\\/w:.*?p>)(.*)(<w:p.*' . $escapedMacroOpeningChars . '\\/' . $blockname . $escapedMacroClosingChars . '<\\/w:.*?p>)/is',\n            $this->tempDocumentMainPart,\n            $matches\n        );\n\n        if (isset($matches[3])) {\n            $this->tempDocumentMainPart = str_replace(\n                $matches[2] . $matches[3] . $matches[4],\n                $replacement,\n                $this->tempDocumentMainPart\n            );\n        }\n    }\n\n    /**\n     * Delete a block of text.\n     *\n     * @param string $blockname\n     */\n    public function deleteBlock($blockname): void\n    {\n        $this->replaceBlock($blockname, '');\n    }\n\n    /**\n     * Automatically Recalculate Fields on Open.\n     *\n     * @param bool $update\n     */\n    public function setUpdateFields($update = true): void\n    {\n        $string = $update ? 'true' : 'false';\n        $matches = [];\n        if (preg_match('/<w:updateFields w:val=\\\"(true|false|1|0|on|off)\\\"\\/>/', $this->tempDocumentSettingsPart, $matches)) {\n            $this->tempDocumentSettingsPart = str_replace($matches[0], '<w:updateFields w:val=\"' . $string . '\"/>', $this->tempDocumentSettingsPart);\n        } else {\n            $this->tempDocumentSettingsPart = str_replace('</w:settings>', '<w:updateFields w:val=\"' . $string . '\"/></w:settings>', $this->tempDocumentSettingsPart);\n        }\n    }\n\n    /**\n     * Saves the result document.\n     *\n     * @return string\n     */\n    public function save()\n    {\n        foreach ($this->tempDocumentHeaders as $index => $xml) {\n            $this->savePartWithRels($this->getHeaderName($index), $xml);\n        }\n\n        $this->savePartWithRels($this->getMainPartName(), $this->tempDocumentMainPart);\n        $this->savePartWithRels($this->getSettingsPartName(), $this->tempDocumentSettingsPart);\n\n        foreach ($this->tempDocumentFooters as $index => $xml) {\n            $this->savePartWithRels($this->getFooterName($index), $xml);\n        }\n\n        $this->zipClass->addFromString($this->getDocumentContentTypesName(), $this->tempDocumentContentTypes);\n\n        // Close zip file\n        if (false === $this->zipClass->close()) {\n            throw new Exception('Could not close zip file.'); // @codeCoverageIgnore\n        }\n\n        return $this->tempDocumentFilename;\n    }\n\n    /**\n     * @param string $fileName\n     * @param string $xml\n     */\n    protected function savePartWithRels($fileName, $xml): void\n    {\n        $this->zipClass->addFromString($fileName, $xml);\n        if (isset($this->tempDocumentRelations[$fileName])) {\n            $relsFileName = $this->getRelationsName($fileName);\n            $this->zipClass->addFromString($relsFileName, $this->tempDocumentRelations[$fileName]);\n        }\n    }\n\n    /**\n     * Saves the result document to the user defined file.\n     *\n     * @since 0.8.0\n     *\n     * @param string $fileName\n     */\n    public function saveAs($fileName): void\n    {\n        $tempFileName = $this->save();\n\n        if (file_exists($fileName)) {\n            unlink($fileName);\n        }\n\n        /*\n         * Note: we do not use `rename` function here, because it loses file ownership data on Windows platform.\n         * As a result, user cannot open the file directly getting \"Access denied\" message.\n         *\n         * @see https://github.com/PHPOffice/PHPWord/issues/532\n         */\n        copy($tempFileName, $fileName);\n        unlink($tempFileName);\n    }\n\n    /**\n     * Finds parts of broken macros and sticks them together.\n     * Macros, while being edited, could be implicitly broken by some of the word processors.\n     *\n     * @param string $documentPart The document part in XML representation\n     *\n     * @return string\n     */\n    protected function fixBrokenMacros($documentPart)\n    {\n        $brokenMacroOpeningChars = substr(self::$macroOpeningChars, 0, 1);\n        $endMacroOpeningChars = substr(self::$macroOpeningChars, 1);\n        $macroClosingChars = self::$macroClosingChars;\n\n        return preg_replace_callback(\n            '/\\\\' . $brokenMacroOpeningChars . '(?:\\\\' . $endMacroOpeningChars . '|[^{$]*\\>\\{)[^' . $macroClosingChars . '$]*\\}/U',\n            function ($match) {\n                return strip_tags($match[0]);\n            },\n            $documentPart\n        );\n    }\n\n    /**\n     * Find and replace macros in the given XML section.\n     *\n     * @param array<string>|string $search\n     * @param array<string>|string $replace\n     * @param array<int, string>|string $documentPartXML\n     * @param int $limit\n     *\n     * @return ($documentPartXML is string ? string : array<string>)\n     */\n    protected function setValueForPart($search, $replace, $documentPartXML, $limit)\n    {\n        // Note: we can't use the same function for both cases here, because of performance considerations.\n        if (self::MAXIMUM_REPLACEMENTS_DEFAULT === $limit) {\n            return str_replace($search, $replace, $documentPartXML);\n        }\n        $regExpEscaper = new RegExp();\n\n        return preg_replace($regExpEscaper->escape($search), $replace, $documentPartXML, $limit);\n    }\n\n    /**\n     * Find all variables in $documentPartXML.\n     *\n     * @param string $documentPartXML\n     *\n     * @return string[]\n     */\n    protected function getVariablesForPart($documentPartXML)\n    {\n        $matches = [];\n        $escapedMacroOpeningChars = preg_quote(self::$macroOpeningChars);\n        $escapedMacroClosingChars = preg_quote(self::$macroClosingChars);\n\n        preg_match_all(\"/$escapedMacroOpeningChars(.*?)$escapedMacroClosingChars/i\", $documentPartXML, $matches);\n\n        return $matches[1];\n    }\n\n    /**\n     * Get the name of the header file for $index.\n     *\n     * @param int $index\n     *\n     * @return string\n     */\n    protected function getHeaderName($index)\n    {\n        return sprintf('word/header%d.xml', $index);\n    }\n\n    /**\n     * Usually, the name of main part document will be 'document.xml'. However, some .docx files (possibly those from Office 365, experienced also on documents from Word Online created from blank templates) have file 'document22.xml' in their zip archive instead of 'document.xml'. This method searches content types file to correctly determine the file name.\n     *\n     * @return string\n     */\n    protected function getMainPartName()\n    {\n        $contentTypes = $this->zipClass->getFromName('[Content_Types].xml');\n\n        $pattern = '~PartName=\"\\/(word\\/document.*?\\.xml)\" ContentType=\"application\\/vnd\\.openxmlformats-officedocument\\.wordprocessingml\\.document\\.main\\+xml\"~';\n\n        $matches = [];\n        preg_match($pattern, $contentTypes, $matches);\n\n        return array_key_exists(1, $matches) ? $matches[1] : 'word/document.xml';\n    }\n\n    /**\n     * The name of the file containing the Settings part.\n     *\n     * @return string\n     */\n    protected function getSettingsPartName()\n    {\n        return 'word/settings.xml';\n    }\n\n    /**\n     * Get the name of the footer file for $index.\n     *\n     * @param int $index\n     *\n     * @return string\n     */\n    protected function getFooterName($index)\n    {\n        return sprintf('word/footer%d.xml', $index);\n    }\n\n    /**\n     * Get the name of the relations file for document part.\n     *\n     * @param string $documentPartName\n     *\n     * @return string\n     */\n    protected function getRelationsName($documentPartName)\n    {\n        return 'word/_rels/' . pathinfo($documentPartName, PATHINFO_BASENAME) . '.rels';\n    }\n\n    protected function getNextRelationsIndex($documentPartName)\n    {\n        if (isset($this->tempDocumentRelations[$documentPartName])) {\n            $candidate = substr_count($this->tempDocumentRelations[$documentPartName], '<Relationship');\n            while (strpos($this->tempDocumentRelations[$documentPartName], 'Id=\"rId' . $candidate . '\"') !== false) {\n                ++$candidate;\n            }\n\n            return $candidate;\n        }\n\n        return 1;\n    }\n\n    /**\n     * @return string\n     */\n    protected function getDocumentContentTypesName()\n    {\n        return '[Content_Types].xml';\n    }\n\n    /**\n     * Find the start position of the nearest table before $offset.\n     */\n    private function findTableStart(int $offset): int\n    {\n        $rowStart = strrpos(\n            $this->tempDocumentMainPart,\n            '<w:tbl ',\n            ((strlen($this->tempDocumentMainPart) - $offset) * -1)\n        );\n\n        if (!$rowStart) {\n            $rowStart = strrpos(\n                $this->tempDocumentMainPart,\n                '<w:tbl>',\n                ((strlen($this->tempDocumentMainPart) - $offset) * -1)\n            );\n        }\n        if (!$rowStart) {\n            throw new Exception('Can not find the start position of the table.');\n        }\n\n        return $rowStart;\n    }\n\n    /**\n     * Find the end position of the nearest table row after $offset.\n     */\n    private function findTableEnd(int $offset): int\n    {\n        return strpos($this->tempDocumentMainPart, '</w:tbl>', $offset) + 7;\n    }\n\n    /**\n     * Find the start position of the nearest table row before $offset.\n     *\n     * @param int $offset\n     *\n     * @return int\n     */\n    protected function findRowStart($offset)\n    {\n        $rowStart = strrpos($this->tempDocumentMainPart, '<w:tr ', ((strlen($this->tempDocumentMainPart) - $offset) * -1));\n\n        if (!$rowStart) {\n            $rowStart = strrpos($this->tempDocumentMainPart, '<w:tr>', ((strlen($this->tempDocumentMainPart) - $offset) * -1));\n        }\n        if (!$rowStart) {\n            throw new Exception('Can not find the start position of the row to clone.');\n        }\n\n        return $rowStart;\n    }\n\n    /**\n     * Find the end position of the nearest table row after $offset.\n     *\n     * @param int $offset\n     *\n     * @return int\n     */\n    protected function findRowEnd($offset)\n    {\n        return strpos($this->tempDocumentMainPart, '</w:tr>', $offset) + 7;\n    }\n\n    /**\n     * Get a slice of a string.\n     *\n     * @param int $startPosition\n     * @param int $endPosition\n     *\n     * @return string\n     */\n    protected function getSlice($startPosition, $endPosition = 0)\n    {\n        if (!$endPosition) {\n            $endPosition = strlen($this->tempDocumentMainPart);\n        }\n\n        return substr($this->tempDocumentMainPart, $startPosition, ($endPosition - $startPosition));\n    }\n\n    /**\n     * Replaces variable names in cloned\n     * rows/blocks with indexed names.\n     *\n     * @param int $count\n     * @param string $xmlBlock\n     *\n     * @return array<string>\n     */\n    protected function indexClonedVariables($count, $xmlBlock)\n    {\n        $results = [];\n        $escapedMacroOpeningChars = preg_quote(self::$macroOpeningChars);\n        $escapedMacroClosingChars = preg_quote(self::$macroClosingChars);\n\n        for ($i = 1; $i <= $count; ++$i) {\n            $results[] = preg_replace(\"/$escapedMacroOpeningChars([^:]*?)(:.*?)?$escapedMacroClosingChars/\", self::$macroOpeningChars . '\\1#' . $i . '\\2' . self::$macroClosingChars, $xmlBlock);\n        }\n\n        return $results;\n    }\n\n    /**\n     * Replace carriage returns with xml.\n     */\n    public function replaceCarriageReturns(string $string): string\n    {\n        return str_replace([\"\\r\\n\", \"\\r\", \"\\n\"], '</w:t><w:br/><w:t>', $string);\n    }\n\n    /**\n     * Replaces variables with values from array, array keys are the variable names.\n     *\n     * @param array $variableReplacements\n     * @param string $xmlBlock\n     *\n     * @return string[]\n     */\n    protected function replaceClonedVariables($variableReplacements, $xmlBlock)\n    {\n        $results = [];\n        foreach ($variableReplacements as $replacementArray) {\n            $localXmlBlock = $xmlBlock;\n            foreach ($replacementArray as $search => $replacement) {\n                $localXmlBlock = $this->setValueForPart(self::ensureMacroCompleted($search), $replacement, $localXmlBlock, self::MAXIMUM_REPLACEMENTS_DEFAULT);\n            }\n            $results[] = $localXmlBlock;\n        }\n\n        return $results;\n    }\n\n    /**\n     * Replace an XML block surrounding a macro with a new block.\n     *\n     * @param string $macro Name of macro\n     * @param string $block New block content\n     * @param string $blockType XML tag type of block\n     *\n     * @return TemplateProcessor Fluent interface\n     */\n    public function replaceXmlBlock($macro, $block, $blockType = 'w:p')\n    {\n        $where = $this->findContainingXmlBlockForMacro($macro, $blockType);\n        if (is_array($where)) {\n            $this->tempDocumentMainPart = $this->getSlice(0, $where['start']) . $block . $this->getSlice($where['end']);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Find start and end of XML block containing the given macro\n     * e.g. <w:p>...${macro}...</w:p>.\n     *\n     * Note that only the first instance of the macro will be found\n     *\n     * @param string $macro Name of macro\n     * @param string $blockType XML tag for block\n     *\n     * @return bool|int[] FALSE if not found, otherwise array with start and end\n     */\n    protected function findContainingXmlBlockForMacro($macro, $blockType = 'w:p')\n    {\n        $macroPos = $this->findMacro($macro);\n        if (0 > $macroPos) {\n            return false;\n        }\n        $start = $this->findXmlBlockStart($macroPos, $blockType);\n        if (0 > $start) {\n            return false;\n        }\n        $end = $this->findXmlBlockEnd($start, $blockType);\n        //if not found or if resulting string does not contain the macro we are searching for\n        if (0 > $end || strstr($this->getSlice($start, $end), $macro) === false) {\n            return false;\n        }\n\n        return ['start' => $start, 'end' => $end];\n    }\n\n    /**\n     * Find the position of (the start of) a macro.\n     *\n     * Returns -1 if not found, otherwise position of opening $\n     *\n     * Note that only the first instance of the macro will be found\n     *\n     * @param string $search Macro name\n     * @param int $offset Offset from which to start searching\n     *\n     * @return int -1 if macro not found\n     */\n    protected function findMacro($search, $offset = 0)\n    {\n        $search = static::ensureMacroCompleted($search);\n        $pos = strpos($this->tempDocumentMainPart, $search, $offset);\n\n        return ($pos === false) ? -1 : $pos;\n    }\n\n    /**\n     * Find the start position of the nearest XML block start before $offset.\n     *\n     * @param int $offset    Search position\n     * @param string  $blockType XML Block tag\n     *\n     * @return int -1 if block start not found\n     */\n    protected function findXmlBlockStart($offset, $blockType)\n    {\n        $reverseOffset = (strlen($this->tempDocumentMainPart) - $offset) * -1;\n        // first try XML tag with attributes\n        $blockStart = strrpos($this->tempDocumentMainPart, '<' . $blockType . ' ', $reverseOffset);\n        // if not found, or if found but contains the XML tag without attribute\n        if (false === $blockStart || strrpos($this->getSlice($blockStart, $offset), '<' . $blockType . '>')) {\n            // also try XML tag without attributes\n            $blockStart = strrpos($this->tempDocumentMainPart, '<' . $blockType . '>', $reverseOffset);\n        }\n\n        return ($blockStart === false) ? -1 : $blockStart;\n    }\n\n    /**\n     * Find the nearest block end position after $offset.\n     *\n     * @param int $offset    Search position\n     * @param string  $blockType XML Block tag\n     *\n     * @return int -1 if block end not found\n     */\n    protected function findXmlBlockEnd($offset, $blockType)\n    {\n        $blockEndStart = strpos($this->tempDocumentMainPart, '</' . $blockType . '>', $offset);\n        // return position of end of tag if found, otherwise -1\n\n        return ($blockEndStart === false) ? -1 : $blockEndStart + 3 + strlen($blockType);\n    }\n\n    /**\n     * Splits a w:r/w:t into a list of w:r where each ${macro} is in a separate w:r.\n     *\n     * @param string $text\n     *\n     * @return string\n     */\n    protected function splitTextIntoTexts($text)\n    {\n        if (!$this->textNeedsSplitting($text)) {\n            return $text;\n        }\n        $matches = [];\n        if (preg_match('/(<w:rPr.*<\\/w:rPr>)/i', $text, $matches)) {\n            $extractedStyle = $matches[0];\n        } else {\n            $extractedStyle = '';\n        }\n\n        $unformattedText = preg_replace('/>\\s+</', '><', $text);\n        $result = str_replace([self::$macroOpeningChars, self::$macroClosingChars], ['</w:t></w:r><w:r>' . $extractedStyle . '<w:t xml:space=\"preserve\">' . self::$macroOpeningChars, self::$macroClosingChars . '</w:t></w:r><w:r>' . $extractedStyle . '<w:t xml:space=\"preserve\">'], $unformattedText);\n\n        return str_replace(['<w:r>' . $extractedStyle . '<w:t xml:space=\"preserve\"></w:t></w:r>', '<w:r><w:t xml:space=\"preserve\"></w:t></w:r>', '<w:t>'], ['', '', '<w:t xml:space=\"preserve\">'], $result);\n    }\n\n    /**\n     * Returns true if string contains a macro that is not in it's own w:r.\n     *\n     * @param string $text\n     *\n     * @return bool\n     */\n    protected function textNeedsSplitting($text)\n    {\n        $escapedMacroOpeningChars = preg_quote(self::$macroOpeningChars);\n        $escapedMacroClosingChars = preg_quote(self::$macroClosingChars);\n\n        return 1 === preg_match('/[^>]' . $escapedMacroOpeningChars . '|' . $escapedMacroClosingChars . '[^<]/i', $text);\n    }\n\n    public function setMacroOpeningChars(string $macroOpeningChars): void\n    {\n        self::$macroOpeningChars = $macroOpeningChars;\n    }\n\n    public function setMacroClosingChars(string $macroClosingChars): void\n    {\n        self::$macroClosingChars = $macroClosingChars;\n    }\n\n    public function setMacroChars(string $macroOpeningChars, string $macroClosingChars): void\n    {\n        self::$macroOpeningChars = $macroOpeningChars;\n        self::$macroClosingChars = $macroClosingChars;\n    }\n\n    public function getTempDocumentFilename(): string\n    {\n        return $this->tempDocumentFilename;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/AbstractWriter.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer;\n\nuse PhpOffice\\PhpWord\\Exception\\CopyFileException;\nuse PhpOffice\\PhpWord\\Exception\\Exception;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Shared\\ZipArchive;\n\n/**\n * Abstract writer class.\n *\n * @since 0.10.0\n */\nabstract class AbstractWriter implements WriterInterface\n{\n    /**\n     * PHPWord object.\n     *\n     * @var PhpWord\n     */\n    protected $phpWord;\n\n    /**\n     * Part name and file name pairs.\n     *\n     * @var array\n     */\n    protected $parts = [];\n\n    /**\n     * Individual writers.\n     *\n     * @var array\n     */\n    protected $writerParts = [];\n\n    /**\n     * Paths to store media files.\n     *\n     * @var array\n     */\n    protected $mediaPaths = ['image' => '', 'object' => ''];\n\n    /**\n     * Use disk caching.\n     *\n     * @var bool\n     */\n    private $useDiskCaching = false;\n\n    /**\n     * Disk caching directory.\n     *\n     * @var string\n     */\n    private $diskCachingDirectory = './';\n\n    /**\n     * Temporary directory.\n     *\n     * @var string\n     */\n    private $tempDir = '';\n\n    /**\n     * Original file name.\n     *\n     * @var string\n     */\n    private $originalFilename;\n\n    /**\n     * Temporary file name.\n     *\n     * @var string\n     */\n    private $tempFilename;\n\n    /**\n     * Get PhpWord object.\n     *\n     * @return PhpWord\n     */\n    public function getPhpWord()\n    {\n        if (null !== $this->phpWord) {\n            return $this->phpWord;\n        }\n\n        throw new Exception('No PhpWord assigned.');\n    }\n\n    /**\n     * Set PhpWord object.\n     *\n     * @return self\n     */\n    public function setPhpWord(?PhpWord $phpWord = null)\n    {\n        $this->phpWord = $phpWord;\n\n        return $this;\n    }\n\n    /**\n     * Get writer part.\n     *\n     * @param string $partName Writer part name\n     *\n     * @return mixed\n     */\n    public function getWriterPart($partName = '')\n    {\n        if ($partName != '' && isset($this->writerParts[strtolower($partName)])) {\n            return $this->writerParts[strtolower($partName)];\n        }\n\n        return null;\n    }\n\n    /**\n     * Get use disk caching status.\n     *\n     * @return bool\n     */\n    public function isUseDiskCaching()\n    {\n        return $this->useDiskCaching;\n    }\n\n    /**\n     * Set use disk caching status.\n     *\n     * @param bool $value\n     * @param string $directory\n     *\n     * @return self\n     */\n    public function setUseDiskCaching($value = false, $directory = null)\n    {\n        $this->useDiskCaching = $value;\n\n        if (null !== $directory) {\n            if (is_dir($directory)) {\n                $this->diskCachingDirectory = $directory;\n            } else {\n                throw new Exception(\"Directory does not exist: $directory\");\n            }\n        }\n\n        return $this;\n    }\n\n    /**\n     * Get disk caching directory.\n     *\n     * @return string\n     */\n    public function getDiskCachingDirectory()\n    {\n        return $this->diskCachingDirectory;\n    }\n\n    /**\n     * Get temporary directory.\n     *\n     * @return string\n     */\n    public function getTempDir()\n    {\n        return $this->tempDir;\n    }\n\n    /**\n     * Set temporary directory.\n     *\n     * @param string $value\n     *\n     * @return self\n     */\n    public function setTempDir($value)\n    {\n        if (!is_dir($value)) {\n            mkdir($value);\n        }\n        $this->tempDir = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get temporary file name.\n     *\n     * If $filename is php://output or php://stdout, make it a temporary file\n     *\n     * @param string $filename\n     *\n     * @return string\n     */\n    protected function getTempFile($filename)\n    {\n        // Temporary directory\n        $this->setTempDir(Settings::getTempDir() . uniqid('/PHPWordWriter_', true) . '/');\n\n        // Temporary file\n        $this->originalFilename = $filename;\n        if (strpos(strtolower($filename), 'php://') === 0) {\n            $filename = tempnam(Settings::getTempDir(), 'PhpWord');\n            if (false === $filename) {\n                $filename = $this->originalFilename; // @codeCoverageIgnore\n            } // @codeCoverageIgnore\n        }\n        $this->tempFilename = $filename;\n\n        return $this->tempFilename;\n    }\n\n    /**\n     * Cleanup temporary file.\n     */\n    protected function cleanupTempFile(): void\n    {\n        if ($this->originalFilename != $this->tempFilename) {\n            // @codeCoverageIgnoreStart\n            // Can't find any test case. Uncomment when found.\n            if (false === copy($this->tempFilename, $this->originalFilename)) {\n                throw new CopyFileException($this->tempFilename, $this->originalFilename);\n            }\n            // @codeCoverageIgnoreEnd\n            @unlink($this->tempFilename);\n        }\n\n        $this->clearTempDir();\n    }\n\n    /**\n     * Clear temporary directory.\n     */\n    protected function clearTempDir(): void\n    {\n        if (is_dir($this->tempDir)) {\n            $this->deleteDir($this->tempDir);\n        }\n    }\n\n    /**\n     * Get ZipArchive object.\n     *\n     * @param string $filename\n     *\n     * @return ZipArchive\n     */\n    protected function getZipArchive($filename)\n    {\n        // Remove any existing file\n        if (file_exists($filename)) {\n            unlink($filename);\n        }\n\n        // Try opening the ZIP file\n        $zip = new ZipArchive();\n\n        // @codeCoverageIgnoreStart\n        // Can't find any test case. Uncomment when found.\n        if ($zip->open($filename, ZipArchive::OVERWRITE) !== true) {\n            if ($zip->open($filename, ZipArchive::CREATE) !== true) {\n                throw new \\Exception(\"Could not open '{$filename}' for writing.\");\n            }\n        }\n        // @codeCoverageIgnoreEnd\n\n        return $zip;\n    }\n\n    /**\n     * Open file for writing.\n     *\n     * @since 0.11.0\n     *\n     * @param string $filename\n     *\n     * @return resource\n     */\n    protected function openFile($filename)\n    {\n        $filename = $this->getTempFile($filename);\n        $fileHandle = fopen($filename, 'wb');\n        // @codeCoverageIgnoreStart\n        // Can't find any test case. Uncomment when found.\n        if ($fileHandle === false) {\n            throw new \\Exception(\"Could not open '{$filename}' for writing.\");\n        }\n        // @codeCoverageIgnoreEnd\n\n        return $fileHandle;\n    }\n\n    /**\n     * Write content to file.\n     *\n     * @since 0.11.0\n     *\n     * @param resource $fileHandle\n     * @param string $content\n     */\n    protected function writeFile($fileHandle, $content): void\n    {\n        fwrite($fileHandle, $content);\n        fclose($fileHandle);\n        $this->cleanupTempFile();\n    }\n\n    /**\n     * Add files to package.\n     *\n     * @param mixed $elements\n     */\n    protected function addFilesToPackage(ZipArchive $zip, $elements): void\n    {\n        foreach ($elements as $element) {\n            $type = $element['type']; // image|object|link\n\n            // Skip nonregistered types and set target\n            if (!isset($this->mediaPaths[$type])) {\n                continue;\n            }\n            $target = $this->mediaPaths[$type] . $element['target'];\n\n            // Retrive GD image content or get local media\n            if (isset($element['isMemImage']) && $element['isMemImage']) {\n                $imageContents = $element['imageString'];\n                $zip->addFromString($target, $imageContents);\n            } else {\n                $this->addFileToPackage($zip, $element['source'], $target);\n            }\n        }\n    }\n\n    /**\n     * Add file to package.\n     *\n     * Get the actual source from an archive image.\n     *\n     * @param ZipArchive $zipPackage\n     * @param string $source\n     * @param string $target\n     */\n    protected function addFileToPackage($zipPackage, $source, $target): void\n    {\n        $isArchive = strpos($source, 'zip://') !== false;\n        $actualSource = null;\n        if ($isArchive) {\n            $source = substr($source, 6);\n            [$zipFilename, $imageFilename] = explode('#', $source);\n\n            $zip = new ZipArchive();\n            if ($zip->open($zipFilename) !== false) {\n                if ($zip->locateName($imageFilename)) {\n                    $zip->extractTo($this->getTempDir(), $imageFilename);\n                    $actualSource = $this->getTempDir() . DIRECTORY_SEPARATOR . $imageFilename;\n                }\n            }\n            $zip->close();\n        } else {\n            $actualSource = $source;\n        }\n\n        if (null !== $actualSource) {\n            $zipPackage->addFile($actualSource, $target);\n        }\n    }\n\n    /**\n     * Delete directory.\n     *\n     * @param string $dir\n     */\n    private function deleteDir($dir): void\n    {\n        foreach (scandir($dir) as $file) {\n            if ($file === '.' || $file === '..') {\n                continue;\n            } elseif (is_file($dir . '/' . $file)) {\n                unlink($dir . '/' . $file);\n            } elseif (is_dir($dir . '/' . $file)) {\n                $this->deleteDir($dir . '/' . $file);\n            }\n        }\n\n        rmdir($dir);\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/EPub3/Element/AbstractElement.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\EPub3\\Element;\n\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\AbstractElement as Word2007AbstractElement;\n\n/**\n * Abstract element writer.\n *\n * @since 0.11.0\n */\nabstract class AbstractElement extends Word2007AbstractElement\n{\n    /**\n     * Get class name of writer element based on read element.\n     *\n     * @param \\PhpOffice\\PhpWord\\Element\\AbstractElement $element\n     */\n    public static function getElementClass($element): string\n    {\n        $elementClass = str_replace('PhpOffice\\\\PhpWord\\\\Element\\\\', '', get_class($element));\n        $writerClass = 'PhpOffice\\\\PhpWord\\\\Writer\\\\EPub3\\\\Element\\\\' . $elementClass;\n        if (!class_exists($writerClass)) {\n            throw new \\PhpOffice\\PhpWord\\Exception\\Exception(\"Writer element class {$writerClass} not found.\");\n        }\n\n        return $writerClass;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/EPub3/Element/Image.php",
    "content": "<?php\n\nnamespace PhpOffice\\PhpWord\\Writer\\EPub3\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\Image as ImageElement;\n\n/**\n * Image element writer for EPub3.\n */\nclass Image extends AbstractElement\n{\n    /**\n     * Write element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $xmlWriter->setIndent(false);\n        $element = $this->getElement();\n        if (!$element instanceof ImageElement) {\n            return;\n        }\n        $mediaIndex = $element->getMediaIndex();\n        $target = 'media/image' . $mediaIndex . '.' . $element->getImageExtension();\n        if (!$this->withoutP) {\n            $xmlWriter->startElement('p');\n        }\n        $xmlWriter->startElement('img');\n        $xmlWriter->writeAttribute('src', $target);\n        $style = '';\n        if ($element->getStyle()->getWidth() !== null) {\n            $style .= 'width:' . $element->getStyle()->getWidth() . 'px;';\n        }\n        if ($element->getStyle()->getHeight() !== null) {\n            $style .= 'height:' . $element->getStyle()->getHeight() . 'px;';\n        }\n        if ($style !== '') {\n            $xmlWriter->writeAttribute('style', $style);\n        }\n        $xmlWriter->endElement(); // img\n        if (!$this->withoutP) {\n            $xmlWriter->endElement(); // p\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/EPub3/Element/Text.php",
    "content": "<?php\n\nnamespace PhpOffice\\PhpWord\\Writer\\EPub3\\Element;\n\n/**\n * Text element writer for EPub3.\n */\nclass Text extends AbstractElement\n{\n    /**\n     * Write element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $xmlWriter->setIndent(true);\n        $xmlWriter->setIndentString('  ');\n        $element = $this->getElement();\n        if (!$element instanceof \\PhpOffice\\PhpWord\\Element\\Text) {\n            return;\n        }\n\n        $fontStyle = $element->getFontStyle();\n        $paragraphStyle = $element->getParagraphStyle();\n\n        if (!$this->withoutP) {\n            $xmlWriter->startElement('p');\n            if (is_string($paragraphStyle) && $paragraphStyle !== '') {\n                $xmlWriter->writeAttribute('class', $paragraphStyle);\n            }\n        }\n\n        if (!empty($fontStyle)) {\n            $xmlWriter->startElement('span');\n            if (is_string($fontStyle)) {\n                $xmlWriter->writeAttribute('class', $fontStyle);\n            }\n        }\n\n        $xmlWriter->text($element->getText());\n\n        if (!empty($fontStyle)) {\n            $xmlWriter->endElement(); // span\n        }\n\n        if (!$this->withoutP) {\n            $xmlWriter->endElement(); // p\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/EPub3/Part/AbstractPart.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\EPub3\\Part;\n\nuse PhpOffice\\PhpWord\\Writer\\AbstractWriter;\nuse PhpOffice\\PhpWord\\Writer\\WriterPartInterface;\n\n/**\n * Abstract class for EPub3 parts.\n */\nabstract class AbstractPart implements WriterPartInterface\n{\n    /**\n     * Parent writer.\n     *\n     * @var AbstractWriter\n     */\n    protected $parentWriter;\n\n    /**\n     * Set parent writer.\n     */\n    public function setParentWriter(AbstractWriter $writer): void\n    {\n        $this->parentWriter = $writer;\n    }\n\n    /**\n     * Get parent writer.\n     */\n    public function getParentWriter(): AbstractWriter\n    {\n        return $this->parentWriter;\n    }\n\n    /**\n     * Write part content.\n     */\n    abstract public function write(): string;\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/EPub3/Part/Content.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\EPub3\\Part;\n\nuse PhpOffice\\PhpWord\\Exception\\Exception;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse XMLWriter;\n\n/**\n * Class for EPub3 content part.\n */\nclass Content extends AbstractPart\n{\n    /**\n     * PHPWord object.\n     *\n     * @var ?PhpWord\n     */\n    private $phpWord;\n\n    /**\n     * Constructor.\n     */\n    public function __construct(?PhpWord $phpWord = null)\n    {\n        $this->phpWord = $phpWord;\n    }\n\n    /**\n     * Get XML Writer.\n     *\n     * @return XMLWriter\n     */\n    protected function getXmlWriter()\n    {\n        $xmlWriter = new XMLWriter();\n        $xmlWriter->openMemory();\n        $xmlWriter->startDocument('1.0', 'UTF-8');\n\n        return $xmlWriter;\n    }\n\n    /**\n     * Write part content.\n     */\n    public function write(): string\n    {\n        if ($this->phpWord === null) {\n            throw new Exception('No PhpWord assigned.');\n        }\n\n        $xmlWriter = $this->getXmlWriter();\n        $docInfo = $this->phpWord->getDocInfo();\n\n        // Write package\n        $xmlWriter->startElement('package');\n        $xmlWriter->writeAttribute('xmlns', 'http://www.idpf.org/2007/opf');\n        $xmlWriter->writeAttribute('version', '3.0');\n        $xmlWriter->writeAttribute('unique-identifier', 'book-id');\n        $xmlWriter->writeAttribute('xml:lang', 'en');\n\n        // Write metadata\n        $xmlWriter->startElement('metadata');\n        $xmlWriter->writeAttribute('xmlns:dc', 'http://purl.org/dc/elements/1.1/');\n        $xmlWriter->writeAttribute('xmlns:opf', 'http://www.idpf.org/2007/opf');\n\n        // Required elements\n        $xmlWriter->startElement('dc:identifier');\n        $xmlWriter->writeAttribute('id', 'book-id');\n        $xmlWriter->text('book-id-' . uniqid());\n        $xmlWriter->endElement();\n        $xmlWriter->writeElement('dc:title', $docInfo->getTitle() ?: 'Untitled');\n        $xmlWriter->writeElement('dc:language', 'en');\n\n        // Required modified timestamp\n        $xmlWriter->startElement('meta');\n        $xmlWriter->writeAttribute('property', 'dcterms:modified');\n        $xmlWriter->text(date('Y-m-d\\TH:i:s\\Z'));\n        $xmlWriter->endElement();\n\n        $xmlWriter->endElement(); // metadata\n\n        // Write manifest\n        $xmlWriter->startElement('manifest');\n\n        // Add nav document (required)\n        $xmlWriter->startElement('item');\n        $xmlWriter->writeAttribute('id', 'nav');\n        $xmlWriter->writeAttribute('href', 'nav.xhtml');\n        $xmlWriter->writeAttribute('media-type', 'application/xhtml+xml');\n        $xmlWriter->writeAttribute('properties', 'nav');\n        $xmlWriter->endElement();\n\n        // Add content document\n        $xmlWriter->startElement('item');\n        $xmlWriter->writeAttribute('id', 'content');\n        $xmlWriter->writeAttribute('href', 'content.xhtml');\n        $xmlWriter->writeAttribute('media-type', 'application/xhtml+xml');\n        $xmlWriter->endElement();\n\n        $xmlWriter->endElement(); // manifest\n\n        // Write spine\n        $xmlWriter->startElement('spine');\n        $xmlWriter->startElement('itemref');\n        $xmlWriter->writeAttribute('idref', 'content');\n        $xmlWriter->endElement();\n        $xmlWriter->endElement(); // spine\n\n        $xmlWriter->endElement(); // package\n\n        return $xmlWriter->outputMemory(true);\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/EPub3/Part/ContentXhtml.php",
    "content": "<?php\n\nnamespace PhpOffice\\PhpWord\\Writer\\EPub3\\Part;\n\nuse PhpOffice\\PhpWord\\Element\\AbstractElement;\nuse PhpOffice\\PhpWord\\Element\\Text;\nuse PhpOffice\\PhpWord\\Element\\TextRun;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse XMLWriter;\n\n/**\n * Class for EPub3 content.xhtml part.\n */\nclass ContentXhtml extends AbstractPart\n{\n    /**\n     * PHPWord object.\n     *\n     * @var ?PhpWord\n     */\n    private $phpWord;\n\n    /**\n     * Constructor.\n     */\n    public function __construct(?PhpWord $phpWord = null)\n    {\n        $this->phpWord = $phpWord;\n    }\n\n    /**\n     * Get XML Writer.\n     *\n     * @return XMLWriter\n     */\n    protected function getXmlWriter()\n    {\n        $xmlWriter = new XMLWriter();\n        $xmlWriter->openMemory();\n\n        return $xmlWriter;\n    }\n\n    /**\n     * Write part content.\n     */\n    public function write(): string\n    {\n        if ($this->phpWord === null) {\n            throw new \\PhpOffice\\PhpWord\\Exception\\Exception('No PhpWord assigned.');\n        }\n\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startDocument('1.0', 'UTF-8');\n        $xmlWriter->startElement('html');\n        $xmlWriter->writeAttribute('xmlns', 'http://www.w3.org/1999/xhtml');\n        $xmlWriter->writeAttribute('xmlns:epub', 'http://www.idpf.org/2007/ops');\n        $xmlWriter->startElement('head');\n        $xmlWriter->writeElement('title', $this->phpWord->getDocInfo()->getTitle() ?: 'Untitled');\n        $xmlWriter->endElement(); // head\n        $xmlWriter->startElement('body');\n\n        // Write sections content\n        foreach ($this->phpWord->getSections() as $section) {\n            $xmlWriter->startElement('div');\n            $xmlWriter->writeAttribute('class', 'section');\n\n            foreach ($section->getElements() as $element) {\n                if ($element instanceof TextRun) {\n                    $xmlWriter->startElement('p');\n                    $this->writeTextRun($element, $xmlWriter);\n                    $xmlWriter->endElement(); // p\n                } elseif (method_exists($element, 'getText')) {\n                    $text = $element->getText();\n                    $xmlWriter->startElement('p');\n                    if ($text instanceof TextRun) {\n                        $this->writeTextRun($text, $xmlWriter);\n                    } elseif ($text !== null) {\n                        $xmlWriter->text((string) $text);\n                    }\n                    $xmlWriter->endElement(); // p\n                }\n            }\n\n            $xmlWriter->endElement(); // div\n        }\n\n        $xmlWriter->endElement(); // body\n        $xmlWriter->endElement(); // html\n\n        return $xmlWriter->outputMemory(true);\n    }\n\n    protected function writeTextElement(AbstractElement $textElement, XMLWriter $xmlWriter): void\n    {\n        if ($textElement instanceof Text) {\n            $text = $textElement->getText();\n            if ($text !== null) {\n                $xmlWriter->text((string) $text);\n            }\n        } elseif (method_exists($textElement, 'getText')) {\n            $text = $textElement->getText();\n            if ($text instanceof TextRun) {\n                $this->writeTextRun($text, $xmlWriter);\n            } elseif ($text !== null) {\n                $xmlWriter->text((string) $text);\n            }\n        }\n    }\n\n    protected function writeTextRun(TextRun $textRun, XMLWriter $xmlWriter): void\n    {\n        foreach ($textRun->getElements() as $element) {\n            $this->writeTextElement($element, $xmlWriter);\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/EPub3/Part/Manifest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\EPub3\\Part;\n\n/**\n * Class for EPub3 manifest part.\n */\nclass Manifest extends AbstractPart\n{\n    /**\n     * Write part content.\n     */\n    public function write(): string\n    {\n        $content = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>';\n        $content .= '<container version=\"1.0\" xmlns=\"urn:oasis:names:tc:opendocument:xmlns:container\">';\n        $content .= '<rootfiles>';\n        $content .= '<rootfile full-path=\"content.opf\" media-type=\"application/oebps-package+xml\"/>';\n        $content .= '</rootfiles>';\n        $content .= '</container>';\n\n        return $content;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/EPub3/Part/Meta.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\EPub3\\Part;\n\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\n\n/**\n * Class for EPub3 metadata part.\n */\nclass Meta extends AbstractPart\n{\n    /**\n     * Get XML Writer.\n     */\n    protected function getXmlWriter(): XMLWriter\n    {\n        $xmlWriter = new XMLWriter();\n        $xmlWriter->openMemory();\n        $xmlWriter->startDocument('1.0', 'UTF-8');\n\n        return $xmlWriter;\n    }\n\n    /**\n     * Write part content.\n     */\n    public function write(): string\n    {\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startElement('metadata');\n        $xmlWriter->writeAttribute('xmlns', 'http://www.idpf.org/2007/opf');\n        $xmlWriter->writeAttribute('xmlns:dc', 'http://purl.org/dc/elements/1.1/');\n\n        // Write basic metadata\n        $title = $this->getParentWriter()->getPhpWord()->getDocInfo()->getTitle() ?: 'Sample EPub3 Document';\n        $xmlWriter->writeRaw('<dc:title>' . htmlspecialchars($title, ENT_QUOTES) . '</dc:title>');\n        $xmlWriter->writeElement('dc:language', 'en');\n        $xmlWriter->writeElement('dc:identifier', 'urn:uuid:12345');\n        $xmlWriter->writeAttribute('id', 'bookid');\n\n        // Write document info if available\n        $docInfo = $this->getParentWriter()->getPhpWord()->getDocInfo();\n        if ($docInfo->getCreator()) {\n            $xmlWriter->writeElement('dc:creator', $docInfo->getCreator());\n        }\n\n        // Write modification date\n        $xmlWriter->startElement('meta');\n        $xmlWriter->writeAttribute('property', 'dcterms:modified');\n        $xmlWriter->text('2023-01-01T00:00:00Z');\n        $xmlWriter->endElement();\n\n        $xmlWriter->endElement(); // metadata\n\n        return $xmlWriter->getData();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/EPub3/Part/Mimetype.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\EPub3\\Part;\n\n/**\n * Class for EPub3 mimetype part.\n */\nclass Mimetype extends AbstractPart\n{\n    /**\n     * Write part content.\n     */\n    public function write(): string\n    {\n        return 'application/epub+zip';\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/EPub3/Part/Nav.php",
    "content": "<?php\n\nnamespace PhpOffice\\PhpWord\\Writer\\EPub3\\Part;\n\nuse XMLWriter;\n\nclass Nav extends AbstractPart\n{\n    protected function getXmlWriter(): XMLWriter\n    {\n        $xmlWriter = new XMLWriter();\n        $xmlWriter->openMemory();\n\n        return $xmlWriter;\n    }\n\n    public function write(): string\n    {\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startDocument('1.0', 'UTF-8');\n        $xmlWriter->startElement('html');\n        $xmlWriter->writeAttribute('xmlns', 'http://www.w3.org/1999/xhtml');\n        $xmlWriter->writeAttribute('xmlns:epub', 'http://www.idpf.org/2007/ops');\n\n        $xmlWriter->startElement('head');\n        $xmlWriter->writeElement('title', 'Navigation');\n        $xmlWriter->endElement(); // head\n\n        $xmlWriter->startElement('body');\n        $xmlWriter->startElement('nav');\n        $xmlWriter->writeAttribute('epub:type', 'toc');\n        $xmlWriter->writeAttribute('id', 'toc');\n\n        // Add navigation items here if needed\n        $xmlWriter->writeElement('h1', 'Table of Contents');\n        $xmlWriter->startElement('ol');\n        // Add at least one list item to satisfy EPUB 3.3 requirements\n        $xmlWriter->startElement('li');\n        $xmlWriter->startElement('a');\n        $xmlWriter->writeAttribute('href', 'content.xhtml');\n        $xmlWriter->text('Content');\n        $xmlWriter->endElement(); // a\n        $xmlWriter->endElement(); // li\n        $xmlWriter->endElement(); // ol\n\n        $xmlWriter->endElement(); // nav\n        $xmlWriter->endElement(); // body\n        $xmlWriter->endElement(); // html\n\n        return $xmlWriter->outputMemory();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/EPub3/Part.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\EPub3;\n\nuse PhpOffice\\PhpWord\\Exception\\Exception;\n\n/**\n * Factory class for EPub3 parts.\n */\nclass Part\n{\n    /**\n     * Get the fully qualified class name for a specific part type.\n     *\n     * @param string $type The type of part (Content, Manifest, Meta, Mimetype)\n     *\n     * @return string The fully qualified class name\n     */\n    public static function getPartClass(string $type): string\n    {\n        $class = 'PhpOffice\\\\PhpWord\\\\Writer\\\\EPub3\\\\Part\\\\' . $type;\n\n        if (!class_exists($class)) {\n            throw new Exception(\"Invalid part type: {$type}\");\n        }\n\n        return $class;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/EPub3/Style/AbstractStyle.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\EPub3\\Style;\n\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\nuse PhpOffice\\PhpWord\\Writer\\AbstractWriter;\n\n/**\n * Abstract class for EPub3 styles.\n */\nabstract class AbstractStyle\n{\n    /**\n     * Parent writer.\n     *\n     * @var AbstractWriter\n     */\n    protected $parentWriter;\n\n    /**\n     * XML Writer.\n     *\n     * @var XMLWriter\n     */\n    protected $xmlWriter;\n\n    /**\n     * Set parent writer.\n     */\n    public function setParentWriter(AbstractWriter $writer): self\n    {\n        $this->parentWriter = $writer;\n\n        return $this;\n    }\n\n    /**\n     * Set XML Writer.\n     */\n    public function setXmlWriter(XMLWriter $writer): self\n    {\n        $this->xmlWriter = $writer;\n\n        return $this;\n    }\n\n    /**\n     * Get parent writer.\n     */\n    public function getParentWriter(): AbstractWriter\n    {\n        return $this->parentWriter;\n    }\n\n    /**\n     * Write style content.\n     */\n    abstract public function write(): string;\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/EPub3/Style/Font.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\EPub3\\Style;\n\n/**\n * Class for EPub3 font styles.\n */\nclass Font extends AbstractStyle\n{\n    /**\n     * Write style content.\n     */\n    public function write(): string\n    {\n        $content = 'body {';\n        $content .= 'font-family: \"Times New Roman\", Times, serif;';\n        $content .= 'font-size: 12pt;';\n        $content .= 'color: #000000;';\n        $content .= '}';\n\n        return $content;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/EPub3/Style/Paragraph.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\EPub3\\Style;\n\n/**\n * Class for EPub3 paragraph styles.\n */\nclass Paragraph extends AbstractStyle\n{\n    /**\n     * Write style content.\n     */\n    public function write(): string\n    {\n        $content = 'p {';\n        $content .= 'margin-top: 0;';\n        $content .= 'margin-bottom: 1em;';\n        $content .= 'text-align: left;';\n        $content .= '}';\n\n        return $content;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/EPub3/Style/Table.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\EPub3\\Style;\n\n/**\n * Class for EPub3 table styles.\n */\nclass Table extends AbstractStyle\n{\n    /**\n     * Write style content.\n     */\n    public function write(): string\n    {\n        $content = 'table {';\n        $content .= 'border-collapse: collapse;';\n        $content .= 'width: 100%;';\n        $content .= '}';\n        $content .= 'th, td {';\n        $content .= 'border: 1px solid black;';\n        $content .= 'padding: 8px;';\n        $content .= 'text-align: left;';\n        $content .= '}';\n\n        return $content;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/EPub3.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Writer\\EPub3\\Part\\AbstractPart;\n\n/**\n * EPub3 writer.\n */\nclass EPub3 extends AbstractWriter implements WriterInterface\n{\n    /**\n     * Create new EPub3 writer.\n     */\n    public function __construct(?PhpWord $phpWord = null)\n    {\n        // Assign PhpWord\n        $this->setPhpWord($phpWord);\n\n        // Create parts\n        $this->parts = [\n            'Mimetype' => 'mimetype',\n            'Content' => 'content.opf',\n            'Toc' => 'toc.ncx',\n            'Styles' => 'styles.css',\n            'Manifest' => 'META-INF/container.xml',\n            'Nav' => 'nav.xhtml',\n            'ContentXhtml' => 'content.xhtml',\n        ];\n        foreach (array_keys($this->parts) as $partName) {\n            $partClass = static::class . '\\\\Part\\\\' . $partName;\n            if (class_exists($partClass)) {\n                /** @var WriterPartInterface $part */\n                $part = new $partClass($partName === 'Content' || $partName === 'ContentXhtml' ? $phpWord : null);\n                $part->setParentWriter($this);\n                $this->writerParts[strtolower($partName)] = $part;\n            }\n        }\n\n        // Set package paths\n        $this->mediaPaths = ['image' => 'Images/', 'object' => 'Objects/'];\n    }\n\n    /**\n     * Save PhpWord to file.\n     */\n    public function save(string $filename): void\n    {\n        $filename = $this->getTempFile($filename);\n        $zip = $this->getZipArchive($filename);\n\n        // Add mimetype first without compression\n        $zip->addFromString('mimetype', 'application/epub+zip');\n        $zip->addEmptyDir('META-INF');\n\n        // Add other files\n        foreach ($this->parts as $partName => $fileName) {\n            if ($fileName === '') {\n                continue;\n            }\n            $part = $this->getWriterPart($partName);\n            if (!$part instanceof AbstractPart) {\n                continue;\n            }\n            $zip->addFromString($fileName, $part->write());\n        }\n\n        // Close zip archive\n        $zip->close();\n\n        // Cleanup temp file\n        $this->cleanupTempFile();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/HTML/Element/AbstractElement.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\HTML\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\AbstractElement as Element;\nuse PhpOffice\\PhpWord\\Writer\\HTML;\n\n/**\n * Abstract HTML element writer.\n *\n * @since 0.11.0\n */\nabstract class AbstractElement\n{\n    /**\n     * Parent writer.\n     *\n     * @var HTML\n     */\n    protected $parentWriter;\n\n    /**\n     * Element.\n     *\n     * @var Element\n     */\n    protected $element;\n\n    /**\n     * Without paragraph.\n     *\n     * @var bool\n     */\n    protected $withoutP = false;\n\n    /**\n     * Write element.\n     */\n    abstract public function write();\n\n    /**\n     * Create new instance.\n     *\n     * @param bool $withoutP\n     */\n    public function __construct(HTML $parentWriter, Element $element, $withoutP = false)\n    {\n        $this->parentWriter = $parentWriter;\n        $this->element = $element;\n        $this->withoutP = $withoutP;\n    }\n\n    /**\n     * Set without paragraph.\n     *\n     * @param bool $value\n     */\n    public function setWithoutP($value): void\n    {\n        $this->withoutP = $value;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/HTML/Element/Bookmark.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\HTML\\Element;\n\n/**\n * Bookmark element HTML writer.\n *\n * @since 0.15.0\n */\nclass Bookmark extends Text\n{\n    /**\n     * Write bookmark.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        if (!$this->element instanceof \\PhpOffice\\PhpWord\\Element\\Bookmark) {\n            return '';\n        }\n\n        $content = '';\n        $content .= $this->writeOpening();\n        $content .= \"<a name=\\\"{$this->element->getName()}\\\"/>\";\n        $content .= $this->writeClosing();\n\n        return $content;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/HTML/Element/Container.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\HTML\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\AbstractContainer as ContainerElement;\n\n/**\n * Container element HTML writer.\n *\n * @since 0.11.0\n */\nclass Container extends AbstractElement\n{\n    /**\n     * Namespace; Can't use __NAMESPACE__ in inherited class (RTF).\n     *\n     * @var string\n     */\n    protected $namespace = 'PhpOffice\\\\PhpWord\\\\Writer\\\\HTML\\\\Element';\n\n    /**\n     * Write container.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $container = $this->element;\n        if (!$container instanceof ContainerElement) {\n            return '';\n        }\n        $containerClass = substr(get_class($container), strrpos(get_class($container), '\\\\') + 1);\n        $withoutP = in_array($containerClass, ['TextRun', 'Footnote', 'Endnote']) ? true : false;\n        $content = '';\n\n        $elements = $container->getElements();\n        foreach ($elements as $element) {\n            $elementClass = get_class($element);\n            $writerClass = str_replace('PhpOffice\\\\PhpWord\\\\Element', $this->namespace, $elementClass);\n            if (class_exists($writerClass)) {\n                /** @var AbstractElement $writer Type hint */\n                $writer = new $writerClass($this->parentWriter, $element, $withoutP);\n                $content .= $writer->write();\n            }\n        }\n\n        return $content;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/HTML/Element/Endnote.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\HTML\\Element;\n\n/**\n * Endnote element HTML writer.\n *\n * @since 0.10.0\n */\nclass Endnote extends Footnote\n{\n    /**\n     * Note type.\n     *\n     * @var string\n     */\n    protected $noteType = 'endnote';\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/HTML/Element/Footnote.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\HTML\\Element;\n\n/**\n * Footnote element HTML writer.\n *\n * @since 0.10.0\n */\nclass Footnote extends AbstractElement\n{\n    /**\n     * Note type footnote|endnote.\n     *\n     * @var string\n     */\n    protected $noteType = 'footnote';\n\n    /**\n     * Write footnote/endnote marks; The actual content is written in parent writer (HTML).\n     *\n     * @return string\n     */\n    public function write()\n    {\n        if (!$this->element instanceof \\PhpOffice\\PhpWord\\Element\\Footnote) {\n            return '';\n        }\n        /** @var \\PhpOffice\\PhpWord\\Writer\\HTML $parentWriter Type hint */\n        $parentWriter = $this->parentWriter;\n\n        $noteId = count($parentWriter->getNotes()) + 1;\n        $noteMark = $this->noteType . '-' . $this->element->getRelationId();\n        $content = \"<a name=\\\"{$noteMark}\\\"><a href=\\\"#note-{$noteId}\\\" class=\\\"NoteRef\\\"><sup>{$noteId}</sup></a>\";\n\n        $parentWriter->addNote($noteId, $noteMark);\n\n        return $content;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/HTML/Element/Image.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\HTML\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\Image as ImageElement;\nuse PhpOffice\\PhpWord\\Writer\\HTML\\Style\\Image as ImageStyleWriter;\n\n/**\n * Image element HTML writer.\n *\n * @since 0.10.0\n */\nclass Image extends Text\n{\n    /**\n     * Write image.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        if (!$this->element instanceof ImageElement) {\n            return '';\n        }\n        $content = '';\n        $imageData = $this->element->getImageStringData(true);\n        if ($imageData !== null) {\n            $styleWriter = new ImageStyleWriter($this->element->getStyle());\n            $style = $styleWriter->write();\n            $imageData = 'data:' . $this->element->getImageType() . ';base64,' . $imageData;\n\n            $content .= $this->writeOpening();\n            $content .= \"<img border=\\\"0\\\" style=\\\"{$style}\\\" src=\\\"{$imageData}\\\"/>\";\n            $content .= $this->writeClosing();\n        }\n\n        return $content;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/HTML/Element/Link.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\HTML\\Element;\n\nuse PhpOffice\\PhpWord\\Writer\\HTML;\n\n/**\n * Link element HTML writer.\n *\n * @since 0.10.0\n */\nclass Link extends Text\n{\n    /**\n     * Write link.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        if (!$this->element instanceof \\PhpOffice\\PhpWord\\Element\\Link) {\n            return '';\n        }\n\n        $prefix = $this->element->isInternal() ? '#' : '';\n        $content = $this->writeOpening();\n        $content .= \"<a href=\\\"{$prefix}\"\n            . $this->parentWriter->escapeHTML($this->element->getSource())\n            . '\">'\n            . $this->parentWriter->escapeHTML($this->element->getText())\n            . '</a>';\n        $content .= $this->writeClosing();\n\n        return $content;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/HTML/Element/ListItem.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\HTML\\Element;\n\nuse PhpOffice\\PhpWord\\Writer\\HTML;\n\n/**\n * ListItem element HTML writer.\n *\n * @since 0.10.0\n */\nclass ListItem extends AbstractElement\n{\n    /**\n     * Write list item.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        if (!$this->element instanceof \\PhpOffice\\PhpWord\\Element\\ListItem) {\n            return '';\n        }\n\n        $content = '<p>' . $this->parentWriter->escapeHTML($this->element->getTextObject()->getText()) . '</p>' . PHP_EOL;\n\n        return $content;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/HTML/Element/ListItemRun.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\HTML\\Element;\n\n/**\n * ListItem element HTML writer.\n *\n * @since 0.10.0\n */\nclass ListItemRun extends TextRun\n{\n    /**\n     * Write list item.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        if (!$this->element instanceof \\PhpOffice\\PhpWord\\Element\\ListItemRun) {\n            return '';\n        }\n\n        $writer = new Container($this->parentWriter, $this->element);\n        $content = $writer->write() . PHP_EOL;\n\n        return $content;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/HTML/Element/PageBreak.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\HTML\\Element;\n\nuse PhpOffice\\PhpWord\\Writer\\PDF\\TCPDF;\n\n/**\n * PageBreak element HTML writer.\n *\n * @since 0.10.0\n */\nclass PageBreak extends TextBreak\n{\n    /**\n     * Write page break.\n     *\n     * @since 0.12.0\n     *\n     * @return string\n     */\n    public function write()\n    {\n        /** @var \\PhpOffice\\PhpWord\\Writer\\HTML $parentWriter Type hint */\n        $parentWriter = $this->parentWriter;\n        if ($parentWriter instanceof TCPDF) {\n            return '<br pagebreak=\"true\"/>';\n        }\n        if ($parentWriter->isPdf()) {\n            return '<pagebreak style=\"page-break-before: always;\" pagebreak=\"true\"></pagebreak>';\n        }\n\n        return '<div style=\"page-break-before: always; height: 0; margin: 0; padding: 0; overflow: hidden;\">&#160;</div>' . PHP_EOL;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/HTML/Element/Ruby.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\HTML\\Element;\n\nuse PhpOffice\\PhpWord\\ComplexType\\RubyProperties;\nuse PhpOffice\\PhpWord\\Element\\TextRun;\nuse PhpOffice\\PhpWord\\Style\\Paragraph;\nuse PhpOffice\\PhpWord\\Writer\\HTML\\Style\\Paragraph as ParagraphStyleWriter;\n\n/**\n * Ruby element HTML writer.\n */\nclass Ruby extends AbstractElement\n{\n    /**\n     * Write text.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        // $this->processFontStyle();\n\n        /** @var \\PhpOffice\\PhpWord\\Element\\Ruby $element Type hint */\n        $element = $this->element;\n\n        $baseText = $this->parentWriter->escapeHTML($element->getBaseTextRun()->getText());\n        $rubyText = $this->parentWriter->escapeHTML($element->getRubyTextRun()->getText());\n\n        $rubyTagPropertyCSS = $this->getPropertyCssForRubyTag($element->getProperties());\n        $lang = $element->getProperties()->getLanguageId();\n        $content = \"<ruby {$this->getParagraphStyleForTextRun($element->getBaseTextRun(), $rubyTagPropertyCSS)} lang=\\\"{$lang}\\\">\";\n        $content .= $baseText;\n        $content .= ' <rp>(</rp>';\n        $rtTagPropertyCSS = $this->getPropertyCssForRtTag($element->getProperties());\n        $content .= \"<rt {$this->getParagraphStyleForTextRun($element->getRubyTextRun(), $rtTagPropertyCSS)}>\";\n        $content .= $rubyText;\n        $content .= '</rt>';\n        $content .= '<rp>)</rp>';\n        $content .= '</ruby>';\n\n        return $content;\n    }\n\n    /**\n     * Get property CSS for the <ruby> tag.\n     */\n    private function getPropertyCssForRubyTag(RubyProperties $properties): string\n    {\n        // alignment CSS: https://developer.mozilla.org/en-US/docs/Web/CSS/ruby-align\n        $alignment = 'space-between';\n        switch ($properties->getAlignment()) {\n            case RubyProperties::ALIGNMENT_CENTER:\n                $alignment = 'center';\n\n                break;\n            case RubyProperties::ALIGNMENT_LEFT:\n                $alignment = 'start';\n\n                break;\n            default:\n                $alignment = 'space-between';\n\n                break;\n        }\n\n        return\n            'font-size:' . $properties->getFontSizeForBaseText() . 'pt' . ';' .\n            'ruby-align:' . $alignment . ';';\n    }\n\n    /**\n     * Get property CSS for the <rt> tag.\n     */\n    private function getPropertyCssForRtTag(RubyProperties $properties): string\n    {\n        // alignment CSS: https://developer.mozilla.org/en-US/docs/Web/CSS/ruby-align\n        return 'font-size:' . $properties->getFontFaceSize() . 'pt' . ';';\n    }\n\n    /**\n     * Write paragraph style for a given TextRun.\n     */\n    private function getParagraphStyleForTextRun(TextRun $textRun, string $extraCSS): string\n    {\n        $style = '';\n        $paragraphStyle = $textRun->getParagraphStyle();\n        $pStyleIsObject = ($paragraphStyle instanceof Paragraph);\n        if ($pStyleIsObject) {\n            $styleWriter = new ParagraphStyleWriter($paragraphStyle);\n            $styleWriter->setParentWriter($this->parentWriter);\n            $style = $styleWriter->write();\n        } elseif (is_string($paragraphStyle)) {\n            $style = $paragraphStyle;\n        }\n        if ($style !== null && $style !== '') {\n            if ($pStyleIsObject) {\n                // CSS pairs (style=\"...\")\n                $style = \" style=\\\"{$style}{$extraCSS}\\\"\";\n            } else {\n                // class name; need to append extra styles manually\n                $style = \" class=\\\"{$style}\\\" style=\\\"{$extraCSS}\\\"\";\n            }\n        } elseif ($extraCSS !== '') {\n            $style = \" style=\\\"{$extraCSS}\\\"\";\n        }\n\n        return $style;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/HTML/Element/Table.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\HTML\\Element;\n\nuse PhpOffice\\PhpWord\\Writer\\HTML\\Style\\Table as TableStyleWriter;\n\n/**\n * Table element HTML writer.\n *\n * @since 0.10.0\n */\nclass Table extends AbstractElement\n{\n    /**\n     * Write table.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        if (!$this->element instanceof \\PhpOffice\\PhpWord\\Element\\Table) {\n            return '';\n        }\n\n        $content = '';\n        $rows = $this->element->getRows();\n        $rowCount = count($rows);\n        if ($rowCount > 0) {\n            $content .= '<table' . $this->getTableStyle($this->element->getStyle()) . '>' . PHP_EOL;\n\n            for ($i = 0; $i < $rowCount; ++$i) {\n                /** @var \\PhpOffice\\PhpWord\\Element\\Row $row Type hint */\n                $rowStyle = $rows[$i]->getStyle();\n                // $height = $row->getHeight();\n                $tblHeader = $rowStyle->isTblHeader();\n                $content .= '<tr>' . PHP_EOL;\n                $rowCells = $rows[$i]->getCells();\n                $rowCellCount = count($rowCells);\n                for ($j = 0; $j < $rowCellCount; ++$j) {\n                    $cellStyle = $rowCells[$j]->getStyle();\n                    $cellStyleCss = $this->getTableStyle($cellStyle);\n                    $cellBgColor = $cellStyle->getBgColor();\n                    $cellFgColor = null;\n                    if ($cellBgColor && $cellBgColor !== 'auto') {\n                        $red = hexdec(substr($cellBgColor, 0, 2));\n                        $green = hexdec(substr($cellBgColor, 2, 2));\n                        $blue = hexdec(substr($cellBgColor, 4, 2));\n                        $cellFgColor = (($red * 0.299 + $green * 0.587 + $blue * 0.114) > 186) ? null : 'ffffff';\n                    }\n                    $cellColSpan = $cellStyle->getGridSpan();\n                    $cellRowSpan = 1;\n                    $cellVMerge = $cellStyle->getVMerge();\n                    // If this is the first cell of the vertical merge, find out how many rows it spans\n                    if ($cellVMerge === 'restart') {\n                        $cellRowSpan = $this->calculateCellRowSpan($rows, $i, $j);\n                    }\n                    // Ignore cells that are merged vertically with previous rows\n                    if ($cellVMerge !== 'continue') {\n                        $cellTag = $tblHeader ? 'th' : 'td';\n                        $cellColSpanAttr = (is_numeric($cellColSpan) && ($cellColSpan > 1) ? \" colspan=\\\"{$cellColSpan}\\\"\" : '');\n                        $cellRowSpanAttr = ($cellRowSpan > 1 ? \" rowspan=\\\"{$cellRowSpan}\\\"\" : '');\n                        $cellBgColorAttr = (empty($cellBgColor) ? '' : \" bgcolor=\\\"#{$cellBgColor}\\\"\");\n                        $cellFgColorAttr = (empty($cellFgColor) ? '' : \" color=\\\"#{$cellFgColor}\\\"\");\n                        $content .= \"<{$cellTag}{$cellStyleCss}{$cellColSpanAttr}{$cellRowSpanAttr}{$cellBgColorAttr}{$cellFgColorAttr}>\" . PHP_EOL;\n                        $writer = new Container($this->parentWriter, $rowCells[$j]);\n                        $content .= $writer->write();\n                        if ($cellRowSpan > 1) {\n                            // There shouldn't be any content in the subsequent merged cells, but lets check anyway\n                            for ($k = $i + 1; $k < $rowCount; ++$k) {\n                                $kRowCells = $rows[$k]->getCells();\n                                if (isset($kRowCells[$j]) && $kRowCells[$j]->getStyle()->getVMerge() === 'continue') {\n                                    $writer = new Container($this->parentWriter, $kRowCells[$j]);\n                                    $content .= $writer->write();\n                                } else {\n                                    break;\n                                }\n                            }\n                        }\n                        $content .= \"</{$cellTag}>\" . PHP_EOL;\n                    }\n                }\n                $content .= '</tr>' . PHP_EOL;\n            }\n            $content .= '</table>' . PHP_EOL;\n        }\n\n        return $content;\n    }\n\n    /**\n     * Translates Table style in CSS equivalent.\n     *\n     * @param null|\\PhpOffice\\PhpWord\\Style\\Cell|\\PhpOffice\\PhpWord\\Style\\Table|string $tableStyle\n     */\n    private function getTableStyle($tableStyle = null): string\n    {\n        if ($tableStyle == null) {\n            return '';\n        }\n        if (is_string($tableStyle)) {\n            return ' class=\"' . $tableStyle . '\"';\n        }\n\n        $styleWriter = new TableStyleWriter($tableStyle);\n        $style = $styleWriter->write();\n        if ($style === '') {\n            return '';\n        }\n\n        return ' style=\"' . $style . '\"';\n    }\n\n    /**\n     * Calculates cell rowspan.\n     *\n     * @param \\PhpOffice\\PhpWord\\Element\\Row[] $rows\n     */\n    private function calculateCellRowSpan(array $rows, int $rowIndex, int $colIndex): int\n    {\n        $currentRow = $rows[$rowIndex];\n        $currentRowCells = $currentRow->getCells();\n        $shiftedColIndex = 0;\n\n        foreach ($currentRowCells as $cell) {\n            if ($cell === $currentRowCells[$colIndex]) {\n                break;\n            }\n\n            $colSpan = 1;\n\n            if ($cell->getStyle()->getGridSpan() !== null) {\n                $colSpan = $cell->getStyle()->getGridSpan();\n            }\n\n            $shiftedColIndex += $colSpan;\n        }\n\n        $rowCount = count($rows);\n        $rowSpan = 1;\n\n        for ($i = $rowIndex + 1; $i < $rowCount; ++$i) {\n            $rowCells = $rows[$i]->getCells();\n            $colIndex = 0;\n\n            foreach ($rowCells as $cell) {\n                if ($colIndex === $shiftedColIndex) {\n                    if ($cell->getStyle()->getVMerge() === 'continue') {\n                        ++$rowSpan;\n                    }\n\n                    break;\n                }\n\n                $colSpan = 1;\n\n                if ($cell->getStyle()->getGridSpan() !== null) {\n                    $colSpan = $cell->getStyle()->getGridSpan();\n                }\n\n                $colIndex += $colSpan;\n            }\n        }\n\n        return $rowSpan;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/HTML/Element/Text.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\HTML\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\TrackChange;\nuse PhpOffice\\PhpWord\\Style;\nuse PhpOffice\\PhpWord\\Style\\Font;\nuse PhpOffice\\PhpWord\\Style\\Paragraph;\nuse PhpOffice\\PhpWord\\Writer\\HTML;\nuse PhpOffice\\PhpWord\\Writer\\HTML\\Style\\Font as FontStyleWriter;\nuse PhpOffice\\PhpWord\\Writer\\HTML\\Style\\Paragraph as ParagraphStyleWriter;\n\n/**\n * Text element HTML writer.\n *\n * @since 0.10.0\n */\nclass Text extends AbstractElement\n{\n    /**\n     * Text written after opening.\n     *\n     * @var string\n     */\n    private $openingText = '';\n\n    /**\n     * Text written before closing.\n     *\n     * @var string\n     */\n    private $closingText = '';\n\n    /**\n     * Opening tags.\n     *\n     * @var string\n     */\n    private $openingTags = '';\n\n    /**\n     * Closing tag.\n     *\n     * @var string\n     */\n    private $closingTags = '';\n\n    /**\n     * Write text.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $this->processFontStyle();\n\n        /** @var \\PhpOffice\\PhpWord\\Element\\Text $element Type hint */\n        $element = $this->element;\n\n        $text = $this->parentWriter->escapeHTML($element->getText() ?? '');\n        if (!$this->withoutP && !trim($text)) {\n            $text = '&nbsp;';\n        }\n\n        $content = '';\n        $content .= $this->writeOpening();\n        $content .= $this->openingText;\n        $content .= $this->openingTags;\n        $content .= $text;\n        $content .= $this->closingTags;\n        $content .= $this->closingText;\n        $content .= $this->writeClosing();\n\n        return $content;\n    }\n\n    /**\n     * Set opening text.\n     *\n     * @param string $value\n     */\n    public function setOpeningText($value): void\n    {\n        $this->openingText = $value;\n    }\n\n    /**\n     * Set closing text.\n     *\n     * @param string $value\n     */\n    public function setClosingText($value): void\n    {\n        $this->closingText = $value;\n    }\n\n    /**\n     * Write opening.\n     *\n     * @return string\n     */\n    protected function writeOpening()\n    {\n        $content = '';\n        if (!$this->withoutP) {\n            $style = $this->getParagraphStyle();\n            $content .= \"<p{$style}>\";\n        }\n\n        //open track change tag\n        $content .= $this->writeTrackChangeOpening();\n\n        return $content;\n    }\n\n    /**\n     * Write ending.\n     *\n     * @return string\n     */\n    protected function writeClosing()\n    {\n        $content = '';\n\n        //close track change tag\n        $content .= $this->writeTrackChangeClosing();\n\n        if (!$this->withoutP) {\n            $content .= $this->parentWriter->escapeHTML($this->closingText);\n            $content .= '</p>' . PHP_EOL;\n        }\n\n        return $content;\n    }\n\n    /**\n     * writes the track change opening tag.\n     *\n     * @return string the HTML, an empty string if no track change information\n     */\n    private function writeTrackChangeOpening()\n    {\n        $changed = $this->element->getTrackChange();\n        if ($changed == null) {\n            return '';\n        }\n\n        $content = '';\n        if (($changed->getChangeType() == TrackChange::INSERTED)) {\n            $content .= '<ins data-phpword-prop=\\'';\n        } elseif ($changed->getChangeType() == TrackChange::DELETED) {\n            $content .= '<del data-phpword-prop=\\'';\n        }\n\n        $changedProp = ['changed' => ['author' => $changed->getAuthor(), 'id' => $this->element->getElementId()]];\n        if ($changed->getDate() != null) {\n            $changedProp['changed']['date'] = $changed->getDate()->format('Y-m-d\\TH:i:s\\Z');\n        }\n        $content .= json_encode($changedProp);\n        $content .= '\\' ';\n        $content .= 'title=\"' . $changed->getAuthor();\n        if ($changed->getDate() != null) {\n            $dateUser = $changed->getDate()->format('Y-m-d H:i:s');\n            $content .= ' - ' . $dateUser;\n        }\n        $content .= '\">';\n\n        return $content;\n    }\n\n    /**\n     * writes the track change closing tag.\n     *\n     * @return string the HTML, an empty string if no track change information\n     */\n    private function writeTrackChangeClosing()\n    {\n        $changed = $this->element->getTrackChange();\n        if ($changed == null) {\n            return '';\n        }\n\n        $content = '';\n        if (($changed->getChangeType() == TrackChange::INSERTED)) {\n            $content .= '</ins>';\n        } elseif ($changed->getChangeType() == TrackChange::DELETED) {\n            $content .= '</del>';\n        }\n\n        return $content;\n    }\n\n    /**\n     * Write paragraph style.\n     *\n     * @return string\n     */\n    private function getParagraphStyle()\n    {\n        /** @var \\PhpOffice\\PhpWord\\Element\\Text $element Type hint */\n        $element = $this->element;\n        $style = '';\n        if (!method_exists($element, 'getParagraphStyle')) {\n            return $style;\n        }\n\n        $paragraphStyle = $element->getParagraphStyle();\n        $pStyleIsObject = ($paragraphStyle instanceof Paragraph);\n        if ($pStyleIsObject) {\n            $styleWriter = new ParagraphStyleWriter($paragraphStyle);\n            $styleWriter->setParentWriter($this->parentWriter);\n            $style = $styleWriter->write();\n        } elseif (is_string($paragraphStyle)) {\n            $style = $paragraphStyle;\n        }\n        if ($style) {\n            $attribute = $pStyleIsObject ? 'style' : 'class';\n            $style = \" {$attribute}=\\\"{$style}\\\"\";\n        }\n\n        return $style;\n    }\n\n    /**\n     * Get font style.\n     */\n    private function processFontStyle(): void\n    {\n        /** @var \\PhpOffice\\PhpWord\\Element\\Text $element Type hint */\n        $element = $this->element;\n\n        $attributeStyle = $attributeLang = '';\n        $lang = null;\n\n        $fontStyle = $element->getFontStyle();\n        if ($fontStyle instanceof Font) {\n            // Attribute style\n            $styleWriter = new FontStyleWriter($fontStyle);\n            $fontCSS = $styleWriter->write();\n            if ($fontCSS) {\n                $attributeStyle = ' style=\"' . $fontCSS . '\"';\n            }\n            // Attribute Lang\n            $lang = $fontStyle->getLang();\n        } elseif (!empty($fontStyle)) {\n            // Attribute class\n            $attributeStyle = ' class=\"' . $fontStyle . '\"';\n            // Attribute Lang\n            /** @var Font $cssClassStyle */\n            $cssClassStyle = Style::getStyle($fontStyle);\n            if ($cssClassStyle !== null && method_exists($cssClassStyle, 'getLang')) {\n                $lang = $cssClassStyle->getLang();\n            }\n        }\n\n        if ($lang) {\n            $attributeLang = $lang->getLatin();\n            if (!$attributeLang) {\n                $attributeLang = $lang->getEastAsia();\n            }\n            if (!$attributeLang) {\n                $attributeLang = $lang->getBidirectional();\n            }\n            if ($attributeLang) {\n                $attributeLang = \" lang='$attributeLang'\";\n            }\n        }\n\n        if ($attributeStyle || $attributeLang) {\n            $this->openingTags = \"<span$attributeLang$attributeStyle>\";\n            $this->closingTags = '</span>';\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/HTML/Element/TextBreak.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\HTML\\Element;\n\n/**\n * TextBreak element HTML writer.\n *\n * @since 0.10.0\n */\nclass TextBreak extends AbstractElement\n{\n    /**\n     * Write text break.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        if ($this->withoutP) {\n            $content = '<br />' . PHP_EOL;\n        } else {\n            $content = '<p>&nbsp;</p>' . PHP_EOL;\n        }\n\n        return $content;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/HTML/Element/TextRun.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\HTML\\Element;\n\n/**\n * TextRun element HTML writer.\n *\n * @since 0.10.0\n */\nclass TextRun extends Text\n{\n    /**\n     * Write text run.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $content = '';\n\n        $content .= $this->writeOpening();\n        $writer = new Container($this->parentWriter, $this->element);\n        $content .= $writer->write();\n        $content .= $this->writeClosing();\n\n        return $content;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/HTML/Element/Title.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\HTML\\Element;\n\nuse PhpOffice\\PhpWord\\Writer\\HTML;\n\n/**\n * TextRun element HTML writer.\n *\n * @since 0.10.0\n */\nclass Title extends AbstractElement\n{\n    /**\n     * Write heading.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        if (!$this->element instanceof \\PhpOffice\\PhpWord\\Element\\Title) {\n            return '';\n        }\n\n        $tag = 'h' . $this->element->getDepth();\n\n        $text = $this->element->getText();\n        if (is_string($text)) {\n            $text = $this->parentWriter->escapeHTML($text);\n        } else {\n            $writer = new Container($this->parentWriter, $text);\n            $text = $writer->write();\n        }\n\n        $content = \"<{$tag}>{$text}</{$tag}>\" . PHP_EOL;\n\n        return $content;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/HTML/Part/AbstractPart.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\HTML\\Part;\n\nuse PhpOffice\\PhpWord\\Exception\\Exception;\nuse PhpOffice\\PhpWord\\Writer\\HTML;\n\n/**\n * @since 0.11.0\n */\nabstract class AbstractPart\n{\n    /**\n     * @var ?HTML\n     */\n    private $parentWriter;\n\n    /**\n     * @return string\n     */\n    abstract public function write();\n\n    public function setParentWriter(?HTML $writer = null): void\n    {\n        $this->parentWriter = $writer;\n    }\n\n    /**\n     * @return HTML\n     */\n    public function getParentWriter()\n    {\n        if ($this->parentWriter !== null) {\n            return $this->parentWriter;\n        }\n\n        throw new Exception('No parent WriterInterface assigned.');\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/HTML/Part/Body.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\HTML\\Part;\n\nuse PhpOffice\\PhpWord\\Writer\\HTML\\Element\\Container;\nuse PhpOffice\\PhpWord\\Writer\\HTML\\Element\\TextRun as TextRunWriter;\nuse PhpOffice\\PhpWord\\Writer\\PDF\\TCPDF;\n\n/**\n * HTML body part writer.\n *\n * @since 0.11.0\n */\nclass Body extends AbstractPart\n{\n    /**\n     * Write part.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $phpWord = $this->getParentWriter()->getPhpWord();\n\n        $content = '';\n\n        $content .= '<body>' . PHP_EOL;\n        $sections = $phpWord->getSections();\n        $secno = 0;\n        $isTCPDFWriter = $this->getParentWriter() instanceof TCPDF;\n        foreach ($sections as $section) {\n            ++$secno;\n            if ($isTCPDFWriter && $secno > 1) {\n                $content .= \"<div style=\\\"page: page$secno; page-break-before:always;\\\">\" . PHP_EOL;\n            } else {\n                $content .= \"<div style='page: page$secno'>\" . PHP_EOL;\n            }\n            $writer = new Container($this->getParentWriter(), $section);\n            $content .= $writer->write();\n            $content .= '</div>' . PHP_EOL;\n        }\n\n        $content .= $this->writeNotes();\n        $content .= '</body>' . PHP_EOL;\n\n        return $content;\n    }\n\n    /**\n     * Write footnote/endnote contents as textruns.\n     *\n     * @return string\n     */\n    private function writeNotes()\n    {\n        /** @var \\PhpOffice\\PhpWord\\Writer\\HTML $parentWriter Type hint */\n        $parentWriter = $this->getParentWriter();\n        $phpWord = $parentWriter->getPhpWord();\n        $notes = $parentWriter->getNotes();\n\n        $content = '';\n\n        if (!empty($notes)) {\n            $content .= '<hr />' . PHP_EOL;\n            foreach ($notes as $noteId => $noteMark) {\n                [$noteType, $noteTypeId] = explode('-', $noteMark);\n                $method = 'get' . ($noteType == 'endnote' ? 'Endnotes' : 'Footnotes');\n                $collection = $phpWord->$method()->getItems();\n\n                if (isset($collection[$noteTypeId])) {\n                    $element = $collection[$noteTypeId];\n                    $noteAnchor = \"<a name=\\\"note-{$noteId}\\\" />\";\n                    $noteAnchor .= \"<a href=\\\"#{$noteMark}\\\" class=\\\"NoteRef\\\"><sup>{$noteId}</sup></a>\";\n\n                    $writer = new TextRunWriter($this->getParentWriter(), $element);\n                    $writer->setOpeningText($noteAnchor);\n                    $content .= $writer->write();\n                }\n            }\n        }\n\n        return $content;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/HTML/Part/Head.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\HTML\\Part;\n\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Shared\\Converter;\nuse PhpOffice\\PhpWord\\Style;\nuse PhpOffice\\PhpWord\\Style\\Font;\nuse PhpOffice\\PhpWord\\Style\\Paragraph;\nuse PhpOffice\\PhpWord\\Style\\Table;\nuse PhpOffice\\PhpWord\\Writer\\HTML\\Style\\Font as FontStyleWriter;\nuse PhpOffice\\PhpWord\\Writer\\HTML\\Style\\Generic as GenericStyleWriter;\nuse PhpOffice\\PhpWord\\Writer\\HTML\\Style\\Paragraph as ParagraphStyleWriter;\nuse PhpOffice\\PhpWord\\Writer\\HTML\\Style\\Table as TableStyleWriter;\n\n/**\n * HTML head part writer.\n *\n * @since 0.11.0\n */\nclass Head extends AbstractPart\n{\n    /**\n     * Write part.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $docProps = $this->getParentWriter()->getPhpWord()->getDocInfo();\n        $propertiesMapping = [\n            'creator' => 'author',\n            'title' => '',\n            'description' => '',\n            'subject' => '',\n            'keywords' => '',\n            'category' => '',\n            'company' => '',\n            'manager' => '',\n        ];\n        $title = $docProps->getTitle();\n        $title = ($title != '') ? $title : 'PHPWord';\n\n        $content = '';\n\n        $content .= '<head>' . PHP_EOL;\n        $content .= '<meta charset=\"UTF-8\" />' . PHP_EOL;\n        $content .= '<title>' . $title . '</title>' . PHP_EOL;\n        foreach ($propertiesMapping as $key => $value) {\n            $value = ($value == '') ? $key : $value;\n            $method = 'get' . $key;\n            if ($docProps->$method() != '') {\n                $content .= '<meta name=\"' . $value . '\"'\n                    . ' content=\"'\n                    . $this->getParentWriter()->escapeHTML($docProps->$method())\n                    . '\"'\n                    . ' />' . PHP_EOL;\n            }\n        }\n        $content .= $this->writeStyles();\n        $content .= '</head>' . PHP_EOL;\n\n        return $content;\n    }\n\n    /**\n     * Get styles.\n     */\n    private function writeStyles(): string\n    {\n        $css = '<style>' . PHP_EOL;\n        $defaultFontColor = Settings::getDefaultFontColor();\n        // Default styles\n        $astarray = [\n            'font-family' => $this->getFontFamily(Settings::getDefaultFontName(), $this->getParentWriter()->getDefaultGenericFont()),\n            'font-size' => Settings::getDefaultFontSize() . 'pt',\n            'color' => \"#{$defaultFontColor}\",\n        ];\n        // Mpdf sometimes needs separate tag for body; doesn't harm others.\n        $bodyarray = $astarray;\n\n        $defaultWhiteSpace = $this->getParentWriter()->getDefaultWhiteSpace();\n        if ($defaultWhiteSpace) {\n            $astarray['white-space'] = $defaultWhiteSpace;\n        }\n\n        foreach ([\n            'body' => $bodyarray,\n            '*' => $astarray,\n            'a.NoteRef' => [\n                'text-decoration' => 'none',\n            ],\n            'hr' => [\n                'height' => '1px',\n                'padding' => '0',\n                'margin' => '1em 0',\n                'border' => '0',\n                'border-top' => '1px solid #CCC',\n            ],\n            'table' => [\n                'border' => '1px solid black',\n                'border-spacing' => '0px',\n                'width ' => '100%',\n            ],\n            'td' => [\n                'border' => '1px solid black',\n            ],\n        ] as $selector => $style) {\n            $styleWriter = new GenericStyleWriter($style);\n            $css .= $selector . ' {' . $styleWriter->write() . '}' . PHP_EOL;\n        }\n\n        // Custom styles\n        $customStyles = Style::getStyles();\n        if (is_array($customStyles)) {\n            foreach ($customStyles as $name => $style) {\n                $styleParagraph = null;\n                if ($style instanceof Font) {\n                    $styleWriter = new FontStyleWriter($style);\n                    if ($style->getStyleType() == 'title') {\n                        $name = str_replace('Heading_', 'h', $name);\n                        $styleParagraph = $style->getParagraph();\n                        $style = $styleParagraph;\n                    } else {\n                        $name = '.' . $name;\n                    }\n                    $css .= \"{$name} {\" . $styleWriter->write() . '}' . PHP_EOL;\n                }\n                if ($style instanceof Paragraph) {\n                    $styleWriter = new ParagraphStyleWriter($style);\n                    $styleWriter->setParentWriter($this->getParentWriter());\n                    if (!$styleParagraph) {\n                        $name = '.' . $name;\n                    }\n                    if ($name === '.Normal') {\n                        $name = \"p, $name\";\n                    }\n                    $css .= \"{$name} {\" . $styleWriter->write() . '}' . PHP_EOL;\n                }\n                if ($style instanceof Table) {\n                    $styleWriter = new TableStyleWriter($style);\n                    $css .= \".{$name} {\" . $styleWriter->write() . '}' . PHP_EOL;\n                }\n            }\n        }\n\n        $css .= 'body > div + div {page-break-before: always;}' . PHP_EOL;\n        $css .= 'div > *:first-child {page-break-before: auto;}' . PHP_EOL;\n\n        $sectionNum = 0;\n        foreach ($this->getParentWriter()->getPhpWord()->getSections() as $section) {\n            ++$sectionNum;\n\n            $css .= \"@page page$sectionNum {\";\n\n            $paperSize = $section->getStyle()->getPaperSize();\n            $orientation = $section->getStyle()->getOrientation();\n            if ($this->getParentWriter()->isPdf()) {\n                if ($orientation === 'landscape') {\n                    $paperSize .= '-L';\n                }\n                $css .= \"sheet-size: $paperSize; \";\n            } else {\n                $css .= \"size: $paperSize $orientation; \";\n            }\n\n            $css .= 'margin-right: ' . (string) ($section->getStyle()->getMarginRight() / Converter::INCH_TO_TWIP) . 'in; ';\n            $css .= 'margin-left: ' . (string) ($section->getStyle()->getMarginLeft() / Converter::INCH_TO_TWIP) . 'in; ';\n            $css .= 'margin-top: ' . (string) ($section->getStyle()->getMarginTop() / Converter::INCH_TO_TWIP) . 'in; ';\n            $css .= 'margin-bottom: ' . (string) ($section->getStyle()->getMarginBottom() / Converter::INCH_TO_TWIP) . 'in; ';\n            $css .= '}' . PHP_EOL;\n        }\n\n        $css .= '</style>' . PHP_EOL;\n\n        return $css;\n    }\n\n    /**\n     * Set font and alternates for css font-family.\n     */\n    private function getFontFamily(string $font, string $genericFont): string\n    {\n        if (empty($font)) {\n            return '';\n        }\n        $fontfamily = \"'\" . htmlspecialchars($font, ENT_QUOTES, 'UTF-8') . \"'\";\n        if (!empty($genericFont)) {\n            $fontfamily .= \", $genericFont\";\n        }\n\n        return $fontfamily;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/HTML/Style/AbstractStyle.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\HTML\\Style;\n\nuse PhpOffice\\PhpWord\\Style\\AbstractStyle as StyleAbstract;\nuse PhpOffice\\PhpWord\\Writer\\HTML;\n\n/**\n * Style writer.\n *\n * @since 0.10.0\n */\nabstract class AbstractStyle\n{\n    /**\n     * Parent writer.\n     *\n     * @var HTML\n     */\n    private $parentWriter;\n\n    /**\n     * Style.\n     *\n     * @var null|array|StyleAbstract\n     */\n    private $style;\n\n    /**\n     * Write style.\n     *\n     * @return mixed\n     */\n    abstract public function write();\n\n    /**\n     * Create new instance.\n     *\n     * @param array|StyleAbstract $style\n     */\n    public function __construct($style = null)\n    {\n        $this->style = $style;\n    }\n\n    /**\n     * Set parent writer.\n     *\n     * @param HTML $writer\n     */\n    public function setParentWriter($writer): void\n    {\n        $this->parentWriter = $writer;\n    }\n\n    /**\n     * Get parent writer.\n     *\n     * @return HTML\n     */\n    public function getParentWriter()\n    {\n        return $this->parentWriter;\n    }\n\n    /**\n     * Get style.\n     *\n     * @return null|array|string|StyleAbstract\n     */\n    public function getStyle()\n    {\n        if (!$this->style instanceof StyleAbstract && !is_array($this->style)) {\n            return '';\n        }\n\n        return $this->style;\n    }\n\n    /**\n     * Takes array where of CSS properties / values and converts to CSS string.\n     *\n     * @param array $css\n     *\n     * @return string\n     */\n    protected function assembleCss($css)\n    {\n        $pairs = [];\n        $string = '';\n        foreach ($css as $key => $value) {\n            if ($value != '') {\n                $pairs[] = $key . ': ' . $value;\n            }\n        }\n        if (!empty($pairs)) {\n            $string = implode('; ', $pairs) . ';';\n        }\n\n        return $string;\n    }\n\n    /**\n     * Get value if ...\n     *\n     * @param null|bool $condition\n     * @param string $value\n     *\n     * @return string\n     */\n    protected function getValueIf($condition, $value)\n    {\n        return $condition == true ? $value : '';\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/HTML/Style/Font.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\HTML\\Style;\n\nuse PhpOffice\\PhpWord\\Style\\Font as FontStyle;\n\n/**\n * Font style HTML writer.\n *\n * @since 0.10.0\n */\nclass Font extends AbstractStyle\n{\n    /**\n     * Write style.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof FontStyle) {\n            return '';\n        }\n        $css = [];\n\n        $font = $this->getFontFamily($style->getName(), $style->getFallbackFont());\n        $size = $style->getSize();\n        $color = $style->getColor();\n        $fgColor = $style->getFgColor();\n        $underline = $style->getUnderline() != FontStyle::UNDERLINE_NONE;\n        $lineThrough = $style->isStrikethrough() || $style->isDoubleStrikethrough();\n\n        $css['font-family'] = $this->getValueIf(!empty($font), $font);\n        $css['font-size'] = $this->getValueIf($size !== null, \"{$size}pt\");\n        $css['color'] = $this->getValueIf($color !== null, \"#{$color}\");\n        $css['background'] = $this->getValueIf($fgColor != '', $fgColor);\n        $css['font-weight'] = $this->getValueIf($style->isBold(), 'bold');\n        $css['font-style'] = $this->getValueIf($style->isItalic(), 'italic');\n        $css['vertical-align'] = '';\n        $css['vertical-align'] .= $this->getValueIf($style->isSuperScript(), 'super');\n        $css['vertical-align'] .= $this->getValueIf($style->isSubScript(), 'sub');\n        $css['text-decoration'] = '';\n        $css['text-decoration'] .= $this->getValueIf($underline, 'underline ');\n        $css['text-decoration'] .= $this->getValueIf($lineThrough, 'line-through ');\n        $css['text-transform'] = $this->getValueIf($style->isAllCaps(), 'uppercase');\n        $css['font-variant'] = $this->getValueIf($style->isSmallCaps(), 'small-caps');\n        $css['display'] = $this->getValueIf($style->isHidden(), 'none');\n        $whitespace = $style->getWhiteSpace();\n        if ($whitespace) {\n            $css['white-space'] = $whitespace;\n        }\n\n        $spacing = $style->getSpacing();\n        $css['letter-spacing'] = $this->getValueIf(null !== $spacing, ($spacing / 20) . 'pt');\n        if ($style->isRTL()) {\n            $css['direction'] = 'rtl';\n        } elseif ($style->isRTL() === false) {\n            $css['direction'] = 'ltr';\n        }\n\n        return $this->assembleCss($css);\n    }\n\n    /**\n     * Set font and alternates for css font-family.\n     */\n    private function getFontFamily(?string $font, string $genericFont): string\n    {\n        if (empty($font)) {\n            return '';\n        }\n        $fontfamily = \"'\" . htmlspecialchars($font, ENT_QUOTES, 'UTF-8') . \"'\";\n        if (!empty($genericFont)) {\n            $fontfamily .= \", $genericFont\";\n        }\n\n        return $fontfamily;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/HTML/Style/Generic.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\HTML\\Style;\n\n/**\n * Generic style writer.\n *\n * @since 0.10.0\n */\nclass Generic extends AbstractStyle\n{\n    /**\n     * Write style.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $style = $this->getStyle();\n        $css = [];\n\n        if (is_array($style) && !empty($style)) {\n            $css = $style;\n        }\n\n        return $this->assembleCss($css);\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/HTML/Style/Image.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\HTML\\Style;\n\n/**\n * Paragraph style HTML writer.\n *\n * @since 0.10.0\n */\nclass Image extends AbstractStyle\n{\n    /**\n     * Write style.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof \\PhpOffice\\PhpWord\\Style\\Image) {\n            return '';\n        }\n        $css = [];\n\n        $width = $style->getWidth();\n        $height = $style->getHeight();\n        $css['width'] = $this->getValueIf(is_numeric($width), $width . 'px');\n        $css['height'] = $this->getValueIf(is_numeric($height), $height . 'px');\n\n        return $this->assembleCss($css);\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/HTML/Style/Paragraph.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\HTML\\Style;\n\nuse PhpOffice\\PhpWord\\Shared\\Converter;\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\nuse PhpOffice\\PhpWord\\Writer\\PDF\\TCPDF;\n\n/**\n * Paragraph style HTML writer.\n *\n * @since 0.10.0\n */\nclass Paragraph extends AbstractStyle\n{\n    /**\n     * Write style.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof \\PhpOffice\\PhpWord\\Style\\Paragraph) {\n            return '';\n        }\n        $css = [];\n\n        // Alignment\n        if ('' !== $style->getAlignment()) {\n            $textAlign = '';\n\n            switch ($style->getAlignment()) {\n                case Jc::CENTER:\n                    $textAlign = 'center';\n\n                    break;\n                case Jc::END:\n                    $textAlign = $style->isBidi() ? 'left' : 'right';\n\n                    break;\n                case Jc::MEDIUM_KASHIDA:\n                case Jc::HIGH_KASHIDA:\n                case Jc::LOW_KASHIDA:\n                case Jc::RIGHT:\n                    $textAlign = 'right';\n\n                    break;\n                case Jc::BOTH:\n                case Jc::DISTRIBUTE:\n                case Jc::THAI_DISTRIBUTE:\n                case Jc::JUSTIFY:\n                    $textAlign = 'justify';\n\n                    break;\n                case Jc::LEFT:\n                    $textAlign = 'left';\n\n                    break;\n                default: //all others, including Jc::START\n                    $textAlign = $style->isBidi() ? 'right' : 'left';\n\n                    break;\n            }\n\n            $css['text-align'] = $textAlign;\n        }\n\n        // Spacing\n        $spacing = $style->getSpace();\n        if (null !== $spacing) {\n            $before = $spacing->getBefore();\n            $after = $spacing->getAfter();\n            $css['margin-top'] = $this->getValueIf(null !== $before, ($before / 20) . 'pt');\n            $css['margin-bottom'] = $this->getValueIf(null !== $after, ($after / 20) . 'pt');\n        }\n\n        // Line Height\n        $lineHeight = $style->getLineHeight();\n        if (!empty($lineHeight)) {\n            $css['line-height'] = $lineHeight;\n        }\n\n        // Indentation (Margin)\n        $indentation = $style->getIndentation();\n        if ($indentation) {\n            $inches = $indentation->getLeft() * 1.0 / Converter::INCH_TO_TWIP;\n            $css[$this->getParentWriter() instanceof TCPDF ? 'text-indent' : 'margin-left'] = ((string) $inches) . 'in';\n\n            $inches = $indentation->getRight() * 1.0 / Converter::INCH_TO_TWIP;\n            $css['margin-right'] = ((string) $inches) . 'in';\n        }\n\n        // Page Break Before\n        if ($style->hasPageBreakBefore()) {\n            $css['page-break-before'] = 'always';\n        }\n\n        // Bidirectional\n        if ($style->isBidi()) {\n            $css['direction'] = 'rtl';\n        }\n\n        return $this->assembleCss($css);\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/HTML/Style/Table.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\ndeclare(strict_types=1);\n\nnamespace PhpOffice\\PhpWord\\Writer\\HTML\\Style;\n\nuse PhpOffice\\PhpWord\\Style\\Cell as StyleCell;\nuse PhpOffice\\PhpWord\\Style\\Table as StyleTable;\n\nclass Table extends AbstractStyle\n{\n    /**\n     * @return string\n     */\n    public function write()\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof StyleTable && !$style instanceof StyleCell) {\n            return '';\n        }\n\n        $css = [];\n        if (method_exists($style, 'getLayout')) {\n            if ($style->getLayout() == StyleTable::LAYOUT_FIXED) {\n                $css['table-layout'] = 'fixed';\n            } elseif ($style->getLayout() == StyleTable::LAYOUT_AUTO) {\n                $css['table-layout'] = 'auto';\n            }\n        }\n        if (method_exists($style, 'isBidiVisual')) {\n            if ($style->isBidiVisual()) {\n                $css['direction'] = 'rtl';\n            }\n        }\n        if (method_exists($style, 'getVAlign')) {\n            $css['vertical-align'] = $style->getVAlign();\n        }\n\n        foreach (['Top', 'Left', 'Bottom', 'Right'] as $direction) {\n            $method = 'getBorder' . $direction . 'Style';\n            if (method_exists($style, $method)) {\n                $outval = $style->{$method}();\n                if ($outval === 'single') {\n                    $outval = 'solid';\n                }\n                if (is_string($outval) && 1 == preg_match('/^[a-z]+$/', $outval)) {\n                    $css['border-' . lcfirst($direction) . '-style'] = $outval;\n                }\n            }\n\n            $method = 'getBorder' . $direction . 'Color';\n            if (method_exists($style, $method)) {\n                $outval = $style->{$method}();\n                if (is_string($outval) && 1 == preg_match('/^[a-z]+$/', $outval)) {\n                    $css['border-' . lcfirst($direction) . '-color'] = $outval;\n                }\n            }\n\n            $method = 'getBorder' . $direction . 'Size';\n            if (method_exists($style, $method)) {\n                $outval = $style->{$method}();\n                if (is_numeric($outval)) {\n                    // size is in twips - divide by 20 to get points\n                    $css['border-' . lcfirst($direction) . '-width'] = ((string) ($outval / 20)) . 'pt';\n                }\n            }\n        }\n\n        return $this->assembleCss($css);\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/HTML.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Shared\\Validate;\nuse PhpOffice\\PhpWord\\Writer\\HTML\\Part\\AbstractPart;\n\n/**\n * HTML writer.\n *\n * Not supported: PreserveText, PageBreak, Object\n *\n * @since 0.10.0\n */\nclass HTML extends AbstractWriter implements WriterInterface\n{\n    /**\n     * Is the current writer creating PDF?\n     *\n     * @var bool\n     */\n    protected $isPdf = false;\n\n    /**\n     * Footnotes and endnotes collection.\n     *\n     * @var array\n     */\n    protected $notes = [];\n\n    /**\n     * Callback for editing generated html.\n     *\n     * @var null|callable\n     */\n    private $editCallback;\n\n    /**\n     * Default generic name for default font for html.\n     *\n     * @var string\n     */\n    private $defaultGenericFont = '';\n\n    /**\n     * Default white space style for html.\n     *\n     * @var string\n     */\n    private $defaultWhiteSpace = '';\n\n    /**\n     * Create new instance.\n     */\n    public function __construct(?PhpWord $phpWord = null)\n    {\n        $this->setPhpWord($phpWord);\n\n        $this->parts = ['Head', 'Body'];\n        foreach ($this->parts as $partName) {\n            $partClass = self::class . '\\\\Part\\\\' . $partName;\n            if (class_exists($partClass)) {\n                /** @var AbstractPart $part Type hint */\n                $part = new $partClass();\n                $part->setParentWriter($this);\n                $this->writerParts[strtolower($partName)] = $part;\n            }\n        }\n    }\n\n    /**\n     * Save PhpWord to file.\n     */\n    public function save(string $filename): void\n    {\n        $this->writeFile($this->openFile($filename), $this->getContent());\n    }\n\n    /**\n     * Get content.\n     *\n     * @return string\n     *\n     * @since 0.11.0\n     */\n    public function getContent()\n    {\n        $content = '';\n\n        $content .= '<!DOCTYPE html>' . PHP_EOL;\n        $content .= '<!-- Generated by PHPWord -->' . PHP_EOL;\n        $langtext = '';\n        $phpWord = $this->getPhpWord();\n        $lang = $phpWord->getSettings()->getThemeFontLang();\n        if (!empty($lang)) {\n            $lang2 = $lang->getLatin();\n            if (!$lang2) {\n                $lang2 = $lang->getEastAsia();\n            }\n            if (!$lang2) {\n                $lang2 = $lang->getBidirectional();\n            }\n            if ($lang2) {\n                $langtext = \" lang='\" . $lang2 . \"'\";\n            }\n        }\n        $content .= \"<html$langtext>\" . PHP_EOL;\n        $content .= $this->getWriterPart('Head')->write();\n        $content .= $this->getWriterPart('Body')->write();\n        $content .= '</html>' . PHP_EOL;\n\n        // Trigger a callback for editing the entire HTML\n        $callback = $this->editCallback;\n        if ($callback !== null) {\n            $content = $callback($content);\n        }\n\n        return $content;\n    }\n\n    /**\n     * Return the callback to edit the entire HTML.\n     */\n    public function getEditCallback(): ?callable\n    {\n        return $this->editCallback;\n    }\n\n    /**\n     * Set a callback to edit the entire HTML.\n     *\n     * The callback must accept the HTML as string as first parameter,\n     * and it must return the edited HTML as string.\n     */\n    public function setEditCallback(?callable $callback): self\n    {\n        $this->editCallback = $callback;\n\n        return $this;\n    }\n\n    /**\n     * Get is PDF.\n     *\n     * @return bool\n     */\n    public function isPdf()\n    {\n        return $this->isPdf;\n    }\n\n    /**\n     * Get notes.\n     *\n     * @return array\n     */\n    public function getNotes()\n    {\n        return $this->notes;\n    }\n\n    /**\n     * Add note.\n     *\n     * @param int $noteId\n     * @param string $noteMark\n     */\n    public function addNote($noteId, $noteMark): void\n    {\n        $this->notes[$noteId] = $noteMark;\n    }\n\n    /**\n     * Get generic name for default font for html.\n     */\n    public function getDefaultGenericFont(): string\n    {\n        return $this->defaultGenericFont;\n    }\n\n    /**\n     * Set generic name for default font for html.\n     */\n    public function setDefaultGenericFont(string $value): self\n    {\n        $this->defaultGenericFont = Validate::validateCSSGenericFont($value);\n\n        return $this;\n    }\n\n    /**\n     * Get default white space style for html.\n     */\n    public function getDefaultWhiteSpace(): string\n    {\n        return $this->defaultWhiteSpace;\n    }\n\n    /**\n     * Set default white space style for html.\n     */\n    public function setDefaultWhiteSpace(string $value): self\n    {\n        $this->defaultWhiteSpace = Validate::validateCSSWhiteSpace($value);\n\n        return $this;\n    }\n\n    /**\n     * Escape string or not depending on setting.\n     */\n    public function escapeHTML(string $txt): string\n    {\n        if (Settings::isOutputEscapingEnabled()) {\n            return htmlspecialchars($txt, ENT_QUOTES | (defined('ENT_SUBSTITUTE') ? ENT_SUBSTITUTE : 0), 'UTF-8');\n        }\n\n        return $txt;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/ODText/Element/AbstractElement.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\ODText\\Element;\n\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\AbstractElement as Word2007AbstractElement;\n\n/**\n * Abstract element writer.\n *\n * @since 0.11.0\n */\nabstract class AbstractElement extends Word2007AbstractElement\n{\n    protected function replaceTabs($text, $xmlWriter): void\n    {\n        if (preg_match('/^ +/', $text, $matches)) {\n            $num = strlen($matches[0]);\n            $xmlWriter->startElement('text:s');\n            $xmlWriter->writeAttributeIf($num > 1, 'text:c', \"$num\");\n            $xmlWriter->endElement();\n            $text = preg_replace('/^ +/', '', $text);\n        }\n        preg_match_all('/([\\\\s\\\\S]*?)(\\\\t|  +| ?$)/', $text, $matches, PREG_SET_ORDER);\n        foreach ($matches as $match) {\n            $this->writeText($match[1]);\n            if ($match[2] === '') {\n                break;\n            } elseif ($match[2] === \"\\t\") {\n                $xmlWriter->writeElement('text:tab');\n            } elseif ($match[2] === ' ') {\n                $xmlWriter->writeElement('text:s');\n\n                break;\n            } else {\n                $num = strlen($match[2]);\n                $xmlWriter->startElement('text:s');\n                $xmlWriter->writeAttributeIf($num > 1, 'text:c', \"$num\");\n                $xmlWriter->endElement();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/ODText/Element/Container.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\ODText\\Element;\n\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\Container as Word2007Container;\n\n/**\n * Container element writer (section, textrun, header, footnote, cell, etc.).\n *\n * @since 0.11.0\n */\nclass Container extends Word2007Container\n{\n    /**\n     * Namespace; Can't use __NAMESPACE__ in inherited class (ODText).\n     *\n     * @var string\n     */\n    protected $namespace = 'PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Element';\n\n    /**\n     * @var array<string>\n     */\n    protected $containerWithoutP = ['TextRun', 'Footnote', 'Endnote'];\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/ODText/Element/Field.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n// Not fully implemented\n//     - supports only PAGE, NUMPAGES, DATE and FILENAME\n//     - supports only default formats and options\n//     - supports style only if specified by name\n//     - spaces before and after field may be dropped\n\nnamespace PhpOffice\\PhpWord\\Writer\\ODText\\Element;\n\n/**\n * Field element writer.\n *\n * @since 0.11.0\n */\nclass Field extends Text\n{\n    /**\n     * Write field element.\n     */\n    public function write(): void\n    {\n        $element = $this->getElement();\n        if (!$element instanceof \\PhpOffice\\PhpWord\\Element\\Field) {\n            return;\n        }\n\n        $type = strtolower($element->getType());\n        switch ($type) {\n            case 'date':\n            case 'page':\n            case 'numpages':\n            case 'filename':\n                $this->writeDefault($element, $type);\n\n                break;\n        }\n    }\n\n    private function writeDefault(\\PhpOffice\\PhpWord\\Element\\Field $element, $type): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startElement('text:span');\n\n        $fstyle = $element->getFontStyle();\n        if (is_string($fstyle)) {\n            $xmlWriter->writeAttribute('text:style-name', $fstyle);\n        }\n\n        switch ($type) {\n            case 'date':\n                $xmlWriter->startElement('text:date');\n                $xmlWriter->writeAttribute('text:fixed', 'false');\n                $xmlWriter->endElement();\n\n                break;\n            case 'page':\n                $xmlWriter->startElement('text:page-number');\n                $xmlWriter->writeAttribute('text:fixed', 'false');\n                $xmlWriter->endElement();\n\n                break;\n            case 'numpages':\n                $xmlWriter->startElement('text:page-count');\n                $xmlWriter->endElement();\n\n                break;\n            case 'filename':\n                $xmlWriter->startElement('text:file-name');\n                $xmlWriter->writeAttribute('text:fixed', 'false');\n                $options = $element->getOptions();\n                if ($options != null && in_array('Path', $options)) {\n                    $xmlWriter->writeAttribute('text:display', 'full');\n                } else {\n                    $xmlWriter->writeAttribute('text:display', 'name');\n                }\n                $xmlWriter->endElement();\n\n                break;\n        }\n        $xmlWriter->endElement(); // text:span\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/ODText/Element/Formula.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\ODText\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\Formula as ElementFormula;\nuse PhpOffice\\PhpWord\\Shared\\Converter;\nuse PhpOffice\\PhpWord\\Writer\\ODText\\Part\\AbstractPart;\n\n/**\n * Formula element writer.\n *\n * @since 0.10.0\n */\nclass Formula extends AbstractElement\n{\n    /**\n     * Write element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $element = $this->getElement();\n        if (!$element instanceof ElementFormula) {\n            return;\n        }\n\n        $part = $this->getPart();\n        if (!$part instanceof AbstractPart) {\n            return;\n        }\n\n        $objectIdx = $part->addObject($element);\n\n        //$style = $element->getStyle();\n        //$width = Converter::pixelToCm($style->getWidth());\n        //$height = Converter::pixelToCm($style->getHeight());\n\n        $xmlWriter->startElement('text:p');\n        $xmlWriter->writeAttribute('text:style-name', 'OB' . $objectIdx);\n\n        $xmlWriter->startElement('draw:frame');\n        $xmlWriter->writeAttribute('draw:name', $element->getElementId());\n        $xmlWriter->writeAttribute('text:anchor-type', 'as-char');\n        //$xmlWriter->writeAttribute('svg:width', $width . 'cm');\n        //$xmlWriter->writeAttribute('svg:height', $height . 'cm');\n        //$xmlWriter->writeAttribute('draw:z-index', $mediaIndex);\n\n        $xmlWriter->startElement('draw:object');\n        $xmlWriter->writeAttribute('xlink:href', 'Formula' . $objectIdx);\n        $xmlWriter->writeAttribute('xlink:type', 'simple');\n        $xmlWriter->writeAttribute('xlink:show', 'embed');\n        $xmlWriter->writeAttribute('xlink:actuate', 'onLoad');\n        $xmlWriter->endElement(); // draw:object\n\n        $xmlWriter->endElement(); // draw:frame\n\n        $xmlWriter->endElement(); // text:p\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/ODText/Element/Image.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\ODText\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\Image as ElementImage;\nuse PhpOffice\\PhpWord\\Shared\\Converter;\n\n/**\n * Image element writer.\n *\n * @since 0.10.0\n */\nclass Image extends AbstractElement\n{\n    /**\n     * Write element.\n     */\n    public function write(): void\n    {\n        $element = $this->getElement();\n        if (!$element instanceof ElementImage) {\n            return;\n        }\n\n        $mediaIndex = $element->getMediaIndex();\n        $target = 'Pictures/' . $element->getTarget();\n        $style = $element->getStyle();\n        $width = Converter::pixelToCm($style->getWidth());\n        $height = Converter::pixelToCm($style->getHeight());\n\n        $xmlWriter = $this->getXmlWriter();\n\n        if (!$this->withoutP) {\n            $xmlWriter->startElement('text:p');\n            $xmlWriter->writeAttribute('text:style-name', 'IM' . $mediaIndex);\n        }\n\n        $xmlWriter->startElement('draw:frame');\n        $xmlWriter->writeAttribute('draw:style-name', 'fr' . $mediaIndex);\n        $xmlWriter->writeAttributeIf($this->withoutP, 'draw:text-style-name', 'IM' . $mediaIndex);\n        $xmlWriter->writeAttribute('draw:name', $element->getElementId());\n        $xmlWriter->writeAttribute('text:anchor-type', 'as-char');\n        $xmlWriter->writeAttribute('svg:width', $width . 'cm');\n        $xmlWriter->writeAttribute('svg:height', $height . 'cm');\n        $xmlWriter->writeAttribute('draw:z-index', $mediaIndex);\n\n        $xmlWriter->startElement('draw:image');\n        $xmlWriter->writeAttribute('xlink:href', $target);\n        $xmlWriter->writeAttribute('xlink:type', 'simple');\n        $xmlWriter->writeAttribute('xlink:show', 'embed');\n        $xmlWriter->writeAttribute('xlink:actuate', 'onLoad');\n        $xmlWriter->endElement(); // draw:image\n\n        $xmlWriter->endElement(); // draw:frame\n\n        if (!$this->withoutP) {\n            $xmlWriter->endElement(); // text:p\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/ODText/Element/Link.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\ODText\\Element;\n\n/**\n * Text element writer.\n *\n * @since 0.10.0\n */\nclass Link extends AbstractElement\n{\n    /**\n     * Write element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $element = $this->getElement();\n        if (!$element instanceof \\PhpOffice\\PhpWord\\Element\\Link) {\n            return;\n        }\n\n        if (!$this->withoutP) {\n            $xmlWriter->startElement('text:p'); // text:p\n        }\n\n        $xmlWriter->startElement('text:a');\n        $xmlWriter->writeAttribute('xlink:type', 'simple');\n        $xmlWriter->writeAttribute('xlink:href', ($element->isInternal() ? '#' : '') . $element->getSource());\n        $this->writeText($element->getText());\n        $xmlWriter->endElement(); // text:a\n\n        if (!$this->withoutP) {\n            $xmlWriter->endElement(); // text:p\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/ODText/Element/ListItemRun.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\ODText\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\ListItemRun as ListItemRunElement;\n\n/**\n * ListItemRun element writer.\n *\n * @since 0.10.0\n */\nclass ListItemRun extends AbstractElement\n{\n    /**\n     * Write list item element.\n     */\n    public function write(): void\n    {\n        $element = $this->getElement();\n        if (!$element instanceof ListItemRunElement) {\n            return;\n        }\n        $depth = $element->getDepth() + 1;\n\n        $xmlWriter = $this->getXmlWriter();\n\n        for ($iDepth = 1; $iDepth <= $depth; ++$iDepth) {\n            $xmlWriter->startElement('text:list');\n            $xmlWriter->writeAttribute('text:style-name', $element->getStyle()->getNumStyle());\n            $xmlWriter->startElement('text:list-item');\n        }\n\n        $containerWriter = new Container($xmlWriter, $element, false);\n        $containerWriter->write();\n\n        for ($iDepth = 1; $iDepth <= $depth; ++$iDepth) {\n            $xmlWriter->endElement(); // text:list-item\n            $xmlWriter->endElement(); // text:list\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/ODText/Element/PageBreak.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\ODText\\Element;\n\n/**\n * PageBreak element writer.\n */\nclass PageBreak extends AbstractElement\n{\n    /**\n     * Write element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startElement('text:p');\n        $xmlWriter->writeAttribute('text:style-name', 'PB');\n        $xmlWriter->endElement();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/ODText/Element/Ruby.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\ODText\\Element;\n\n/**\n * Ruby element writer.\n * NOTE: This class will write out a Ruby element in the format {baseText} ({rubyText})\n * just like RTF; however, ODT files natively support Ruby text elements.\n * This implementation should be changed in the future to support ODT's native\n * Ruby elements and usage.\n */\nclass Ruby extends AbstractElement\n{\n    /**\n     * Write element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $element = $this->getElement();\n        if (!$element instanceof \\PhpOffice\\PhpWord\\Element\\Ruby) {\n            return;\n        }\n        $paragraphStyle = $element->getBaseTextRun()->getParagraphStyle();\n\n        if (!$this->withoutP) {\n            $xmlWriter->startElement('text:p'); // text:p\n        }\n        if (empty($paragraphStyle)) {\n            if (!$this->withoutP) {\n                $xmlWriter->writeAttribute('text:style-name', 'Normal');\n            }\n        } elseif (is_string($paragraphStyle)) {\n            if (!$this->withoutP) {\n                $xmlWriter->writeAttribute('text:style-name', $paragraphStyle);\n            }\n        }\n\n        $this->replaceTabs($element->getBaseTextRun()->getText(), $xmlWriter);\n        $this->writeText(' (');\n        $this->replaceTabs($element->getRubyTextRun()->getText(), $xmlWriter);\n        $this->writeText(')');\n\n        if (!$this->withoutP) {\n            $xmlWriter->endElement(); // text:p\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/ODText/Element/Table.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\ODText\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\Row as RowElement;\nuse PhpOffice\\PhpWord\\Element\\Table as TableElement;\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\n\n/**\n * Table element writer.\n *\n * @since 0.10.0\n */\nclass Table extends AbstractElement\n{\n    /**\n     * Write element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $element = $this->getElement();\n        if (!$element instanceof TableElement) {\n            return;\n        }\n        $rows = $element->getRows();\n        $rowCount = count($rows);\n\n        if ($rowCount > 0) {\n            $xmlWriter->startElement('table:table');\n            $xmlWriter->writeAttribute('table:name', $element->getElementId());\n            $xmlWriter->writeAttribute('table:style-name', $element->getElementId());\n\n            // Write columns\n            $this->writeColumns($xmlWriter, $element);\n\n            // Write rows\n            foreach ($rows as $row) {\n                $this->writeRow($xmlWriter, $row);\n            }\n            $xmlWriter->endElement(); // table:table\n        }\n    }\n\n    /**\n     * Write column.\n     */\n    private function writeColumns(XMLWriter $xmlWriter, TableElement $element): void\n    {\n        $colCount = $element->countColumns();\n\n        for ($i = 0; $i < $colCount; ++$i) {\n            $xmlWriter->startElement('table:table-column');\n            $xmlWriter->writeAttribute('table:style-name', $element->getElementId() . '.' . $i);\n            $xmlWriter->endElement();\n        }\n    }\n\n    /**\n     * Write row.\n     */\n    private function writeRow(XMLWriter $xmlWriter, RowElement $row): void\n    {\n        $xmlWriter->startElement('table:table-row');\n        /** @var RowElement $row Type hint */\n        foreach ($row->getCells() as $cell) {\n            $xmlWriter->startElement('table:table-cell');\n            $xmlWriter->writeAttribute('office:value-type', 'string');\n\n            $containerWriter = new Container($xmlWriter, $cell);\n            $containerWriter->write();\n\n            $xmlWriter->endElement(); // table:table-cell\n        }\n        $xmlWriter->endElement(); // table:table-row\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/ODText/Element/Text.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\ODText\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\TrackChange;\nuse PhpOffice\\PhpWord\\Exception\\Exception;\n\n/**\n * Text element writer.\n *\n * @since 0.10.0\n */\nclass Text extends AbstractElement\n{\n    /**\n     * Write element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $element = $this->getElement();\n        if (!$element instanceof \\PhpOffice\\PhpWord\\Element\\Text) {\n            return;\n        }\n        $fontStyle = $element->getFontStyle();\n        $paragraphStyle = $element->getParagraphStyle();\n\n        // @todo Commented for TextRun. Should really checkout this value\n        // $fStyleIsObject = ($fontStyle instanceof Font) ? true : false;\n        //$fStyleIsObject = false;\n\n        //if ($fStyleIsObject) {\n        // Don't never be the case, because I browse all sections for cleaning all styles not declared\n        //    throw new Exception('PhpWord : $fStyleIsObject wouldn\\'t be an object');\n        //}\n\n        if (!$this->withoutP) {\n            $xmlWriter->startElement('text:p'); // text:p\n        }\n        if ($element->getTrackChange() != null && $element->getTrackChange()->getChangeType() == TrackChange::DELETED) {\n            $xmlWriter->startElement('text:change');\n            $xmlWriter->writeAttribute('text:change-id', $element->getTrackChange()->getElementId());\n            $xmlWriter->endElement();\n        } else {\n            if (empty($paragraphStyle)) {\n                if (!$this->withoutP) {\n                    $xmlWriter->writeAttribute('text:style-name', 'Normal');\n                }\n            } elseif (is_string($paragraphStyle)) {\n                if (!$this->withoutP) {\n                    $xmlWriter->writeAttribute('text:style-name', $paragraphStyle);\n                }\n            }\n\n            if (!empty($fontStyle)) {\n                // text:span\n                $xmlWriter->startElement('text:span');\n                if (is_string($fontStyle)) {\n                    $xmlWriter->writeAttribute('text:style-name', $fontStyle);\n                }\n            }\n\n            $this->writeChangeInsertion(true, $element->getTrackChange());\n            $this->replaceTabs($element->getText(), $xmlWriter);\n            $this->writeChangeInsertion(false, $element->getTrackChange());\n\n            if (!empty($fontStyle)) {\n                $xmlWriter->endElement();\n            }\n        }\n        if (!$this->withoutP) {\n            $xmlWriter->endElement(); // text:p\n        }\n    }\n\n    private function writeChangeInsertion($start = true, ?TrackChange $trackChange = null): void\n    {\n        if ($trackChange == null || $trackChange->getChangeType() != TrackChange::INSERTED) {\n            return;\n        }\n        $xmlWriter = $this->getXmlWriter();\n        $xmlWriter->startElement('text:change-' . ($start ? 'start' : 'end'));\n        $xmlWriter->writeAttribute('text:change-id', $trackChange->getElementId());\n        $xmlWriter->endElement();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/ODText/Element/TextBreak.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\ODText\\Element;\n\n/**\n * TextBreak element writer.\n *\n * @since 0.10.0\n */\nclass TextBreak extends AbstractElement\n{\n    /**\n     * Write element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startElement('text:p');\n        $xmlWriter->writeAttribute('text:style-name', 'Standard');\n        $xmlWriter->endElement();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/ODText/Element/TextRun.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\ODText\\Element;\n\n/**\n * TextRun element writer.\n *\n * @since 0.10.0\n */\nclass TextRun extends Text\n{\n    /**\n     * Write element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $element = $this->getElement();\n\n        $xmlWriter->startElement('text:p');\n        /** @scrutinizer ignore-call */\n        $pStyle = $element->getParagraphStyle();\n        if (!is_string($pStyle)) {\n            $pStyle = 'Normal';\n        }\n        $xmlWriter->writeAttribute('text:style-name', $pStyle);\n\n        $containerWriter = new Container($xmlWriter, $element);\n        $containerWriter->write();\n\n        $xmlWriter->endElement();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/ODText/Element/Title.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\ODText\\Element;\n\n/**\n * Title element writer.\n *\n * @since 0.11.0\n */\nclass Title extends AbstractElement\n{\n    /**\n     * Write element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $element = $this->getElement();\n        if (!$element instanceof \\PhpOffice\\PhpWord\\Element\\Title) {\n            return;\n        }\n\n        $xmlWriter->startElement('text:h');\n        $hdname = 'HD';\n        $sect = $element->getParent();\n        if ($sect instanceof \\PhpOffice\\PhpWord\\Element\\Section) {\n            if (self::compareToFirstElement($element, $sect->getElements())) {\n                $hdname = 'HE';\n            }\n        }\n        $depth = $element->getDepth();\n        $xmlWriter->writeAttribute('text:style-name', \"$hdname$depth\");\n        $xmlWriter->writeAttribute('text:outline-level', $depth);\n        $xmlWriter->startElement('text:span');\n        if ($depth > 0) {\n            $xmlWriter->writeAttribute('text:style-name', 'Heading_' . $depth);\n        } else {\n            $xmlWriter->writeAttribute('text:style-name', 'Title');\n        }\n        $text = $element->getText();\n        if (is_string($text)) {\n            $this->writeText($text);\n        }\n        if ($text instanceof \\PhpOffice\\PhpWord\\Element\\AbstractContainer) {\n            $containerWriter = new Container($xmlWriter, $text);\n            $containerWriter->write();\n        }\n        $xmlWriter->endElement(); // text:span\n        $xmlWriter->endElement(); // text:h\n    }\n\n    /**\n     * Test if element is same as first element in array.\n     *\n     * @param \\PhpOffice\\PhpWord\\Element\\AbstractElement $elem\n     * @param \\PhpOffice\\PhpWord\\Element\\AbstractElement[] $elemarray\n     *\n     * @return bool\n     */\n    private static function compareToFirstElement($elem, $elemarray)\n    {\n        return $elem === $elemarray[0];\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/ODText/Part/AbstractPart.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\ODText\\Part;\n\nuse PhpOffice\\PhpWord\\Element\\AbstractElement;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\nuse PhpOffice\\PhpWord\\Style;\nuse PhpOffice\\PhpWord\\Style\\Font;\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Part\\AbstractPart as Word2007AbstractPart;\n\n/**\n * ODText writer part abstract.\n */\nabstract class AbstractPart extends Word2007AbstractPart\n{\n    /**\n     * @var AbstractElement[]\n     */\n    protected $objects = [];\n\n    /**\n     * @var string Date format\n     */\n    protected $dateFormat = 'Y-m-d\\TH:i:s.000';\n\n    /**\n     * Write common root attributes.\n     */\n    protected function writeCommonRootAttributes(XMLWriter $xmlWriter): void\n    {\n        $xmlWriter->writeAttribute('office:version', '1.2');\n        $xmlWriter->writeAttribute('xmlns:office', 'urn:oasis:names:tc:opendocument:xmlns:office:1.0');\n        $xmlWriter->writeAttribute('xmlns:style', 'urn:oasis:names:tc:opendocument:xmlns:style:1.0');\n        $xmlWriter->writeAttribute('xmlns:text', 'urn:oasis:names:tc:opendocument:xmlns:text:1.0');\n        $xmlWriter->writeAttribute('xmlns:table', 'urn:oasis:names:tc:opendocument:xmlns:table:1.0');\n        $xmlWriter->writeAttribute('xmlns:draw', 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0');\n        $xmlWriter->writeAttribute('xmlns:fo', 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0');\n        $xmlWriter->writeAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink');\n        $xmlWriter->writeAttribute('xmlns:dc', 'http://purl.org/dc/elements/1.1/');\n        $xmlWriter->writeAttribute('xmlns:meta', 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0');\n        $xmlWriter->writeAttribute('xmlns:number', 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0');\n        $xmlWriter->writeAttribute('xmlns:svg', 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0');\n        $xmlWriter->writeAttribute('xmlns:chart', 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0');\n        $xmlWriter->writeAttribute('xmlns:dr3d', 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0');\n        $xmlWriter->writeAttribute('xmlns:math', 'http://www.w3.org/1998/Math/MathML');\n        $xmlWriter->writeAttribute('xmlns:form', 'urn:oasis:names:tc:opendocument:xmlns:form:1.0');\n        $xmlWriter->writeAttribute('xmlns:script', 'urn:oasis:names:tc:opendocument:xmlns:script:1.0');\n        $xmlWriter->writeAttribute('xmlns:ooo', 'http://openoffice.org/2004/office');\n        $xmlWriter->writeAttribute('xmlns:ooow', 'http://openoffice.org/2004/writer');\n        $xmlWriter->writeAttribute('xmlns:oooc', 'http://openoffice.org/2004/calc');\n        $xmlWriter->writeAttribute('xmlns:dom', 'http://www.w3.org/2001/xml-events');\n        $xmlWriter->writeAttribute('xmlns:rpt', 'http://openoffice.org/2005/report');\n        $xmlWriter->writeAttribute('xmlns:of', 'urn:oasis:names:tc:opendocument:xmlns:of:1.2');\n        $xmlWriter->writeAttribute('xmlns:xhtml', 'http://www.w3.org/1999/xhtml');\n        $xmlWriter->writeAttribute('xmlns:grddl', 'http://www.w3.org/2003/g/data-view#');\n        $xmlWriter->writeAttribute('xmlns:tableooo', 'http://openoffice.org/2009/table');\n        $xmlWriter->writeAttribute('xmlns:css3t', 'http://www.w3.org/TR/css3-text/');\n    }\n\n    /**\n     * Write font faces declaration.\n     */\n    protected function writeFontFaces(XMLWriter $xmlWriter): void\n    {\n        $xmlWriter->startElement('office:font-face-decls');\n        $fontTable = [];\n        $styles = Style::getStyles();\n        $numFonts = 0;\n        if (count($styles) > 0) {\n            foreach ($styles as $style) {\n                // Font\n                if ($style instanceof Font) {\n                    ++$numFonts;\n                    $name = $style->getName();\n                    if (!in_array($name, $fontTable)) {\n                        $fontTable[] = $name;\n\n                        // style:font-face\n                        $xmlWriter->startElement('style:font-face');\n                        $xmlWriter->writeAttribute('style:name', $name);\n                        $xmlWriter->writeAttribute('svg:font-family', $name);\n                        $xmlWriter->endElement();\n                    }\n                }\n            }\n        }\n        if (!in_array(Settings::getDefaultFontName(), $fontTable)) {\n            $xmlWriter->startElement('style:font-face');\n            $xmlWriter->writeAttribute('style:name', Settings::getDefaultFontName());\n            $xmlWriter->writeAttribute('svg:font-family', Settings::getDefaultFontName());\n            $xmlWriter->endElement();\n        }\n        $xmlWriter->endElement();\n    }\n\n    public function addObject(AbstractElement $object): int\n    {\n        $this->objects[] = $object;\n\n        return count($this->objects) - 1;\n    }\n\n    /**\n     * @param AbstractElement[] $objects\n     */\n    public function setObjects(array $objects): self\n    {\n        $this->objects = $objects;\n\n        return $this;\n    }\n\n    /**\n     * @return AbstractElement[]\n     */\n    public function getObjects(): array\n    {\n        return $this->objects;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/ODText/Part/Content.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\ODText\\Part;\n\nuse PhpOffice\\PhpWord\\Element\\AbstractContainer;\nuse PhpOffice\\PhpWord\\Element\\Field;\nuse PhpOffice\\PhpWord\\Element\\Image;\nuse PhpOffice\\PhpWord\\Element\\Table;\nuse PhpOffice\\PhpWord\\Element\\Text;\nuse PhpOffice\\PhpWord\\Element\\TextRun;\nuse PhpOffice\\PhpWord\\Element\\TrackChange;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\nuse PhpOffice\\PhpWord\\Style;\nuse PhpOffice\\PhpWord\\Style\\Font;\nuse PhpOffice\\PhpWord\\Style\\Paragraph;\nuse PhpOffice\\PhpWord\\Style\\Table as TableStyle;\nuse PhpOffice\\PhpWord\\Writer\\ODText\\Element\\Container;\nuse PhpOffice\\PhpWord\\Writer\\ODText\\Style\\Paragraph as ParagraphStyleWriter;\n\n/**\n * ODText content part writer: content.xml.\n */\nclass Content extends AbstractPart\n{\n    /**\n     * Auto style collection.\n     *\n     * Collect inline style information from section, image, and table elements\n     *\n     * @todo Merge font and paragraph styles\n     *\n     * @var array\n     */\n    private $autoStyles = ['Section' => [], 'Image' => [], 'Table' => []];\n\n    private $imageParagraphStyles = [];\n\n    /**\n     * Write part.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $phpWord = $this->getParentWriter()->getPhpWord();\n\n        $this->getAutoStyles($phpWord);\n\n        $xmlWriter->startDocument('1.0', 'UTF-8');\n        $xmlWriter->startElement('office:document-content');\n        $this->writeCommonRootAttributes($xmlWriter);\n        $xmlWriter->writeAttribute('xmlns:xforms', 'http://www.w3.org/2002/xforms');\n        $xmlWriter->writeAttribute('xmlns:xsd', 'http://www.w3.org/2001/XMLSchema');\n        $xmlWriter->writeAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');\n        $xmlWriter->writeAttribute('xmlns:field', 'urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0');\n        $xmlWriter->writeAttribute('xmlns:formx', 'urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0');\n\n        // Font declarations and automatic styles\n        $this->writeFontFaces($xmlWriter); // office:font-face-decls\n        $this->writeAutoStyles($xmlWriter); // office:automatic-styles\n\n        // Body\n        $xmlWriter->startElement('office:body');\n        $xmlWriter->startElement('office:text');\n\n        // Tracked changes declarations\n        $trackedChanges = [];\n        $sections = $phpWord->getSections();\n        foreach ($sections as $section) {\n            $this->collectTrackedChanges($section, $trackedChanges);\n        }\n        $xmlWriter->startElement('text:tracked-changes');\n        foreach ($trackedChanges as $trackedElement) {\n            $trackedChange = $trackedElement->getTrackChange();\n            $xmlWriter->startElement('text:changed-region');\n            $trackedChange->setElementId();\n            $xmlWriter->writeAttribute('text:id', $trackedChange->getElementId());\n\n            if (($trackedChange->getChangeType() == TrackChange::INSERTED)) {\n                $xmlWriter->startElement('text:insertion');\n            } elseif ($trackedChange->getChangeType() == TrackChange::DELETED) {\n                $xmlWriter->startElement('text:deletion');\n            }\n\n            $xmlWriter->startElement('office:change-info');\n            $xmlWriter->writeElement('dc:creator', $trackedChange->getAuthor());\n            if ($trackedChange->getDate() != null) {\n                $xmlWriter->writeElement('dc:date', $trackedChange->getDate()->format('Y-m-d\\TH:i:s\\Z'));\n            }\n            $xmlWriter->endElement(); // office:change-info\n            if ($trackedChange->getChangeType() == TrackChange::DELETED && method_exists($trackedElement, 'getText')) {\n                // @phpstan-ignore-next-line\n                $xmlWriter->writeElement('text:p', $trackedElement->getText());\n            }\n\n            $xmlWriter->endElement(); // text:insertion|text:deletion\n            $xmlWriter->endElement(); // text:changed-region\n        }\n        $xmlWriter->endElement(); // text:tracked-changes\n\n        // Sequence declarations\n        $sequences = ['Illustration', 'Table', 'Text', 'Drawing'];\n        $xmlWriter->startElement('text:sequence-decls');\n        foreach ($sequences as $sequence) {\n            $xmlWriter->startElement('text:sequence-decl');\n            $xmlWriter->writeAttribute('text:display-outline-level', 0);\n            $xmlWriter->writeAttribute('text:name', $sequence);\n            $xmlWriter->endElement();\n        }\n        $xmlWriter->endElement(); // text:sequence-decl\n\n        // Sections\n        $sections = $phpWord->getSections();\n        foreach ($sections as $section) {\n            $name = 'Section' . $section->getSectionId();\n            $xmlWriter->startElement('text:section');\n            $xmlWriter->writeAttribute('text:name', $name);\n            $xmlWriter->writeAttribute('text:style-name', $name);\n            $xmlWriter->startElement('text:p');\n            $xmlWriter->writeAttribute('text:style-name', 'SB' . $section->getSectionId());\n            $xmlWriter->endElement();\n\n            $containerWriter = new Container($xmlWriter, $section);\n            $containerWriter->setPart($this);\n            $containerWriter->write();\n\n            $xmlWriter->endElement(); // text:section\n        }\n\n        $xmlWriter->endElement(); // office:text\n        $xmlWriter->endElement(); // office:body\n\n        $xmlWriter->endElement(); // office:document-content\n\n        return $xmlWriter->getData();\n    }\n\n    /**\n     * Write automatic styles other than fonts and paragraphs.\n     *\n     * @since 0.11.0\n     */\n    private function writeAutoStyles(XMLWriter $xmlWriter): void\n    {\n        $xmlWriter->startElement('office:automatic-styles');\n\n        $this->writeTextStyles($xmlWriter);\n        foreach ($this->autoStyles as $element => $styles) {\n            $writerClass = 'PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Style\\\\' . $element;\n            foreach ($styles as $style) {\n                /** @var \\PhpOffice\\PhpWord\\Writer\\ODText\\Style\\AbstractStyle $styleWriter Type hint */\n                $styleWriter = new $writerClass($xmlWriter, $style);\n                $styleWriter->write();\n            }\n        }\n\n        $xmlWriter->endElement(); // office:automatic-styles\n    }\n\n    /**\n     * Write automatic styles.\n     */\n    private function writeTextStyles(XMLWriter $xmlWriter): void\n    {\n        $styles = Style::getStyles();\n        $paragraphStyleCount = 0;\n\n        $style = new Paragraph();\n        $style->setStyleName('PB');\n        $style->setAuto();\n        $styleWriter = new ParagraphStyleWriter($xmlWriter, $style);\n        $styleWriter->write();\n\n        $sects = $this->getParentWriter()->getPhpWord()->getSections();\n        $countsects = count($sects);\n        for ($i = 0; $i < $countsects; ++$i) {\n            $iplus1 = $i + 1;\n            $style = new Paragraph();\n            $style->setStyleName(\"SB$iplus1\");\n            $style->setAuto();\n            $pnstart = $sects[$i]->getStyle()->getPageNumberingStart();\n            $style->setNumLevel($pnstart);\n            $styleWriter = new ParagraphStyleWriter($xmlWriter, $style);\n            $styleWriter->write();\n        }\n\n        foreach ($styles as $style) {\n            $sty = (string) $style->getStyleName();\n            if (substr($sty, 0, 8) === 'Heading_') {\n                $style = new Paragraph();\n                $style->setStyleName('HD' . substr($sty, 8));\n                $style->setAuto();\n                $styleWriter = new ParagraphStyleWriter($xmlWriter, $style);\n                $styleWriter->write();\n                $style = new Paragraph();\n                $style->setStyleName('HE' . substr($sty, 8));\n                $style->setAuto();\n                $styleWriter = new ParagraphStyleWriter($xmlWriter, $style);\n                $styleWriter->write();\n            }\n        }\n\n        foreach ($styles as $style) {\n            if ($style->isAuto() === true) {\n                $styleClass = str_replace('\\\\Style\\\\', '\\\\Writer\\\\ODText\\\\Style\\\\', get_class($style));\n                if (class_exists($styleClass)) {\n                    /** @var \\PhpOffice\\PhpWord\\Writer\\ODText\\Style\\AbstractStyle $styleWriter Type hint */\n                    $styleWriter = new $styleClass($xmlWriter, $style);\n                    $styleWriter->write();\n                }\n                if ($style instanceof Paragraph) {\n                    ++$paragraphStyleCount;\n                }\n            }\n        }\n        foreach ($this->imageParagraphStyles as $style) {\n            $styleWriter = new ParagraphStyleWriter($xmlWriter, $style);\n            $styleWriter->write();\n        }\n    }\n\n    /**\n     * Get automatic styles.\n     */\n    private function getAutoStyles(PhpWord $phpWord): void\n    {\n        $sections = $phpWord->getSections();\n        $paragraphStyleCount = 0;\n        $fontStyleCount = 0;\n        foreach ($sections as $section) {\n            $style = $section->getStyle();\n            $style->setStyleName(\"Section{$section->getSectionId()}\");\n            $this->autoStyles['Section'][] = $style;\n            $this->getContainerStyle($section, $paragraphStyleCount, $fontStyleCount);\n        }\n    }\n\n    /**\n     * Get all styles of each elements in container recursively.\n     *\n     * Table style can be null or string of the style name\n     *\n     * @param AbstractContainer $container\n     * @param int $paragraphStyleCount\n     * @param int $fontStyleCount\n     *\n     * @todo Simplify the logic\n     */\n    private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyleCount): void\n    {\n        $elements = $container->getElements();\n        foreach ($elements as $element) {\n            if ($element instanceof TextRun) {\n                $this->getElementStyleTextRun($element, $paragraphStyleCount);\n                $this->getContainerStyle($element, $paragraphStyleCount, $fontStyleCount);\n            } elseif ($element instanceof Text) {\n                $this->getElementStyle($element, $paragraphStyleCount, $fontStyleCount);\n            } elseif ($element instanceof Field) {\n                $this->getElementStyleField($element, $fontStyleCount);\n            } elseif ($element instanceof Image) {\n                $style = $element->getStyle();\n                $style->setStyleName('fr' . $element->getMediaIndex());\n                $this->autoStyles['Image'][] = $style;\n                $sty = new Paragraph();\n                $sty->setStyleName('IM' . $element->getMediaIndex());\n                $sty->setAuto();\n                $sty->setAlignment($style->getAlignment());\n                $this->imageParagraphStyles[] = $sty;\n            } elseif ($element instanceof Table) {\n                $style = $element->getStyle();\n                if (is_string($style)) {\n                    $style = Style::getStyle($style);\n                }\n                if ($style === null) {\n                    $style = new TableStyle();\n                }\n                $style->setStyleName($element->getElementId());\n                $style->setColumnWidths($element->findFirstDefinedCellWidths());\n                $this->autoStyles['Table'][] = $style;\n            }\n        }\n    }\n\n    /**\n     * Get style of individual element.\n     *\n     * @param Text $element\n     * @param int $paragraphStyleCount\n     * @param int $fontStyleCount\n     */\n    private function getElementStyle($element, &$paragraphStyleCount, &$fontStyleCount): void\n    {\n        $fontStyle = $element->getFontStyle();\n        $paragraphStyle = $element->getParagraphStyle();\n        $phpWord = $this->getParentWriter()->getPhpWord();\n\n        if ($fontStyle instanceof Font) {\n            // Font\n            $name = $fontStyle->getStyleName();\n            if (!$name) {\n                ++$fontStyleCount;\n                $style = $phpWord->addFontStyle(\"T{$fontStyleCount}\", $fontStyle, null);\n                $style->setAuto();\n                $style->setParagraph(null);\n                $element->setFontStyle(\"T{$fontStyleCount}\");\n            } else {\n                $element->setFontStyle($name);\n            }\n        }\n        if ($paragraphStyle instanceof Paragraph) {\n            // Paragraph\n            $name = $paragraphStyle->getStyleName();\n            if (!$name) {\n                ++$paragraphStyleCount;\n                $style = $phpWord->addParagraphStyle(\"P{$paragraphStyleCount}\", $paragraphStyle);\n                $style->setAuto();\n                $element->setParagraphStyle(\"P{$paragraphStyleCount}\");\n            } else {\n                $element->setParagraphStyle($name);\n            }\n        } elseif ($paragraphStyle) {\n            ++$paragraphStyleCount;\n            $parstylename = \"P$paragraphStyleCount\" . \"_$paragraphStyle\";\n            $style = $phpWord->addParagraphStyle($parstylename, $paragraphStyle);\n            $style->setAuto();\n            $element->setParagraphStyle($parstylename);\n        }\n    }\n\n    /**\n     * Get font style of individual field element.\n     *\n     * @param Field $element\n     * @param int $fontStyleCount\n     */\n    private function getElementStyleField($element, &$fontStyleCount): void\n    {\n        $fontStyle = $element->getFontStyle();\n        $phpWord = $this->getParentWriter()->getPhpWord();\n\n        if ($fontStyle instanceof Font) {\n            $name = $fontStyle->getStyleName();\n            if (!$name) {\n                ++$fontStyleCount;\n                $style = $phpWord->addFontStyle(\"T{$fontStyleCount}\", $fontStyle, null);\n                $style->setAuto();\n                $style->setParagraph(null);\n                $element->setFontStyle(\"T{$fontStyleCount}\");\n            } else {\n                $element->setFontStyle($name);\n            }\n        }\n    }\n\n    /**\n     * Get style of individual element.\n     *\n     * @param TextRun $element\n     * @param int $paragraphStyleCount\n     */\n    private function getElementStyleTextRun($element, &$paragraphStyleCount): void\n    {\n        $paragraphStyle = $element->getParagraphStyle();\n        $phpWord = $this->getParentWriter()->getPhpWord();\n\n        if ($paragraphStyle instanceof Paragraph) {\n            // Paragraph\n            $name = $paragraphStyle->getStyleName();\n            if (!$name) {\n                ++$paragraphStyleCount;\n                $style = $phpWord->addParagraphStyle(\"P{$paragraphStyleCount}\", $paragraphStyle);\n                $style->setAuto();\n                $element->setParagraphStyle(\"P{$paragraphStyleCount}\");\n            } else {\n                $element->setParagraphStyle($name);\n            }\n        } elseif ($paragraphStyle) {\n            ++$paragraphStyleCount;\n            $parstylename = \"P$paragraphStyleCount\" . \"_$paragraphStyle\";\n            $style = $phpWord->addParagraphStyle($parstylename, $paragraphStyle);\n            $style->setAuto();\n            $element->setParagraphStyle($parstylename);\n        }\n    }\n\n    /**\n     * Finds all tracked changes.\n     *\n     * @param \\PhpOffice\\PhpWord\\Element\\AbstractElement[] $trackedChanges\n     */\n    private function collectTrackedChanges(AbstractContainer $container, &$trackedChanges = []): void\n    {\n        $elements = $container->getElements();\n        foreach ($elements as $element) {\n            if ($element->getTrackChange() != null) {\n                $trackedChanges[] = $element;\n            }\n            if (is_callable([$element, 'getElements'])) {\n                $this->collectTrackedChanges($element, $trackedChanges);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/ODText/Part/Manifest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\ODText\\Part;\n\nuse PhpOffice\\PhpWord\\Element\\Formula;\nuse PhpOffice\\PhpWord\\Media;\nuse PhpOffice\\PhpWord\\Writer\\ODText;\n\n/**\n * ODText manifest part writer: META-INF/manifest.xml.\n */\nclass Manifest extends AbstractPart\n{\n    /**\n     * Write part.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startDocument('1.0', 'UTF-8');\n        $xmlWriter->startElement('manifest:manifest');\n        $xmlWriter->writeAttribute('manifest:version', '1.2');\n        $xmlWriter->writeAttribute('xmlns:manifest', 'urn:oasis:names:tc:opendocument:xmlns:manifest:1.0');\n\n        $xmlWriter->startElement('manifest:file-entry');\n        $xmlWriter->writeAttribute('manifest:media-type', 'application/vnd.oasis.opendocument.text');\n        $xmlWriter->writeAttribute('manifest:full-path', '/');\n        $xmlWriter->writeAttribute('manifest:version', '1.2');\n        $xmlWriter->endElement();\n\n        // Parts\n        foreach (['content.xml', 'meta.xml', 'styles.xml'] as $part) {\n            $xmlWriter->startElement('manifest:file-entry');\n            $xmlWriter->writeAttribute('manifest:media-type', 'text/xml');\n            $xmlWriter->writeAttribute('manifest:full-path', $part);\n            $xmlWriter->endElement();\n        }\n\n        // Media files\n        $media = Media::getElements('section');\n        foreach ($media as $medium) {\n            if ($medium['type'] == 'image') {\n                $xmlWriter->startElement('manifest:file-entry');\n                $xmlWriter->writeAttribute('manifest:media-type', $medium['imageType']);\n                $xmlWriter->writeAttribute('manifest:full-path', 'Pictures/' . $medium['target']);\n                $xmlWriter->endElement();\n            }\n        }\n\n        foreach ($this->getObjects() as $idxObject => $object) {\n            if ($object instanceof Formula) {\n                $xmlWriter->startElement('manifest:file-entry');\n                $xmlWriter->writeAttribute('manifest:full-path', 'Formula' . $idxObject . '/content.xml');\n                $xmlWriter->writeAttribute('manifest:media-type', 'text/xml');\n                $xmlWriter->endElement();\n                $xmlWriter->startElement('manifest:file-entry');\n                $xmlWriter->writeAttribute('manifest:full-path', 'Formula' . $idxObject . '/');\n                $xmlWriter->writeAttribute('manifest:version', '1.2');\n                $xmlWriter->writeAttribute('manifest:media-type', 'application/vnd.oasis.opendocument.formula');\n                $xmlWriter->endElement();\n            }\n        }\n\n        $xmlWriter->endElement(); // manifest:manifest\n\n        return $xmlWriter->getData();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/ODText/Part/Meta.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\ODText\\Part;\n\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\n\n/**\n * ODText meta part writer: meta.xml.\n *\n * @since 0.11.0\n */\nclass Meta extends AbstractPart\n{\n    /**\n     * Write part.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $phpWord = $this->getParentWriter()->getPhpWord();\n        $docProps = $phpWord->getDocInfo();\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startDocument('1.0', 'UTF-8');\n        $xmlWriter->startElement('office:document-meta');\n        $xmlWriter->writeAttribute('office:version', '1.2');\n        $xmlWriter->writeAttribute('xmlns:office', 'urn:oasis:names:tc:opendocument:xmlns:office:1.0');\n        $xmlWriter->writeAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink');\n        $xmlWriter->writeAttribute('xmlns:dc', 'http://purl.org/dc/elements/1.1/');\n        $xmlWriter->writeAttribute('xmlns:meta', 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0');\n        $xmlWriter->writeAttribute('xmlns:ooo', 'http://openoffice.org/2004/office');\n        $xmlWriter->writeAttribute('xmlns:grddl', 'http://www.w3.org/2003/g/data-view#');\n        $xmlWriter->startElement('office:meta');\n\n        // Core properties\n        $xmlWriter->writeElement('dc:title', $docProps->getTitle());\n        $xmlWriter->writeElement('dc:subject', $docProps->getSubject());\n        $xmlWriter->writeElement('dc:description', $docProps->getDescription());\n        $xmlWriter->writeElement('dc:creator', $docProps->getLastModifiedBy());\n        $xmlWriter->writeElement('dc:date', gmdate($this->dateFormat, $docProps->getModified()));\n\n        // Extended properties\n        $xmlWriter->writeElement('meta:generator', 'PHPWord');\n        $xmlWriter->writeElement('meta:initial-creator', $docProps->getCreator());\n        $xmlWriter->writeElement('meta:creation-date', gmdate($this->dateFormat, $docProps->getCreated()));\n        $xmlWriter->writeElement('meta:keyword', $docProps->getKeywords());\n\n        // Category, company, and manager are put in meta namespace\n        $properties = ['Category', 'Company', 'Manager'];\n        foreach ($properties as $property) {\n            $method = \"get{$property}\";\n            if ($docProps->$method() !== null) {\n                $this->writeCustomProperty($xmlWriter, $property, $docProps->$method());\n            }\n        }\n\n        // Other custom properties\n        // @todo Check type. Currently all assumed as string\n        foreach ($docProps->getCustomProperties() as $property) {\n            $value = $docProps->getCustomPropertyValue($property);\n            $this->writeCustomProperty($xmlWriter, $property, $value);\n        }\n\n        $xmlWriter->endElement(); // office:meta\n        $xmlWriter->endElement(); // office:document-meta\n\n        return $xmlWriter->getData();\n    }\n\n    /**\n     * Write individual property.\n     *\n     * @param string $property\n     * @param string $value\n     *\n     * @todo Handle other `$type`: double|date|dateTime|duration|boolean (4th arguments)\n     */\n    private function writeCustomProperty(XMLWriter $xmlWriter, $property, $value): void\n    {\n        $xmlWriter->startElement('meta:user-defined');\n        $xmlWriter->writeAttribute('meta:name', $property);\n        // if ($type !== null) {\n        //     $xmlWriter->writeAttribute('meta:value-type', $type);\n        // }\n        $this->writeText($value);\n        $xmlWriter->endElement(); // meta:user-defined\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/ODText/Part/Mimetype.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\ODText\\Part;\n\n/**\n * ODText mimetype part writer: mimetype.\n */\nclass Mimetype extends AbstractPart\n{\n    /**\n     * Write part.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        return 'application/vnd.oasis.opendocument.text';\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/ODText/Part/Styles.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\ODText\\Part;\n\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Shared\\Converter;\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\nuse PhpOffice\\PhpWord\\Style;\n\n/**\n * ODText styles part writer: styles.xml.\n */\nclass Styles extends AbstractPart\n{\n    /**\n     * Write part.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $xmlWriter = $this->getXmlWriter();\n\n        // XML header\n        $xmlWriter->startDocument('1.0', 'UTF-8');\n        $xmlWriter->startElement('office:document-styles');\n        $this->writeCommonRootAttributes($xmlWriter);\n\n        // Font declarations\n        $this->writeFontFaces($xmlWriter);\n\n        // Office styles\n        $xmlWriter->startElement('office:styles');\n        $this->writeDefault($xmlWriter);\n        $this->writeNamed($xmlWriter);\n        $xmlWriter->endElement();\n\n        // Automatic styles\n        $xmlWriter->startElement('office:automatic-styles');\n        $this->writePageLayout($xmlWriter);\n        $xmlWriter->endElement(); // office:automatic-styles\n\n        // Master style\n        $this->writeMaster($xmlWriter);\n\n        $xmlWriter->endElement(); // office:document-styles\n\n        return $xmlWriter->getData();\n    }\n\n    /**\n     * Write default styles.\n     */\n    private function writeDefault(XMLWriter $xmlWriter): void\n    {\n        $xmlWriter->startElement('style:default-style');\n        $xmlWriter->writeAttribute('style:family', 'paragraph');\n\n        // Paragraph\n        $xmlWriter->startElement('style:paragraph-properties');\n        $xmlWriter->writeAttribute('fo:hyphenation-ladder-count', 'no-limit');\n        $xmlWriter->writeAttribute('style:text-autospace', 'ideograph-alpha');\n        $xmlWriter->writeAttribute('style:punctuation-wrap', 'hanging');\n        $xmlWriter->writeAttribute('style:line-break', 'strict');\n        $xmlWriter->writeAttribute('style:tab-stop-distance', '1.249cm');\n        $xmlWriter->writeAttribute('style:writing-mode', 'page');\n        $xmlWriter->endElement(); // style:paragraph-properties\n\n        $language = $this->getParentWriter()->getPhpWord()->getSettings()->getThemeFontLang();\n        $latinLang = $language != null && is_string($language->getLatin()) ? explode('-', $language->getLatin()) : ['fr', 'FR'];\n        $asianLang = $language != null && is_string($language->getEastAsia()) ? explode('-', $language->getEastAsia()) : ['zh', 'CN'];\n        $complexLang = $language != null && is_string($language->getBidirectional()) ? explode('-', $language->getBidirectional()) : ['hi', 'IN'];\n        if ($this->getParentWriter()->getPhpWord()->getSettings()->hasHideGrammaticalErrors()) {\n            $latinLang = $asianLang = $complexLang = ['zxx', 'none'];\n        }\n\n        // Font\n        $xmlWriter->startElement('style:text-properties');\n        $xmlWriter->writeAttribute('style:use-window-font-color', 'false');\n        $xmlWriter->writeAttribute('style:font-name', Settings::getDefaultFontName());\n        $xmlWriter->writeAttribute('fo:font-size', Settings::getDefaultFontSize() . 'pt');\n        $xmlWriter->writeAttribute('fo:language', $latinLang[0]);\n        $xmlWriter->writeAttribute('fo:country', $latinLang[1]);\n        $xmlWriter->writeAttribute('fo:color', '#' . Settings::getDefaultFontColor());\n        $xmlWriter->writeAttribute('style:letter-kerning', 'true');\n        $xmlWriter->writeAttribute('style:font-name-asian', Settings::getDefaultFontName() . '2');\n        $xmlWriter->writeAttribute('style:font-size-asian', Settings::getDefaultFontSize() . 'pt');\n        $xmlWriter->writeAttribute('style:language-asian', $asianLang[0]);\n        $xmlWriter->writeAttribute('style:country-asian', $asianLang[1]);\n        $xmlWriter->writeAttribute('style:font-name-complex', Settings::getDefaultFontName() . '2');\n        $xmlWriter->writeAttribute('style:font-size-complex', Settings::getDefaultFontSize() . 'pt');\n        $xmlWriter->writeAttribute('style:language-complex', $complexLang[0]);\n        $xmlWriter->writeAttribute('style:country-complex', $complexLang[1]);\n        $xmlWriter->writeAttribute('fo:hyphenate', 'false');\n        $xmlWriter->writeAttribute('fo:hyphenation-remain-char-count', '2');\n        $xmlWriter->writeAttribute('fo:hyphenation-push-char-count', '2');\n        $xmlWriter->endElement(); // style:text-properties\n\n        $xmlWriter->endElement(); // style:default-style\n    }\n\n    /**\n     * Write named styles.\n     */\n    private function writeNamed(XMLWriter $xmlWriter): void\n    {\n        $styles = Style::getStyles();\n        if (count($styles) > 0) {\n            foreach ($styles as $style) {\n                if ($style->isAuto() === false) {\n                    $styleClass = str_replace('\\\\Style\\\\', '\\\\Writer\\\\ODText\\\\Style\\\\', get_class($style));\n                    if (class_exists($styleClass)) {\n                        /** @var \\PhpOffice\\PhpWord\\Writer\\ODText\\Style\\AbstractStyle $styleWriter Type hint */\n                        $styleWriter = new $styleClass($xmlWriter, $style);\n                        $styleWriter->write();\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Convert int in twips to inches/cm then to string and append unit.\n     *\n     * @param float|int $twips\n     * @param float $factor\n     * return string\n     */\n    private static function cvttwiptostr($twips, $factor = 1.0)\n    {\n        $ins = (string) ($twips * $factor / Converter::INCH_TO_TWIP) . 'in';\n        $cms = (string) ($twips * $factor * Converter::INCH_TO_CM / Converter::INCH_TO_TWIP) . 'cm';\n\n        return (strlen($ins) < strlen($cms)) ? $ins : $cms;\n    }\n\n    /**\n     * call writePageLayoutIndiv to write page layout styles for each page.\n     */\n    private function writePageLayout(XMLWriter $xmlWriter): void\n    {\n        $sections = $this->getParentWriter()->getPhpWord()->getSections();\n        $countsects = count($sections);\n        for ($i = 0; $i < $countsects; ++$i) {\n            $this->writePageLayoutIndiv($xmlWriter, $sections[$i], $i + 1);\n        }\n    }\n\n    /**\n     * Write page layout styles.\n     *\n     * @param \\PhpOffice\\PhpWord\\Element\\Section $section\n     * @param int $sectionNbr\n     */\n    private function writePageLayoutIndiv(XMLWriter $xmlWriter, $section, $sectionNbr): void\n    {\n        $sty = $section->getStyle();\n        if (count($section->getHeaders()) > 0) {\n            $topfactor = 0.5;\n        } else {\n            $topfactor = 1.0;\n        }\n        if (count($section->getFooters()) > 0) {\n            $botfactor = 0.5;\n        } else {\n            $botfactor = 1.0;\n        }\n        $orient = $sty->getOrientation();\n        $pwidth = self::cvttwiptostr($sty->getPageSizeW());\n        $pheight = self::cvttwiptostr($sty->getPageSizeH());\n        $mtop = self::cvttwiptostr($sty->getMarginTop(), $topfactor);\n        $mbottom = self::cvttwiptostr($sty->getMarginBottom(), $botfactor);\n        $mleft = self::cvttwiptostr($sty->getMarginRight());\n        $mright = self::cvttwiptostr($sty->getMarginLeft());\n\n        $xmlWriter->startElement('style:page-layout');\n        $xmlWriter->writeAttribute('style:name', \"Mpm$sectionNbr\");\n\n        $xmlWriter->startElement('style:page-layout-properties');\n        $xmlWriter->writeAttribute('fo:page-width', $pwidth);\n        $xmlWriter->writeAttribute('fo:page-height', $pheight);\n        $xmlWriter->writeAttribute('style:num-format', '1');\n        $xmlWriter->writeAttribute('style:print-orientation', $orient);\n        $xmlWriter->writeAttribute('fo:margin-top', $mtop);\n        $xmlWriter->writeAttribute('fo:margin-bottom', $mbottom);\n        $xmlWriter->writeAttribute('fo:margin-left', $mleft);\n        $xmlWriter->writeAttribute('fo:margin-right', $mright);\n        $xmlWriter->writeAttribute('style:writing-mode', 'lr-tb');\n        $xmlWriter->writeAttribute('style:layout-grid-color', '#c0c0c0');\n        $xmlWriter->writeAttribute('style:layout-grid-lines', '25199');\n        $xmlWriter->writeAttribute('style:layout-grid-base-height', '0.423cm');\n        $xmlWriter->writeAttribute('style:layout-grid-ruby-height', '0cm');\n        $xmlWriter->writeAttribute('style:layout-grid-mode', 'none');\n        $xmlWriter->writeAttribute('style:layout-grid-ruby-below', 'false');\n        $xmlWriter->writeAttribute('style:layout-grid-print', 'false');\n        $xmlWriter->writeAttribute('style:layout-grid-display', 'false');\n        $xmlWriter->writeAttribute('style:layout-grid-base-width', '0.37cm');\n        $xmlWriter->writeAttribute('style:layout-grid-snap-to', 'true');\n        $xmlWriter->writeAttribute('style:footnote-max-height', '0cm');\n\n        $xmlWriter->startElement('style:footnote-sep');\n        $xmlWriter->writeAttribute('style:width', '0.018cm');\n        $xmlWriter->writeAttribute('style:line-style', 'solid');\n        $xmlWriter->writeAttribute('style:adjustment', 'left');\n        $xmlWriter->writeAttribute('style:rel-width', '25%');\n        $xmlWriter->writeAttribute('style:color', '#000000');\n        $xmlWriter->endElement(); //style:footnote-sep\n\n        $xmlWriter->endElement(); // style:page-layout-properties\n\n        $xmlWriter->startElement('style:header-style');\n        if ($topfactor < 1.0) {\n            $xmlWriter->startElement('style:header-footer-properties');\n            $xmlWriter->writeAttribute('fo:min-height', $mtop);\n            $xmlWriter->writeAttribute('fo:margin-bottom', $mtop);\n            $xmlWriter->writeAttribute('style:dynamic-spacing', 'true');\n            $xmlWriter->endElement(); // style:header-footer-properties\n        }\n        $xmlWriter->endElement(); // style:header-style\n\n        $xmlWriter->startElement('style:footer-style');\n        if ($botfactor < 1.0) {\n            $xmlWriter->startElement('style:header-footer-properties');\n            $xmlWriter->writeAttribute('fo:min-height', $mbottom);\n            $xmlWriter->writeAttribute('fo:margin-top', $mbottom);\n            $xmlWriter->writeAttribute('style:dynamic-spacing', 'true');\n            $xmlWriter->endElement(); // style:header-footer-properties\n        }\n        $xmlWriter->endElement(); // style:footer-style\n\n        $xmlWriter->endElement(); // style:page-layout\n    }\n\n    /**\n     * Write master style.\n     */\n    private function writeMaster(XMLWriter $xmlWriter): void\n    {\n        $xmlWriter->startElement('office:master-styles');\n\n        $sections = $this->getParentWriter()->getPhpWord()->getSections();\n        $countsects = count($sections);\n        for ($i = 0; $i < $countsects; ++$i) {\n            $iplus1 = $i + 1;\n            $xmlWriter->startElement('style:master-page');\n            $xmlWriter->writeAttribute('style:name', \"Standard$iplus1\");\n            $xmlWriter->writeAttribute('style:page-layout-name', \"Mpm$iplus1\");\n            // Multiple headers and footers probably not supported,\n            //   and, even if they are, I'm not sure how,\n            //   so quit after generating one.\n            foreach ($sections[$i]->getHeaders() as $hdr) {\n                $xmlWriter->startElement('style:header');\n                foreach ($hdr->getElements() as $elem) {\n                    $cl1 = get_class($elem);\n                    $cl2 = str_replace('\\\\Element\\\\', '\\\\Writer\\\\ODText\\\\Element\\\\', $cl1);\n                    if (class_exists($cl2)) {\n                        $wtr = new $cl2($xmlWriter, $elem);\n                        $wtr->write();\n                    }\n                }\n                $xmlWriter->endElement(); // style:header\n\n                break;\n            }\n            foreach ($sections[$i]->getFooters() as $hdr) {\n                $xmlWriter->startElement('style:footer');\n                foreach ($hdr->getElements() as $elem) {\n                    $cl1 = get_class($elem);\n                    $cl2 = str_replace('\\\\Element\\\\', '\\\\Writer\\\\ODText\\\\Element\\\\', $cl1);\n                    if (class_exists($cl2)) {\n                        $wtr = new $cl2($xmlWriter, $elem);\n                        $wtr->write();\n                    }\n                }\n                $xmlWriter->endElement(); // style:footer\n\n                break;\n            }\n            $xmlWriter->endElement(); // style:master-page\n        }\n        $xmlWriter->endElement(); // office:master-styles\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/ODText/Style/AbstractStyle.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\ODText\\Style;\n\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\AbstractStyle as Word2007AbstractStyle;\n\n/**\n * Style writer.\n *\n * @since 0.10.0\n */\nabstract class AbstractStyle extends Word2007AbstractStyle\n{\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/ODText/Style/Font.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\ODText\\Style;\n\n/**\n * Font style writer.\n *\n * @since 0.10.0\n */\nclass Font extends AbstractStyle\n{\n    /**\n     * Write style.\n     */\n    public function write(): void\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof \\PhpOffice\\PhpWord\\Style\\Font) {\n            return;\n        }\n        $xmlWriter = $this->getXmlWriter();\n\n        $stylep = $style->getParagraph();\n        if ($stylep instanceof \\PhpOffice\\PhpWord\\Style\\Paragraph) {\n            $temp1 = clone $stylep;\n            $temp1->setStyleName($style->getStyleName());\n            $temp2 = new Paragraph($xmlWriter, $temp1);\n            $temp2->write();\n        }\n\n        $xmlWriter->startElement('style:style');\n        $xmlWriter->writeAttribute('style:name', $style->getStyleName());\n        $xmlWriter->writeAttribute('style:family', 'text');\n        $xmlWriter->startElement('style:text-properties');\n\n        // Name\n        $font = $style->getName();\n        $xmlWriter->writeAttributeIf($font != '', 'style:font-name', $font);\n        $xmlWriter->writeAttributeIf($font != '', 'style:font-name-complex', $font);\n        $size = $style->getSize();\n\n        // Size\n        $xmlWriter->writeAttributeIf(is_numeric($size), 'fo:font-size', $size . 'pt');\n        $xmlWriter->writeAttributeIf(is_numeric($size), 'style:font-size-asian', $size . 'pt');\n        $xmlWriter->writeAttributeIf(is_numeric($size), 'style:font-size-complex', $size . 'pt');\n\n        // Color\n        $color = $style->getColor();\n        $xmlWriter->writeAttributeIf($color != '', 'fo:color', '#' . \\PhpOffice\\PhpWord\\Shared\\Converter::stringToRgb($color));\n\n        // Bold & italic\n        $xmlWriter->writeAttributeIf($style->isBold(), 'fo:font-weight', 'bold');\n        $xmlWriter->writeAttributeIf($style->isBold(), 'style:font-weight-asian', 'bold');\n        $xmlWriter->writeAttributeIf($style->isItalic(), 'fo:font-style', 'italic');\n        $xmlWriter->writeAttributeIf($style->isItalic(), 'style:font-style-asian', 'italic');\n        $xmlWriter->writeAttributeIf($style->isItalic(), 'style:font-style-complex', 'italic');\n\n        // Underline\n        // @todo Various mode of underline\n        $underline = $style->getUnderline();\n        $xmlWriter->writeAttributeIf($underline != 'none', 'style:text-underline-style', 'solid');\n\n        // Strikethrough, double strikethrough\n        $xmlWriter->writeAttributeIf($style->isStrikethrough(), 'style:text-line-through-type', 'single');\n        $xmlWriter->writeAttributeIf($style->isDoubleStrikethrough(), 'style:text-line-through-type', 'double');\n\n        // Small caps, all caps\n        $xmlWriter->writeAttributeIf($style->isSmallCaps(), 'fo:font-variant', 'small-caps');\n        $xmlWriter->writeAttributeIf($style->isAllCaps(), 'fo:text-transform', 'uppercase');\n\n        //Hidden text\n        $xmlWriter->writeAttributeIf($style->isHidden(), 'text:display', 'none');\n\n        // Superscript/subscript\n        $xmlWriter->writeAttributeIf($style->isSuperScript(), 'style:text-position', 'super');\n        $xmlWriter->writeAttributeIf($style->isSubScript(), 'style:text-position', 'sub');\n\n        if ($style->isNoProof()) {\n            $xmlWriter->writeAttribute('fo:language', 'zxx');\n            $xmlWriter->writeAttribute('style:language-asian', 'zxx');\n            $xmlWriter->writeAttribute('style:language-complex', 'zxx');\n            $xmlWriter->writeAttribute('fo:country', 'none');\n            $xmlWriter->writeAttribute('style:country-asian', 'none');\n            $xmlWriter->writeAttribute('style:country-complex', 'none');\n        }\n\n        // @todo Foreground-Color\n\n        // @todo Background color\n\n        $xmlWriter->endElement(); // style:text-properties\n        $xmlWriter->endElement(); // style:style\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/ODText/Style/Image.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\ODText\\Style;\n\n/**\n * Image style writer.\n *\n * @since 0.11.0\n */\nclass Image extends AbstractStyle\n{\n    /**\n     * Write style.\n     */\n    public function write(): void\n    {\n        /** @var \\PhpOffice\\PhpWord\\Style\\Image $style Type hint */\n        $style = $this->getStyle();\n        if (!$style instanceof \\PhpOffice\\PhpWord\\Style\\Image) {\n            return;\n        }\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startElement('style:style');\n        $xmlWriter->writeAttribute('style:name', $style->getStyleName());\n        $xmlWriter->writeAttribute('style:family', 'graphic');\n        $xmlWriter->writeAttribute('style:parent-style-name', 'Graphics');\n        $xmlWriter->startElement('style:graphic-properties');\n        $xmlWriter->writeAttribute('style:vertical-pos', 'top');\n        $xmlWriter->writeAttribute('style:vertical-rel', 'baseline');\n        $xmlWriter->endElement(); // style:graphic-properties\n        $xmlWriter->endElement(); // style:style\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/ODText/Style/Numbering.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\ODText\\Style;\n\nuse PhpOffice\\PhpWord\\Shared\\Converter;\nuse PhpOffice\\PhpWord\\Style\\Numbering as StyleNumbering;\n\n/**\n * Numbering style writer.\n */\nclass Numbering extends AbstractStyle\n{\n    /**\n     * Write style.\n     */\n    public function write(): void\n    {\n        /** @var StyleNumbering $style Type hint */\n        $style = $this->getStyle();\n        if (!$style instanceof StyleNumbering) {\n            return;\n        }\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startElement('text:list-style');\n        $xmlWriter->writeAttribute('style:name', $style->getStyleName());\n\n        foreach ($style->getLevels() as $styleLevel) {\n            $numLevel = $styleLevel->getLevel() + 1;\n\n            // In Twips\n            $tabPos = $styleLevel->getTabPos();\n            // In Inches\n            $tabPos /= Converter::INCH_TO_TWIP;\n            // In Centimeters\n            $tabPos *= Converter::INCH_TO_CM;\n\n            // In Twips\n            $hanging = $styleLevel->getHanging();\n            // In Inches\n            $hanging /= Converter::INCH_TO_TWIP;\n            // In Centimeters\n            $hanging *= Converter::INCH_TO_CM;\n\n            $xmlWriter->startElement('text:list-level-style-bullet');\n            $xmlWriter->writeAttribute('text:level', $numLevel);\n            $xmlWriter->writeAttribute('text:style-name', $style->getStyleName() . '_' . $numLevel);\n            $xmlWriter->writeAttribute('text:bullet-char', $styleLevel->getText());\n\n            $xmlWriter->startElement('style:list-level-properties');\n            $xmlWriter->writeAttribute('text:list-level-position-and-space-mode', 'label-alignment');\n\n            $xmlWriter->startElement('style:list-level-label-alignment');\n            $xmlWriter->writeAttribute('text:label-followed-by', 'listtab');\n            $xmlWriter->writeAttribute('text:list-tab-stop-position', number_format($tabPos, 2, '.', '') . 'cm');\n            $xmlWriter->writeAttribute('fo:text-indent', '-' . number_format($hanging, 2, '.', '') . 'cm');\n            $xmlWriter->writeAttribute('fo:margin-left', number_format($tabPos, 2, '.', '') . 'cm');\n\n            $xmlWriter->endElement(); // style:list-level-label-alignment\n            $xmlWriter->endElement(); // style:list-level-properties\n\n            $xmlWriter->startElement('style:text-properties');\n            $xmlWriter->writeAttribute('style:font-name', $styleLevel->getFont());\n            $xmlWriter->endElement(); // style:text-properties\n\n            $xmlWriter->endElement(); // text:list-level-style-bullet\n        }\n\n        $xmlWriter->endElement(); // text:list-style\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/ODText/Style/Paragraph.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\ODText\\Style;\n\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Shared\\Converter;\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\nuse PhpOffice\\PhpWord\\Style;\n\n/**\n * Font style writer.\n *\n * @since 0.10.0\n */\nclass Paragraph extends AbstractStyle\n{\n    private const BIDI_MAP = [\n        Jc::END => Jc::LEFT,\n        Jc::START => Jc::RIGHT,\n    ];\n\n    private const NON_BIDI_MAP = [\n        Jc::START => Jc::LEFT,\n        Jc::END => Jc::RIGHT,\n    ];\n\n    /**\n     * Write style.\n     */\n    public function write(): void\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof Style\\Paragraph) {\n            return;\n        }\n        $xmlWriter = $this->getXmlWriter();\n\n        $marginTop = $style->getSpaceBefore();\n        $marginBottom = $style->getSpaceAfter();\n\n        $xmlWriter->startElement('style:style');\n\n        $styleName = (string) $style->getStyleName();\n        $styleAuto = false;\n        $mpm = '';\n        $psm = '';\n        $pagestart = -1;\n        $breakafter = $breakbefore = $breakauto = false;\n        if ($style->isAuto()) {\n            if (substr($styleName, 0, 2) === 'PB') {\n                $styleAuto = true;\n                $breakafter = true;\n            } elseif (substr($styleName, 0, 2) === 'SB') {\n                $styleAuto = true;\n                $mpm = 'Standard' . substr($styleName, 2);\n                $psn = $style->getNumLevel();\n                $pagestart = $psn;\n            } elseif (substr($styleName, 0, 2) === 'HD') {\n                $styleAuto = true;\n                $psm = 'Heading_' . substr($styleName, 2);\n                $stylep = Style::getStyle($psm);\n                if ($stylep instanceof Style\\Font) {\n                    $stylep = $stylep->getParagraph();\n                }\n                if ($stylep instanceof Style\\Paragraph) {\n                    if ($stylep->hasPageBreakBefore()) {\n                        $breakbefore = true;\n                    }\n                }\n            } elseif (substr($styleName, 0, 2) === 'HE') {\n                $styleAuto = true;\n                $psm = 'Heading_' . substr($styleName, 2);\n                $breakauto = true;\n            } else {\n                $styleAuto = true;\n                $psm = 'Normal';\n                if (preg_match('/^P\\\\d+_(\\\\w+)$/', $styleName, $matches)) {\n                    $psm = $matches[1];\n                }\n            }\n        }\n\n        $xmlWriter->writeAttribute('style:name', $style->getStyleName());\n        $xmlWriter->writeAttribute('style:family', 'paragraph');\n        if ($styleAuto) {\n            $xmlWriter->writeAttributeIf($psm !== '', 'style:parent-style-name', $psm);\n            $xmlWriter->writeAttributeIf($mpm !== '', 'style:master-page-name', $mpm);\n        }\n\n        $xmlWriter->startElement('style:paragraph-properties');\n        if ($styleAuto) {\n            if ($breakafter) {\n                $xmlWriter->writeAttribute('fo:break-after', 'page');\n                $xmlWriter->writeAttribute('fo:margin-top', '0cm');\n                $xmlWriter->writeAttribute('fo:margin-bottom', '0cm');\n            } elseif ($breakbefore) {\n                $xmlWriter->writeAttribute('fo:break-before', 'page');\n            } elseif ($breakauto) {\n                $xmlWriter->writeAttribute('fo:break-before', 'auto');\n            }\n            if ($pagestart > 0) {\n                $xmlWriter->writeAttribute('style:page-number', $pagestart);\n            }\n        }\n        if (!$breakafter && !$breakbefore && !$breakauto) {\n            $twipToPoint = Converter::INCH_TO_TWIP / Converter::INCH_TO_POINT; // 20\n            $xmlWriter->writeAttributeIf($marginTop !== null, 'fo:margin-top', ($marginTop / $twipToPoint) . 'pt');\n            $xmlWriter->writeAttributeIf($marginBottom !== null, 'fo:margin-bottom', ($marginBottom / $twipToPoint) . 'pt');\n        }\n        $alignment = $style->getAlignment();\n        $bidi = $style->isBidi();\n        $defaultRtl = Settings::isDefaultRtl();\n        if ($alignment === '' && $bidi !== null) {\n            $alignment = Jc::START;\n        }\n        if ($bidi) {\n            $alignment = self::BIDI_MAP[$alignment] ?? $alignment;\n        } elseif ($defaultRtl !== null) {\n            $alignment = self::NON_BIDI_MAP[$alignment] ?? $alignment;\n        }\n        $xmlWriter->writeAttributeIf($alignment !== '', 'fo:text-align', $alignment);\n        $temp = $style->getLineHeight();\n        $xmlWriter->writeAttributeIf($temp !== null, 'fo:line-height', ((string) ($temp * 100) . '%'));\n        $xmlWriter->writeAttributeIf($style->hasPageBreakBefore() === true, 'fo:break-before', 'page');\n\n        $tabs = $style->getTabs();\n        if ($tabs !== null && count($tabs) > 0) {\n            $xmlWriter->startElement('style:tab-stops');\n            foreach ($tabs as $tab) {\n                $xmlWriter->startElement('style:tab-stop');\n                $xmlWriter->writeAttribute('style:type', $tab->getType());\n                $xmlWriter->writeAttribute('style:position', (string) ($tab->getPosition() / Converter::INCH_TO_TWIP) . 'in');\n                $xmlWriter->endElement();\n            }\n            $xmlWriter->endElement();\n        }\n\n        //Right to left\n        $xmlWriter->writeAttributeIf($style->isBidi(), 'style:writing-mode', 'rl-tb');\n\n        //Indentation\n        $indent = $style->getIndentation();\n        //if ($indent instanceof \\PhpOffice\\PhpWord\\Style\\Indentation) {\n        if (!empty($indent)) {\n            $marg = $indent->getLeft();\n            $xmlWriter->writeAttributeIf($marg !== null, 'fo:margin-left', (string) ($marg / Converter::INCH_TO_TWIP) . 'in');\n            $marg = $indent->getRight();\n            $xmlWriter->writeAttributeIf($marg !== null, 'fo:margin-right', (string) ($marg / Converter::INCH_TO_TWIP) . 'in');\n        }\n\n        $xmlWriter->endElement(); //style:paragraph-properties\n\n        if ($styleAuto && substr($styleName, 0, 2) === 'SB') {\n            $xmlWriter->startElement('style:text-properties');\n            $xmlWriter->writeAttribute('text:display', 'none');\n            $xmlWriter->endElement();\n        }\n\n        $xmlWriter->endElement(); //style:style\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/ODText/Style/Section.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\ODText\\Style;\n\n/**\n * Section style writer.\n *\n * @since 0.11.0\n */\nclass Section extends AbstractStyle\n{\n    /**\n     * Write style.\n     */\n    public function write(): void\n    {\n        /** @var \\PhpOffice\\PhpWord\\Style\\Section $style Type hint */\n        $style = $this->getStyle();\n        if (!$style instanceof \\PhpOffice\\PhpWord\\Style\\Section) {\n            return;\n        }\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startElement('style:style');\n        $xmlWriter->writeAttribute('style:name', $style->getStyleName());\n        $xmlWriter->writeAttribute('style:family', 'section');\n        $xmlWriter->startElement('style:section-properties');\n\n        $xmlWriter->startElement('style:columns');\n        $xmlWriter->writeAttribute('fo:column-count', $style->getColsNum());\n        $xmlWriter->endElement(); // style:columns\n\n        $xmlWriter->endElement(); // style:section-properties\n        $xmlWriter->endElement(); // style:style\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/ODText/Style/Table.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\ODText\\Style;\n\n/**\n * Table style writer.\n *\n * @since 0.11.0\n */\nclass Table extends AbstractStyle\n{\n    /**\n     * Write style.\n     */\n    public function write(): void\n    {\n        /** @var \\PhpOffice\\PhpWord\\Style\\Table $style Type hint */\n        $style = $this->getStyle();\n        if (!$style instanceof \\PhpOffice\\PhpWord\\Style\\Table) {\n            return;\n        }\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startElement('style:style');\n        $xmlWriter->writeAttribute('style:name', $style->getStyleName());\n        $xmlWriter->writeAttribute('style:family', 'table');\n        $xmlWriter->startElement('style:table-properties');\n        //$xmlWriter->writeAttribute('style:width', 'table');\n        $xmlWriter->writeAttribute('style:rel-width', 100);\n        $xmlWriter->writeAttribute('table:align', 'center');\n        $xmlWriter->writeAttributeIf($style->isBidiVisual(), 'style:writing-mode', 'rl-tb');\n        $xmlWriter->endElement(); // style:table-properties\n        $xmlWriter->endElement(); // style:style\n\n        $cellWidths = $style->getColumnWidths();\n        $countCellWidths = $cellWidths === null ? 0 : count($cellWidths);\n\n        for ($i = 0; $i < $countCellWidths; ++$i) {\n            $width = $cellWidths[$i];\n            $xmlWriter->startElement('style:style');\n            $xmlWriter->writeAttribute('style:name', $style->getStyleName() . '.' . $i);\n            $xmlWriter->writeAttribute('style:family', 'table-column');\n            $xmlWriter->startElement('style:table-column-properties');\n            $xmlWriter->writeAttribute('style:column-width', number_format($width * 0.0017638889, 2, '.', '') . 'cm');\n            $xmlWriter->endElement(); // style:table-column-properties\n            $xmlWriter->endElement(); // style:style\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/ODText.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer;\n\nuse PhpOffice\\Math\\Writer\\MathML;\nuse PhpOffice\\PhpWord\\Element\\AbstractElement;\nuse PhpOffice\\PhpWord\\Element\\Formula;\nuse PhpOffice\\PhpWord\\Media;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Writer\\ODText\\Part\\AbstractPart;\n\n/**\n * ODText writer.\n *\n * @since 0.7.0\n */\nclass ODText extends AbstractWriter implements WriterInterface\n{\n    /**\n     * @var AbstractElement[]\n     */\n    protected $objects = [];\n\n    /**\n     * Create new ODText writer.\n     */\n    public function __construct(?PhpWord $phpWord = null)\n    {\n        // Assign PhpWord\n        $this->setPhpWord($phpWord);\n\n        // Create parts\n        $this->parts = [\n            'Mimetype' => 'mimetype',\n            'Content' => 'content.xml',\n            'Meta' => 'meta.xml',\n            'Styles' => 'styles.xml',\n            'Manifest' => 'META-INF/manifest.xml',\n        ];\n        foreach (array_keys($this->parts) as $partName) {\n            $partClass = static::class . '\\\\Part\\\\' . $partName;\n            if (class_exists($partClass)) {\n                /** @var AbstractPart $partObject Type hint */\n                $partObject = new $partClass();\n                $partObject->setParentWriter($this);\n                $this->writerParts[strtolower($partName)] = $partObject;\n            }\n        }\n\n        // Set package paths\n        $this->mediaPaths = ['image' => 'Pictures/'];\n    }\n\n    /**\n     * Save PhpWord to file.\n     */\n    public function save(string $filename): void\n    {\n        $filename = $this->getTempFile($filename);\n        $zip = $this->getZipArchive($filename);\n\n        // Add section media files\n        $sectionMedia = Media::getElements('section');\n        if (!empty($sectionMedia)) {\n            $this->addFilesToPackage($zip, $sectionMedia);\n        }\n\n        // Write parts\n        foreach ($this->parts as $partName => $fileName) {\n            if ($fileName === '') {\n                continue;\n            }\n            $part = $this->getWriterPart($partName);\n            if (!$part instanceof AbstractPart) {\n                continue;\n            }\n\n            $part->setObjects($this->objects);\n\n            $zip->addFromString($fileName, $part->write());\n\n            $this->objects = $part->getObjects();\n        }\n\n        // Write objects charts\n        if (!empty($this->objects)) {\n            $writer = new MathML();\n            foreach ($this->objects as $idxObject => $object) {\n                if ($object instanceof Formula) {\n                    $zip->addFromString('Formula' . $idxObject . '/content.xml', $writer->write($object->getMath()));\n                }\n            }\n        }\n\n        // Close zip archive and cleanup temp file\n        $zip->close();\n        $this->cleanupTempFile();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/PDF/AbstractRenderer.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PhpWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\PDF;\n\nuse PhpOffice\\PhpWord\\Exception\\Exception;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Writer\\HTML;\n\n/**\n * Abstract PDF renderer.\n *\n * @since 0.10.0\n */\nabstract class AbstractRenderer extends HTML\n{\n    /**\n     * Name of renderer include file.\n     *\n     * @var string\n     */\n    protected $includeFile;\n\n    /**\n     * Temporary storage directory.\n     *\n     * @var string\n     */\n    protected $tempDir = '';\n\n    /**\n     * Font.\n     *\n     * @var string\n     */\n    protected $font;\n\n    /**\n     * Paper size.\n     *\n     * @var int\n     */\n    protected $paperSize;\n\n    /**\n     * Orientation.\n     *\n     * @var string\n     */\n    protected $orientation;\n\n    /**\n     * Paper Sizes xRef List.\n     *\n     * @var array\n     */\n    protected static $paperSizes = [\n        9 => 'A4', // (210 mm by 297 mm)\n    ];\n\n    /**\n     * Create new instance.\n     *\n     * @param PhpWord $phpWord PhpWord object\n     */\n    public function __construct(PhpWord $phpWord)\n    {\n        parent::__construct($phpWord);\n        $this->isPdf = true;\n        if ($this->includeFile != null) {\n            $includeFile = Settings::getPdfRendererPath() . '/' . $this->includeFile;\n            if (file_exists($includeFile)) {\n                /** @noinspection PhpIncludeInspection Dynamic includes */\n                require_once $includeFile;\n            } else {\n                // @codeCoverageIgnoreStart\n                // Can't find any test case. Uncomment when found.\n                throw new Exception('Unable to load PDF Rendering library');\n                // @codeCoverageIgnoreEnd\n            }\n        }\n\n        // Configuration\n        $options = Settings::getPdfRendererOptions();\n        if (!empty($options['font'])) {\n            $this->setFont($options['font']);\n        }\n    }\n\n    /**\n     * Get Font.\n     *\n     * @return string\n     */\n    public function getFont()\n    {\n        return $this->font;\n    }\n\n    /**\n     * Set font. Examples:\n     *      'arialunicid0-chinese-simplified'\n     *      'arialunicid0-chinese-traditional'\n     *      'arialunicid0-korean'\n     *      'arialunicid0-japanese'.\n     *\n     * @param string $fontName\n     *\n     * @return self\n     */\n    public function setFont($fontName)\n    {\n        $this->font = $fontName;\n\n        return $this;\n    }\n\n    /**\n     * Get Paper Size.\n     *\n     * @return int\n     */\n    public function getPaperSize()\n    {\n        return $this->paperSize;\n    }\n\n    /**\n     * Set Paper Size.\n     *\n     * @param int $value Paper size = PAPERSIZE_A4\n     *\n     * @return self\n     */\n    public function setPaperSize($value = 9)\n    {\n        $this->paperSize = $value;\n\n        return $this;\n    }\n\n    /**\n     * Get Orientation.\n     *\n     * @return string\n     */\n    public function getOrientation()\n    {\n        return $this->orientation;\n    }\n\n    /**\n     * Set Orientation.\n     *\n     * @param string $value Page orientation ORIENTATION_DEFAULT\n     *\n     * @return self\n     */\n    public function setOrientation($value = 'default')\n    {\n        $this->orientation = $value;\n\n        return $this;\n    }\n\n    /**\n     * Save PhpWord to PDF file, pre-save.\n     *\n     * @param string $filename Name of the file to save as\n     *\n     * @return resource\n     */\n    protected function prepareForSave($filename = null)\n    {\n        $fileHandle = fopen($filename, 'wb');\n        // @codeCoverageIgnoreStart\n        // Can't find any test case. Uncomment when found.\n        if ($fileHandle === false) {\n            throw new Exception(\"Could not open file $filename for writing.\");\n        }\n        // @codeCoverageIgnoreEnd\n\n        return $fileHandle;\n    }\n\n    /**\n     * Save PhpWord to PDF file, post-save.\n     *\n     * @param resource $fileHandle\n     */\n    protected function restoreStateAfterSave($fileHandle): void\n    {\n        fclose($fileHandle);\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/PDF/DomPDF.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PhpWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\PDF;\n\nuse Dompdf\\Dompdf as DompdfLib;\nuse Dompdf\\Options;\nuse PhpOffice\\PhpWord\\Writer\\WriterInterface;\n\n/**\n * DomPDF writer.\n *\n * @see  https://github.com/dompdf/dompdf\n * @since 0.10.0\n */\nclass DomPDF extends AbstractRenderer implements WriterInterface\n{\n    /**\n     * Name of renderer include file.\n     *\n     * @var string\n     */\n    protected $includeFile;\n\n    /**\n     * Gets the implementation of external PDF library that should be used.\n     *\n     * @return Dompdf implementation\n     */\n    protected function createExternalWriterInstance()\n    {\n        $options = new Options();\n        if ($this->getFont()) {\n            $options->set('defaultFont', $this->getFont());\n        }\n\n        return new DompdfLib($options);\n    }\n\n    /**\n     * Save PhpWord to file.\n     */\n    public function save(string $filename): void\n    {\n        $fileHandle = parent::prepareForSave($filename);\n\n        //  PDF settings\n        $paperSize = 'A4';\n        $orientation = 'portrait';\n\n        //  Create PDF\n        $pdf = $this->createExternalWriterInstance();\n        $pdf->setPaper(strtolower($paperSize), $orientation);\n        $pdf->loadHtml(str_replace(PHP_EOL, '', $this->getContent()));\n        $pdf->render();\n\n        //  Write to file\n        fwrite($fileHandle, $pdf->output());\n\n        parent::restoreStateAfterSave($fileHandle);\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/PDF/MPDF.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PhpWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\PDF;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Writer\\WriterInterface;\n\n/**\n * MPDF writer.\n *\n * @see  http://www.mpdf1.com/\n * @since 0.11.0\n */\nclass MPDF extends AbstractRenderer implements WriterInterface\n{\n    public const SIMULATED_BODY_START = '<!-- simulated body start -->';\n    private const BODY_TAG = '<body>';\n\n    /**\n     * Overridden to set the correct includefile, only needed for MPDF 5.\n     *\n     * @codeCoverageIgnore\n     */\n    public function __construct(PhpWord $phpWord)\n    {\n        if (file_exists(Settings::getPdfRendererPath() . '/mpdf.php')) {\n            // MPDF version 5.* needs this file to be included, later versions not\n            $this->includeFile = 'mpdf.php';\n        }\n        parent::__construct($phpWord);\n    }\n\n    /**\n     * Gets the implementation of external PDF library that should be used.\n     *\n     * @return \\Mpdf\\Mpdf implementation\n     */\n    protected function createExternalWriterInstance()\n    {\n        $mPdfClass = $this->getMPdfClassName();\n\n        $options = [];\n        if ($this->getFont()) {\n            $options['default_font'] = $this->getFont();\n        }\n\n        return new $mPdfClass($options);\n    }\n\n    /**\n     * Save PhpWord to file.\n     */\n    public function save(string $filename): void\n    {\n        $fileHandle = parent::prepareForSave($filename);\n\n        //  PDF settings\n        $paperSize = strtoupper('A4');\n        $orientation = strtoupper('portrait');\n\n        //  Create PDF\n        $pdf = $this->createExternalWriterInstance();\n        $pdf->_setPageSize($paperSize, $orientation);\n        $pdf->addPage($orientation);\n\n        // Write document properties\n        $phpWord = $this->getPhpWord();\n        $docProps = $phpWord->getDocInfo();\n        $pdf->setTitle($docProps->getTitle());\n        $pdf->setAuthor($docProps->getCreator());\n        $pdf->setSubject($docProps->getSubject());\n        $pdf->setKeywords($docProps->getKeywords());\n        $pdf->setCreator($docProps->getCreator());\n\n        $html = $this->getContent();\n        $bodyLocation = strpos($html, self::SIMULATED_BODY_START);\n        if ($bodyLocation === false) {\n            $bodyLocation = strpos($html, self::BODY_TAG);\n            if ($bodyLocation !== false) {\n                $bodyLocation += strlen(self::BODY_TAG);\n            }\n        }\n        // Make sure first data presented to Mpdf includes body tag\n        //   (and any htmlpageheader/htmlpagefooter tags)\n        //   so that Mpdf doesn't parse it as content. Issue 2432.\n        if ($bodyLocation !== false) {\n            $pdf->WriteHTML(substr($html, 0, $bodyLocation));\n            $html = substr($html, $bodyLocation);\n        }\n        foreach (explode(\"\\n\", $html) as $line) {\n            $pdf->WriteHTML(\"$line\\n\");\n        }\n\n        //  Write to file\n        fwrite($fileHandle, $pdf->output($filename, 'S'));\n\n        parent::restoreStateAfterSave($fileHandle);\n    }\n\n    /**\n     * Return classname of MPDF to instantiate.\n     *\n     * @codeCoverageIgnore\n     *\n     * @return string\n     */\n    private function getMPdfClassName()\n    {\n        if ($this->includeFile != null) {\n            // MPDF version 5.*\n            return '\\mpdf';\n        }\n\n        // MPDF version > 6.*\n        return '\\Mpdf\\Mpdf';\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/PDF/TCPDF.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PhpWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\PDF;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Style;\nuse PhpOffice\\PhpWord\\Writer\\WriterInterface;\nuse TCPDF as TCPDFBase;\n\n/**\n * TCPDF writer.\n *\n * @deprecated 0.13.0 Use `DomPDF` or `MPDF` instead.\n * @see  http://www.tcpdf.org/\n * @since 0.11.0\n */\nclass TCPDF extends AbstractRenderer implements WriterInterface\n{\n    /**\n     * Name of renderer include file.\n     *\n     * @var string\n     */\n    protected $includeFile = 'tcpdf.php';\n\n    /**\n     * Gets the implementation of external PDF library that should be used.\n     *\n     * @param string $orientation Page orientation\n     * @param string $unit Unit measure\n     * @param string $paperSize Paper size\n     *\n     * @return TCPDFBase implementation\n     */\n    protected function createExternalWriterInstance($orientation, $unit, $paperSize)\n    {\n        $instance = new TCPDFBase($orientation, $unit, $paperSize);\n\n        if ($this->getFont()) {\n            $instance->setFont($this->getFont(), $instance->getFontStyle(), $instance->getFontSizePt());\n        }\n\n        return $instance;\n    }\n\n    /**\n     * Overwriteable function to allow user to extend TCPDF.\n     * There should always be an AddPage call, preceded or followed\n     *   by code to customize TCPDF configuration.\n     * The customization below sets vertical spacing\n     *   between paragaraphs when the user has\n     *   explicitly set those values to numeric in default style.\n     */\n    protected function prepareToWrite(TCPDFBase $pdf): void\n    {\n        $pdf->AddPage();\n        $customStyles = Style::getStyles();\n        $normal = $customStyles['Normal'] ?? null;\n        if ($normal instanceof Style\\Paragraph) {\n            $before = $normal->getSpaceBefore();\n            $after = $normal->getSpaceAfter();\n            if (is_numeric($before) && is_numeric($after)) {\n                $height = $normal->getLineHeight() ?? '';\n                $pdf->setHtmlVSpace([\n                    'p' => [\n                        ['n' => $before, 'h' => $height],\n                        ['n' => $after, 'h' => $height],\n                    ],\n                ]);\n            }\n        }\n    }\n\n    /**\n     * Save PhpWord to file.\n     */\n    public function save(string $filename): void\n    {\n        $fileHandle = parent::prepareForSave($filename);\n\n        //  PDF settings\n        $paperSize = strtoupper(Settings::getDefaultPaper());\n        $orientation = 'P';\n\n        // Create PDF\n        $pdf = $this->createExternalWriterInstance($orientation, 'pt', $paperSize);\n        $pdf->setFontSubsetting(false);\n        $pdf->setPrintHeader(false);\n        $pdf->setPrintFooter(false);\n        $pdf->SetFont($this->getFont());\n        $this->prepareToWrite($pdf);\n        $pdf->writeHTML($this->getContent());\n\n        // Write document properties\n        $phpWord = $this->getPhpWord();\n        $docProps = $phpWord->getDocInfo();\n        $pdf->SetTitle($docProps->getTitle());\n        $pdf->SetAuthor($docProps->getCreator());\n        $pdf->SetSubject($docProps->getSubject());\n        $pdf->SetKeywords($docProps->getKeywords());\n        $pdf->SetCreator($docProps->getCreator());\n\n        //  Write to file\n        fwrite($fileHandle, $pdf->Output($filename, 'S'));\n\n        parent::restoreStateAfterSave($fileHandle);\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/PDF.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PhpWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer;\n\nuse PhpOffice\\PhpWord\\Exception\\Exception;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Writer\\PDF\\AbstractRenderer;\n\n/**\n * PDF Writer.\n *\n * @since 0.10.0\n */\nclass PDF\n{\n    /**\n     * The wrapper for the requested PDF rendering engine.\n     *\n     * @var AbstractRenderer\n     */\n    private $renderer;\n\n    /**\n     * Instantiate a new renderer of the configured type within this container class.\n     */\n    public function __construct(PhpWord $phpWord)\n    {\n        $pdfLibraryName = Settings::getPdfRendererName();\n        $pdfLibraryPath = Settings::getPdfRendererPath();\n        if (null === $pdfLibraryName || null === $pdfLibraryPath) {\n            throw new Exception('PDF rendering library or library path has not been defined.');\n        }\n\n        $includePath = str_replace('\\\\', '/', get_include_path());\n        $rendererPath = str_replace('\\\\', '/', $pdfLibraryPath);\n        if (strpos($rendererPath, $includePath) === false) {\n            set_include_path(get_include_path() . PATH_SEPARATOR . $pdfLibraryPath);\n        }\n\n        $rendererName = static::class . '\\\\' . $pdfLibraryName;\n        $this->renderer = new $rendererName($phpWord);\n    }\n\n    /**\n     * Magic method to handle direct calls to the configured PDF renderer wrapper class.\n     *\n     * @param string $name Renderer library method name\n     * @param mixed[] $arguments Array of arguments to pass to the renderer method\n     *\n     * @return mixed Returned data from the PDF renderer wrapper method\n     */\n    public function __call($name, $arguments)\n    {\n        // Note: Commented because all exceptions should already be catched by `__construct`\n        // if ($this->renderer === null) {\n        //     throw new Exception(\"PDF Rendering library has not been defined.\");\n        // }\n\n        return call_user_func_array([$this->getRenderer(), $name], $arguments);\n    }\n\n    public function save(string $filename): void\n    {\n        $this->getRenderer()->save($filename);\n    }\n\n    public function getRenderer(): AbstractRenderer\n    {\n        return $this->renderer;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/RTF/Element/AbstractElement.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\RTF\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\AbstractElement as Element;\nuse PhpOffice\\PhpWord\\Escaper\\Rtf;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Shared\\Text as SharedText;\nuse PhpOffice\\PhpWord\\Style;\nuse PhpOffice\\PhpWord\\Style\\Font as FontStyle;\nuse PhpOffice\\PhpWord\\Style\\Paragraph as ParagraphStyle;\nuse PhpOffice\\PhpWord\\Writer\\RTF as WriterRTF;\nuse PhpOffice\\PhpWord\\Writer\\RTF\\Style\\Font as FontStyleWriter;\nuse PhpOffice\\PhpWord\\Writer\\RTF\\Style\\Paragraph as ParagraphStyleWriter;\n\n/**\n * Abstract RTF element writer.\n *\n * @since 0.11.0\n */\nabstract class AbstractElement\n{\n    /**\n     * Parent writer.\n     *\n     * @var WriterRTF\n     */\n    protected $parentWriter;\n\n    /**\n     * Element.\n     *\n     * @var Element\n     */\n    protected $element;\n\n    /**\n     * Without paragraph.\n     *\n     * @var bool\n     */\n    protected $withoutP = false;\n\n    /**\n     * Write element.\n     *\n     * @return string\n     */\n    abstract public function write();\n\n    /**\n     * Font style.\n     *\n     * @var FontStyle\n     */\n    protected $fontStyle;\n\n    /**\n     * Paragraph style.\n     *\n     * @var ParagraphStyle\n     */\n    protected $paragraphStyle;\n\n    /**\n     * @var \\PhpOffice\\PhpWord\\Escaper\\EscaperInterface\n     */\n    protected $escaper;\n\n    public function __construct(WriterRTF $parentWriter, Element $element, bool $withoutP = false)\n    {\n        $this->parentWriter = $parentWriter;\n        $this->element = $element;\n        $this->withoutP = $withoutP;\n        $this->escaper = new Rtf();\n    }\n\n    /**\n     * Get font and paragraph styles.\n     */\n    protected function getStyles(): void\n    {\n        /** @var WriterRTF $parentWriter Type hint */\n        $parentWriter = $this->parentWriter;\n\n        /** @var \\PhpOffice\\PhpWord\\Element\\Text $element Type hint */\n        $element = $this->element;\n\n        // Font style\n        if (method_exists($element, 'getFontStyle')) {\n            $this->fontStyle = $element->getFontStyle();\n            if (is_string($this->fontStyle)) {\n                $this->fontStyle = Style::getStyle($this->fontStyle);\n            }\n        }\n\n        // Paragraph style\n        if (method_exists($element, 'getParagraphStyle')) {\n            $this->paragraphStyle = $element->getParagraphStyle();\n            if (is_string($this->paragraphStyle)) {\n                $this->paragraphStyle = Style::getStyle($this->paragraphStyle);\n            }\n\n            if ($this->paragraphStyle !== null && !$this->withoutP) {\n                if ($parentWriter->getLastParagraphStyle() != $element->getParagraphStyle()) {\n                    $parentWriter->setLastParagraphStyle($element->getParagraphStyle());\n                } else {\n                    $parentWriter->setLastParagraphStyle();\n                    $this->paragraphStyle = null;\n                }\n            } else {\n                $parentWriter->setLastParagraphStyle();\n                $this->paragraphStyle = null;\n            }\n        }\n    }\n\n    /**\n     * Write opening.\n     *\n     * @return string\n     */\n    protected function writeOpening()\n    {\n        if ($this->withoutP || !$this->paragraphStyle instanceof ParagraphStyle) {\n            return '';\n        }\n\n        $styleWriter = new ParagraphStyleWriter($this->paragraphStyle);\n        $styleWriter->setNestedLevel($this->element->getNestedLevel());\n\n        return $styleWriter->write();\n    }\n\n    /**\n     * Write text.\n     *\n     * @param string $text\n     *\n     * @return string\n     */\n    protected function writeText($text)\n    {\n        if (Settings::isOutputEscapingEnabled()) {\n            return $this->escaper->escape($text);\n        }\n\n        return SharedText::toUnicode($text); // todo: replace with `return $text;` later.\n    }\n\n    /**\n     * Write closing.\n     *\n     * @return string\n     */\n    protected function writeClosing()\n    {\n        if ($this->withoutP) {\n            return '';\n        }\n\n        return '\\par' . PHP_EOL;\n    }\n\n    /**\n     * Write font style.\n     *\n     * @return string\n     */\n    protected function writeFontStyle()\n    {\n        if (!$this->fontStyle instanceof FontStyle) {\n            return '';\n        }\n\n        /** @var WriterRTF $parentWriter Type hint */\n        $parentWriter = $this->parentWriter;\n\n        // Create style writer and set color/name index\n        $styleWriter = new FontStyleWriter($this->fontStyle);\n        if ($this->fontStyle->getColor() != null) {\n            $colorIndex = array_search($this->fontStyle->getColor(), $parentWriter->getColorTable());\n            if ($colorIndex !== false) {\n                $styleWriter->setColorIndex($colorIndex + 1);\n            }\n        }\n        if ($this->fontStyle->getName() != null) {\n            $fontIndex = array_search($this->fontStyle->getName(), $parentWriter->getFontTable());\n            if ($fontIndex !== false) {\n                $styleWriter->setNameIndex($fontIndex);\n            }\n        }\n\n        // Write style\n        $content = $styleWriter->write();\n\n        return $content;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/RTF/Element/Container.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\RTF\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\AbstractContainer as ContainerElement;\n\n/**\n * Container element RTF writer.\n *\n * @since 0.11.0\n */\nclass Container extends AbstractElement\n{\n    /**\n     * Namespace; Can't use __NAMESPACE__ in inherited class (RTF).\n     *\n     * @var string\n     */\n    protected $namespace = 'PhpOffice\\\\PhpWord\\\\Writer\\\\RTF\\\\Element';\n\n    /**\n     * Write container.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $container = $this->element;\n        if (!$container instanceof ContainerElement) {\n            return '';\n        }\n        $containerClass = substr(get_class($container), strrpos(get_class($container), '\\\\') + 1);\n        $withoutP = in_array($containerClass, ['TextRun', 'Footnote', 'Endnote']) ? true : false;\n        $content = '';\n\n        $elements = $container->getElements();\n        foreach ($elements as $element) {\n            $elementClass = get_class($element);\n            $writerClass = str_replace('PhpOffice\\\\PhpWord\\\\Element', $this->namespace, $elementClass);\n            if (class_exists($writerClass)) {\n                /** @var AbstractElement $writer Type hint */\n                $writer = new $writerClass($this->parentWriter, $element, $withoutP);\n                $content .= $writer->write();\n            }\n        }\n\n        return $content;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/RTF/Element/Field.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\RTF\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\Field as ElementField;\n\n/**\n * Field element writer.\n *\n * Note: for now, only date, page, numpages and filename fields are implemented for RTF.\n */\nclass Field extends Text\n{\n    /**\n     * Write field element.\n     */\n    public function write()\n    {\n        $element = $this->element;\n        if (!$element instanceof ElementField) {\n            return;\n        }\n\n        $this->getStyles();\n\n        $content = '';\n        $content .= $this->writeOpening();\n        $content .= '{';\n        $content .= $this->writeFontStyle();\n\n        $methodName = 'write' . ucfirst(strtolower($element->getType()));\n        if (!method_exists($this, $methodName)) {\n            // Unsupported field\n            $content .= '';\n        } else {\n            $content .= '\\\\field{\\\\*\\\\fldinst ';\n            $content .= $this->$methodName($element);\n            $content .= '}{\\\\fldrslt}';\n        }\n        $content .= '}';\n        $content .= $this->writeClosing();\n\n        return $content;\n    }\n\n    protected function writePage()\n    {\n        return 'PAGE';\n    }\n\n    protected function writeNumpages()\n    {\n        return 'NUMPAGES';\n    }\n\n    protected function writeFilename(ElementField $element): string\n    {\n        $content = 'FILENAME';\n        $options = $element->getOptions();\n        if ($options != null && in_array('Path', $options)) {\n            $content .= ' \\\\\\\\p';\n        }\n\n        return $content;\n    }\n\n    protected function writeDate(ElementField $element)\n    {\n        $content = '';\n        $content .= 'DATE';\n        $properties = $element->getProperties();\n        if (isset($properties['dateformat'])) {\n            $content .= ' \\\\\\\\@ \"' . $properties['dateformat'] . '\"';\n        }\n\n        return $content;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/RTF/Element/Image.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\RTF\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\Image as ImageElement;\nuse PhpOffice\\PhpWord\\Shared\\Converter;\n\n/**\n * Image element RTF writer.\n *\n * @since 0.11.0\n */\nclass Image extends AbstractElement\n{\n    /**\n     * Write element.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        if (!$this->element instanceof ImageElement) {\n            return '';\n        }\n\n        $this->getStyles();\n        $style = $this->element->getStyle();\n\n        $content = '';\n        $content .= $this->writeOpening();\n        $content .= '{\\*\\shppict {\\pict';\n        $content .= '\\pngblip\\picscalex100\\picscaley100';\n        $content .= '\\picwgoal' . round(Converter::pixelToTwip($style->getWidth()));\n        $content .= '\\pichgoal' . round(Converter::pixelToTwip($style->getHeight()));\n        $content .= PHP_EOL;\n        $content .= $this->element->getImageStringData();\n        $content .= '}}';\n        $content .= $this->writeClosing();\n\n        return $content;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/RTF/Element/Link.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\RTF\\Element;\n\n/**\n * Link element RTF writer.\n *\n * @since 0.11.0\n */\nclass Link extends AbstractElement\n{\n    /**\n     * Write element.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        if (!$this->element instanceof \\PhpOffice\\PhpWord\\Element\\Link) {\n            return '';\n        }\n\n        $this->getStyles();\n\n        $content = '';\n        $content .= $this->writeOpening();\n        $content .= '{\\field {\\*\\fldinst {HYPERLINK \"' . $this->element->getSource() . '\"}}{\\\\fldrslt {';\n        $content .= $this->writeFontStyle();\n        $content .= $this->writeText($this->element->getText());\n        $content .= '}}}';\n        $content .= $this->writeClosing();\n\n        return $content;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/RTF/Element/ListItem.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\RTF\\Element;\n\n/**\n * ListItem element RTF writer; extends from text.\n *\n * @since 0.11.0\n */\nclass ListItem extends Text\n{\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/RTF/Element/PageBreak.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\RTF\\Element;\n\n/**\n * PageBreak element RTF writer.\n *\n * @since 0.11.0\n */\nclass PageBreak extends AbstractElement\n{\n    /**\n     * Write element.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        return '\\page' . PHP_EOL;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/RTF/Element/Ruby.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\RTF\\Element;\n\n/**\n * Ruby element RTF writer. Writes {baseText} ({rubyText}) in current paragraph style\n * because RTF does not natively support ruby text.\n */\nclass Ruby extends AbstractElement\n{\n    /**\n     * Write element.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        /** @var \\PhpOffice\\PhpWord\\Element\\Ruby $element */\n        $element = $this->element;\n        $elementClass = str_replace('\\\\Writer\\\\RTF', '', static::class);\n        if (!$element instanceof $elementClass || !is_string($element->getBaseTextRun()->getText())) {\n            return '';\n        }\n\n        $this->getStyles();\n\n        $content = '';\n        $content .= $this->writeOpening();\n        $content .= '{';\n        $content .= $this->writeFontStyle();\n        $content .= $this->writeText($element->getBaseTextRun()->getText());\n        $rubyText = $element->getRubyTextRun()->getText();\n        if ($rubyText !== '') {\n            $content .= ' (';\n            $content .= $this->writeText($rubyText);\n            $content .= ')';\n        }\n        $content .= '}';\n        $content .= $this->writeClosing();\n\n        return $content;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/RTF/Element/Table.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\RTF\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\Cell as CellElement;\nuse PhpOffice\\PhpWord\\Element\\Row as RowElement;\nuse PhpOffice\\PhpWord\\Element\\Table as TableElement;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\SimpleType\\Border;\nuse PhpOffice\\PhpWord\\Style;\nuse PhpOffice\\PhpWord\\Style\\Cell as CellStyle;\nuse PhpOffice\\PhpWord\\Style\\Table as TableStyle;\n\n/**\n * Table element RTF writer.\n *\n * @since 0.11.0\n */\nclass Table extends AbstractElement\n{\n    /**\n     * @var TableElement\n     */\n    protected $element;\n\n    /**\n     * Write element.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        if (!$this->element instanceof TableElement) {\n            return '';\n        }\n        $element = $this->element;\n        // No nesting table for now\n        if ($element->getNestedLevel() >= 1) {\n            return '';\n        }\n\n        $content = '';\n        $style = $this->element->getStyle();\n        $bidiStyle = (is_object($style) && method_exists($style, 'isBidiVisual')) ? $style->isBidiVisual() : Settings::isDefaultRtl();\n        $bidi = $bidiStyle ? '\\rtlrow' : '';\n        $rows = $element->getRows();\n        $rowCount = count($rows);\n\n        if ($rowCount > 0) {\n            $content .= '\\pard' . PHP_EOL;\n\n            for ($i = 0; $i < $rowCount; ++$i) {\n                $content .= \"\\\\trowd$bidi \";\n                $content .= $this->writeRowDef($rows[$i]);\n                $content .= PHP_EOL;\n                $content .= $this->writeRow($rows[$i]);\n                $content .= '\\row' . PHP_EOL;\n            }\n            $content .= '\\pard' . PHP_EOL;\n        }\n\n        return $content;\n    }\n\n    /**\n     * Write column.\n     *\n     * @return string\n     */\n    private function writeRowDef(RowElement $row)\n    {\n        $content = '';\n        $tableStyle = $this->element->getStyle();\n        if (is_string($tableStyle)) {\n            $tableStyle = Style::getStyle($tableStyle);\n            if (!($tableStyle instanceof TableStyle)) {\n                $tableStyle = null;\n            }\n        }\n\n        $rightMargin = 0;\n        foreach ($row->getCells() as $cell) {\n            $content .= $this->writeCellStyle($cell->getStyle(), $tableStyle);\n\n            $width = $cell->getWidth();\n            $vMerge = $this->getVMerge($cell->getStyle()->getVMerge());\n            if ($width === null) {\n                $width = 720; // Arbitrary default width\n            }\n            $rightMargin += $width;\n            $content .= \"{$vMerge}\\\\cellx{$rightMargin} \";\n        }\n\n        return $content;\n    }\n\n    /**\n     * Write row.\n     *\n     * @return string\n     */\n    private function writeRow(RowElement $row)\n    {\n        $content = '';\n\n        // Write cells\n        foreach ($row->getCells() as $cell) {\n            $content .= $this->writeCell($cell);\n        }\n\n        return $content;\n    }\n\n    /**\n     * Write cell.\n     *\n     * @return string\n     */\n    private function writeCell(CellElement $cell)\n    {\n        $content = '\\intbl' . PHP_EOL;\n\n        // Write content\n        $writer = new Container($this->parentWriter, $cell);\n        $content .= $writer->write();\n\n        $content .= '\\cell' . PHP_EOL;\n\n        return $content;\n    }\n\n    private function writeCellStyle(CellStyle $cell, ?TableStyle $table): string\n    {\n        $content = $this->writeCellBorder(\n            't',\n            $cell->getBorderTopStyle() ?: ($table ? $table->getBorderTopStyle() : null),\n            (int) round($cell->getBorderTopSize() ?: ($table ? ($table->getBorderTopSize() ?: 0) : 0)),\n            $cell->getBorderTopColor() ?? ($table ? $table->getBorderTopColor() : null)\n        );\n        $content .= $this->writeCellBorder(\n            'l',\n            $cell->getBorderLeftStyle() ?: ($table ? $table->getBorderLeftStyle() : null),\n            (int) round($cell->getBorderLeftSize() ?: ($table ? ($table->getBorderLeftSize() ?: 0) : 0)),\n            $cell->getBorderLeftColor() ?? ($table ? $table->getBorderLeftColor() : null)\n        );\n        $content .= $this->writeCellBorder(\n            'b',\n            $cell->getBorderBottomStyle() ?: ($table ? $table->getBorderBottomStyle() : null),\n            (int) round($cell->getBorderBottomSize() ?: ($table ? ($table->getBorderBottomSize() ?: 0) : 0)),\n            $cell->getBorderBottomColor() ?? ($table ? $table->getBorderBottomColor() : null)\n        );\n        $content .= $this->writeCellBorder(\n            'r',\n            $cell->getBorderRightStyle() ?: ($table ? $table->getBorderRightStyle() : null),\n            (int) round($cell->getBorderRightSize() ?: ($table ? ($table->getBorderRightSize() ?: 0) : 0)),\n            $cell->getBorderRightColor() ?? ($table ? $table->getBorderRightColor() : null)\n        );\n\n        return $content;\n    }\n\n    private function writeCellBorder(string $prefix, ?string $borderStyle, int $borderSize, ?string $borderColor): string\n    {\n        if ($borderSize == 0) {\n            return '';\n        }\n\n        $content = '\\clbrdr' . $prefix;\n        /**\n         * \\brdrs \tSingle-thickness border.\n         * \\brdrth \tDouble-thickness border.\n         * \\brdrsh \tShadowed border.\n         * \\brdrdb \tDouble border.\n         * \\brdrdot \tDotted border.\n         * \\brdrdash \tDashed border.\n         * \\brdrhair \tHairline border.\n         * \\brdrinset \tInset border.\n         * \\brdrdashsm \tDash border (small).\n         * \\brdrdashd \tDot dash border.\n         * \\brdrdashdd \tDot dot dash border.\n         * \\brdroutset \tOutset border.\n         * \\brdrtriple \tTriple border.\n         * \\brdrtnthsg \tThick thin border (small).\n         * \\brdrthtnsg \tThin thick border (small).\n         * \\brdrtnthtnsg \tThin thick thin border (small).\n         * \\brdrtnthmg \tThick thin border (medium).\n         * \\brdrthtnmg \tThin thick border (medium).\n         * \\brdrtnthtnmg \tThin thick thin border (medium).\n         * \\brdrtnthlg \tThick thin border (large).\n         * \\brdrthtnlg \tThin thick border (large).\n         * \\brdrtnthtnlg \tThin thick thin border (large).\n         * \\brdrwavy \tWavy border.\n         * \\brdrwavydb \tDouble wavy border.\n         * \\brdrdashdotstr \tStriped border.\n         * \\brdremboss \tEmboss border.\n         * \\brdrengrave \tEngrave border.\n         */\n        switch ($borderStyle) {\n            case Border::DOTTED:\n                $content .= '\\brdrdot';\n\n                break;\n            case Border::SINGLE:\n            default:\n                $content .= '\\brdrs';\n\n                break;\n        }\n\n        // \\brdrwN \tN is the width in twips (1/20 pt) of the pen used to draw the paragraph border line.\n        //          N cannot be greater than 75.\n        //          To obtain a larger border width, the \\brdth control word can be used to obtain a width double that of N.\n        // $borderSize is in eights of a point, i.e. 4 / 8 = .5pt\n        // 1/20 pt => 1/8 / 2.5\n        $content .= '\\brdrw' . (int) ($borderSize / 2.5);\n\n        // \\brdrcfN \tN is the color of the paragraph border, specified as an index into the color table in the RTF header.\n        $colorIndex = 0;\n        $index = array_search($borderColor, $this->parentWriter->getColorTable());\n        if ($index !== false) {\n            $colorIndex = (int) $index + 1;\n        }\n        $content .= '\\brdrcf' . $colorIndex;\n        $content .= PHP_EOL;\n\n        return $content;\n    }\n\n    /**\n     * Get vertical merge style.\n     *\n     * @param string $value\n     *\n     * @return string\n     *\n     * @todo Move to style\n     */\n    private function getVMerge($value)\n    {\n        $style = '';\n        if ($value == 'restart') {\n            $style = '\\clvmgf';\n        } elseif ($value == 'continue') {\n            $style = '\\clvmrg';\n        }\n\n        return $style;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/RTF/Element/Text.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\RTF\\Element;\n\n/**\n * Text element RTF writer.\n *\n * @since 0.10.0\n */\nclass Text extends AbstractElement\n{\n    /**\n     * Write element.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        /** @var \\PhpOffice\\PhpWord\\Element\\Text $element Type hint */\n        $element = $this->element;\n        $elementClass = str_replace('\\\\Writer\\\\RTF', '', static::class);\n        if (!$element instanceof $elementClass || !is_string($element->getText())) {\n            return '';\n        }\n\n        $this->getStyles();\n\n        $content = '';\n        $content .= $this->writeOpening();\n        $content .= '{';\n        $content .= $this->writeFontStyle();\n        $content .= $this->writeText($element->getText());\n        $content .= '}';\n        $content .= $this->writeClosing();\n\n        return $content;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/RTF/Element/TextBreak.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\RTF\\Element;\n\n/**\n * TextBreak element RTF writer.\n *\n * @since 0.10.0\n */\nclass TextBreak extends AbstractElement\n{\n    /**\n     * Write element.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        /** @var \\PhpOffice\\PhpWord\\Writer\\RTF $parentWriter Type hint */\n        $parentWriter = $this->parentWriter;\n        $parentWriter->setLastParagraphStyle();\n\n        return '\\pard\\par' . PHP_EOL;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/RTF/Element/TextRun.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\RTF\\Element;\n\n/**\n * TextRun element RTF writer.\n *\n * @since 0.10.0\n */\nclass TextRun extends AbstractElement\n{\n    /**\n     * Write element.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $writer = new Container($this->parentWriter, $this->element);\n        $this->getStyles();\n\n        $content = '';\n        $content .= $this->writeOpening();\n        $content .= '{';\n        $content .= $writer->write();\n        $content .= '}';\n        $content .= $this->writeClosing();\n\n        return $content;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/RTF/Element/Title.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\RTF\\Element;\n\n/**\n * Title element RTF writer; extends from text.\n *\n * @since 0.11.0\n */\nclass Title extends Text\n{\n    protected function getStyles(): void\n    {\n        /** @var \\PhpOffice\\PhpWord\\Element\\Title $element Type hint */\n        $element = $this->element;\n        $style = $element->getStyle();\n        $style = str_replace('Heading', 'Heading_', $style ?? '');\n        $style = \\PhpOffice\\PhpWord\\Style::getStyle($style);\n        if ($style instanceof \\PhpOffice\\PhpWord\\Style\\Font) {\n            $this->fontStyle = $style;\n            $pstyle = $style->getParagraph();\n            if ($pstyle instanceof \\PhpOffice\\PhpWord\\Style\\Paragraph && $pstyle->hasPageBreakBefore()) {\n                $sect = $element->getParent();\n                if ($sect instanceof \\PhpOffice\\PhpWord\\Element\\Section) {\n                    $elems = $sect->getElements();\n                    if ($elems[0] === $element) {\n                        $pstyle = clone $pstyle;\n                        $pstyle->setPageBreakBefore(false);\n                    }\n                }\n            }\n            $this->paragraphStyle = $pstyle;\n        }\n    }\n\n    /**\n     * Write element.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        /** @var \\PhpOffice\\PhpWord\\Element\\Title $element Type hint */\n        $element = $this->element;\n        $elementClass = str_replace('\\\\Writer\\\\RTF', '', static::class);\n        if (!$element instanceof $elementClass) {\n            return '';\n        }\n\n        $textToWrite = $element->getText();\n        if ($textToWrite instanceof \\PhpOffice\\PhpWord\\Element\\TextRun) {\n            $textToWrite = $textToWrite->getText(); // gets text from TextRun\n        }\n\n        $this->getStyles();\n\n        $content = '';\n\n        $content .= $this->writeOpening();\n        $endout = '';\n        $style = $element->getStyle();\n        if (is_string($style)) {\n            $style = str_replace('Heading', '', $style);\n            if (\"$style\" !== '') {\n                $style = (int) $style - 1;\n                if ($style >= 0 && $style <= 8) {\n                    $content .= '{\\\\outlinelevel' . $style;\n                    $endout = '}';\n                }\n            }\n        }\n\n        $content .= '{';\n        $content .= $this->writeFontStyle();\n        $content .= $this->writeText($textToWrite);\n        $content .= '}';\n        $content .= $this->writeClosing();\n        $content .= $endout;\n\n        return $content;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/RTF/Part/AbstractPart.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\RTF\\Part;\n\nuse PhpOffice\\PhpWord\\Escaper\\Rtf;\nuse PhpOffice\\PhpWord\\Exception\\Exception;\nuse PhpOffice\\PhpWord\\Writer\\AbstractWriter;\n\n/**\n * @since 0.11.0\n */\nabstract class AbstractPart\n{\n    /**\n     * @var \\PhpOffice\\PhpWord\\Writer\\RTF\n     */\n    private $parentWriter;\n\n    /**\n     * @var \\PhpOffice\\PhpWord\\Escaper\\EscaperInterface\n     */\n    protected $escaper;\n\n    public function __construct()\n    {\n        $this->escaper = new Rtf();\n    }\n\n    /**\n     * @return string\n     */\n    abstract public function write();\n\n    /**\n     * @param \\PhpOffice\\PhpWord\\Writer\\RTF $writer\n     */\n    public function setParentWriter(?AbstractWriter $writer = null): void\n    {\n        $this->parentWriter = $writer;\n    }\n\n    /**\n     * @return \\PhpOffice\\PhpWord\\Writer\\RTF\n     */\n    public function getParentWriter()\n    {\n        if ($this->parentWriter !== null) {\n            return $this->parentWriter;\n        }\n\n        throw new Exception('No parent WriterInterface assigned.');\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/RTF/Part/Document.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\RTF\\Part;\n\nuse PhpOffice\\PhpWord\\Element\\Footer;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Writer\\RTF\\Element\\Container;\nuse PhpOffice\\PhpWord\\Writer\\RTF\\Style\\Section as SectionStyleWriter;\n\n/**\n * RTF document part writer.\n *\n * @since 0.11.0\n * @see  http://www.biblioscape.com/rtf15_spec.htm#Heading24\n */\nclass Document extends AbstractPart\n{\n    /**\n     * Write part.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $content = '';\n\n        $content .= $this->writeInfo();\n        $content .= $this->writeFormatting();\n        $content .= $this->writeSections();\n\n        return $content;\n    }\n\n    /**\n     * Write document information.\n     *\n     * @return string\n     */\n    private function writeInfo()\n    {\n        $docProps = $this->getParentWriter()->getPhpWord()->getDocInfo();\n        $properties = [\n            'title' => 'title',\n            'subject' => 'subject',\n            'category' => 'category',\n            'keywords' => 'keywords',\n            'comment' => 'description',\n            'author' => 'creator',\n            'operator' => 'lastModifiedBy',\n            'creatim' => 'created',\n            'revtim' => 'modified',\n            'company' => 'company',\n            'manager' => 'manager',\n        ];\n        $dateFields = ['creatim', 'revtim'];\n\n        $content = '';\n\n        $content .= '{';\n        $content .= '\\info';\n        foreach ($properties as $property => $propertyMethod) {\n            $method = 'get' . $propertyMethod;\n\n            $value = $docProps->$method();\n            if (!in_array($property, $dateFields) && Settings::isOutputEscapingEnabled()) {\n                $value = $this->escaper->escape($value);\n            }\n\n            $value = in_array($property, $dateFields) ? $this->getDateValue($value) : $value;\n            $content .= \"{\\\\{$property} {$value}}\";\n        }\n        $content .= '}';\n        $content .= PHP_EOL;\n\n        return $content;\n    }\n\n    /**\n     * Write document formatting properties.\n     *\n     * @return string\n     */\n    private function writeFormatting()\n    {\n        $docSettings = $this->getParentWriter()->getPhpWord()->getSettings();\n        // Applies a language to a text run (defaults to 1036 : French (France))\n        $langId = $docSettings->getThemeFontLang() != null && $docSettings->getThemeFontLang()->getLangId() != null ? $docSettings->getThemeFontLang()->getLangId() : 1036;\n\n        $content = '';\n\n        $content .= '\\deftab720'; // Set the default tab size (720 twips)\n        $content .= '\\viewkind1'; // Set the view mode of the document\n\n        $content .= '\\uc1'; // Set the numberof bytes that follows a unicode character\n        $content .= '\\pard'; // Resets to default paragraph properties.\n        $content .= '\\nowidctlpar'; // No widow/orphan control\n        $content .= '\\lang' . $langId;\n        $content .= '\\kerning1'; // Point size (in half-points) above which to kern character pairs\n        $content .= '\\fs' . (Settings::getDefaultFontSize() * 2); // Set the font size in half-points\n        if ($docSettings->hasEvenAndOddHeaders()) {\n            $content .= '\\\\facingp';\n        }\n        $content .= PHP_EOL;\n\n        return $content;\n    }\n\n    /**\n     * Write titlepg directive if any \"f\" headers or footers.\n     *\n     * @param \\PhpOffice\\PhpWord\\Element\\Section $section\n     *\n     * @return string\n     */\n    private static function writeTitlepg($section)\n    {\n        foreach ($section->getHeaders() as $header) {\n            if ($header->getType() === Footer::FIRST) {\n                return '\\\\titlepg' . PHP_EOL;\n            }\n        }\n        foreach ($section->getFooters() as $header) {\n            if ($header->getType() === Footer::FIRST) {\n                return '\\\\titlepg' . PHP_EOL;\n            }\n        }\n\n        return '';\n    }\n\n    /**\n     * Write sections.\n     *\n     * @return string\n     */\n    private function writeSections()\n    {\n        $content = '';\n\n        $sections = $this->getParentWriter()->getPhpWord()->getSections();\n        $evenOdd = $this->getParentWriter()->getPhpWord()->getSettings()->hasEvenAndOddHeaders();\n        $sectOwed = false;\n        foreach ($sections as $section) {\n            if ($sectOwed) {\n                $content .= '\\sect' . PHP_EOL;\n            } else {\n                $sectOwed = true;\n            }\n            $styleWriter = new SectionStyleWriter($section->getStyle());\n            $styleWriter->setParentWriter($this->getParentWriter());\n            $content .= $styleWriter->write();\n            $content .= self::writeTitlepg($section);\n\n            foreach ($section->getHeaders() as $header) {\n                $type = $header->getType();\n                if ($evenOdd || $type !== Footer::EVEN) {\n                    $content .= '{\\\\header';\n                    if ($type === Footer::FIRST) {\n                        $content .= 'f';\n                    } elseif ($evenOdd) {\n                        $content .= ($type === Footer::EVEN) ? 'l' : 'r';\n                    }\n                    foreach ($header->getElements() as $element) {\n                        $cl = get_class($element);\n                        $cl2 = str_replace('Element', 'Writer\\\\RTF\\\\Element', $cl);\n                        if (class_exists($cl2)) {\n                            $elementWriter = new $cl2($this->getParentWriter(), $element);\n                            $content .= $elementWriter->write();\n                        }\n                    }\n                    $content .= '}' . PHP_EOL;\n                }\n            }\n            foreach ($section->getFooters() as $footer) {\n                $type = $footer->getType();\n                if ($evenOdd || $type !== Footer::EVEN) {\n                    $content .= '{\\\\footer';\n                    if ($type === Footer::FIRST) {\n                        $content .= 'f';\n                    } elseif ($evenOdd) {\n                        $content .= ($type === Footer::EVEN) ? 'l' : 'r';\n                    }\n                    foreach ($footer->getElements() as $element) {\n                        $cl = get_class($element);\n                        $cl2 = str_replace('Element', 'Writer\\\\RTF\\\\Element', $cl);\n                        if (class_exists($cl2)) {\n                            $elementWriter = new $cl2($this->getParentWriter(), $element);\n                            $content .= $elementWriter->write();\n                        }\n                    }\n                    $content .= '}' . PHP_EOL;\n                }\n            }\n\n            $elementWriter = new Container($this->getParentWriter(), $section);\n            $content .= $elementWriter->write();\n        }\n\n        return $content;\n    }\n\n    /**\n     * Get date value.\n     *\n     * The format of date value is `\\yr?\\mo?\\dy?\\hr?\\min?\\sec?`\n     *\n     * @param int $value\n     *\n     * @return string\n     */\n    private function getDateValue($value)\n    {\n        $dateParts = [\n            'Y' => 'yr',\n            'm' => 'mo',\n            'd' => 'dy',\n            'H' => 'hr',\n            'i' => 'min',\n            's' => 'sec',\n        ];\n        $result = '';\n        foreach ($dateParts as $dateFormat => $controlWord) {\n            $result .= '\\\\' . $controlWord . date($dateFormat, $value);\n        }\n\n        return $result;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/RTF/Part/Header.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\RTF\\Part;\n\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Shared\\Converter;\nuse PhpOffice\\PhpWord\\Style;\nuse PhpOffice\\PhpWord\\Style\\Font;\nuse PhpOffice\\PhpWord\\Style\\Table;\n\n/**\n * RTF header part writer.\n *\n * - Character set\n * - Font table\n * - File table (not supported yet)\n * - Color table\n * - Style sheet (not supported yet)\n * - List table (not supported yet)\n *\n * @since 0.11.0\n * @see  http://www.biblioscape.com/rtf15_spec.htm#Heading6\n */\nclass Header extends AbstractPart\n{\n    /**\n     * Font table.\n     *\n     * @var array\n     */\n    private $fontTable = [];\n\n    /**\n     * Color table.\n     *\n     * @var array\n     */\n    private $colorTable = [];\n\n    /**\n     * Get font table.\n     *\n     * @return array\n     */\n    public function getFontTable()\n    {\n        return $this->fontTable;\n    }\n\n    /**\n     * Get color table.\n     *\n     * @return array\n     */\n    public function getColorTable()\n    {\n        return $this->colorTable;\n    }\n\n    /**\n     * Write part.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $this->registerFont();\n\n        $content = '';\n\n        $content .= $this->writeCharset();\n        $content .= $this->writeDefaults();\n        $content .= $this->writeFontTable();\n        $content .= $this->writeColorTable();\n        $content .= $this->writeGenerator();\n        $content .= PHP_EOL;\n\n        return $content;\n    }\n\n    /**\n     * Write character set.\n     *\n     * @return string\n     */\n    private function writeCharset()\n    {\n        $content = '';\n\n        $content .= '\\ansi';\n        $content .= '\\ansicpg1252';\n        $content .= PHP_EOL;\n\n        return $content;\n    }\n\n    /**\n     * Write header defaults.\n     *\n     * @return string\n     */\n    private function writeDefaults()\n    {\n        $content = '';\n\n        $content .= '\\deff0';\n        $content .= PHP_EOL;\n\n        return $content;\n    }\n\n    /**\n     * Write font table.\n     *\n     * @return string\n     */\n    private function writeFontTable()\n    {\n        $content = '';\n\n        $content .= '{';\n        $content .= '\\fonttbl';\n        foreach ($this->fontTable as $index => $font) {\n            $content .= \"{\\\\f{$index}\\\\fnil\\\\fcharset0 {$font};}\";\n        }\n        $content .= '}';\n        $content .= PHP_EOL;\n\n        return $content;\n    }\n\n    /**\n     * Write color table.\n     *\n     * @return string\n     */\n    private function writeColorTable()\n    {\n        $content = '';\n\n        $content .= '{';\n        $content .= '\\colortbl;';\n        foreach ($this->colorTable as $color) {\n            [$red, $green, $blue] = Converter::htmlToRgb($color);\n            $content .= \"\\\\red{$red}\\\\green{$green}\\\\blue{$blue};\";\n        }\n        $content .= '}';\n        $content .= PHP_EOL;\n\n        return $content;\n    }\n\n    /**\n     * Write.\n     *\n     * @return string\n     */\n    private function writeGenerator()\n    {\n        $content = '';\n\n        $content .= '{\\*\\generator PHPWord;}'; // Set the generator\n        $content .= PHP_EOL;\n\n        return $content;\n    }\n\n    /**\n     * Register all fonts and colors in both named and inline styles to appropriate header table.\n     */\n    private function registerFont(): void\n    {\n        $phpWord = $this->getParentWriter()->getPhpWord();\n        $this->fontTable[] = Settings::getDefaultFontName();\n\n        // Search named styles\n        $styles = Style::getStyles();\n        foreach ($styles as $style) {\n            $this->registerFontItems($style);\n        }\n\n        // Search inline styles\n        $sections = $phpWord->getSections();\n        foreach ($sections as $section) {\n            $elements = $section->getElements();\n            $this->registerBorderColor($section->getStyle());\n            foreach ($elements as $element) {\n                if (method_exists($element, 'getFontStyle')) {\n                    $style = $element->getFontStyle();\n                    $this->registerFontItems($style);\n                }\n            }\n        }\n    }\n\n    /**\n     * Register border colors.\n     *\n     * @param Style\\Border $style\n     */\n    private function registerBorderColor($style): void\n    {\n        $colors = $style->getBorderColor();\n        foreach ($colors as $color) {\n            if ($color !== null) {\n                $this->registerTableItem($this->colorTable, $color);\n            }\n        }\n    }\n\n    /**\n     * Register fonts and colors.\n     *\n     * @param Style\\AbstractStyle $style\n     */\n    private function registerFontItems($style): void\n    {\n        $defaultFont = Settings::getDefaultFontName();\n        $defaultColor = Settings::DEFAULT_FONT_COLOR;\n\n        if ($style instanceof Font) {\n            $this->registerTableItem($this->fontTable, $style->getName(), $defaultFont);\n            $this->registerTableItem($this->colorTable, $style->getColor(), $defaultColor);\n            $this->registerTableItem($this->colorTable, $style->getFgColor(), $defaultColor);\n\n            return;\n        }\n        if ($style instanceof Table) {\n            $this->registerTableItem($this->colorTable, $style->getBorderTopColor(), $defaultColor);\n            $this->registerTableItem($this->colorTable, $style->getBorderRightColor(), $defaultColor);\n            $this->registerTableItem($this->colorTable, $style->getBorderLeftColor(), $defaultColor);\n            $this->registerTableItem($this->colorTable, $style->getBorderBottomColor(), $defaultColor);\n        }\n    }\n\n    /**\n     * Register individual font and color.\n     *\n     * @param array &$table\n     * @param string $value\n     * @param string $default\n     */\n    private function registerTableItem(&$table, $value, $default = null): void\n    {\n        if (in_array($value, $table) === false && $value !== null && $value != $default) {\n            $table[] = $value;\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/RTF/Style/AbstractStyle.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\RTF\\Style;\n\nuse PhpOffice\\PhpWord\\Style\\AbstractStyle as StyleAbstract;\nuse PhpOffice\\PhpWord\\Writer\\RTF;\n\n/**\n * Abstract RTF style writer.\n *\n * @since 0.11.0\n */\nabstract class AbstractStyle\n{\n    /**\n     * Parent writer.\n     *\n     * @var RTF\n     */\n    private $parentWriter;\n\n    /**\n     * Style.\n     *\n     * @var null|array|StyleAbstract\n     */\n    private $style;\n\n    /**\n     * Write style.\n     *\n     * @return mixed\n     */\n    abstract public function write();\n\n    /**\n     * Create new instance.\n     *\n     * @param array|StyleAbstract $style\n     */\n    public function __construct($style = null)\n    {\n        $this->style = $style;\n    }\n\n    /**\n     * Set parent writer.\n     *\n     * @param RTF $writer\n     */\n    public function setParentWriter($writer): void\n    {\n        $this->parentWriter = $writer;\n    }\n\n    /**\n     * Get parent writer.\n     *\n     * @return RTF\n     */\n    public function getParentWriter()\n    {\n        return $this->parentWriter;\n    }\n\n    /**\n     * Get style.\n     *\n     * @return null|array|string|StyleAbstract\n     */\n    public function getStyle()\n    {\n        if (!$this->style instanceof StyleAbstract && !is_array($this->style)) {\n            return '';\n        }\n\n        return $this->style;\n    }\n\n    /**\n     * Get value if ...\n     *\n     * @param null|bool $condition\n     * @param string $value\n     *\n     * @return string\n     */\n    protected function getValueIf($condition, $value)\n    {\n        return $condition == true ? $value : '';\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/RTF/Style/Border.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\RTF\\Style;\n\n/**\n * Border style writer.\n *\n * @since 0.12.0\n */\nclass Border extends AbstractStyle\n{\n    /**\n     * Sizes.\n     *\n     * @var array\n     */\n    private $sizes = [];\n\n    /**\n     * Colors.\n     *\n     * @var array\n     */\n    private $colors = [];\n\n    /**\n     * Write style.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $content = '';\n\n        $sides = ['top', 'left', 'right', 'bottom'];\n        $sizeCount = count($this->sizes);\n\n        // Page border measure\n        // 8 = from text, infront off; 32 = from edge, infront on; 40 = from edge, infront off\n        $content .= '\\pgbrdropt32';\n\n        for ($i = 0; $i < $sizeCount; ++$i) {\n            if ($this->sizes[$i] !== null) {\n                $color = null;\n                if (isset($this->colors[$i])) {\n                    $color = $this->colors[$i];\n                }\n                $content .= $this->writeSide($sides[$i], $this->sizes[$i], $color);\n            }\n        }\n\n        return $content;\n    }\n\n    /**\n     * Write side.\n     *\n     * @param string $side\n     * @param int $width\n     * @param string $color\n     *\n     * @return string\n     */\n    private function writeSide($side, $width, $color = '')\n    {\n        /** @var \\PhpOffice\\PhpWord\\Writer\\RTF $rtfWriter */\n        $rtfWriter = $this->getParentWriter();\n        $colorIndex = 0;\n        if ($rtfWriter !== null) {\n            $colorTable = $rtfWriter->getColorTable();\n            $index = array_search($color, $colorTable);\n            if ($index !== false) {\n                $colorIndex = $index + 1;\n            }\n        }\n\n        $content = '';\n\n        $content .= '\\pgbrdr' . substr($side, 0, 1);\n        $content .= '\\brdrs'; // Single-thickness border; @todo Get other type of border\n        $content .= '\\brdrw' . round($width); // Width\n        $content .= '\\brdrcf' . $colorIndex; // Color\n        $content .= '\\brsp480'; // Space in twips between borders and the paragraph (24pt, following OOXML)\n        $content .= ' ';\n\n        return $content;\n    }\n\n    /**\n     * Set sizes.\n     *\n     * @param int[] $value\n     */\n    public function setSizes($value): void\n    {\n        $this->sizes = $value;\n    }\n\n    /**\n     * Set colors.\n     *\n     * @param string[] $value\n     */\n    public function setColors($value): void\n    {\n        $this->colors = $value;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/RTF/Style/Font.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\RTF\\Style;\n\nuse PhpOffice\\PhpWord\\Style\\Font as FontStyle;\n\n/**\n * RTF font style writer.\n *\n * @since 0.11.0\n */\nclass Font extends AbstractStyle\n{\n    /**\n     * @var int Font name index\n     */\n    private $nameIndex = 0;\n\n    /**\n     * @var int Font color index\n     */\n    private $colorIndex = 0;\n\n    /**\n     * Write style.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof FontStyle) {\n            return '';\n        }\n\n        $content = '';\n        $content .= $this->getValueIf($style->isRTL(), '\\rtlch');\n        $content .= '\\cf' . $this->colorIndex;\n        $content .= '\\f' . $this->nameIndex;\n\n        $size = $style->getSize();\n        $content .= $this->getValueIf(is_numeric($size), '\\fs' . round($size * 2));\n\n        $content .= $this->getValueIf($style->isBold(), '\\b');\n        $content .= $this->getValueIf($style->isItalic(), '\\i');\n        $content .= $this->getValueIf($style->getUnderline() != FontStyle::UNDERLINE_NONE, '\\ul');\n        $content .= $this->getValueIf($style->isStrikethrough(), '\\strike');\n        $content .= $this->getValueIf($style->isSuperScript(), '\\super');\n        $content .= $this->getValueIf($style->isSubScript(), '\\sub');\n\n        return $content . ' ';\n    }\n\n    /**\n     * Set font name index.\n     *\n     * @param int $value\n     */\n    public function setNameIndex($value = 0): void\n    {\n        $this->nameIndex = $value;\n    }\n\n    /**\n     * Set font color index.\n     *\n     * @param int $value\n     */\n    public function setColorIndex($value = 0): void\n    {\n        $this->colorIndex = $value;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/RTF/Style/Indentation.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\RTF\\Style;\n\n/**\n * RTF indentation style writer.\n *\n * @since 0.11.0\n */\nclass Indentation extends AbstractStyle\n{\n    /**\n     * Write style.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof \\PhpOffice\\PhpWord\\Style\\Indentation) {\n            return '';\n        }\n\n        $content = '\\fi' . round($style->getFirstLine());\n        $content .= '\\li' . round($style->getLeft());\n        $content .= '\\ri' . round($style->getRight());\n\n        return $content . ' ';\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/RTF/Style/Paragraph.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\RTF\\Style;\n\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\n\n/**\n * RTF paragraph style writer.\n *\n * @since 0.11.0\n */\nclass Paragraph extends AbstractStyle\n{\n    /**\n     * Depth of table container nested level; Primarily used for RTF writer/reader.\n     *\n     * 0 = Not in a table; 1 = in a table; 2 = in a table inside another table, etc.\n     *\n     * @var int\n     */\n    private $nestedLevel = 0;\n\n    private const LEFT = Jc::LEFT;\n    private const RIGHT = Jc::RIGHT;\n    private const JUSTIFY = Jc::JUSTIFY;\n\n    /**\n     * Write style.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof \\PhpOffice\\PhpWord\\Style\\Paragraph) {\n            return '';\n        }\n\n        $alignments = [\n            Jc::START => '\\ql',\n            Jc::END => '\\qr',\n            Jc::CENTER => '\\qc',\n            Jc::BOTH => '\\qj',\n            self::LEFT => '\\ql',\n            self::RIGHT => '\\qr',\n            self::JUSTIFY => '\\qj',\n        ];\n        $bidiAlignments = [\n            Jc::START => '\\qr',\n            Jc::END => '\\ql',\n            Jc::CENTER => '\\qc',\n            Jc::BOTH => '\\qj',\n            self::LEFT => '\\ql',\n            self::RIGHT => '\\qr',\n            self::JUSTIFY => '\\qj',\n        ];\n\n        $spaceAfter = $style->getSpaceAfter();\n        $spaceBefore = $style->getSpaceBefore();\n\n        $content = '';\n        if ($this->nestedLevel == 0) {\n            $content .= '\\pard\\nowidctlpar ';\n        }\n        $alignment = $style->getAlignment();\n        $bidi = $style->isBidi();\n        if ($alignment === '' && $bidi !== null) {\n            $alignment = Jc::START;\n        }\n        if (isset($alignments[$alignment])) {\n            $content .= $bidi ? $bidiAlignments[$alignment] : $alignments[$alignment];\n        }\n        $content .= $this->writeIndentation($style->getIndentation());\n        $content .= $this->getValueIf($spaceBefore !== null, '\\sb' . round($spaceBefore ?? 0));\n        $content .= $this->getValueIf($spaceAfter !== null, '\\sa' . round($spaceAfter ?? 0));\n        $lineHeight = $style->getLineHeight();\n        if ($lineHeight) {\n            $lineHeightAdjusted = (int) ($lineHeight * 240);\n            $content .= \"\\\\sl$lineHeightAdjusted\\\\slmult1\";\n        }\n        if ($style->hasPageBreakBefore()) {\n            $content .= '\\\\page';\n        }\n\n        $styles = $style->getStyleValues();\n        $content .= $this->writeTabs($styles['tabs']);\n\n        return $content;\n    }\n\n    /**\n     * Writes an \\PhpOffice\\PhpWord\\Style\\Indentation.\n     *\n     * @param null|\\PhpOffice\\PhpWord\\Style\\Indentation $indent\n     *\n     * @return string\n     */\n    private function writeIndentation($indent = null)\n    {\n        if (isset($indent) && $indent instanceof \\PhpOffice\\PhpWord\\Style\\Indentation) {\n            $writer = new Indentation($indent);\n\n            return $writer->write();\n        }\n\n        return '';\n    }\n\n    /**\n     * Writes tabs.\n     *\n     * @param \\PhpOffice\\PhpWord\\Style\\Tab[] $tabs\n     *\n     * @return string\n     */\n    private function writeTabs($tabs = null)\n    {\n        $content = '';\n        if (!empty($tabs)) {\n            foreach ($tabs as $tab) {\n                $styleWriter = new Tab($tab);\n                $content .= $styleWriter->write();\n            }\n        }\n\n        return $content;\n    }\n\n    /**\n     * Set nested level.\n     *\n     * @param int $value\n     */\n    public function setNestedLevel($value): void\n    {\n        $this->nestedLevel = $value;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/RTF/Style/Section.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\RTF\\Style;\n\nuse PhpOffice\\PhpWord\\Style\\Section as SectionStyle;\n\n/**\n * RTF section style writer.\n *\n * @since 0.12.0\n */\nclass Section extends AbstractStyle\n{\n    /**\n     * Write style.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof SectionStyle) {\n            return '';\n        }\n\n        $content = '';\n\n        $content .= '\\sectd ';\n\n        // Size & margin\n        $content .= $this->getValueIf($style->getPageSizeW() !== null, '\\pgwsxn' . round($style->getPageSizeW()));\n        $content .= $this->getValueIf($style->getPageSizeH() !== null, '\\pghsxn' . round($style->getPageSizeH()));\n        $content .= ' ';\n        $content .= $this->getValueIf($style->getMarginTop() !== null, '\\margtsxn' . round($style->getMarginTop()));\n        $content .= $this->getValueIf($style->getMarginRight() !== null, '\\margrsxn' . round($style->getMarginRight()));\n        $content .= $this->getValueIf($style->getMarginBottom() !== null, '\\margbsxn' . round($style->getMarginBottom()));\n        $content .= $this->getValueIf($style->getMarginLeft() !== null, '\\marglsxn' . round($style->getMarginLeft()));\n        $content .= $this->getValueIf($style->getHeaderHeight() !== null, '\\headery' . round($style->getHeaderHeight()));\n        $content .= $this->getValueIf($style->getFooterHeight() !== null, '\\footery' . round($style->getFooterHeight()));\n        $content .= $this->getValueIf($style->getGutter() !== null, '\\guttersxn' . round($style->getGutter()));\n        $content .= $this->getValueIf($style->getPageNumberingStart() !== null, '\\pgnstarts' . $style->getPageNumberingStart() . '\\pgnrestart');\n        $content .= ' ';\n\n        // Borders\n        if ($style->hasBorder()) {\n            $styleWriter = new Border($style);\n            $styleWriter->setParentWriter($this->getParentWriter());\n            $styleWriter->setSizes($style->getBorderSize());\n            $styleWriter->setColors($style->getBorderColor());\n            $content .= $styleWriter->write();\n        }\n\n        return $content . PHP_EOL;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/RTF/Style/Tab.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\RTF\\Style;\n\n/**\n * Line numbering style writer.\n *\n * @since 0.10.0\n */\nclass Tab extends AbstractStyle\n{\n    /**\n     * Write style.\n     */\n    public function write()\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof \\PhpOffice\\PhpWord\\Style\\Tab) {\n            return;\n        }\n        $tabs = [\n            \\PhpOffice\\PhpWord\\Style\\Tab::TAB_STOP_RIGHT => '\\tqr',\n            \\PhpOffice\\PhpWord\\Style\\Tab::TAB_STOP_CENTER => '\\tqc',\n            \\PhpOffice\\PhpWord\\Style\\Tab::TAB_STOP_DECIMAL => '\\tqdec',\n        ];\n        $content = '';\n        if (isset($tabs[$style->getType()])) {\n            $content .= $tabs[$style->getType()];\n        }\n        $content .= '\\tx' . round($style->getPosition());\n\n        return $content;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/RTF.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer;\n\nuse PhpOffice\\PhpWord\\PhpWord;\n\n/**\n * RTF writer.\n *\n * @since 0.7.0\n */\nclass RTF extends AbstractWriter implements WriterInterface\n{\n    /**\n     * Last paragraph style.\n     *\n     * @var mixed\n     */\n    private $lastParagraphStyle;\n\n    /**\n     * Create new instance.\n     */\n    public function __construct(?PhpWord $phpWord = null)\n    {\n        $this->setPhpWord($phpWord);\n\n        $this->parts = ['Header', 'Document'];\n        foreach ($this->parts as $partName) {\n            $partClass = static::class . '\\\\Part\\\\' . $partName;\n            if (class_exists($partClass)) {\n                /** @var RTF\\Part\\AbstractPart $part Type hint */\n                $part = new $partClass();\n                $part->setParentWriter($this);\n                $this->writerParts[strtolower($partName)] = $part;\n            }\n        }\n    }\n\n    /**\n     * Save content to file.\n     */\n    public function save(string $filename): void\n    {\n        $this->writeFile($this->openFile($filename), $this->getContent());\n    }\n\n    /**\n     * Get content.\n     *\n     * @return string\n     *\n     * @since 0.11.0\n     */\n    private function getContent()\n    {\n        $content = '';\n\n        $content .= '{';\n        $content .= '\\rtf1' . PHP_EOL;\n        $content .= $this->getWriterPart('Header')->write();\n        $content .= $this->getWriterPart('Document')->write();\n        $content .= '}';\n\n        return $content;\n    }\n\n    /**\n     * Get font table.\n     *\n     * @return array\n     */\n    public function getFontTable()\n    {\n        return $this->getWriterPart('Header')->getFontTable();\n    }\n\n    /**\n     * Get color table.\n     *\n     * @return array\n     */\n    public function getColorTable()\n    {\n        return $this->getWriterPart('Header')->getColorTable();\n    }\n\n    /**\n     * Get last paragraph style.\n     *\n     * @return mixed\n     */\n    public function getLastParagraphStyle()\n    {\n        return $this->lastParagraphStyle;\n    }\n\n    /**\n     * Set last paragraph style.\n     *\n     * @param mixed $value\n     */\n    public function setLastParagraphStyle($value = ''): void\n    {\n        $this->lastParagraphStyle = $value;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Element/AbstractElement.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\AbstractElement as Element;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Shared\\Text as SharedText;\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Part\\AbstractPart;\n\n/**\n * Abstract element writer.\n *\n * @since 0.11.0\n */\nabstract class AbstractElement\n{\n    /**\n     * XML writer.\n     *\n     * @var XMLWriter\n     */\n    private $xmlWriter;\n\n    /**\n     * Element.\n     *\n     * @var Element\n     */\n    private $element;\n\n    /**\n     * Without paragraph.\n     *\n     * @var bool\n     */\n    protected $withoutP = false;\n\n    /**\n     * @var null|AbstractPart\n     */\n    protected $part;\n\n    /**\n     * Write element.\n     */\n    abstract public function write();\n\n    /**\n     * Create new instance.\n     */\n    public function __construct(XMLWriter $xmlWriter, Element $element, bool $withoutP = false)\n    {\n        $this->xmlWriter = $xmlWriter;\n        $this->element = $element;\n        $this->withoutP = $withoutP;\n    }\n\n    /**\n     * Get XML Writer.\n     *\n     * @return XMLWriter\n     */\n    protected function getXmlWriter()\n    {\n        return $this->xmlWriter;\n    }\n\n    /**\n     * Get element.\n     *\n     * @return Element\n     */\n    protected function getElement()\n    {\n        return $this->element;\n    }\n\n    /**\n     * Start w:p DOM element.\n     *\n     * @uses \\PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\PageBreak::write()\n     */\n    protected function startElementP(): void\n    {\n        if (!$this->withoutP) {\n            $this->xmlWriter->startElement('w:p');\n            // Paragraph style\n            if (method_exists($this->element, 'getParagraphStyle')) {\n                $this->writeParagraphStyle();\n            }\n        }\n        $this->writeCommentRangeStart();\n    }\n\n    /**\n     * End w:p DOM element.\n     */\n    protected function endElementP(): void\n    {\n        $this->writeCommentRangeEnd();\n        if (!$this->withoutP) {\n            $this->xmlWriter->endElement(); // w:p\n        }\n    }\n\n    /**\n     * Writes the w:commentRangeStart DOM element.\n     */\n    protected function writeCommentRangeStart(): void\n    {\n        if ($this->element->getCommentsRangeStart() != null) {\n            foreach ($this->element->getCommentsRangeStart()->getItems() as $comment) {\n                $this->xmlWriter->writeElementBlock('w:commentRangeStart', ['w:id' => $comment->getElementId()]);\n            }\n        }\n    }\n\n    /**\n     * Writes the w:commentRangeEnd DOM element.\n     */\n    protected function writeCommentRangeEnd(): void\n    {\n        if ($this->element->getCommentsRangeEnd() != null) {\n            foreach ($this->element->getCommentsRangeEnd()->getItems() as $comment) {\n                $this->xmlWriter->writeElementBlock('w:commentRangeEnd', ['w:id' => $comment->getElementId()]);\n                $this->xmlWriter->startElement('w:r');\n                $this->xmlWriter->writeElementBlock('w:commentReference', ['w:id' => $comment->getElementId()]);\n                $this->xmlWriter->endElement();\n            }\n        }\n        if ($this->element->getCommentsRangeStart() != null) {\n            foreach ($this->element->getCommentsRangeStart()->getItems() as $comment) {\n                if ($comment->getEndElement() == null) {\n                    $this->xmlWriter->writeElementBlock('w:commentRangeEnd', ['w:id' => $comment->getElementId()]);\n                    $this->xmlWriter->startElement('w:r');\n                    $this->xmlWriter->writeElementBlock('w:commentReference', ['w:id' => $comment->getElementId()]);\n                    $this->xmlWriter->endElement();\n                }\n            }\n        }\n    }\n\n    /**\n     * Write ending.\n     */\n    protected function writeParagraphStyle(): void\n    {\n        $this->writeTextStyle('Paragraph');\n    }\n\n    /**\n     * Write ending.\n     */\n    protected function writeFontStyle(): void\n    {\n        $this->writeTextStyle('Font');\n    }\n\n    /**\n     * Write text style.\n     *\n     * @param string $styleType Font|Paragraph\n     */\n    private function writeTextStyle($styleType): void\n    {\n        $method = \"get{$styleType}Style\";\n        $class = \"PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007\\\\Style\\\\{$styleType}\";\n        $styleObject = $this->element->$method();\n\n        /** @var \\PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\AbstractStyle $styleWriter Type Hint */\n        $styleWriter = new $class($this->xmlWriter, $styleObject);\n        if (method_exists($styleWriter, 'setIsInline')) {\n            $styleWriter->setIsInline(true);\n        }\n\n        $styleWriter->write();\n    }\n\n    /**\n     * Convert text to valid format.\n     *\n     * @param string $text\n     *\n     * @return string\n     */\n    protected function getText($text)\n    {\n        return SharedText::controlCharacterPHP2OOXML($text);\n    }\n\n    /**\n     * Write an XML text, this will call text() or writeRaw() depending on the value of Settings::isOutputEscapingEnabled().\n     *\n     * @param string $content The text string to write\n     *\n     * @return bool Returns true on success or false on failure\n     */\n    protected function writeText($content)\n    {\n        if (Settings::isOutputEscapingEnabled()) {\n            return $this->getXmlWriter()->text($content);\n        }\n\n        return $this->getXmlWriter()->writeRaw($content);\n    }\n\n    public function setPart(?AbstractPart $part): self\n    {\n        $this->part = $part;\n\n        return $this;\n    }\n\n    public function getPart(): ?AbstractPart\n    {\n        return $this->part;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Element/Bookmark.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Element;\n\n/**\n * Bookmark element writer.\n *\n * @since 0.12.0\n */\nclass Bookmark extends AbstractElement\n{\n    /**\n     * Write bookmark element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $element = $this->getElement();\n        if (!$element instanceof \\PhpOffice\\PhpWord\\Element\\Bookmark) {\n            return;\n        }\n\n        $rId = $element->getRelationId();\n\n        $xmlWriter->startElement('w:bookmarkStart');\n        $xmlWriter->writeAttribute('w:id', $rId);\n        $xmlWriter->writeAttribute('w:name', $element->getName());\n        $xmlWriter->endElement();\n\n        $xmlWriter->startElement('w:bookmarkEnd');\n        $xmlWriter->writeAttribute('w:id', $rId);\n        $xmlWriter->endElement();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Element/Chart.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\Chart as ChartElement;\n\n/**\n * Chart element writer.\n *\n * @since 0.12.0\n */\nclass Chart extends AbstractElement\n{\n    /**\n     * Write element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $element = $this->getElement();\n        if (!$element instanceof ChartElement) {\n            return;\n        }\n\n        $rId = $element->getRelationId();\n        $style = $element->getStyle();\n\n        if (!$this->withoutP) {\n            $xmlWriter->startElement('w:p');\n        }\n        $this->writeCommentRangeStart();\n\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:drawing');\n        $xmlWriter->startElement('wp:inline');\n\n        // EMU\n        $xmlWriter->writeElementBlock('wp:extent', ['cx' => $style->getWidth(), 'cy' => $style->getHeight()]);\n        $xmlWriter->writeElementBlock('wp:docPr', ['id' => $rId, 'name' => \"Chart{$rId}\"]);\n\n        $xmlWriter->startElement('a:graphic');\n        $xmlWriter->writeAttribute('xmlns:a', 'http://schemas.openxmlformats.org/drawingml/2006/main');\n        $xmlWriter->startElement('a:graphicData');\n        $xmlWriter->writeAttribute('uri', 'http://schemas.openxmlformats.org/drawingml/2006/chart');\n\n        $xmlWriter->startElement('c:chart');\n        $xmlWriter->writeAttribute('r:id', \"rId{$rId}\");\n        $xmlWriter->writeAttribute('xmlns:c', 'http://schemas.openxmlformats.org/drawingml/2006/chart');\n        $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');\n        $xmlWriter->endElement(); // c:chart\n\n        $xmlWriter->endElement(); // a:graphicData\n        $xmlWriter->endElement(); // a:graphic\n\n        $xmlWriter->endElement(); // wp:inline\n        $xmlWriter->endElement(); // w:drawing\n        $xmlWriter->endElement(); // w:r\n\n        $this->endElementP(); // w:p\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Element/CheckBox.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Element;\n\n/**\n * CheckBox element writer.\n *\n * @since 0.10.0\n */\nclass CheckBox extends Text\n{\n    /**\n     * Write element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $element = $this->getElement();\n        if (!$element instanceof \\PhpOffice\\PhpWord\\Element\\CheckBox) {\n            return;\n        }\n\n        $this->startElementP();\n\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:fldChar');\n        $xmlWriter->writeAttribute('w:fldCharType', 'begin');\n        $xmlWriter->startElement('w:ffData');\n        $xmlWriter->startElement('w:name');\n        $xmlWriter->writeAttribute('w:val', $this->getText($element->getName()));\n        $xmlWriter->endElement(); //w:name\n        $xmlWriter->writeAttribute('w:enabled', '');\n        $xmlWriter->startElement('w:calcOnExit');\n        $xmlWriter->writeAttribute('w:val', '0');\n        $xmlWriter->endElement(); //w:calcOnExit\n        $xmlWriter->startElement('w:checkBox');\n        $xmlWriter->writeAttribute('w:sizeAuto', '');\n        $xmlWriter->startElement('w:default');\n        $xmlWriter->writeAttribute('w:val', 0);\n        $xmlWriter->endElement(); //w:default\n        $xmlWriter->endElement(); //w:checkBox\n        $xmlWriter->endElement(); // w:ffData\n        $xmlWriter->endElement(); // w:fldChar\n        $xmlWriter->endElement(); // w:r\n\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:instrText');\n        $xmlWriter->writeAttribute('xml:space', 'preserve');\n        $xmlWriter->text(' FORMCHECKBOX ');\n        $xmlWriter->endElement(); // w:instrText\n        $xmlWriter->endElement(); // w:r\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:fldChar');\n        $xmlWriter->writeAttribute('w:fldCharType', 'separate');\n        $xmlWriter->endElement(); // w:fldChar\n        $xmlWriter->endElement(); // w:r\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:fldChar');\n        $xmlWriter->writeAttribute('w:fldCharType', 'end');\n        $xmlWriter->endElement(); // w:fldChar\n        $xmlWriter->endElement(); // w:r\n\n        $xmlWriter->startElement('w:r');\n\n        $this->writeFontStyle();\n\n        $xmlWriter->startElement('w:t');\n        $xmlWriter->writeAttribute('xml:space', 'preserve');\n        $this->writeText($this->getText($element->getText()));\n        $xmlWriter->endElement(); // w:t\n        $xmlWriter->endElement(); // w:r\n\n        $this->endElementP(); // w:p\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Element/Container.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\AbstractContainer as ContainerElement;\nuse PhpOffice\\PhpWord\\Element\\AbstractElement as Element;\nuse PhpOffice\\PhpWord\\Element\\TextBreak as TextBreakElement;\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\n\n/**\n * Container element writer (section, textrun, header, footnote, cell, etc.).\n *\n * @since 0.11.0\n */\nclass Container extends AbstractElement\n{\n    /**\n     * Namespace; Can't use __NAMESPACE__ in inherited class (ODText).\n     *\n     * @var string\n     */\n    protected $namespace = 'PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007\\\\Element';\n\n    /**\n     * @var array<string>\n     */\n    protected $containerWithoutP = ['TextRun', 'Footnote', 'Endnote', 'ListItemRun'];\n\n    /**\n     * Write element.\n     */\n    public function write(): void\n    {\n        $container = $this->getElement();\n        if (!$container instanceof ContainerElement) {\n            return;\n        }\n        $containerClass = substr(get_class($container), strrpos(get_class($container), '\\\\') + 1);\n        $withoutP = in_array($containerClass, $this->containerWithoutP);\n        $xmlWriter = $this->getXmlWriter();\n\n        // Loop through elements\n        $elements = $container->getElements();\n        $elementClass = '';\n        foreach ($elements as $element) {\n            $elementClass = $this->writeElement($xmlWriter, $element, $withoutP);\n        }\n\n        // Special case for Cell: They have to contain a w:p element at the end.\n        // The $elementClass contains the last element name. If it's empty string\n        // or Table, the last element is not w:p\n        $writeLastTextBreak = ($containerClass == 'Cell') && ($elementClass == '' || $elementClass == 'Table');\n        if ($writeLastTextBreak) {\n            $writerClass = $this->namespace . '\\\\TextBreak';\n            /** @var AbstractElement $writer Type hint */\n            $writer = new $writerClass($xmlWriter, new TextBreakElement(), $withoutP);\n            $writer->write();\n        }\n    }\n\n    /**\n     * Write individual element.\n     */\n    private function writeElement(XMLWriter $xmlWriter, Element $element, bool $withoutP): string\n    {\n        $elementClass = substr(get_class($element), strrpos(get_class($element), '\\\\') + 1);\n        $writerClass = $this->namespace . '\\\\' . $elementClass;\n\n        if (class_exists($writerClass)) {\n            /** @var AbstractElement $writer Type hint */\n            $writer = new $writerClass($xmlWriter, $element, $withoutP);\n            $writer->setPart($this->getPart());\n            $writer->write();\n        }\n\n        return $elementClass;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Element/Endnote.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Element;\n\n/**\n * Endnote element writer.\n *\n * @since 0.10.0\n */\nclass Endnote extends Footnote\n{\n    /**\n     * Reference type.\n     *\n     * @var string\n     */\n    protected $referenceType = 'endnoteReference';\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Element/Field.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\Field as ElementField;\nuse PhpOffice\\PhpWord\\Element\\TextRun;\n\n/**\n * Field element writer.\n *\n * @since 0.11.0\n */\nclass Field extends Text\n{\n    /**\n     * Write field element.\n     */\n    public function write(): void\n    {\n        $element = $this->getElement();\n        if (!$element instanceof ElementField) {\n            return;\n        }\n\n        $methodName = 'write' . ucfirst(strtolower($element->getType()));\n        if (method_exists($this, $methodName)) {\n            $this->$methodName($element);\n        } else {\n            $this->writeDefault($element);\n        }\n    }\n\n    private function writeDefault(ElementField $element): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $this->startElementP();\n\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:fldChar');\n        $xmlWriter->writeAttribute('w:fldCharType', 'begin');\n        $xmlWriter->endElement(); // w:fldChar\n        $xmlWriter->endElement(); // w:r\n\n        $instruction = ' ' . $element->getType() . ' ';\n        if ($element->getText() != null) {\n            if (is_string($element->getText())) {\n                $instruction .= '\"' . $element->getText() . '\" ';\n                $instruction .= $this->buildPropertiesAndOptions($element);\n            } else {\n                $instruction .= '\"';\n            }\n        } else {\n            $instruction .= $this->buildPropertiesAndOptions($element);\n        }\n        $xmlWriter->startElement('w:r');\n        $this->writeFontStyle();\n        $xmlWriter->startElement('w:instrText');\n        $xmlWriter->writeAttribute('xml:space', 'preserve');\n        $xmlWriter->text($instruction);\n        $xmlWriter->endElement(); // w:instrText\n        $xmlWriter->endElement(); // w:r\n\n        if ($element->getText() != null) {\n            if ($element->getText() instanceof TextRun) {\n                $containerWriter = new Container($xmlWriter, $element->getText(), true);\n                $containerWriter->write();\n\n                $xmlWriter->startElement('w:r');\n                $xmlWriter->startElement('w:instrText');\n                $xmlWriter->text('\"' . $this->buildPropertiesAndOptions($element));\n                $xmlWriter->endElement(); // w:instrText\n                $xmlWriter->endElement(); // w:r\n\n                $xmlWriter->startElement('w:r');\n                $xmlWriter->startElement('w:instrText');\n                $xmlWriter->writeAttribute('xml:space', 'preserve');\n                $xmlWriter->text(' ');\n                $xmlWriter->endElement(); // w:instrText\n                $xmlWriter->endElement(); // w:r\n            }\n        }\n\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:fldChar');\n        $xmlWriter->writeAttribute('w:fldCharType', 'separate');\n        $xmlWriter->endElement(); // w:fldChar\n        $xmlWriter->endElement(); // w:r\n\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:rPr');\n        $xmlWriter->startElement('w:noProof');\n        $xmlWriter->endElement(); // w:noProof\n        $xmlWriter->endElement(); // w:rPr\n        $xmlWriter->writeElement('w:t', $element->getText() != null && is_string($element->getText()) ? $element->getText() : '1');\n        $xmlWriter->endElement(); // w:r\n\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:fldChar');\n        $xmlWriter->writeAttribute('w:fldCharType', 'end');\n        $xmlWriter->endElement(); // w:fldChar\n        $xmlWriter->endElement(); // w:r\n\n        $this->endElementP(); // w:p\n    }\n\n    /**\n     * Writes a macrobutton field.\n     *\n     * //TODO A lot of code duplication with general method, should maybe be refactored\n     */\n    protected function writeMacrobutton(ElementField $element): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $this->startElementP();\n\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:fldChar');\n        $xmlWriter->writeAttribute('w:fldCharType', 'begin');\n        $xmlWriter->endElement(); // w:fldChar\n        $xmlWriter->endElement(); // w:r\n\n        $instruction = ' ' . $element->getType() . ' ' . $this->buildPropertiesAndOptions($element);\n        if (is_string($element->getText())) {\n            $instruction .= $element->getText() . ' ';\n        }\n\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:instrText');\n        $xmlWriter->writeAttribute('xml:space', 'preserve');\n        $xmlWriter->text($instruction);\n        $xmlWriter->endElement(); // w:instrText\n        $xmlWriter->endElement(); // w:r\n\n        if ($element->getText() != null) {\n            if ($element->getText() instanceof TextRun) {\n                $containerWriter = new Container($xmlWriter, $element->getText(), true);\n                $containerWriter->write();\n            }\n        }\n\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:fldChar');\n        $xmlWriter->writeAttribute('w:fldCharType', 'end');\n        $xmlWriter->endElement(); // w:fldChar\n        $xmlWriter->endElement(); // w:r\n\n        $this->endElementP(); // w:p\n    }\n\n    private function buildPropertiesAndOptions(ElementField $element)\n    {\n        $propertiesAndOptions = '';\n        $properties = $element->getProperties();\n        foreach ($properties as $propkey => $propval) {\n            switch ($propkey) {\n                case 'format':\n                    $propertiesAndOptions .= '\\\\* ' . $propval . ' ';\n\n                    break;\n                case 'numformat':\n                    $propertiesAndOptions .= '\\\\# ' . $propval . ' ';\n\n                    break;\n                case 'dateformat':\n                    $propertiesAndOptions .= '\\\\@ \"' . $propval . '\" ';\n\n                    break;\n                case 'macroname':\n                    $propertiesAndOptions .= $propval . ' ';\n\n                    break;\n                default:\n                    $propertiesAndOptions .= '\"' . $propval . '\" ';\n\n                    break;\n            }\n        }\n\n        $options = $element->getOptions();\n        foreach ($options as $option) {\n            switch ($option) {\n                case 'PreserveFormat':\n                    $propertiesAndOptions .= '\\\\* MERGEFORMAT ';\n\n                    break;\n                case 'LunarCalendar':\n                    $propertiesAndOptions .= '\\\\h ';\n\n                    break;\n                case 'SakaEraCalendar':\n                    $propertiesAndOptions .= '\\\\s ';\n\n                    break;\n                case 'LastUsedFormat':\n                    $propertiesAndOptions .= '\\\\l ';\n\n                    break;\n                case 'Bold':\n                    $propertiesAndOptions .= '\\\\b ';\n\n                    break;\n                case 'Italic':\n                    $propertiesAndOptions .= '\\\\i ';\n\n                    break;\n                case 'Path':\n                    $propertiesAndOptions .= '\\\\p ';\n\n                    break;\n                default:\n                    $propertiesAndOptions .= $option . ' ';\n            }\n        }\n\n        return $propertiesAndOptions;\n    }\n\n    /**\n     * Writes a REF field.\n     */\n    protected function writeRef(ElementField $element): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $this->startElementP();\n\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:fldChar');\n        $xmlWriter->writeAttribute('w:fldCharType', 'begin');\n        $xmlWriter->endElement(); // w:fldChar\n        $xmlWriter->endElement(); // w:r\n\n        $instruction = ' ' . $element->getType() . ' ';\n\n        foreach ($element->getProperties() as $property) {\n            $instruction .= $property . ' ';\n        }\n        foreach ($element->getOptions() as $optionKey => $optionValue) {\n            $instruction .= $this->convertRefOption($optionKey, $optionValue) . ' ';\n        }\n\n        $xmlWriter->startElement('w:r');\n        $this->writeFontStyle();\n        $xmlWriter->startElement('w:instrText');\n        $xmlWriter->writeAttribute('xml:space', 'preserve');\n        $xmlWriter->text($instruction);\n        $xmlWriter->endElement(); // w:instrText\n        $xmlWriter->endElement(); // w:r\n\n        if ($element->getText() != null) {\n            if ($element->getText() instanceof TextRun) {\n                $containerWriter = new Container($xmlWriter, $element->getText(), true);\n                $containerWriter->write();\n\n                $xmlWriter->startElement('w:r');\n                $xmlWriter->startElement('w:instrText');\n                $xmlWriter->text('\"' . $this->buildPropertiesAndOptions($element));\n                $xmlWriter->endElement(); // w:instrText\n                $xmlWriter->endElement(); // w:r\n\n                $xmlWriter->startElement('w:r');\n                $xmlWriter->startElement('w:instrText');\n                $xmlWriter->writeAttribute('xml:space', 'preserve');\n                $xmlWriter->text(' ');\n                $xmlWriter->endElement(); // w:instrText\n                $xmlWriter->endElement(); // w:r\n            }\n        }\n\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:fldChar');\n        $xmlWriter->writeAttribute('w:fldCharType', 'separate');\n        $xmlWriter->endElement(); // w:fldChar\n        $xmlWriter->endElement(); // w:r\n\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:rPr');\n        $xmlWriter->startElement('w:noProof');\n        $xmlWriter->endElement(); // w:noProof\n        $xmlWriter->endElement(); // w:rPr\n        $xmlWriter->writeElement('w:t', $element->getText() != null && is_string($element->getText()) ? $element->getText() : '1');\n        $xmlWriter->endElement(); // w:r\n\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:fldChar');\n        $xmlWriter->writeAttribute('w:fldCharType', 'end');\n        $xmlWriter->endElement(); // w:fldChar\n        $xmlWriter->endElement(); // w:r\n\n        $this->endElementP(); // w:p\n    }\n\n    private function convertRefOption(string $optionKey, string $optionValue): string\n    {\n        if ($optionKey === 'NumberSeperatorSequence') {\n            return '\\\\d ' . $optionValue;\n        }\n\n        switch ($optionValue) {\n            case 'IncrementAndInsertText':\n                return '\\\\f';\n            case 'CreateHyperLink':\n                return '\\\\h';\n            case 'NoTrailingPeriod':\n                return '\\\\n';\n            case 'IncludeAboveOrBelow':\n                return '\\\\p';\n            case 'InsertParagraphNumberRelativeContext':\n                return '\\\\r';\n            case 'SuppressNonDelimiterNonNumericalText':\n                return '\\\\t';\n            case 'InsertParagraphNumberFullContext':\n                return '\\\\w';\n            default:\n                return '';\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Element/Footnote.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Element;\n\n/**\n * Footnote element writer.\n *\n * @since 0.10.0\n */\nclass Footnote extends Text\n{\n    /**\n     * Reference type footnoteReference|endnoteReference.\n     *\n     * @var string\n     */\n    protected $referenceType = 'footnoteReference';\n\n    /**\n     * Write element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $element = $this->getElement();\n        if (!$element instanceof \\PhpOffice\\PhpWord\\Element\\Footnote) {\n            return;\n        }\n\n        $this->startElementP();\n\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:rPr');\n        $xmlWriter->startElement('w:rStyle');\n        $xmlWriter->writeAttribute('w:val', ucfirst($this->referenceType));\n        $xmlWriter->endElement(); // w:rStyle\n        $xmlWriter->endElement(); // w:rPr\n        $xmlWriter->startElement(\"w:{$this->referenceType}\");\n        $xmlWriter->writeAttribute('w:id', $element->getRelationId() + 1);\n        $xmlWriter->endElement(); // w:$referenceType\n        $xmlWriter->endElement(); // w:r\n\n        $this->endElementP(); // w:p\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Element/FormField.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\FormField as FormFieldElement;\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\n\n/**\n * FormField element writer.\n *\n * Note: DropDown is active when document protection is set to `forms`\n *\n * @since 0.12.0\n * @see  http://www.datypic.com/sc/ooxml/t-w_CT_FFData.html\n *\n * @SuppressWarnings(\"PHPMD.UnusedPrivateMethod\")\n */\nclass FormField extends Text\n{\n    /** @const int Length of filler when value is null */\n    const FILLER_LENGTH = 30;\n\n    /**\n     * Write element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $element = $this->getElement();\n        if (!$element instanceof FormFieldElement) {\n            return;\n        }\n\n        $type = $element->getType();\n        $instructions = ['textinput' => 'FORMTEXT', 'checkbox' => 'FORMCHECKBOX', 'dropdown' => 'FORMDROPDOWN'];\n        $instruction = $instructions[$type];\n        $writeFormField = \"write{$type}\";\n        $name = $element->getName();\n        if ($name === null) {\n            $name = $type . $element->getElementId();\n        }\n        $value = $element->getValue();\n        if ($value === null) {\n            $value = str_repeat(' ', self::FILLER_LENGTH);\n        }\n\n        $this->startElementP();\n\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:fldChar');\n        $xmlWriter->writeAttribute('w:fldCharType', 'begin');\n        $xmlWriter->startElement('w:ffData');\n        $xmlWriter->writeElementBlock('w:enabled', 'w:val', 1);\n        $xmlWriter->writeElementBlock('w:name', 'w:val', $name);\n        $xmlWriter->writeElementBlock('w:calcOnExit', 'w:val', 0);\n        $this->$writeFormField($xmlWriter, $element);\n        $xmlWriter->endElement(); // w:ffData\n        $xmlWriter->endElement(); // w:fldChar\n        $xmlWriter->endElement(); // w:r\n\n        $xmlWriter->startElement('w:r');\n        $this->writeFontStyle();\n        $xmlWriter->startElement('w:instrText');\n        $xmlWriter->writeAttribute('xml:space', 'preserve');\n        $xmlWriter->text(\"{$instruction}\");\n        $xmlWriter->endElement(); // w:instrText\n        $xmlWriter->endElement(); // w:r\n\n        $xmlWriter->startElement('w:r');\n        $this->writeFontStyle();\n        $xmlWriter->writeElementBlock('w:fldChar', 'w:fldCharType', 'separate');\n        $xmlWriter->endElement(); // w:r\n\n        $xmlWriter->startElement('w:r');\n        $this->writeFontStyle();\n        $xmlWriter->startElement('w:t');\n        $xmlWriter->writeAttribute('xml:space', 'preserve');\n        $this->writeText($value);\n        $xmlWriter->endElement(); // w:t\n        $xmlWriter->endElement(); // w:r\n\n        $xmlWriter->startElement('w:r');\n        $this->writeFontStyle();\n        $xmlWriter->writeElementBlock('w:fldChar', 'w:fldCharType', 'end');\n        $xmlWriter->endElement(); // w:r\n\n        $this->endElementP(); // w:p\n    }\n\n    /**\n     * Write textinput.\n     *\n     * @see  http://www.datypic.com/sc/ooxml/t-w_CT_FFTextInput.html\n     */\n    private function writeTextInput(XMLWriter $xmlWriter, FormFieldElement $element): void\n    {\n        $default = $element->getDefault();\n\n        $xmlWriter->startElement('w:textInput');\n        $xmlWriter->writeElementBlock('w:default', 'w:val', $default);\n        $xmlWriter->endElement();\n    }\n\n    /**\n     * Write checkbox.\n     *\n     * @see  http://www.datypic.com/sc/ooxml/t-w_CT_FFCheckBox.html\n     */\n    private function writeCheckBox(XMLWriter $xmlWriter, FormFieldElement $element): void\n    {\n        $default = $element->getDefault() ? 1 : 0;\n        $value = $element->getValue();\n        if ($value == null) {\n            $value = $default;\n        }\n        $value = $value ? 1 : 0;\n\n        $xmlWriter->startElement('w:checkBox');\n        $xmlWriter->writeElementBlock('w:sizeAuto', 'w:val', '');\n        $xmlWriter->writeElementBlock('w:default', 'w:val', $default);\n        $xmlWriter->writeElementBlock('w:checked', 'w:val', $value);\n        $xmlWriter->endElement();\n    }\n\n    /**\n     * Write dropdown.\n     *\n     * @see  http://www.datypic.com/sc/ooxml/t-w_CT_FFDDList.html\n     */\n    private function writeDropDown(XMLWriter $xmlWriter, FormFieldElement $element): void\n    {\n        $default = $element->getDefault();\n        $value = $element->getValue();\n        if ($value == null) {\n            $value = $default;\n        }\n        $entries = $element->getEntries();\n\n        $xmlWriter->startElement('w:ddList');\n        $xmlWriter->writeElementBlock('w:result', 'w:val', $value);\n        $xmlWriter->writeElementBlock('w:default', 'w:val', $default);\n        foreach ($entries as $entry) {\n            if ($entry == null || $entry == '') {\n                $entry = str_repeat(' ', self::FILLER_LENGTH);\n            }\n            $xmlWriter->writeElementBlock('w:listEntry', 'w:val', $entry);\n        }\n        $xmlWriter->endElement();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Element/Formula.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Element;\n\nuse PhpOffice\\Math\\Writer\\OfficeMathML;\nuse PhpOffice\\PhpWord\\Element\\Formula as FormulaElement;\n\n/**\n * Formula element writer.\n */\nclass Formula extends AbstractElement\n{\n    /**\n     * Write element.\n     */\n    public function write(): void\n    {\n        $element = $this->getElement();\n        if (!$element instanceof FormulaElement) {\n            return;\n        }\n\n        $this->startElementP();\n\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->writeElement('w:rPr');\n        $xmlWriter->endElement();\n\n        $xmlWriter->writeRaw((new OfficeMathML())->write($element->getMath()));\n\n        $this->endElementP();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Element/Image.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\Image as ImageElement;\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\nuse PhpOffice\\PhpWord\\Style\\Font as FontStyle;\nuse PhpOffice\\PhpWord\\Style\\Frame as FrameStyle;\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Font as FontStyleWriter;\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Image as ImageStyleWriter;\n\n/**\n * Image element writer.\n *\n * @since 0.10.0\n */\nclass Image extends AbstractElement\n{\n    /**\n     * Write element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $element = $this->getElement();\n        if (!$element instanceof ImageElement) {\n            return;\n        }\n\n        if ($element->isWatermark()) {\n            $this->writeWatermark($xmlWriter, $element);\n        } else {\n            $this->writeImage($xmlWriter, $element);\n        }\n    }\n\n    /**\n     * Write image element.\n     */\n    private function writeImage(XMLWriter $xmlWriter, ImageElement $element): void\n    {\n        $rId = $element->getRelationId() + ($element->isInSection() ? 6 : 0);\n        $style = $element->getStyle();\n        $styleWriter = new ImageStyleWriter($xmlWriter, $style);\n\n        if (!$this->withoutP) {\n            $xmlWriter->startElement('w:p');\n            $styleWriter->writeAlignment();\n        }\n        $this->writeCommentRangeStart();\n\n        $xmlWriter->startElement('w:r');\n\n        // Write position\n        $position = $style->getPosition();\n        if ($position && $style->getWrap() == FrameStyle::WRAP_INLINE) {\n            $fontStyle = new FontStyle('text');\n            $fontStyle->setPosition($position);\n            $fontStyleWriter = new FontStyleWriter($xmlWriter, $fontStyle);\n            $fontStyleWriter->write();\n        }\n\n        $xmlWriter->startElement('w:pict');\n        $xmlWriter->startElement('v:shape');\n        $xmlWriter->writeAttribute('type', '#_x0000_t75');\n        $xmlWriter->writeAttribute('stroked', 'f');\n\n        $styleWriter->write();\n\n        $xmlWriter->startElement('v:imagedata');\n        $xmlWriter->writeAttribute('r:id', 'rId' . $rId);\n        $xmlWriter->writeAttribute('o:title', '');\n        $xmlWriter->endElement(); // v:imagedata\n\n        $xmlWriter->endElement(); // v:shape\n        $xmlWriter->endElement(); // w:pict\n        $xmlWriter->endElement(); // w:r\n\n        $this->endElementP();\n    }\n\n    /**\n     * Write watermark element.\n     */\n    private function writeWatermark(XMLWriter $xmlWriter, ImageElement $element): void\n    {\n        $rId = $element->getRelationId();\n        $style = $element->getStyle();\n        $style->setPositioning('absolute');\n        $styleWriter = new ImageStyleWriter($xmlWriter, $style);\n\n        if (!$this->withoutP) {\n            $xmlWriter->startElement('w:p');\n        }\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:pict');\n        $xmlWriter->startElement('v:shape');\n        $xmlWriter->writeAttribute('type', '#_x0000_t75');\n        $xmlWriter->writeAttribute('stroked', 'f');\n\n        $styleWriter->write();\n\n        $xmlWriter->startElement('v:imagedata');\n        $xmlWriter->writeAttribute('r:id', 'rId' . $rId);\n        $xmlWriter->writeAttribute('o:title', '');\n        $xmlWriter->endElement(); // v:imagedata\n        $xmlWriter->endElement(); // v:shape\n        $xmlWriter->endElement(); // w:pict\n        $xmlWriter->endElement(); // w:r\n        if (!$this->withoutP) {\n            $xmlWriter->endElement(); // w:p\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Element/Line.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\Line as LineElement;\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Line as LineStyleWriter;\n\n/**\n * Line element writer.\n */\nclass Line extends AbstractElement\n{\n    /**\n     * Write element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $element = $this->getElement();\n        if (!$element instanceof LineElement) {\n            return;\n        }\n\n        $style = $element->getStyle();\n        $styleWriter = new LineStyleWriter($xmlWriter, $style);\n\n        $elementId = $element->getElementIndex();\n\n        if (!$this->withoutP) {\n            $xmlWriter->startElement('w:p');\n            $styleWriter->writeAlignment();\n        }\n        $this->writeCommentRangeStart();\n\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:pict');\n\n        // Shapetype could be defined for each line separately, but then a unique id would be necessary\n        if ($elementId == 1) {\n            $xmlWriter->startElement('v:shapetype');\n            $xmlWriter->writeAttribute('id', '_x0000_t32');\n            $xmlWriter->writeAttribute('coordsize', '21600,21600');\n            $xmlWriter->writeAttribute('o:spt', '32');\n            $xmlWriter->writeAttribute('o:oned', 't');\n            $xmlWriter->writeAttribute('path', 'm,l21600,21600e');\n            $xmlWriter->writeAttribute('filled', 'f');\n            $xmlWriter->startElement('v:path');\n            $xmlWriter->writeAttribute('arrowok', 't');\n            $xmlWriter->writeAttribute('fillok', 'f');\n            $xmlWriter->writeAttribute('o:connecttype', 'none');\n            $xmlWriter->endElement(); // v:path\n            $xmlWriter->startElement('o:lock');\n            $xmlWriter->writeAttribute('v:ext', 'edit');\n            $xmlWriter->writeAttribute('shapetype', 't');\n            $xmlWriter->endElement(); // o:lock\n            $xmlWriter->endElement(); // v:shapetype\n        }\n\n        $xmlWriter->startElement('v:shape');\n        $xmlWriter->writeAttribute('id', sprintf('_x0000_s1%1$03d', $elementId));\n        $xmlWriter->writeAttribute('type', '#_x0000_t32'); //type should correspond to shapetype id\n\n        $styleWriter->write();\n        $styleWriter->writeStroke();\n\n        $xmlWriter->endElement(); // v:shape\n\n        $xmlWriter->endElement(); // w:pict\n        $xmlWriter->endElement(); // w:r\n\n        $this->endElementP(); // w:p\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Element/Link.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Element;\n\n/**\n * Link element writer.\n *\n * @since 0.10.0\n */\nclass Link extends Text\n{\n    /**\n     * Write link element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $element = $this->getElement();\n        if (!$element instanceof \\PhpOffice\\PhpWord\\Element\\Link) {\n            return;\n        }\n\n        $rId = $element->getRelationId() + ($element->isInSection() ? 6 : 0);\n\n        $this->startElementP();\n\n        $xmlWriter->startElement('w:hyperlink');\n        if ($element->isInternal()) {\n            $xmlWriter->writeAttribute('w:anchor', $element->getSource());\n        } else {\n            $xmlWriter->writeAttribute('r:id', 'rId' . $rId);\n        }\n        $xmlWriter->writeAttribute('w:history', '1');\n        $xmlWriter->startElement('w:r');\n\n        $this->writeFontStyle();\n\n        $xmlWriter->startElement('w:t');\n        $xmlWriter->writeAttribute('xml:space', 'preserve');\n        $this->writeText($element->getText());\n        $xmlWriter->endElement(); // w:t\n        $xmlWriter->endElement(); // w:r\n        $xmlWriter->endElement(); // w:hyperlink\n\n        $this->endElementP(); // w:p\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Element/ListItem.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Element;\n\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Paragraph as ParagraphStyleWriter;\n\n/**\n * ListItem element writer.\n *\n * @since 0.10.0\n */\nclass ListItem extends AbstractElement\n{\n    /**\n     * Write list item element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $element = $this->getElement();\n        if (!$element instanceof \\PhpOffice\\PhpWord\\Element\\ListItem) {\n            return;\n        }\n\n        $textObject = $element->getTextObject();\n\n        $styleWriter = new ParagraphStyleWriter($xmlWriter, $textObject->getParagraphStyle());\n        $styleWriter->setWithoutPPR(true);\n        $styleWriter->setIsInline(true);\n\n        $xmlWriter->startElement('w:p');\n\n        $xmlWriter->startElement('w:pPr');\n        $styleWriter->write();\n\n        $xmlWriter->startElement('w:numPr');\n        $xmlWriter->startElement('w:ilvl');\n        $xmlWriter->writeAttribute('w:val', $element->getDepth());\n        $xmlWriter->endElement(); // w:ilvl\n        $xmlWriter->startElement('w:numId');\n        $xmlWriter->writeAttribute('w:val', $element->getStyle()->getNumId());\n        $xmlWriter->endElement(); // w:numId\n        $xmlWriter->endElement(); // w:numPr\n\n        $xmlWriter->endElement(); // w:pPr\n\n        $elementWriter = new Text($xmlWriter, $textObject, true);\n        $elementWriter->write();\n\n        $xmlWriter->endElement(); // w:p\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Element/ListItemRun.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\ListItemRun as ListItemRunElement;\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Paragraph as ParagraphStyleWriter;\n\n/**\n * ListItemRun element writer.\n *\n * @since 0.10.0\n */\nclass ListItemRun extends AbstractElement\n{\n    /**\n     * Write list item element.\n     */\n    public function write(): void\n    {\n        $element = $this->getElement();\n\n        if (!$element instanceof ListItemRunElement) {\n            return;\n        }\n\n        $this->writeParagraph($element);\n    }\n\n    private function writeParagraph(ListItemRunElement $element): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $xmlWriter->startElement('w:p');\n\n        $this->writeParagraphProperties($element);\n\n        $containerWriter = new Container($xmlWriter, $element);\n        $containerWriter->write();\n\n        $xmlWriter->endElement(); // w:p\n    }\n\n    private function writeParagraphProperties(ListItemRunElement $element): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $xmlWriter->startElement('w:pPr');\n\n        $styleWriter = new ParagraphStyleWriter($xmlWriter, $element->getParagraphStyle());\n        $styleWriter->setIsInline(true);\n        $styleWriter->setWithoutPPR(true);\n        $styleWriter->write();\n\n        $this->writeParagraphPropertiesNumbering($element);\n\n        $xmlWriter->endElement(); // w:pPr\n    }\n\n    private function writeParagraphPropertiesNumbering(ListItemRunElement $element): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $xmlWriter->startElement('w:numPr');\n\n        $xmlWriter->writeElementBlock('w:ilvl', [\n            'w:val' => $element->getDepth(),\n        ]);\n\n        $xmlWriter->writeElementBlock('w:numId', [\n            'w:val' => $element->getStyle()->getNumId(),\n        ]);\n\n        $xmlWriter->endElement(); // w:numPr\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Element/OLEObject.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Element;\n\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Image as ImageStyleWriter;\n\n/**\n * OLEObject element writer.\n *\n * @since 0.10.0\n */\nclass OLEObject extends AbstractElement\n{\n    /**\n     * Write object element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $element = $this->getElement();\n        if (!$element instanceof \\PhpOffice\\PhpWord\\Element\\OLEObject) {\n            return;\n        }\n\n        $rIdObject = $element->getRelationId() + ($element->isInSection() ? 6 : 0);\n        $rIdImage = $element->getImageRelationId() + ($element->isInSection() ? 6 : 0);\n        $shapeId = md5($rIdObject . '_' . $rIdImage);\n        $objectId = $element->getRelationId() + 1325353440;\n\n        $style = $element->getStyle();\n        $styleWriter = new ImageStyleWriter($xmlWriter, $style);\n\n        if (!$this->withoutP) {\n            $xmlWriter->startElement('w:p');\n            $styleWriter->writeAlignment();\n        }\n        $this->writeCommentRangeStart();\n\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:object');\n        $xmlWriter->writeAttribute('w:dxaOrig', '249');\n        $xmlWriter->writeAttribute('w:dyaOrig', '160');\n\n        // Icon\n        $xmlWriter->startElement('v:shape');\n        $xmlWriter->writeAttribute('id', $shapeId);\n        $xmlWriter->writeAttribute('type', '#_x0000_t75');\n        $xmlWriter->writeAttribute('style', 'width:104px;height:67px');\n        $xmlWriter->writeAttribute('o:ole', '');\n\n        $xmlWriter->startElement('v:imagedata');\n        $xmlWriter->writeAttribute('r:id', 'rId' . $rIdImage);\n        $xmlWriter->writeAttribute('o:title', '');\n        $xmlWriter->endElement(); // v:imagedata\n\n        $xmlWriter->endElement(); // v:shape\n\n        // Object\n        $xmlWriter->startElement('o:OLEObject');\n        $xmlWriter->writeAttribute('Type', 'Embed');\n        $xmlWriter->writeAttribute('ProgID', 'Package');\n        $xmlWriter->writeAttribute('ShapeID', $shapeId);\n        $xmlWriter->writeAttribute('DrawAspect', 'Icon');\n        $xmlWriter->writeAttribute('ObjectID', '_' . $objectId);\n        $xmlWriter->writeAttribute('r:id', 'rId' . $rIdObject);\n        $xmlWriter->endElement(); // o:OLEObject\n\n        $xmlWriter->endElement(); // w:object\n        $xmlWriter->endElement(); // w:r\n\n        $this->endElementP(); // w:p\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Element/PageBreak.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Element;\n\n/**\n * PageBreak element writer.\n *\n * @since 0.10.0\n */\nclass PageBreak extends AbstractElement\n{\n    /**\n     * Write element.\n     *\n     * @usedby \\PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\AbstractElement::startElementP()\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startElement('w:p');\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:br');\n        $xmlWriter->writeAttribute('w:type', 'page');\n        $xmlWriter->endElement(); // w:br\n        $xmlWriter->endElement(); // w:r\n        $xmlWriter->endElement(); // w:p\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Element/ParagraphAlignment.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Element;\n\n/**\n * @since 0.13.0\n */\nclass ParagraphAlignment\n{\n    private $name = 'w:jc';\n\n    private $attributes = [];\n\n    /**\n     * @since 0.13.0\n     *\n     * @param string $value Any value provided by Jc simple type\n     *\n     * @see \\PhpOffice\\PhpWord\\SimpleType\\Jc For the allowed values of $value parameter.\n     */\n    final public function __construct($value)\n    {\n        $this->attributes['w:val'] = $value;\n    }\n\n    /**\n     * @since 0.13.0\n     *\n     * @return string\n     */\n    final public function getName()\n    {\n        return $this->name;\n    }\n\n    /**\n     * @since 0.13.0\n     *\n     * @return string[]\n     */\n    final public function getAttributes()\n    {\n        return $this->attributes;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Element/PreserveText.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Element;\n\n/**\n * PreserveText element writer.\n *\n * @since 0.10.0\n */\nclass PreserveText extends Text\n{\n    /**\n     * Write preserve text element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $element = $this->getElement();\n        if (!$element instanceof \\PhpOffice\\PhpWord\\Element\\PreserveText) {\n            return;\n        }\n\n        $texts = $element->getText();\n        if (!is_array($texts)) {\n            $texts = [$texts];\n        }\n\n        $this->startElementP();\n\n        foreach ($texts as $text) {\n            if (substr($text, 0, 1) == '{') {\n                $text = substr($text, 1, -1);\n\n                $xmlWriter->startElement('w:r');\n                $xmlWriter->startElement('w:fldChar');\n                $xmlWriter->writeAttribute('w:fldCharType', 'begin');\n                $xmlWriter->endElement();\n                $xmlWriter->endElement();\n\n                $xmlWriter->startElement('w:r');\n\n                $this->writeFontStyle();\n\n                $xmlWriter->startElement('w:instrText');\n                $xmlWriter->writeAttribute('xml:space', 'preserve');\n                $this->writeText($text);\n                $xmlWriter->endElement();\n                $xmlWriter->endElement();\n\n                $xmlWriter->startElement('w:r');\n                $xmlWriter->startElement('w:fldChar');\n                $xmlWriter->writeAttribute('w:fldCharType', 'separate');\n                $xmlWriter->endElement();\n                $xmlWriter->endElement();\n\n                $xmlWriter->startElement('w:r');\n                $xmlWriter->startElement('w:fldChar');\n                $xmlWriter->writeAttribute('w:fldCharType', 'end');\n                $xmlWriter->endElement();\n                $xmlWriter->endElement();\n            } else {\n                $xmlWriter->startElement('w:r');\n\n                $this->writeFontStyle();\n\n                $xmlWriter->startElement('w:t');\n                $xmlWriter->writeAttribute('xml:space', 'preserve');\n                $this->writeText($this->getText($text));\n                $xmlWriter->endElement();\n                $xmlWriter->endElement();\n            }\n        }\n\n        $this->endElementP(); // w:p\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Element/Ruby.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Element;\n\n/**\n * Ruby element writer.\n */\nclass Ruby extends AbstractElement\n{\n    /**\n     * Write ruby element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $element = $this->getElement();\n        if (!$element instanceof \\PhpOffice\\PhpWord\\Element\\Ruby) {\n            return;\n        }\n        /** @var \\PhpOffice\\PhpWord\\Element\\Ruby $element */\n        $this->startElementP();\n\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:ruby');\n\n        // write properties\n        $xmlWriter->startElement('w:rubyPr');\n        $properties = $element->getProperties();\n        $xmlWriter->startElement('w:rubyAlign');\n        $xmlWriter->writeAttribute('w:val', $properties->getAlignment());\n        $xmlWriter->endElement(); // w:rubyAlign\n        $xmlWriter->startElement('w:hps');\n        $xmlWriter->writeAttribute('w:val', $properties->getFontFaceSize());\n        $xmlWriter->endElement(); // w:hps\n        $xmlWriter->startElement('w:hpsRaise');\n        $xmlWriter->writeAttribute('w:val', $properties->getFontPointsAboveBaseText());\n        $xmlWriter->endElement(); // w:hpsRaise\n        $xmlWriter->startElement('w:hpsBaseText');\n        $xmlWriter->writeAttribute('w:val', $properties->getFontSizeForBaseText());\n        $xmlWriter->endElement(); // w:hpsBaseText\n        $xmlWriter->startElement('w:lid');\n        $xmlWriter->writeAttribute('w:val', $properties->getLanguageId());\n        $xmlWriter->endElement(); // w:lid\n\n        $xmlWriter->endElement(); // w:rubyPr\n\n        // write ruby text\n        $xmlWriter->startElement('w:rt');\n        $rubyTextRun = $element->getRubyTextRun();\n        $textRunWriter = new TextRun($xmlWriter, $rubyTextRun, true);\n        $textRunWriter->write();\n        $xmlWriter->endElement(); // w:rt\n        // write base text\n        $xmlWriter->startElement('w:rubyBase');\n        $baseTextRun = $element->getBaseTextRun();\n        $textRunWriter = new TextRun($xmlWriter, $baseTextRun, true);\n        $textRunWriter->write();\n        $xmlWriter->endElement(); // w:rubyBase\n\n        $xmlWriter->endElement(); // w:ruby\n        $xmlWriter->endElement(); // w:r\n\n        $this->endElementP();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Element/SDT.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\SDT as SDTElement;\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\n\n/**\n * Structured document tag element writer.\n *\n * @since 0.12.0\n * @see  http://www.datypic.com/sc/ooxml/t-w_CT_SdtBlock.html\n *\n * @SuppressWarnings(\"PHPMD.UnusedPrivateMethod\")\n */\nclass SDT extends Text\n{\n    /**\n     * Write element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $element = $this->getElement();\n        if (!$element instanceof SDTElement) {\n            return;\n        }\n        $type = $element->getType();\n        $writeFormField = \"write{$type}\";\n        $alias = $element->getAlias();\n        $tag = $element->getTag();\n        $value = $element->getValue();\n        if ($value === null) {\n            $value = 'Pick value';\n        }\n\n        $this->startElementP();\n\n        $xmlWriter->startElement('w:sdt');\n\n        // Properties\n        $xmlWriter->startElement('w:sdtPr');\n        $xmlWriter->writeElementIf($alias != null, 'w:alias', 'w:val', $alias);\n        $xmlWriter->writeElementBlock('w:lock', 'w:val', 'sdtLocked');\n        $xmlWriter->writeElementBlock('w:id', 'w:val', mt_rand(100000000, 999999999));\n        $xmlWriter->writeElementIf($tag != null, 'w:tag', 'w:val', $tag);\n        $this->$writeFormField($xmlWriter, $element);\n        $xmlWriter->endElement(); // w:sdtPr\n\n        // Content\n        $xmlWriter->startElement('w:sdtContent');\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->writeElement('w:t', $value);\n        $xmlWriter->endElement(); // w:r\n        $xmlWriter->endElement(); // w:sdtContent\n\n        $xmlWriter->endElement(); // w:sdt\n\n        $this->endElementP(); // w:p\n    }\n\n    /**\n     * Write text.\n     *\n     * @see  http://www.datypic.com/sc/ooxml/t-w_CT_SdtText.html\n     */\n    private function writePlainText(XMLWriter $xmlWriter): void\n    {\n        $xmlWriter->startElement('w:text');\n        $xmlWriter->endElement(); // w:text\n    }\n\n    /**\n     * Write combo box.\n     *\n     * @see  http://www.datypic.com/sc/ooxml/t-w_CT_SdtComboBox.html\n     */\n    private function writeComboBox(XMLWriter $xmlWriter, SDTElement $element): void\n    {\n        $type = $element->getType();\n        $listItems = $element->getListItems();\n\n        $xmlWriter->startElement(\"w:{$type}\");\n        foreach ($listItems as $key => $val) {\n            $xmlWriter->writeElementBlock('w:listItem', ['w:value' => $key, 'w:displayText' => $val]);\n        }\n        $xmlWriter->endElement(); // w:{$type}\n    }\n\n    /**\n     * Write drop down list.\n     *\n     * @see  http://www.datypic.com/sc/ooxml/t-w_CT_SdtDropDownList.html\n     */\n    private function writeDropDownList(XMLWriter $xmlWriter, SDTElement $element): void\n    {\n        $this->writeComboBox($xmlWriter, $element);\n    }\n\n    /**\n     * Write date.\n     *\n     * @see  http://www.datypic.com/sc/ooxml/t-w_CT_SdtDate.html\n     */\n    private function writeDate(XMLWriter $xmlWriter, SDTElement $element): void\n    {\n        $type = $element->getType();\n\n        $xmlWriter->startElement(\"w:{$type}\");\n        $xmlWriter->writeElementBlock('w:dateFormat', 'w:val', 'd/M/yyyy');\n        $xmlWriter->writeElementBlock('w:lid', 'w:val', 'en-US');\n        $xmlWriter->writeElementBlock('w:storeMappedDataAs', 'w:val', 'dateTime');\n        $xmlWriter->writeElementBlock('w:calendar', 'w:val', 'gregorian');\n        $xmlWriter->endElement(); // w:date\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Element/Shape.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\Shape as ShapeElement;\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\nuse PhpOffice\\PhpWord\\Style\\Shape as ShapeStyle;\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Shape as ShapeStyleWriter;\n\n/**\n * Shape element writer.\n *\n * @since 0.12.0\n *\n * @SuppressWarnings(\"PHPMD.UnusedPrivateMethod\")\n */\nclass Shape extends AbstractElement\n{\n    /**\n     * Write element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $element = $this->getElement();\n        if (!$element instanceof ShapeElement) {\n            return;\n        }\n\n        $style = $element->getStyle();\n        $styleWriter = new ShapeStyleWriter($xmlWriter, $style);\n\n        $type = $element->getType();\n        if ($type == 'rect' && $style->getRoundness() !== null) {\n            $type = 'roundrect';\n        }\n        $method = \"write{$type}\";\n\n        if (!$this->withoutP) {\n            $xmlWriter->startElement('w:p');\n        }\n        $this->writeCommentRangeStart();\n\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:pict');\n        $xmlWriter->startElement(\"v:{$type}\");\n\n        // Element style\n        if (method_exists($this, $method)) {\n            $this->$method($xmlWriter, $style);\n        }\n\n        // Child style\n        $styleWriter->write();\n\n        $xmlWriter->endElement(); // v:$type\n        $xmlWriter->endElement(); // w:pict\n        $xmlWriter->endElement(); // w:r\n\n        $this->endElementP(); // w:p\n    }\n\n    /**\n     * Write arc.\n     */\n    private function writeArc(XMLWriter $xmlWriter, ShapeStyle $style): void\n    {\n        $points = $this->getPoints('arc', $style->getPoints());\n\n        $xmlWriter->writeAttributeIf($points['start'] !== null, 'startAngle', $points['start']);\n        $xmlWriter->writeAttributeIf($points['end'] !== null, 'endAngle', $points['end']);\n    }\n\n    /**\n     * Write curve.\n     */\n    private function writeCurve(XMLWriter $xmlWriter, ShapeStyle $style): void\n    {\n        $points = $this->getPoints('curve', $style->getPoints());\n\n        $this->writeLine($xmlWriter, $style);\n        $xmlWriter->writeAttributeIf($points['point1'] !== null, 'control1', $points['point1']);\n        $xmlWriter->writeAttributeIf($points['point2'] !== null, 'control2', $points['point2']);\n    }\n\n    /**\n     * Write line.\n     */\n    private function writeLine(XMLWriter $xmlWriter, ShapeStyle $style): void\n    {\n        $points = $this->getPoints('line', $style->getPoints());\n\n        $xmlWriter->writeAttributeIf($points['start'] !== null, 'from', $points['start']);\n        $xmlWriter->writeAttributeIf($points['end'] !== null, 'to', $points['end']);\n    }\n\n    /**\n     * Write polyline.\n     */\n    private function writePolyline(XMLWriter $xmlWriter, ShapeStyle $style): void\n    {\n        $xmlWriter->writeAttributeIf($style->getPoints() !== null, 'points', $style->getPoints());\n    }\n\n    /**\n     * Write rectangle.\n     */\n    private function writeRoundRect(XMLWriter $xmlWriter, ShapeStyle $style): void\n    {\n        $xmlWriter->writeAttribute('arcsize', $style->getRoundness());\n    }\n\n    /**\n     * Set points.\n     *\n     * @param string $type\n     * @param string $value\n     *\n     * @return array\n     */\n    private function getPoints($type, $value)\n    {\n        $points = [];\n\n        switch ($type) {\n            case 'arc':\n            case 'line':\n                $points = explode(' ', $value);\n                [$start, $end] = array_pad($points, 2, null);\n                $points = ['start' => $start, 'end' => $end];\n\n                break;\n            case 'curve':\n                $points = explode(' ', $value);\n                [$start, $end, $point1, $point2] = array_pad($points, 4, null);\n                $points = ['start' => $start, 'end' => $end, 'point1' => $point1, 'point2' => $point2];\n\n                break;\n        }\n\n        return $points;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Element/TOC.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\Title;\nuse PhpOffice\\PhpWord\\Element\\TOC as TOCElement;\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\nuse PhpOffice\\PhpWord\\Style\\Font;\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Font as FontStyleWriter;\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Paragraph as ParagraphStyleWriter;\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Tab as TabStyleWriter;\n\n/**\n * TOC element writer.\n *\n * @since 0.10.0\n */\nclass TOC extends AbstractElement\n{\n    /**\n     * Write element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $element = $this->getElement();\n        if (!$element instanceof TOCElement) {\n            return;\n        }\n\n        $titles = $element->getTitles();\n        $writeFieldMark = true;\n\n        foreach ($titles as $title) {\n            $this->writeTitle($xmlWriter, $element, $title, $writeFieldMark);\n            if ($writeFieldMark) {\n                $writeFieldMark = false;\n            }\n        }\n\n        $xmlWriter->startElement('w:p');\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:fldChar');\n        $xmlWriter->writeAttribute('w:fldCharType', 'end');\n        $xmlWriter->endElement();\n        $xmlWriter->endElement();\n        $xmlWriter->endElement();\n    }\n\n    /**\n     * Write title.\n     */\n    private function writeTitle(XMLWriter $xmlWriter, TOCElement $element, Title $title, bool $writeFieldMark): void\n    {\n        $tocStyle = $element->getStyleTOC();\n        $fontStyle = $element->getStyleFont();\n        $isObject = ($fontStyle instanceof Font) ? true : false;\n        $rId = $title->getRelationId();\n        $indent = (int) (($title->getDepth() - 1) * $tocStyle->getIndent());\n\n        $xmlWriter->startElement('w:p');\n\n        // Write style and field mark\n        $this->writeStyle($xmlWriter, $element, $indent);\n        if ($writeFieldMark) {\n            $this->writeFieldMark($xmlWriter, $element);\n        }\n\n        // Hyperlink\n        $xmlWriter->startElement('w:hyperlink');\n        $xmlWriter->writeAttribute('w:anchor', \"_Toc{$rId}\");\n        $xmlWriter->writeAttribute('w:history', '1');\n\n        // Title text\n        $xmlWriter->startElement('w:r');\n        if ($isObject) {\n            $styleWriter = new FontStyleWriter($xmlWriter, $fontStyle);\n            $styleWriter->write();\n        }\n        $xmlWriter->startElement('w:t');\n\n        $titleText = $title->getText();\n        $this->writeText(is_string($titleText) ? $titleText : '');\n\n        $xmlWriter->endElement(); // w:t\n        $xmlWriter->endElement(); // w:r\n\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->writeElement('w:tab', null);\n        $xmlWriter->endElement();\n\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:fldChar');\n        $xmlWriter->writeAttribute('w:fldCharType', 'begin');\n        $xmlWriter->endElement();\n        $xmlWriter->endElement();\n\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:instrText');\n        $xmlWriter->writeAttribute('xml:space', 'preserve');\n        $xmlWriter->text(\"PAGEREF $rId \\\\h\");\n        $xmlWriter->endElement();\n        $xmlWriter->endElement();\n\n        if ($title->getPageNumber() !== null) {\n            $xmlWriter->startElement('w:r');\n            $xmlWriter->startElement('w:fldChar');\n            $xmlWriter->writeAttribute('w:fldCharType', 'separate');\n            $xmlWriter->endElement();\n            $xmlWriter->endElement();\n\n            $xmlWriter->startElement('w:r');\n            $xmlWriter->startElement('w:t');\n            $xmlWriter->text((string) $title->getPageNumber());\n            $xmlWriter->endElement();\n            $xmlWriter->endElement();\n        }\n\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:fldChar');\n        $xmlWriter->writeAttribute('w:fldCharType', 'end');\n        $xmlWriter->endElement();\n        $xmlWriter->endElement();\n\n        $xmlWriter->endElement(); // w:hyperlink\n\n        $xmlWriter->endElement(); // w:p\n    }\n\n    /**\n     * Write style.\n     */\n    private function writeStyle(XMLWriter $xmlWriter, TOCElement $element, int $indent): void\n    {\n        $tocStyle = $element->getStyleTOC();\n        $fontStyle = $element->getStyleFont();\n        $isObject = ($fontStyle instanceof Font) ? true : false;\n\n        $xmlWriter->startElement('w:pPr');\n\n        // Paragraph\n        if ($isObject && null !== $fontStyle->getParagraph()) {\n            $styleWriter = new ParagraphStyleWriter($xmlWriter, $fontStyle->getParagraph());\n            $styleWriter->write();\n        }\n\n        // Font\n        if (!empty($fontStyle) && !$isObject) {\n            $xmlWriter->startElement('w:rPr');\n            $xmlWriter->startElement('w:rStyle');\n            $xmlWriter->writeAttribute('w:val', $fontStyle);\n            $xmlWriter->endElement();\n            $xmlWriter->endElement(); // w:rPr\n        }\n\n        // Tab\n        $xmlWriter->startElement('w:tabs');\n        $styleWriter = new TabStyleWriter($xmlWriter, $tocStyle);\n        $styleWriter->write();\n        $xmlWriter->endElement();\n\n        // Indent\n        if ($indent > 0) {\n            $xmlWriter->startElement('w:ind');\n            $xmlWriter->writeAttribute('w:left', $indent);\n            $xmlWriter->endElement();\n        }\n\n        $xmlWriter->endElement(); // w:pPr\n    }\n\n    /**\n     * Write TOC Field.\n     */\n    private function writeFieldMark(XMLWriter $xmlWriter, TOCElement $element): void\n    {\n        $minDepth = $element->getMinDepth();\n        $maxDepth = $element->getMaxDepth();\n\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:fldChar');\n        $xmlWriter->writeAttribute('w:fldCharType', 'begin');\n        $xmlWriter->endElement();\n        $xmlWriter->endElement();\n\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:instrText');\n        $xmlWriter->writeAttribute('xml:space', 'preserve');\n        $xmlWriter->text(\"TOC \\\\o {$minDepth}-{$maxDepth} \\\\h \\\\z \\\\u\");\n        $xmlWriter->endElement();\n        $xmlWriter->endElement();\n\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:fldChar');\n        $xmlWriter->writeAttribute('w:fldCharType', 'separate');\n        $xmlWriter->endElement();\n        $xmlWriter->endElement();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Element/Table.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\Cell as CellElement;\nuse PhpOffice\\PhpWord\\Element\\Row as RowElement;\nuse PhpOffice\\PhpWord\\Element\\Table as TableElement;\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\nuse PhpOffice\\PhpWord\\Style\\Cell as CellStyle;\nuse PhpOffice\\PhpWord\\Style\\Row as RowStyle;\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Cell as CellStyleWriter;\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Row as RowStyleWriter;\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Table as TableStyleWriter;\n\n/**\n * Table element writer.\n *\n * @since 0.10.0\n */\nclass Table extends AbstractElement\n{\n    /**\n     * Write element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $element = $this->getElement();\n        if (!$element instanceof TableElement) {\n            return;\n        }\n\n        $rows = $element->getRows();\n        $rowCount = count($rows);\n\n        if ($rowCount > 0) {\n            $xmlWriter->startElement('w:tbl');\n\n            // Write columns\n            $this->writeColumns($xmlWriter, $element);\n\n            // Write style\n            $styleWriter = new TableStyleWriter($xmlWriter, $element->getStyle());\n            $styleWriter->setWidth($element->getWidth());\n            $styleWriter->write();\n\n            // Write rows\n            for ($i = 0; $i < $rowCount; ++$i) {\n                $this->writeRow($xmlWriter, $rows[$i]);\n            }\n\n            $xmlWriter->endElement(); // w:tbl\n        }\n    }\n\n    /**\n     * Write column.\n     */\n    private function writeColumns(XMLWriter $xmlWriter, TableElement $element): void\n    {\n        $cellWidths = $element->findFirstDefinedCellWidths();\n\n        $xmlWriter->startElement('w:tblGrid');\n        foreach ($cellWidths as $width) {\n            $xmlWriter->startElement('w:gridCol');\n            if ($width !== null) {\n                $xmlWriter->writeAttribute('w:w', $width);\n                $xmlWriter->writeAttribute('w:type', 'dxa');\n            }\n            $xmlWriter->endElement();\n        }\n        $xmlWriter->endElement(); // w:tblGrid\n    }\n\n    /**\n     * Write row.\n     */\n    private function writeRow(XMLWriter $xmlWriter, RowElement $row): void\n    {\n        $xmlWriter->startElement('w:tr');\n\n        // Write style\n        $rowStyle = $row->getStyle();\n        if ($rowStyle instanceof RowStyle) {\n            $styleWriter = new RowStyleWriter($xmlWriter, $rowStyle);\n            $styleWriter->setHeight($row->getHeight());\n            $styleWriter->write();\n        }\n\n        // Write cells\n        $cells = $row->getCells();\n        if (count($cells) === 0) {\n            // issue 2505 - Word treats doc as corrupt if row without cell\n            $this->writeCell($xmlWriter, new CellElement());\n        } else {\n            foreach ($cells as $cell) {\n                $this->writeCell($xmlWriter, $cell);\n            }\n        }\n\n        $xmlWriter->endElement(); // w:tr\n    }\n\n    /**\n     * Write cell.\n     */\n    private function writeCell(XMLWriter $xmlWriter, CellElement $cell): void\n    {\n        $xmlWriter->startElement('w:tc');\n\n        // Write style\n        $cellStyle = $cell->getStyle();\n        if ($cellStyle instanceof CellStyle) {\n            $styleWriter = new CellStyleWriter($xmlWriter, $cellStyle);\n            $styleWriter->setWidth($cell->getWidth());\n            $styleWriter->write();\n        }\n\n        // Write content\n        $containerWriter = new Container($xmlWriter, $cell);\n        $containerWriter->write();\n\n        $xmlWriter->endElement(); // w:tc\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Element/TableAlignment.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Element;\n\n/**\n * @since 0.13.0\n */\nclass TableAlignment\n{\n    private $name = 'w:jc';\n\n    private $attributes = [];\n\n    /**\n     * @since 0.13.0\n     *\n     * @param string $value Any value provided by JcTable simple type\n     *\n     * @see \\PhpOffice\\PhpWord\\SimpleType\\JcTable For the allowed values of $value parameter.\n     */\n    final public function __construct($value)\n    {\n        $this->attributes['w:val'] = $value;\n    }\n\n    /**\n     * @since 0.13.0\n     *\n     * @return string\n     */\n    final public function getName()\n    {\n        return $this->name;\n    }\n\n    /**\n     * @since 0.13.0\n     *\n     * @return string[]\n     */\n    final public function getAttributes()\n    {\n        return $this->attributes;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Element/Text.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\TrackChange;\n\n/**\n * Text element writer.\n *\n * @since 0.10.0\n */\nclass Text extends AbstractElement\n{\n    /**\n     * Write text element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $element = $this->getElement();\n        if (!$element instanceof \\PhpOffice\\PhpWord\\Element\\Text) {\n            return;\n        }\n\n        $this->startElementP();\n\n        $this->writeOpeningTrackChange();\n\n        $xmlWriter->startElement('w:r');\n\n        $this->writeFontStyle();\n\n        $textElement = 'w:t';\n        //'w:delText' in case of deleted text\n        $changed = $element->getTrackChange();\n        if ($changed != null && $changed->getChangeType() == TrackChange::DELETED) {\n            $textElement = 'w:delText';\n        }\n        $xmlWriter->startElement($textElement);\n\n        $xmlWriter->writeAttribute('xml:space', 'preserve');\n        $this->writeText($this->getText($element->getText()));\n        $xmlWriter->endElement();\n        $xmlWriter->endElement(); // w:r\n\n        $this->writeClosingTrackChange();\n\n        $this->endElementP(); // w:p\n    }\n\n    /**\n     * Write opening of changed element.\n     */\n    protected function writeOpeningTrackChange(): void\n    {\n        $changed = $this->getElement()->getTrackChange();\n        if ($changed == null) {\n            return;\n        }\n\n        $xmlWriter = $this->getXmlWriter();\n\n        if (($changed->getChangeType() == TrackChange::INSERTED)) {\n            $xmlWriter->startElement('w:ins');\n        } elseif ($changed->getChangeType() == TrackChange::DELETED) {\n            $xmlWriter->startElement('w:del');\n        }\n        $xmlWriter->writeAttribute('w:author', $changed->getAuthor());\n        if ($changed->getDate() != null) {\n            $xmlWriter->writeAttribute('w:date', $changed->getDate()->format('Y-m-d\\TH:i:s\\Z'));\n        }\n        $xmlWriter->writeAttribute('w:id', $this->getElement()->getElementId());\n    }\n\n    /**\n     * Write ending.\n     */\n    protected function writeClosingTrackChange(): void\n    {\n        $changed = $this->getElement()->getTrackChange();\n        if ($changed == null) {\n            return;\n        }\n\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->endElement(); // w:ins|w:del\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Element/TextBox.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Element;\n\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\TextBox as TextBoxStyleWriter;\n\n/**\n * TextBox element writer.\n *\n * @since 0.11.0\n */\nclass TextBox extends Image\n{\n    /**\n     * Write element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $element = $this->getElement();\n        if (!$element instanceof \\PhpOffice\\PhpWord\\Element\\TextBox) {\n            return;\n        }\n        $style = $element->getStyle();\n        $styleWriter = new TextBoxStyleWriter($xmlWriter, $style);\n\n        if (!$this->withoutP) {\n            $xmlWriter->startElement('w:p');\n            $styleWriter->writeAlignment();\n        }\n        $this->writeCommentRangeStart();\n\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:pict');\n        $xmlWriter->startElement('v:shape');\n        $xmlWriter->writeAttribute('type', '#_x0000_t0202');\n\n        if ($style->getBgColor()) {\n            $xmlWriter->writeAttribute('fillcolor', $style->getBgColor());\n        } else {\n            $xmlWriter->writeAttribute('filled', 'f');\n        }\n\n        if (!$style->getBorderColor()) {\n            $xmlWriter->writeAttribute('stroked', 'f');\n            $xmlWriter->writeAttribute('strokecolor', 'white');\n        }\n\n        $styleWriter->write();\n        $styleWriter->writeBorder();\n\n        $xmlWriter->startElement('v:textbox');\n        $styleWriter->writeInnerMargin();\n\n        // TextBox content, serving as a container\n        $xmlWriter->startElement('w:txbxContent');\n        $containerWriter = new Container($xmlWriter, $element);\n        $containerWriter->write();\n        $xmlWriter->endElement(); // w:txbxContent\n\n        $xmlWriter->endElement(); // v: textbox\n\n        $xmlWriter->endElement(); // v:shape\n        $xmlWriter->endElement(); // w:pict\n        $xmlWriter->endElement(); // w:r\n\n        $this->endElementP();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Element/TextBreak.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Element;\n\n/**\n * TextBreak element writer.\n *\n * @since 0.10.0\n */\nclass TextBreak extends Text\n{\n    /**\n     * Write text break element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $element = $this->getElement();\n        if (!$element instanceof \\PhpOffice\\PhpWord\\Element\\TextBreak) {\n            return;\n        }\n\n        if (!$this->withoutP) {\n            $hasStyle = $element->hasStyle();\n            $this->startElementP();\n\n            if ($hasStyle) {\n                $xmlWriter->startElement('w:pPr');\n                $this->writeFontStyle();\n                $xmlWriter->endElement(); // w:pPr\n            }\n\n            $this->endElementP(); // w:p\n        } else {\n            $xmlWriter->writeElement('w:br');\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Element/TextRun.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Element;\n\n/**\n * TextRun element writer.\n *\n * @since 0.10.0\n */\nclass TextRun extends Text\n{\n    /**\n     * Write textrun element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $element = $this->getElement();\n\n        $this->startElementP();\n\n        $containerWriter = new Container($xmlWriter, $element);\n        $containerWriter->write();\n\n        $this->endElementP(); // w:p\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Element/Title.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Element;\n\n/**\n * TextRun element writer.\n *\n * @since 0.10.0\n */\nclass Title extends AbstractElement\n{\n    /**\n     * Write title element.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $element = $this->getElement();\n        if (!$element instanceof \\PhpOffice\\PhpWord\\Element\\Title) {\n            return;\n        }\n\n        $style = $element->getStyle();\n\n        $xmlWriter->startElement('w:p');\n\n        if (!empty($style)) {\n            $xmlWriter->startElement('w:pPr');\n            $xmlWriter->startElement('w:pStyle');\n            $xmlWriter->writeAttribute('w:val', $style);\n            $xmlWriter->endElement();\n            $xmlWriter->endElement();\n        }\n\n        $bookmarkRId = null;\n        if ($element->getDepth() !== 0) {\n            $rId = $element->getRelationId();\n            $bookmarkRId = $element->getPhpWord()->addBookmark();\n\n            // Bookmark start for TOC\n            $xmlWriter->startElement('w:bookmarkStart');\n            $xmlWriter->writeAttribute('w:id', $bookmarkRId);\n            $xmlWriter->writeAttribute('w:name', \"_Toc{$rId}\");\n            $xmlWriter->endElement(); //w:bookmarkStart\n        }\n\n        // Actual text\n        $text = $element->getText();\n        if (is_string($text)) {\n            $xmlWriter->startElement('w:r');\n            $xmlWriter->startElement('w:t');\n            $this->writeText($text);\n            $xmlWriter->endElement(); // w:t\n            $xmlWriter->endElement(); // w:r\n        }\n        if ($text instanceof \\PhpOffice\\PhpWord\\Element\\AbstractContainer) {\n            $containerWriter = new Container($xmlWriter, $text);\n            $containerWriter->write();\n        }\n\n        if ($element->getDepth() !== 0) {\n            // Bookmark end\n            $xmlWriter->startElement('w:bookmarkEnd');\n            $xmlWriter->writeAttribute('w:id', $bookmarkRId);\n            $xmlWriter->endElement(); //w:bookmarkEnd\n        }\n        $xmlWriter->endElement(); //w:p\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Part/AbstractPart.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Part;\n\nuse PhpOffice\\PhpWord\\Exception\\Exception;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\nuse PhpOffice\\PhpWord\\Writer\\AbstractWriter;\n\n/**\n * Word2007 writer part abstract class.\n */\nabstract class AbstractPart\n{\n    /**\n     * Parent writer.\n     *\n     * @var AbstractWriter\n     */\n    protected $parentWriter;\n\n    /**\n     * @var string Date format\n     */\n    protected $dateFormat = 'Y-m-d\\TH:i:sP';\n\n    /**\n     * Write part.\n     *\n     * @return string\n     */\n    abstract public function write();\n\n    /**\n     * Set parent writer.\n     */\n    public function setParentWriter(?AbstractWriter $writer = null): void\n    {\n        $this->parentWriter = $writer;\n    }\n\n    /**\n     * Get parent writer.\n     *\n     * @return AbstractWriter\n     */\n    public function getParentWriter()\n    {\n        if (null !== $this->parentWriter) {\n            return $this->parentWriter;\n        }\n\n        throw new Exception('No parent WriterInterface assigned.');\n    }\n\n    /**\n     * Get XML Writer.\n     *\n     * @return XMLWriter\n     */\n    protected function getXmlWriter()\n    {\n        $useDiskCaching = false;\n        if (null !== $this->parentWriter) {\n            if ($this->parentWriter->isUseDiskCaching()) {\n                $useDiskCaching = true;\n            }\n        }\n        if ($useDiskCaching) {\n            return new XMLWriter(XMLWriter::STORAGE_DISK, $this->parentWriter->getDiskCachingDirectory(), Settings::hasCompatibility());\n        }\n\n        return new XMLWriter(XMLWriter::STORAGE_MEMORY, './', Settings::hasCompatibility());\n    }\n\n    /**\n     * Write an XML text, this will call text() or writeRaw() depending on the value of Settings::isOutputEscapingEnabled().\n     *\n     * @param string $content The text string to write\n     *\n     * @return bool Returns true on success or false on failure\n     */\n    protected function writeText($content)\n    {\n        if (Settings::isOutputEscapingEnabled()) {\n            return $this->getXmlWriter()->text($content);\n        }\n\n        return $this->getXmlWriter()->writeRaw($content);\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Part/Chart.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Part;\n\nuse PhpOffice\\PhpWord\\Element\\Chart as ChartElement;\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\n\n/**\n * Word2007 chart part writer: word/charts/chartx.xml.\n *\n * @since 0.12.0\n * @see  http://www.datypic.com/sc/ooxml/e-draw-chart_chartSpace.html\n */\nclass Chart extends AbstractPart\n{\n    /**\n     * Chart element.\n     *\n     * @var ChartElement\n     */\n    private $element;\n\n    /**\n     * Type definition.\n     *\n     * @var array\n     */\n    private $types = [\n        'pie' => ['type' => 'pie', 'colors' => 1],\n        'doughnut' => ['type' => 'doughnut', 'colors' => 1, 'hole' => 75, 'no3d' => true],\n        'bar' => ['type' => 'bar', 'colors' => 0, 'axes' => true, 'bar' => 'bar', 'grouping' => 'clustered'],\n        'stacked_bar' => ['type' => 'bar', 'colors' => 0, 'axes' => true, 'bar' => 'bar', 'grouping' => 'stacked'],\n        'percent_stacked_bar' => ['type' => 'bar', 'colors' => 0, 'axes' => true, 'bar' => 'bar', 'grouping' => 'percentStacked'],\n        'column' => ['type' => 'bar', 'colors' => 0, 'axes' => true, 'bar' => 'col', 'grouping' => 'clustered'],\n        'stacked_column' => ['type' => 'bar', 'colors' => 0, 'axes' => true, 'bar' => 'col', 'grouping' => 'stacked'],\n        'percent_stacked_column' => ['type' => 'bar', 'colors' => 0, 'axes' => true, 'bar' => 'col', 'grouping' => 'percentStacked'],\n        'line' => ['type' => 'line', 'colors' => 0, 'axes' => true],\n        'area' => ['type' => 'area', 'colors' => 0, 'axes' => true],\n        'radar' => ['type' => 'radar', 'colors' => 0, 'axes' => true, 'radar' => 'standard', 'no3d' => true],\n        'scatter' => ['type' => 'scatter', 'colors' => 0, 'axes' => true, 'scatter' => 'marker', 'no3d' => true],\n    ];\n\n    /**\n     * Chart options.\n     *\n     * @var array\n     */\n    private $options = [];\n\n    /**\n     * Set chart element.\n     */\n    public function setElement(ChartElement $element): void\n    {\n        $this->element = $element;\n    }\n\n    /**\n     * Write part.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startDocument('1.0', 'UTF-8', 'yes');\n        $xmlWriter->startElement('c:chartSpace');\n        $xmlWriter->writeAttribute('xmlns:c', 'http://schemas.openxmlformats.org/drawingml/2006/chart');\n        $xmlWriter->writeAttribute('xmlns:a', 'http://schemas.openxmlformats.org/drawingml/2006/main');\n        $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');\n\n        $this->writeChart($xmlWriter);\n        $this->writeShape($xmlWriter);\n\n        $xmlWriter->endElement(); // c:chartSpace\n\n        return $xmlWriter->getData();\n    }\n\n    /**\n     * Write chart.\n     *\n     * @see  http://www.datypic.com/sc/ooxml/t-draw-chart_CT_Chart.html\n     */\n    private function writeChart(XMLWriter $xmlWriter): void\n    {\n        $xmlWriter->startElement('c:chart');\n\n        $this->writePlotArea($xmlWriter);\n\n        $xmlWriter->endElement(); // c:chart\n    }\n\n    /**\n     * Write plot area.\n     *\n     * @see  http://www.datypic.com/sc/ooxml/t-draw-chart_CT_PlotArea.html\n     * @see  http://www.datypic.com/sc/ooxml/t-draw-chart_CT_PieChart.html\n     * @see  http://www.datypic.com/sc/ooxml/t-draw-chart_CT_DoughnutChart.html\n     * @see  http://www.datypic.com/sc/ooxml/t-draw-chart_CT_BarChart.html\n     * @see  http://www.datypic.com/sc/ooxml/t-draw-chart_CT_LineChart.html\n     * @see  http://www.datypic.com/sc/ooxml/t-draw-chart_CT_AreaChart.html\n     * @see  http://www.datypic.com/sc/ooxml/t-draw-chart_CT_RadarChart.html\n     * @see  http://www.datypic.com/sc/ooxml/t-draw-chart_CT_ScatterChart.html\n     */\n    private function writePlotArea(XMLWriter $xmlWriter): void\n    {\n        $type = $this->element->getType();\n        $style = $this->element->getStyle();\n        $this->options = $this->types[$type];\n\n        $title = $style->getTitle();\n        $showLegend = $style->isShowLegend();\n        $legendPosition = $style->getLegendPosition();\n\n        //Chart title\n        if ($title) {\n            $xmlWriter->startElement('c:title');\n            $xmlWriter->startElement('c:tx');\n            $xmlWriter->startElement('c:rich');\n            $xmlWriter->writeRaw('\n                <a:bodyPr/>\n                <a:lstStyle/>\n                <a:p>\n                <a:pPr>\n                <a:defRPr/></a:pPr><a:r><a:rPr/><a:t>' . $title . '</a:t></a:r>\n                <a:endParaRPr/>\n                </a:p>');\n            $xmlWriter->endElement(); // c:rich\n            $xmlWriter->endElement(); // c:tx\n            $xmlWriter->endElement(); // c:title\n        } else {\n            $xmlWriter->writeElementBlock('c:autoTitleDeleted', 'val', 1);\n        }\n\n        //Chart legend\n        if ($showLegend) {\n            $xmlWriter->writeRaw('<c:legend><c:legendPos val=\"' . $legendPosition . '\"/></c:legend>');\n        }\n\n        $xmlWriter->startElement('c:plotArea');\n        $xmlWriter->writeElement('c:layout');\n\n        // Chart\n        $chartType = $this->options['type'];\n        $chartType .= $style->is3d() && !isset($this->options['no3d']) ? '3D' : '';\n        $chartType .= 'Chart';\n        $xmlWriter->startElement(\"c:{$chartType}\");\n\n        $xmlWriter->writeElementBlock('c:varyColors', 'val', $this->options['colors']);\n        if ($type == 'area') {\n            $xmlWriter->writeElementBlock('c:grouping', 'val', 'standard');\n        }\n        if (isset($this->options['hole'])) {\n            $xmlWriter->writeElementBlock('c:holeSize', 'val', $this->options['hole']);\n        }\n        if (isset($this->options['bar'])) {\n            $xmlWriter->writeElementBlock('c:barDir', 'val', $this->options['bar']); // bar|col\n            $xmlWriter->writeElementBlock('c:grouping', 'val', $this->options['grouping']); // 3d; standard = percentStacked\n        }\n        if (isset($this->options['radar'])) {\n            $xmlWriter->writeElementBlock('c:radarStyle', 'val', $this->options['radar']);\n        }\n        if (isset($this->options['scatter'])) {\n            $xmlWriter->writeElementBlock('c:scatterStyle', 'val', $this->options['scatter']);\n        }\n\n        // Series\n        $this->writeSeries($xmlWriter, isset($this->options['scatter']));\n\n        // don't overlap if grouping is 'clustered'\n        if (!isset($this->options['grouping']) || $this->options['grouping'] != 'clustered') {\n            $xmlWriter->writeElementBlock('c:overlap', 'val', '100');\n        }\n\n        // Axes\n        if (isset($this->options['axes'])) {\n            $xmlWriter->writeElementBlock('c:axId', 'val', 1);\n            $xmlWriter->writeElementBlock('c:axId', 'val', 2);\n        }\n\n        $xmlWriter->endElement(); // chart type\n\n        // Axes\n        if (isset($this->options['axes'])) {\n            $this->writeAxis($xmlWriter, 'cat');\n            $this->writeAxis($xmlWriter, 'val');\n        }\n\n        $xmlWriter->endElement(); // c:plotArea\n    }\n\n    /**\n     * Write series.\n     *\n     * @param bool $scatter\n     */\n    private function writeSeries(XMLWriter $xmlWriter, $scatter = false): void\n    {\n        $series = $this->element->getSeries();\n        $style = $this->element->getStyle();\n        $colors = $style->getColors();\n\n        $index = 0;\n        $colorIndex = 0;\n        foreach ($series as $seriesItem) {\n            $categories = $seriesItem['categories'];\n            $values = $seriesItem['values'];\n\n            $xmlWriter->startElement('c:ser');\n\n            $xmlWriter->writeElementBlock('c:idx', 'val', $index);\n            $xmlWriter->writeElementBlock('c:order', 'val', $index);\n\n            if (null !== $seriesItem['name'] && $seriesItem['name'] != '') {\n                $xmlWriter->startElement('c:tx');\n                $xmlWriter->startElement('c:strRef');\n                $xmlWriter->startElement('c:strCache');\n                $xmlWriter->writeElementBlock('c:ptCount', 'val', 1);\n                $xmlWriter->startElement('c:pt');\n                $xmlWriter->writeAttribute('idx', 0);\n                $xmlWriter->startElement('c:v');\n                $xmlWriter->writeRaw($seriesItem['name']);\n                $xmlWriter->endElement(); // c:v\n                $xmlWriter->endElement(); // c:pt\n                $xmlWriter->endElement(); // c:strCache\n                $xmlWriter->endElement(); // c:strRef\n                $xmlWriter->endElement(); // c:tx\n            }\n\n            // The c:dLbls was added to make word charts look more like the reports in SurveyGizmo\n            // This section needs to be made configurable before a pull request is made\n            $xmlWriter->startElement('c:dLbls');\n\n            foreach ($style->getDataLabelOptions() as $option => $val) {\n                $xmlWriter->writeElementBlock(\"c:{$option}\", 'val', (int) $val);\n            }\n\n            $xmlWriter->endElement(); // c:dLbls\n\n            if (isset($this->options['scatter'])) {\n                $this->writeShape($xmlWriter);\n            }\n\n            if ($scatter === true) {\n                $this->writeSeriesItem($xmlWriter, 'xVal', $categories);\n                $this->writeSeriesItem($xmlWriter, 'yVal', $values);\n            } else {\n                $this->writeSeriesItem($xmlWriter, 'cat', $categories);\n                $this->writeSeriesItem($xmlWriter, 'val', $values);\n\n                // check that there are colors\n                if (is_array($colors) && count($colors) > 0) {\n                    // assign a color to each value\n                    $valueIndex = 0;\n                    for ($i = 0; $i < count($values); ++$i) {\n                        // check that there are still enought colors\n                        $xmlWriter->startElement('c:dPt');\n                        $xmlWriter->writeElementBlock('c:idx', 'val', $valueIndex);\n                        $xmlWriter->startElement('c:spPr');\n                        $xmlWriter->startElement('a:solidFill');\n                        $xmlWriter->writeElementBlock('a:srgbClr', 'val', $colors[$colorIndex++ % count($colors)]);\n                        $xmlWriter->endElement(); // a:solidFill\n                        $xmlWriter->endElement(); // c:spPr\n                        $xmlWriter->endElement(); // c:dPt\n                        ++$valueIndex;\n                    }\n                }\n            }\n\n            $xmlWriter->endElement(); // c:ser\n            ++$index;\n        }\n    }\n\n    /**\n     * Write series items.\n     *\n     * @param string $type\n     * @param array $values\n     */\n    private function writeSeriesItem(XMLWriter $xmlWriter, $type, $values): void\n    {\n        $types = [\n            'cat' => ['c:cat', 'c:strLit'],\n            'val' => ['c:val', 'c:numLit'],\n            'xVal' => ['c:xVal', 'c:strLit'],\n            'yVal' => ['c:yVal', 'c:numLit'],\n        ];\n        [$itemType, $itemLit] = $types[$type];\n\n        $xmlWriter->startElement($itemType);\n        $xmlWriter->startElement($itemLit);\n        $xmlWriter->writeElementBlock('c:ptCount', 'val', count($values));\n\n        $index = 0;\n        foreach ($values as $value) {\n            $xmlWriter->startElement('c:pt');\n            $xmlWriter->writeAttribute('idx', $index);\n            if (\\PhpOffice\\PhpWord\\Settings::isOutputEscapingEnabled()) {\n                $xmlWriter->writeElement('c:v', $value);\n            } else {\n                $xmlWriter->startElement('c:v');\n                $xmlWriter->writeRaw($value);\n                $xmlWriter->endElement(); // c:v\n            }\n            $xmlWriter->endElement(); // c:pt\n            ++$index;\n        }\n\n        $xmlWriter->endElement(); // $itemLit\n        $xmlWriter->endElement(); // $itemType\n    }\n\n    /**\n     * Write axis.\n     *\n     * @see  http://www.datypic.com/sc/ooxml/t-draw-chart_CT_CatAx.html\n     *\n     * @param string $type\n     */\n    private function writeAxis(XMLWriter $xmlWriter, $type): void\n    {\n        $style = $this->element->getStyle();\n        $types = [\n            'cat' => ['c:catAx', 1, 'b', 2],\n            'val' => ['c:valAx', 2, 'l', 1],\n        ];\n        [$axisType, $axisId, $axisPos, $axisCross] = $types[$type];\n\n        $xmlWriter->startElement($axisType);\n\n        $xmlWriter->writeElementBlock('c:axId', 'val', $axisId);\n        $xmlWriter->writeElementBlock('c:axPos', 'val', $axisPos);\n\n        $categoryAxisTitle = $style->getCategoryAxisTitle();\n        $valueAxisTitle = $style->getValueAxisTitle();\n\n        if ($axisType == 'c:catAx') {\n            if (null !== $categoryAxisTitle) {\n                $this->writeAxisTitle($xmlWriter, $categoryAxisTitle);\n            }\n        } elseif ($axisType == 'c:valAx') {\n            if (null !== $valueAxisTitle) {\n                $this->writeAxisTitle($xmlWriter, $valueAxisTitle);\n            }\n        }\n\n        $xmlWriter->writeElementBlock('c:crossAx', 'val', $axisCross);\n        $xmlWriter->writeElementBlock('c:auto', 'val', 1);\n\n        if (isset($this->options['axes'])) {\n            $xmlWriter->writeElementBlock('c:delete', 'val', 0);\n            $xmlWriter->writeElementBlock('c:majorTickMark', 'val', $style->getMajorTickPosition());\n            $xmlWriter->writeElementBlock('c:minorTickMark', 'val', 'none');\n            if ($style->showAxisLabels()) {\n                if ($axisType == 'c:catAx') {\n                    $xmlWriter->writeElementBlock('c:tickLblPos', 'val', $style->getCategoryLabelPosition());\n                } else {\n                    $xmlWriter->writeElementBlock('c:tickLblPos', 'val', $style->getValueLabelPosition());\n                }\n            } else {\n                $xmlWriter->writeElementBlock('c:tickLblPos', 'val', 'none');\n            }\n            $xmlWriter->writeElementBlock('c:crosses', 'val', 'autoZero');\n        }\n        if (isset($this->options['radar']) || ($type == 'cat' && $style->showGridX()) || ($type == 'val' && $style->showGridY())) {\n            $xmlWriter->writeElement('c:majorGridlines');\n        }\n\n        $xmlWriter->startElement('c:scaling');\n        $xmlWriter->writeElementBlock('c:orientation', 'val', 'minMax');\n        $xmlWriter->endElement(); // c:scaling\n\n        $this->writeShape($xmlWriter, true);\n\n        $xmlWriter->endElement(); // $axisType\n    }\n\n    /**\n     * Write shape.\n     *\n     * @see  http://www.datypic.com/sc/ooxml/t-a_CT_ShapeProperties.html\n     *\n     * @param bool $line\n     */\n    private function writeShape(XMLWriter $xmlWriter, $line = false): void\n    {\n        $xmlWriter->startElement('c:spPr');\n        $xmlWriter->startElement('a:ln');\n        if ($line === true) {\n            $xmlWriter->writeElement('a:solidFill');\n        } else {\n            $xmlWriter->writeElement('a:noFill');\n        }\n        $xmlWriter->endElement(); // a:ln\n        $xmlWriter->endElement(); // c:spPr\n    }\n\n    private function writeAxisTitle(XMLWriter $xmlWriter, $title): void\n    {\n        $xmlWriter->startElement('c:title'); //start c:title\n        $xmlWriter->startElement('c:tx'); //start c:tx\n        $xmlWriter->startElement('c:rich'); // start c:rich\n        $xmlWriter->writeElement('a:bodyPr');\n        $xmlWriter->writeElement('a:lstStyle');\n        $xmlWriter->startElement('a:p');\n        $xmlWriter->startElement('a:pPr');\n        $xmlWriter->writeElement('a:defRPr');\n        $xmlWriter->endElement(); // end a:pPr\n        $xmlWriter->startElement('a:r');\n        $xmlWriter->writeElementBlock('a:rPr', 'lang', 'en-US');\n\n        $xmlWriter->startElement('a:t');\n        $xmlWriter->writeRaw($title);\n        $xmlWriter->endElement(); //end a:t\n\n        $xmlWriter->endElement(); // end a:r\n        $xmlWriter->endElement(); //end a:p\n        $xmlWriter->endElement(); //end c:rich\n        $xmlWriter->endElement(); // end c:tx\n        $xmlWriter->writeElementBlock('c:overlay', 'val', '0');\n        $xmlWriter->endElement(); // end c:title\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Part/Comments.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Part;\n\nuse PhpOffice\\PhpWord\\Element\\Comment;\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\Container;\n\n/**\n * Word2007 comments part writer: word/comments.xml.\n */\nclass Comments extends AbstractPart\n{\n    /**\n     * Comments collection to be written.\n     *\n     * @var Comment[]\n     */\n    protected $elements;\n\n    /**\n     * Write part.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startDocument('1.0', 'UTF-8', 'yes');\n        $xmlWriter->startElement('w:comments');\n        $xmlWriter->writeAttribute('xmlns:ve', 'http://schemas.openxmlformats.org/markup-compatibility/2006');\n        $xmlWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office');\n        $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');\n        $xmlWriter->writeAttribute('xmlns:m', 'http://schemas.openxmlformats.org/officeDocument/2006/math');\n        $xmlWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml');\n        $xmlWriter->writeAttribute('xmlns:wp', 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing');\n        $xmlWriter->writeAttribute('xmlns:w10', 'urn:schemas-microsoft-com:office:word');\n        $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main');\n        $xmlWriter->writeAttribute('xmlns:wne', 'http://schemas.microsoft.com/office/word/2006/wordml');\n\n        if ($this->elements !== null) {\n            foreach ($this->elements as $element) {\n                if ($element instanceof Comment) {\n                    $this->writeComment($xmlWriter, $element);\n                }\n            }\n        }\n\n        $xmlWriter->endElement(); // w:comments\n\n        return $xmlWriter->getData();\n    }\n\n    /**\n     * Write comment item.\n     */\n    protected function writeComment(XMLWriter $xmlWriter, Comment $comment): void\n    {\n        $xmlWriter->startElement('w:comment');\n        $xmlWriter->writeAttribute('w:id', $comment->getElementId());\n        $xmlWriter->writeAttribute('w:author', $comment->getAuthor());\n        if ($comment->getDate() != null) {\n            $xmlWriter->writeAttribute('w:date', $comment->getDate()->format($this->dateFormat));\n        }\n        $xmlWriter->writeAttributeIf($comment->getInitials() != null, 'w:initials', $comment->getInitials());\n\n        $containerWriter = new Container($xmlWriter, $comment);\n        $containerWriter->write();\n\n        $xmlWriter->endElement(); // w:comment\n    }\n\n    /**\n     * Set element.\n     *\n     * @param Comment[] $elements\n     *\n     * @return self\n     */\n    public function setElements($elements)\n    {\n        $this->elements = $elements;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Part/ContentTypes.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Part;\n\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\n\n/**\n * Word2007 contenttypes part writer: [Content_Types].xml.\n */\nclass ContentTypes extends AbstractPart\n{\n    /**\n     * Write part.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        /** @var \\PhpOffice\\PhpWord\\Writer\\Word2007 $parentWriter Type hint */\n        $parentWriter = $this->getParentWriter();\n        $contentTypes = $parentWriter->getContentTypes();\n\n        $openXMLPrefix = 'application/vnd.openxmlformats-';\n        $wordMLPrefix = $openXMLPrefix . 'officedocument.wordprocessingml.';\n        $drawingMLPrefix = $openXMLPrefix . 'officedocument.drawingml.';\n        $overrides = [\n            '/docProps/core.xml' => $openXMLPrefix . 'package.core-properties+xml',\n            '/docProps/app.xml' => $openXMLPrefix . 'officedocument.extended-properties+xml',\n            '/docProps/custom.xml' => $openXMLPrefix . 'officedocument.custom-properties+xml',\n            '/word/document.xml' => $wordMLPrefix . 'document.main+xml',\n            '/word/styles.xml' => $wordMLPrefix . 'styles+xml',\n            '/word/numbering.xml' => $wordMLPrefix . 'numbering+xml',\n            '/word/settings.xml' => $wordMLPrefix . 'settings+xml',\n            '/word/theme/theme1.xml' => $openXMLPrefix . 'officedocument.theme+xml',\n            '/word/webSettings.xml' => $wordMLPrefix . 'webSettings+xml',\n            '/word/fontTable.xml' => $wordMLPrefix . 'fontTable+xml',\n            '/word/comments.xml' => $wordMLPrefix . 'comments+xml',\n        ];\n\n        $defaults = $contentTypes['default'];\n        if (!empty($contentTypes['override'])) {\n            foreach ($contentTypes['override'] as $key => $val) {\n                if ($val == 'chart') {\n                    $overrides[$key] = $drawingMLPrefix . $val . '+xml';\n                } else {\n                    $overrides[$key] = $wordMLPrefix . $val . '+xml';\n                }\n            }\n        }\n\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startDocument('1.0', 'UTF-8', 'yes');\n        $xmlWriter->startElement('Types');\n        $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/content-types');\n\n        $this->writeContentType($xmlWriter, $defaults, true);\n        $this->writeContentType($xmlWriter, $overrides, false);\n\n        $xmlWriter->endElement(); // Types\n\n        return $xmlWriter->getData();\n    }\n\n    /**\n     * Write content types element.\n     *\n     * @param XMLWriter $xmlWriter XML Writer\n     * @param array $parts\n     * @param bool $isDefault\n     */\n    private function writeContentType(XMLWriter $xmlWriter, $parts, $isDefault): void\n    {\n        foreach ($parts as $partName => $contentType) {\n            $partType = $isDefault ? 'Default' : 'Override';\n            $partAttribute = $isDefault ? 'Extension' : 'PartName';\n            $xmlWriter->startElement($partType);\n            $xmlWriter->writeAttribute($partAttribute, $partName);\n            $xmlWriter->writeAttribute('ContentType', $contentType);\n            $xmlWriter->endElement();\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Part/DocPropsApp.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Part;\n\n/**\n * Word2007 extended document properties part writer: docProps/app.xml.\n *\n * @since 0.11.0\n */\nclass DocPropsApp extends AbstractPart\n{\n    /**\n     * Write part.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $phpWord = $this->getParentWriter()->getPhpWord();\n        $xmlWriter = $this->getXmlWriter();\n        $schema = 'http://schemas.openxmlformats.org/officeDocument/2006/extended-properties';\n\n        $xmlWriter->startDocument('1.0', 'UTF-8', 'yes');\n        $xmlWriter->startElement('Properties');\n        $xmlWriter->writeAttribute('xmlns', $schema);\n        $xmlWriter->writeAttribute('xmlns:vt', 'http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes');\n\n        $xmlWriter->writeElement('Application', 'PHPWord');\n        $xmlWriter->writeElement('Company', $phpWord->getDocInfo()->getCompany());\n        $xmlWriter->writeElement('Manager', $phpWord->getDocInfo()->getManager());\n\n        $xmlWriter->endElement(); // Properties\n\n        return $xmlWriter->getData();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Part/DocPropsCore.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Part;\n\n/**\n * Word2007 core document properties part writer: docProps/core.xml.\n *\n * @since 0.11.0\n */\nclass DocPropsCore extends AbstractPart\n{\n    /**\n     * Write part.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $phpWord = $this->getParentWriter()->getPhpWord();\n        $xmlWriter = $this->getXmlWriter();\n        $schema = 'http://schemas.openxmlformats.org/package/2006/metadata/core-properties';\n\n        $xmlWriter->startDocument('1.0', 'UTF-8', 'yes');\n        $xmlWriter->startElement('cp:coreProperties');\n        $xmlWriter->writeAttribute('xmlns:cp', $schema);\n        $xmlWriter->writeAttribute('xmlns:dc', 'http://purl.org/dc/elements/1.1/');\n        $xmlWriter->writeAttribute('xmlns:dcterms', 'http://purl.org/dc/terms/');\n        $xmlWriter->writeAttribute('xmlns:dcmitype', 'http://purl.org/dc/dcmitype/');\n        $xmlWriter->writeAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');\n\n        $xmlWriter->writeElement('dc:creator', $phpWord->getDocInfo()->getCreator());\n        $xmlWriter->writeElement('dc:title', $phpWord->getDocInfo()->getTitle());\n        $xmlWriter->writeElement('dc:description', $phpWord->getDocInfo()->getDescription());\n        $xmlWriter->writeElement('dc:subject', $phpWord->getDocInfo()->getSubject());\n        $xmlWriter->writeElement('cp:keywords', $phpWord->getDocInfo()->getKeywords());\n        $xmlWriter->writeElement('cp:category', $phpWord->getDocInfo()->getCategory());\n        $xmlWriter->writeElement('cp:lastModifiedBy', $phpWord->getDocInfo()->getLastModifiedBy());\n\n        // dcterms:created\n        $xmlWriter->startElement('dcterms:created');\n        $xmlWriter->writeAttribute('xsi:type', 'dcterms:W3CDTF');\n        $xmlWriter->text(date($this->dateFormat, $phpWord->getDocInfo()->getCreated()));\n        $xmlWriter->endElement();\n\n        // dcterms:modified\n        $xmlWriter->startElement('dcterms:modified');\n        $xmlWriter->writeAttribute('xsi:type', 'dcterms:W3CDTF');\n        $xmlWriter->text(date($this->dateFormat, $phpWord->getDocInfo()->getModified()));\n        $xmlWriter->endElement();\n\n        $xmlWriter->endElement(); // cp:coreProperties\n\n        return $xmlWriter->getData();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Part/DocPropsCustom.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Part;\n\nuse DateTime;\n\n/**\n * Word2007 custom document properties part writer: docProps/custom.xml.\n *\n * @since 0.11.0\n */\nclass DocPropsCustom extends AbstractPart\n{\n    /**\n     * Write part.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $phpWord = $this->getParentWriter()->getPhpWord();\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startDocument('1.0', 'UTF-8', 'yes');\n        $xmlWriter->startElement('Properties');\n        $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/officeDocument/2006/custom-properties');\n        $xmlWriter->writeAttribute('xmlns:vt', 'http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes');\n\n        $docProps = $phpWord->getDocInfo();\n        $properties = $docProps->getCustomProperties();\n        foreach ($properties as $key => $property) {\n            $propertyValue = $docProps->getCustomPropertyValue($property);\n            $propertyType = $docProps->getCustomPropertyType($property);\n\n            $xmlWriter->startElement('property');\n            $xmlWriter->writeAttribute('fmtid', '{D5CDD505-2E9C-101B-9397-08002B2CF9AE}');\n            $xmlWriter->writeAttribute('pid', $key + 2);\n            $xmlWriter->writeAttribute('name', $property);\n            switch ($propertyType) {\n                case 'i':\n                    $xmlWriter->writeElement('vt:i4', $propertyValue);\n\n                    break;\n                case 'f':\n                    $xmlWriter->writeElement('vt:r8', $propertyValue);\n\n                    break;\n                case 'b':\n                    $xmlWriter->writeElement('vt:bool', ($propertyValue) ? 'true' : 'false');\n\n                    break;\n                case 'd':\n                    if ($propertyValue instanceof DateTime) {\n                        $xmlWriter->writeElement('vt:filetime', $propertyValue->format($this->dateFormat));\n                    } else {\n                        $xmlWriter->writeElement('vt:filetime', date($this->dateFormat, $propertyValue));\n                    }\n\n                    break;\n                default:\n                    $xmlWriter->writeElement('vt:lpwstr', $propertyValue);\n\n                    break;\n            }\n            $xmlWriter->endElement(); // property\n        }\n\n        $xmlWriter->endElement(); // Properties\n\n        return $xmlWriter->getData();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Part/Document.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Part;\n\nuse PhpOffice\\PhpWord\\Element\\Section;\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\Container;\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Section as SectionStyleWriter;\n\n/**\n * Word2007 document part writer: word/document.xml.\n */\nclass Document extends AbstractPart\n{\n    /**\n     * Write part.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $phpWord = $this->getParentWriter()->getPhpWord();\n        $xmlWriter = $this->getXmlWriter();\n\n        $sections = $phpWord->getSections();\n        $sectionCount = count($sections);\n        $currentSection = 0;\n        $drawingSchema = 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing';\n\n        $xmlWriter->startDocument('1.0', 'UTF-8', 'yes');\n        $xmlWriter->startElement('w:document');\n        $xmlWriter->writeAttribute('xmlns:ve', 'http://schemas.openxmlformats.org/markup-compatibility/2006');\n        $xmlWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office');\n        $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');\n        $xmlWriter->writeAttribute('xmlns:m', 'http://schemas.openxmlformats.org/officeDocument/2006/math');\n        $xmlWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml');\n        $xmlWriter->writeAttribute('xmlns:wp', $drawingSchema);\n        $xmlWriter->writeAttribute('xmlns:w10', 'urn:schemas-microsoft-com:office:word');\n        $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main');\n        $xmlWriter->writeAttribute('xmlns:wne', 'http://schemas.microsoft.com/office/word/2006/wordml');\n\n        $xmlWriter->startElement('w:body');\n\n        if ($sectionCount > 0) {\n            foreach ($sections as $section) {\n                ++$currentSection;\n\n                $containerWriter = new Container($xmlWriter, $section);\n                $containerWriter->write();\n\n                if ($currentSection == $sectionCount) {\n                    $this->writeSectionSettings($xmlWriter, $section);\n                } else {\n                    $this->writeSection($xmlWriter, $section);\n                }\n            }\n        }\n\n        $xmlWriter->endElement(); // w:body\n        $xmlWriter->endElement(); // w:document\n\n        return $xmlWriter->getData();\n    }\n\n    /**\n     * Write begin section.\n     */\n    private function writeSection(XMLWriter $xmlWriter, Section $section): void\n    {\n        $xmlWriter->startElement('w:p');\n        $xmlWriter->startElement('w:pPr');\n        $this->writeSectionSettings($xmlWriter, $section);\n        $xmlWriter->endElement();\n        $xmlWriter->endElement();\n    }\n\n    /**\n     * Write end section.\n     */\n    private function writeSectionSettings(XMLWriter $xmlWriter, Section $section): void\n    {\n        $xmlWriter->startElement('w:sectPr');\n\n        // Header reference\n        foreach ($section->getHeaders() as $header) {\n            $rId = $header->getRelationId();\n            $xmlWriter->startElement('w:headerReference');\n            $xmlWriter->writeAttribute('w:type', $header->getType());\n            $xmlWriter->writeAttribute('r:id', 'rId' . $rId);\n            $xmlWriter->endElement();\n        }\n\n        // Footer reference\n        foreach ($section->getFooters() as $footer) {\n            $rId = $footer->getRelationId();\n            $xmlWriter->startElement('w:footerReference');\n            $xmlWriter->writeAttribute('w:type', $footer->getType());\n            $xmlWriter->writeAttribute('r:id', 'rId' . $rId);\n            $xmlWriter->endElement();\n        }\n\n        // Different first page\n        if ($section->hasDifferentFirstPage()) {\n            $xmlWriter->startElement('w:titlePg');\n            $xmlWriter->endElement();\n        }\n\n        // Footnote properties\n        if ($section->getFootnoteProperties() !== null) {\n            $xmlWriter->startElement('w:footnotePr');\n            if ($section->getFootnoteProperties()->getPos() != null) {\n                $xmlWriter->startElement('w:pos');\n                $xmlWriter->writeAttribute('w:val', $section->getFootnoteProperties()->getPos());\n                $xmlWriter->endElement();\n            }\n            if ($section->getFootnoteProperties()->getNumFmt() != null) {\n                $xmlWriter->startElement('w:numFmt');\n                $xmlWriter->writeAttribute('w:val', $section->getFootnoteProperties()->getNumFmt());\n                $xmlWriter->endElement();\n            }\n            if ($section->getFootnoteProperties()->getNumStart() != null) {\n                $xmlWriter->startElement('w:numStart');\n                $xmlWriter->writeAttribute('w:val', $section->getFootnoteProperties()->getNumStart());\n                $xmlWriter->endElement();\n            }\n            if ($section->getFootnoteProperties()->getNumRestart() != null) {\n                $xmlWriter->startElement('w:numRestart');\n                $xmlWriter->writeAttribute('w:val', $section->getFootnoteProperties()->getNumRestart());\n                $xmlWriter->endElement();\n            }\n            $xmlWriter->endElement();\n        }\n\n        // Section settings\n        $styleWriter = new SectionStyleWriter($xmlWriter, $section->getStyle());\n        $styleWriter->write();\n\n        $xmlWriter->endElement(); // w:sectPr\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Part/Endnotes.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Part;\n\n/**\n * Word2007 endnotes part writer: word/endnotes.xml.\n */\nclass Endnotes extends Footnotes\n{\n    /**\n     * Name of XML root element.\n     *\n     * @var string\n     */\n    protected $rootNode = 'w:endnotes';\n\n    /**\n     * Name of XML node element.\n     *\n     * @var string\n     */\n    protected $elementNode = 'w:endnote';\n\n    /**\n     * Name of XML reference element.\n     *\n     * @var string\n     */\n    protected $refNode = 'w:endnoteRef';\n\n    /**\n     * Reference style name.\n     *\n     * @var string\n     */\n    protected $refStyle = 'EndnoteReference';\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Part/FontTable.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Part;\n\n/**\n * Word2007 font table writer: word/fontTable.xml.\n *\n * @todo Generate content dynamically\n *\n * @since 0.10.0\n */\nclass FontTable extends AbstractPart\n{\n    /**\n     * Write fontTable.xml.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $str = '';\n        $str .= '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>';\n        $str .= '<w:fonts ' .\n            'xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" ' .\n            'xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\">';\n\n        $str .= '<w:font w:name=\"Times New Roman\">';\n        $str .= '<w:panose1 w:val=\"02020603050405020304\" />';\n        $str .= '<w:charset w:val=\"00\" />';\n        $str .= '<w:family w:val=\"roman\" />';\n        $str .= '<w:pitch w:val=\"variable\" />';\n        $str .= '<w:sig w:usb0=\"E0002AFF\" w:usb1=\"C0007841\" w:usb2=\"00000009\" w:usb3=\"00000000\" ' .\n            'w:csb0=\"000001FF\" w:csb1=\"00000000\" />';\n        $str .= '</w:font>';\n\n        $str .= '<w:font w:name=\"Courier New\">';\n        $str .= '<w:panose1 w:val=\"02070309020205020404\" />';\n        $str .= '<w:charset w:val=\"00\" />';\n        $str .= '<w:family w:val=\"modern\" />';\n        $str .= '<w:pitch w:val=\"fixed\" />';\n        $str .= '<w:sig w:usb0=\"E0002AFF\" w:usb1=\"C0007843\" w:usb2=\"00000009\" w:usb3=\"00000000\" ' .\n            'w:csb0=\"000001FF\" w:csb1=\"00000000\" />';\n        $str .= '</w:font>';\n\n        $str .= '<w:font w:name=\"Wingdings\">';\n        $str .= '<w:panose1 w:val=\"05000000000000000000\" />';\n        $str .= '<w:charset w:val=\"02\" />';\n        $str .= '<w:family w:val=\"auto\" />';\n        $str .= '<w:pitch w:val=\"variable\" />';\n        $str .= '<w:sig w:usb0=\"00000000\" w:usb1=\"10000000\" w:usb2=\"00000000\" w:usb3=\"00000000\" ' .\n            'w:csb0=\"80000000\" w:csb1=\"00000000\" />';\n        $str .= '</w:font>';\n\n        $str .= '<w:font w:name=\"Symbol\">';\n        $str .= '<w:panose1 w:val=\"05050102010706020507\" />';\n        $str .= '<w:charset w:val=\"02\" />';\n        $str .= '<w:family w:val=\"roman\" />';\n        $str .= '<w:pitch w:val=\"variable\" />';\n        $str .= '<w:sig w:usb0=\"00000000\" w:usb1=\"10000000\" w:usb2=\"00000000\" w:usb3=\"00000000\" ' .\n            'w:csb0=\"80000000\" w:csb1=\"00000000\" />';\n        $str .= '</w:font>';\n\n        $str .= '<w:font w:name=\"Arial\">';\n        $str .= '<w:panose1 w:val=\"020B0604020202020204\" />';\n        $str .= '<w:charset w:val=\"00\" />';\n        $str .= '<w:family w:val=\"swiss\" />';\n        $str .= '<w:pitch w:val=\"variable\" />';\n        $str .= '<w:sig w:usb0=\"E0002AFF\" w:usb1=\"C0007843\" w:usb2=\"00000009\" w:usb3=\"00000000\" ' .\n            'w:csb0=\"000001FF\" w:csb1=\"00000000\" />';\n        $str .= '</w:font>';\n\n        $str .= '<w:font w:name=\"Cambria\">';\n        $str .= '<w:panose1 w:val=\"02040503050406030204\" />';\n        $str .= '<w:charset w:val=\"00\" />';\n        $str .= '<w:family w:val=\"roman\" />';\n        $str .= '<w:pitch w:val=\"variable\" />';\n        $str .= '<w:sig w:usb0=\"A00002EF\" w:usb1=\"4000004B\" w:usb2=\"00000000\" w:usb3=\"00000000\" ' .\n            'w:csb0=\"0000019F\" w:csb1=\"00000000\" />';\n        $str .= '</w:font>';\n\n        $str .= '<w:font w:name=\"Calibri\">';\n        $str .= '<w:panose1 w:val=\"020F0502020204030204\" />';\n        $str .= '<w:charset w:val=\"00\" />';\n        $str .= '<w:family w:val=\"swiss\" />';\n        $str .= '<w:pitch w:val=\"variable\" />';\n        $str .= '<w:sig w:usb0=\"E10002FF\" w:usb1=\"4000ACFF\" w:usb2=\"00000009\" w:usb3=\"00000000\" ' .\n            'w:csb0=\"0000019F\" w:csb1=\"00000000\" />';\n        $str .= '</w:font>';\n\n        $str .= '<w:font w:name=\"Garamond\">';\n        $str .= '<w:panose1 w:val=\"02020404030301010803\" />';\n        $str .= '<w:charset w:val=\"00\" />';\n        $str .= '<w:family w:val=\"roman\" />';\n        $str .= '<w:pitch w:val=\"variable\" />';\n        $str .= '<w:sig w:usb0=\"00000287\" w:usb1=\"00000002\" w:usb2=\"00000000\" w:usb3=\"00000000\" ' .\n            'w:csb0=\"0000009F\" w:csb1=\"00000000\" />';\n        $str .= '</w:font>';\n\n        $str .= '</w:fonts>';\n\n        return $str;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Part/Footer.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Part;\n\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\Container;\n\n/**\n * Word2007 footer part writer: word/footerx.xml.\n */\nclass Footer extends AbstractPart\n{\n    /**\n     * Root element name.\n     *\n     * @var string\n     */\n    protected $rootElement = 'w:ftr';\n\n    /**\n     * Footer/header element to be written.\n     *\n     * @var \\PhpOffice\\PhpWord\\Element\\Footer\n     */\n    protected $element;\n\n    /**\n     * Write part.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $drawingSchema = 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing';\n\n        $xmlWriter->startDocument('1.0', 'UTF-8', 'yes');\n        $xmlWriter->startElement($this->rootElement);\n        $xmlWriter->writeAttribute('xmlns:ve', 'http://schemas.openxmlformats.org/markup-compatibility/2006');\n        $xmlWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office');\n        $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');\n        $xmlWriter->writeAttribute('xmlns:m', 'http://schemas.openxmlformats.org/officeDocument/2006/math');\n        $xmlWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml');\n        $xmlWriter->writeAttribute('xmlns:wp', $drawingSchema);\n        $xmlWriter->writeAttribute('xmlns:w10', 'urn:schemas-microsoft-com:office:word');\n        $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main');\n        $xmlWriter->writeAttribute('xmlns:wne', 'http://schemas.microsoft.com/office/word/2006/wordml');\n\n        $containerWriter = new Container($xmlWriter, $this->element);\n        $containerWriter->write();\n\n        $xmlWriter->endElement(); // $this->rootElement\n\n        return $xmlWriter->getData();\n    }\n\n    /**\n     * Set element.\n     *\n     * @param \\PhpOffice\\PhpWord\\Element\\Footer|\\PhpOffice\\PhpWord\\Element\\Header $element\n     *\n     * @return self\n     */\n    public function setElement($element)\n    {\n        $this->element = $element;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Part/Footnotes.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Part;\n\nuse PhpOffice\\PhpWord\\Element\\Footnote;\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\Container;\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Paragraph as ParagraphStyleWriter;\n\n/**\n * Word2007 footnotes part writer: word/(footnotes|endnotes).xml.\n */\nclass Footnotes extends AbstractPart\n{\n    /**\n     * Name of XML root element.\n     *\n     * @var string\n     */\n    protected $rootNode = 'w:footnotes';\n\n    /**\n     * Name of XML node element.\n     *\n     * @var string\n     */\n    protected $elementNode = 'w:footnote';\n\n    /**\n     * Name of XML reference element.\n     *\n     * @var string\n     */\n    protected $refNode = 'w:footnoteRef';\n\n    /**\n     * Reference style name.\n     *\n     * @var string\n     */\n    protected $refStyle = 'FootnoteReference';\n\n    /**\n     * Footnotes/endnotes collection to be written.\n     *\n     * @var \\PhpOffice\\PhpWord\\Collection\\Endnotes|\\PhpOffice\\PhpWord\\Collection\\Footnotes\n     */\n    protected $elements;\n\n    /**\n     * Write part.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $drawingSchema = 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing';\n\n        $xmlWriter->startDocument('1.0', 'UTF-8', 'yes');\n        $xmlWriter->startElement($this->rootNode);\n        $xmlWriter->writeAttribute('xmlns:ve', 'http://schemas.openxmlformats.org/markup-compatibility/2006');\n        $xmlWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office');\n        $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');\n        $xmlWriter->writeAttribute('xmlns:m', 'http://schemas.openxmlformats.org/officeDocument/2006/math');\n        $xmlWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml');\n        $xmlWriter->writeAttribute('xmlns:wp', $drawingSchema);\n        $xmlWriter->writeAttribute('xmlns:w10', 'urn:schemas-microsoft-com:office:word');\n        $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main');\n        $xmlWriter->writeAttribute('xmlns:wne', 'http://schemas.microsoft.com/office/word/2006/wordml');\n\n        // Separator and continuation separator\n        $xmlWriter->startElement($this->elementNode);\n        $xmlWriter->writeAttribute('w:id', -1);\n        $xmlWriter->writeAttribute('w:type', 'separator');\n        $xmlWriter->startElement('w:p');\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:separator');\n        $xmlWriter->endElement(); // w:separator\n        $xmlWriter->endElement(); // w:r\n        $xmlWriter->endElement(); // w:p\n        $xmlWriter->endElement(); // $this->elementNode\n        $xmlWriter->startElement($this->elementNode);\n        $xmlWriter->writeAttribute('w:id', 0);\n        $xmlWriter->writeAttribute('w:type', 'continuationSeparator');\n        $xmlWriter->startElement('w:p');\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:continuationSeparator');\n        $xmlWriter->endElement(); // w:continuationSeparator\n        $xmlWriter->endElement(); // w:r\n        $xmlWriter->endElement(); // w:p\n        $xmlWriter->endElement(); // $this->elementNode\n\n        /** @var array $elements Type hint */\n        $elements = $this->elements;\n        foreach ($elements as $element) {\n            if ($element instanceof Footnote) {\n                $this->writeNote($xmlWriter, $element);\n            }\n        }\n\n        $xmlWriter->endElement(); // $this->rootNode\n\n        return $xmlWriter->getData();\n    }\n\n    /**\n     * Set element.\n     *\n     * @param \\PhpOffice\\PhpWord\\Collection\\Endnotes|\\PhpOffice\\PhpWord\\Collection\\Footnotes $elements\n     *\n     * @return self\n     */\n    public function setElements($elements)\n    {\n        $this->elements = $elements;\n\n        return $this;\n    }\n\n    /**\n     * Write note item.\n     *\n     * @param Footnote|\\PhpOffice\\PhpWord\\Element\\Endnote $element\n     */\n    protected function writeNote(XMLWriter $xmlWriter, $element): void\n    {\n        $xmlWriter->startElement($this->elementNode);\n        $xmlWriter->writeAttribute('w:id', $element->getRelationId() + 1);\n        $xmlWriter->startElement('w:p');\n\n        // Paragraph style\n        $styleWriter = new ParagraphStyleWriter($xmlWriter, $element->getParagraphStyle());\n        $styleWriter->setIsInline(true);\n        $styleWriter->write();\n\n        // Reference symbol\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:rPr');\n        $xmlWriter->startElement('w:rStyle');\n        $xmlWriter->writeAttribute('w:val', $this->refStyle);\n        $xmlWriter->endElement(); // w:rStyle\n        $xmlWriter->endElement(); // w:rPr\n        $xmlWriter->writeElement($this->refNode);\n        $xmlWriter->endElement(); // w:r\n\n        // Empty space after refence symbol\n        $xmlWriter->startElement('w:r');\n        $xmlWriter->startElement('w:t');\n        $xmlWriter->writeAttribute('xml:space', 'preserve');\n        $xmlWriter->text(' ');\n        $xmlWriter->endElement(); // w:t\n        $xmlWriter->endElement(); // w:r\n\n        $containerWriter = new Container($xmlWriter, $element);\n        $containerWriter->write();\n\n        $xmlWriter->endElement(); // w:p\n        $xmlWriter->endElement(); // $this->elementNode\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Part/Header.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Part;\n\n/**\n * Word2007 header part writer: word/headerx.xml.\n */\nclass Header extends Footer\n{\n    /**\n     * Root element name.\n     *\n     * @var string\n     */\n    protected $rootElement = 'w:hdr';\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Part/Numbering.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Part;\n\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\nuse PhpOffice\\PhpWord\\Style;\nuse PhpOffice\\PhpWord\\Style\\Numbering as NumberingStyle;\nuse PhpOffice\\PhpWord\\Style\\NumberingLevel;\n\n/**\n * Word2007 numbering part writer: word/numbering.xml.\n *\n * @since 0.10.0\n */\nclass Numbering extends AbstractPart\n{\n    /**\n     * Write part.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $styles = Style::getStyles();\n        $drawingSchema = 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing';\n\n        $xmlWriter->startDocument('1.0', 'UTF-8', 'yes');\n        $xmlWriter->startElement('w:numbering');\n        $xmlWriter->writeAttribute('xmlns:ve', 'http://schemas.openxmlformats.org/markup-compatibility/2006');\n        $xmlWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office');\n        $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');\n        $xmlWriter->writeAttribute('xmlns:m', 'http://schemas.openxmlformats.org/officeDocument/2006/math');\n        $xmlWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml');\n        $xmlWriter->writeAttribute('xmlns:wp', $drawingSchema);\n        $xmlWriter->writeAttribute('xmlns:w10', 'urn:schemas-microsoft-com:office:word');\n        $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main');\n        $xmlWriter->writeAttribute('xmlns:wne', 'http://schemas.microsoft.com/office/word/2006/wordml');\n\n        // Abstract numbering definitions\n        foreach ($styles as $style) {\n            if ($style instanceof NumberingStyle) {\n                $levels = $style->getLevels();\n\n                $xmlWriter->startElement('w:abstractNum');\n                $xmlWriter->writeAttribute('w:abstractNumId', $style->getIndex());\n\n                $xmlWriter->startElement('w:nsid');\n                $xmlWriter->writeAttribute('w:val', $this->getRandomHexNumber());\n                $xmlWriter->endElement(); // w:nsid\n\n                $xmlWriter->startElement('w:multiLevelType');\n                $xmlWriter->writeAttribute('w:val', $style->getType());\n                $xmlWriter->endElement(); // w:multiLevelType\n\n                foreach ($levels as $level) {\n                    $this->writeLevel($xmlWriter, $level);\n                }\n                $xmlWriter->endElement(); // w:abstractNum\n            }\n        }\n\n        // Numbering definition instances\n        foreach ($styles as $style) {\n            if ($style instanceof NumberingStyle) {\n                $xmlWriter->startElement('w:num');\n                $xmlWriter->writeAttribute('w:numId', $style->getIndex());\n                $xmlWriter->startElement('w:abstractNumId');\n                $xmlWriter->writeAttribute('w:val', $style->getIndex());\n                $xmlWriter->endElement(); // w:abstractNumId\n                $xmlWriter->endElement(); // w:num\n            }\n        }\n\n        $xmlWriter->endElement(); // w:numbering\n\n        return $xmlWriter->getData();\n    }\n\n    /**\n     * Write level.\n     */\n    private function writeLevel(XMLWriter $xmlWriter, NumberingLevel $level): void\n    {\n        $xmlWriter->startElement('w:lvl');\n        $xmlWriter->writeAttribute('w:ilvl', $level->getLevel());\n\n        // Numbering level properties\n        $properties = [\n            'start' => 'start',\n            'format' => 'numFmt',\n            'restart' => 'lvlRestart',\n            'pStyle' => 'pStyle',\n            'suffix' => 'suff',\n            'text' => 'lvlText',\n            'alignment' => 'lvlJc',\n        ];\n        foreach ($properties as $property => $nodeName) {\n            $getMethod = \"get{$property}\";\n            if ('' !== $level->$getMethod()         // this condition is now supported by `alignment` only\n                && null !== $level->$getMethod()) {\n                $xmlWriter->startElement(\"w:{$nodeName}\");\n                $xmlWriter->writeAttribute('w:val', $level->$getMethod());\n                $xmlWriter->endElement(); // w:start\n            }\n        }\n\n        // Paragraph & font styles\n        $this->writeParagraph($xmlWriter, $level);\n        $this->writeFont($xmlWriter, $level);\n\n        $xmlWriter->endElement(); // w:lvl\n    }\n\n    /**\n     * Write level paragraph.\n     *\n     * @since 0.11.0\n     *\n     * @todo Use paragraph style writer\n     */\n    private function writeParagraph(XMLWriter $xmlWriter, NumberingLevel $level): void\n    {\n        $tabPos = $level->getTabPos();\n        $left = $level->getLeft();\n        $hanging = $level->getHanging();\n\n        $xmlWriter->startElement('w:pPr');\n\n        $xmlWriter->startElement('w:tabs');\n        $xmlWriter->startElement('w:tab');\n        $xmlWriter->writeAttribute('w:val', 'num');\n        $xmlWriter->writeAttributeIf($tabPos !== null, 'w:pos', $tabPos);\n        $xmlWriter->endElement(); // w:tab\n        $xmlWriter->endElement(); // w:tabs\n\n        $xmlWriter->startElement('w:ind');\n        $xmlWriter->writeAttributeIf($left !== null, 'w:left', $left);\n        $xmlWriter->writeAttributeIf($hanging !== null, 'w:hanging', $hanging);\n        $xmlWriter->endElement(); // w:ind\n\n        $xmlWriter->endElement(); // w:pPr\n    }\n\n    /**\n     * Write level font.\n     *\n     * @since 0.11.0\n     *\n     * @todo Use font style writer\n     */\n    private function writeFont(XMLWriter $xmlWriter, NumberingLevel $level): void\n    {\n        $font = $level->getFont();\n        $hint = $level->getHint();\n\n        $xmlWriter->startElement('w:rPr');\n        $xmlWriter->startElement('w:rFonts');\n        $xmlWriter->writeAttributeIf($font !== null, 'w:ascii', $font);\n        $xmlWriter->writeAttributeIf($font !== null, 'w:hAnsi', $font);\n        $xmlWriter->writeAttributeIf($font !== null, 'w:cs', $font);\n        $xmlWriter->writeAttributeIf($hint !== null, 'w:hint', $hint);\n        $xmlWriter->endElement(); // w:rFonts\n        $xmlWriter->endElement(); // w:rPr\n    }\n\n    /**\n     * Get random hexadecimal number value.\n     *\n     * @param int $length\n     *\n     * @return string\n     */\n    private function getRandomHexNumber($length = 8)\n    {\n        return strtoupper((string) substr(md5((string) mt_rand()), 0, $length));\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Part/Rels.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Part;\n\nuse PhpOffice\\PhpWord\\Exception\\Exception;\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\n\n/**\n * Word2007 main relationship writer: _rels/.rels.\n *\n * @since 0.10.0\n */\nclass Rels extends AbstractPart\n{\n    /**\n     * Write part.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $xmlRels = [\n            'docProps/core.xml' => 'package/2006/relationships/metadata/core-properties',\n            'docProps/app.xml' => 'officeDocument/2006/relationships/extended-properties',\n            'docProps/custom.xml' => 'officeDocument/2006/relationships/custom-properties',\n            'word/document.xml' => 'officeDocument/2006/relationships/officeDocument',\n        ];\n        $xmlWriter = $this->getXmlWriter();\n        $this->writeRels($xmlWriter, $xmlRels);\n\n        return $xmlWriter->getData();\n    }\n\n    /**\n     * Write relationships.\n     *\n     * @param array $xmlRels\n     * @param array $mediaRels\n     * @param int $relId\n     */\n    protected function writeRels(XMLWriter $xmlWriter, $xmlRels = [], $mediaRels = [], $relId = 1): void\n    {\n        $xmlWriter->startDocument('1.0', 'UTF-8', 'yes');\n        $xmlWriter->startElement('Relationships');\n        $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships');\n\n        // XML files relationships\n        foreach ($xmlRels as $target => $type) {\n            $this->writeRel($xmlWriter, $relId++, $type, $target);\n        }\n\n        // Media relationships\n        foreach ($mediaRels as $mediaRel) {\n            $this->writeMediaRel($xmlWriter, $relId++, $mediaRel);\n        }\n\n        $xmlWriter->endElement(); // Relationships\n    }\n\n    /**\n     * Write media relationships.\n     *\n     * @param int $relId\n     * @param array $mediaRel\n     */\n    private function writeMediaRel(XMLWriter $xmlWriter, $relId, $mediaRel): void\n    {\n        $typePrefix = 'officeDocument/2006/relationships/';\n        $typeMapping = ['image' => 'image', 'object' => 'oleObject', 'link' => 'hyperlink'];\n        $targetMapping = ['image' => 'media/', 'object' => 'embeddings/'];\n\n        $mediaType = $mediaRel['type'];\n        $type = $typeMapping[$mediaType] ?? $mediaType;\n        $targetPrefix = $targetMapping[$mediaType] ?? '';\n        $target = $mediaRel['target'];\n        $targetMode = ($type == 'hyperlink') ? 'External' : '';\n\n        $this->writeRel($xmlWriter, $relId, $typePrefix . $type, $targetPrefix . $target, $targetMode);\n    }\n\n    /**\n     * Write individual rels entry.\n     *\n     * Format:\n     * <Relationship Id=\"rId...\" Type=\"http://...\" Target=\"....xml\" TargetMode=\"...\" />\n     *\n     * @param int $relId Relationship ID\n     * @param string $type Relationship type\n     * @param string $target Relationship target\n     * @param string $targetMode Relationship target mode\n     */\n    private function writeRel(XMLWriter $xmlWriter, $relId, $type, $target, $targetMode = ''): void\n    {\n        if ($type != '' && $target != '') {\n            if (strpos($relId, 'rId') === false) {\n                $relId = 'rId' . $relId;\n            }\n            $xmlWriter->startElement('Relationship');\n            $xmlWriter->writeAttribute('Id', $relId);\n            $xmlWriter->writeAttribute('Type', 'http://schemas.openxmlformats.org/' . $type);\n            $xmlWriter->writeAttribute('Target', $target);\n            if ($targetMode != '') {\n                $xmlWriter->writeAttribute('TargetMode', $targetMode);\n            }\n            $xmlWriter->endElement();\n        } else {\n            throw new Exception('Invalid parameters passed.');\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Part/RelsDocument.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Part;\n\n/**\n * Word2007 document relationship writer: word/_rels/document.xml.rels.\n *\n * @since 0.11.0\n */\nclass RelsDocument extends Rels\n{\n    /**\n     * Write part.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $xmlRels = [\n            'styles.xml' => 'officeDocument/2006/relationships/styles',\n            'numbering.xml' => 'officeDocument/2006/relationships/numbering',\n            'settings.xml' => 'officeDocument/2006/relationships/settings',\n            'theme/theme1.xml' => 'officeDocument/2006/relationships/theme',\n            'webSettings.xml' => 'officeDocument/2006/relationships/webSettings',\n            'fontTable.xml' => 'officeDocument/2006/relationships/fontTable',\n        ];\n        $xmlWriter = $this->getXmlWriter();\n\n        /** @var \\PhpOffice\\PhpWord\\Writer\\Word2007 $parentWriter Type hint */\n        $parentWriter = $this->getParentWriter();\n        $this->writeRels($xmlWriter, $xmlRels, $parentWriter->getRelationships());\n\n        return $xmlWriter->getData();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Part/RelsPart.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Part;\n\n/**\n * Word2007 part relationship writer: word/_rels/(header|footer|footnotes|endnotes)*.xml.rels.\n *\n * @since 0.11.0\n */\nclass RelsPart extends Rels\n{\n    /**\n     * Media relationships.\n     *\n     * @var array\n     */\n    private $media = [];\n\n    /**\n     * Write part.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $this->writeRels($xmlWriter, [], $this->media);\n\n        return $xmlWriter->getData();\n    }\n\n    /**\n     * Set media.\n     *\n     * @param array $media\n     *\n     * @return self\n     */\n    public function setMedia($media)\n    {\n        $this->media = $media;\n\n        return $this;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Part/Settings.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Part;\n\nuse PhpOffice\\PhpWord\\ComplexType\\ProofState;\nuse PhpOffice\\PhpWord\\ComplexType\\TrackChangesView;\nuse PhpOffice\\PhpWord\\Shared\\Microsoft\\PasswordEncoder;\nuse PhpOffice\\PhpWord\\Style\\Language;\n\n/**\n * Word2007 settings part writer: word/settings.xml.\n *\n * @see  http://www.schemacentral.com/sc/ooxml/t-w_CT_Settings.html\n */\nclass Settings extends AbstractPart\n{\n    /**\n     * Settings value.\n     *\n     * @var array\n     */\n    private $settings = [];\n\n    /**\n     * Write part.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $this->getSettings();\n\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startDocument('1.0', 'UTF-8', 'yes');\n        $xmlWriter->startElement('w:settings');\n        $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');\n        $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main');\n        $xmlWriter->writeAttribute('xmlns:m', 'http://schemas.openxmlformats.org/officeDocument/2006/math');\n        $xmlWriter->writeAttribute('xmlns:sl', 'http://schemas.openxmlformats.org/schemaLibrary/2006/main');\n        $xmlWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office');\n        $xmlWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml');\n        $xmlWriter->writeAttribute('xmlns:w10', 'urn:schemas-microsoft-com:office:word');\n\n        foreach ($this->settings as $settingKey => $settingValue) {\n            $this->writeSetting($xmlWriter, $settingKey, $settingValue);\n        }\n\n        $xmlWriter->endElement(); // w:settings\n\n        return $xmlWriter->getData();\n    }\n\n    /**\n     * Write indivual setting, recursive to any child settings.\n     *\n     * @param \\PhpOffice\\PhpWord\\Shared\\XMLWriter $xmlWriter\n     * @param string $settingKey\n     * @param array|string $settingValue\n     */\n    protected function writeSetting($xmlWriter, $settingKey, $settingValue): void\n    {\n        if ($settingValue == '') {\n            $xmlWriter->writeElement($settingKey);\n        } elseif (is_array($settingValue) && !empty($settingValue)) {\n            $xmlWriter->startElement($settingKey);\n\n            /** @var array $settingValue Type hint */\n            foreach ($settingValue as $childKey => $childValue) {\n                if ($childKey == '@attributes') {\n                    foreach ($childValue as $key => $val) {\n                        $xmlWriter->writeAttribute($key, $val);\n                    }\n                } else {\n                    $this->writeSetting($xmlWriter, $childKey, $childValue);\n                }\n            }\n            $xmlWriter->endElement();\n        }\n    }\n\n    /**\n     * Get settings.\n     */\n    private function getSettings(): void\n    {\n        /** @var \\PhpOffice\\PhpWord\\Metadata\\Settings $documentSettings */\n        $documentSettings = $this->getParentWriter()->getPhpWord()->getSettings();\n\n        // Default settings\n        $this->settings = [\n            'w:defaultTabStop' => ['@attributes' => ['w:val' => '708']],\n            'w:hyphenationZone' => ['@attributes' => ['w:val' => '425']],\n            'w:characterSpacingControl' => ['@attributes' => ['w:val' => 'doNotCompress']],\n            'w:decimalSymbol' => ['@attributes' => ['w:val' => $documentSettings->getDecimalSymbol()]],\n            'w:listSeparator' => ['@attributes' => ['w:val' => ';']],\n            'w:compat' => [],\n            'm:mathPr' => [\n                'm:mathFont' => ['@attributes' => ['m:val' => 'Cambria Math']],\n                'm:brkBin' => ['@attributes' => ['m:val' => 'before']],\n                'm:brkBinSub' => ['@attributes' => ['m:val' => '--']],\n                'm:smallFrac' => ['@attributes' => ['m:val' => 'off']],\n                'm:dispDef' => '',\n                'm:lMargin' => ['@attributes' => ['m:val' => '0']],\n                'm:rMargin' => ['@attributes' => ['m:val' => '0']],\n                'm:defJc' => ['@attributes' => ['m:val' => 'centerGroup']],\n                'm:wrapIndent' => ['@attributes' => ['m:val' => '1440']],\n                'm:intLim' => ['@attributes' => ['m:val' => 'subSup']],\n                'm:naryLim' => ['@attributes' => ['m:val' => 'undOvr']],\n            ],\n            'w:clrSchemeMapping' => [\n                '@attributes' => [\n                    'w:bg1' => 'light1',\n                    'w:t1' => 'dark1',\n                    'w:bg2' => 'light2',\n                    'w:t2' => 'dark2',\n                    'w:accent1' => 'accent1',\n                    'w:accent2' => 'accent2',\n                    'w:accent3' => 'accent3',\n                    'w:accent4' => 'accent4',\n                    'w:accent5' => 'accent5',\n                    'w:accent6' => 'accent6',\n                    'w:hyperlink' => 'hyperlink',\n                    'w:followedHyperlink' => 'followedHyperlink',\n                ],\n            ],\n        ];\n\n        $this->setOnOffValue('w:mirrorMargins', $documentSettings->hasMirrorMargins());\n        $this->setOnOffValue('w:hideSpellingErrors', $documentSettings->hasHideSpellingErrors());\n        $this->setOnOffValue('w:hideGrammaticalErrors', $documentSettings->hasHideGrammaticalErrors());\n        $this->setOnOffValue('w:trackRevisions', $documentSettings->hasTrackRevisions());\n        $this->setOnOffValue('w:doNotTrackMoves', $documentSettings->hasDoNotTrackMoves());\n        $this->setOnOffValue('w:doNotTrackFormatting', $documentSettings->hasDoNotTrackFormatting());\n        $this->setOnOffValue('w:evenAndOddHeaders', $documentSettings->hasEvenAndOddHeaders());\n        $this->setOnOffValue('w:updateFields', $documentSettings->hasUpdateFields());\n        $this->setOnOffValue('w:autoHyphenation', $documentSettings->hasAutoHyphenation());\n        $this->setOnOffValue('w:doNotHyphenateCaps', $documentSettings->hasDoNotHyphenateCaps());\n        $this->setOnOffValue('w:bookFoldPrinting', $documentSettings->hasBookFoldPrinting());\n\n        $this->setThemeFontLang($documentSettings->getThemeFontLang());\n        $this->setRevisionView($documentSettings->getRevisionView());\n        $this->setDocumentProtection($documentSettings->getDocumentProtection());\n        $this->setProofState($documentSettings->getProofState());\n        $this->setZoom($documentSettings->getZoom());\n        $this->setConsecutiveHyphenLimit($documentSettings->getConsecutiveHyphenLimit());\n        $this->setHyphenationZone($documentSettings->getHyphenationZone());\n        $this->setCompatibility();\n    }\n\n    /**\n     * Adds a boolean attribute to the settings array.\n     *\n     * @param string $settingName\n     * @param null|bool $booleanValue\n     */\n    private function setOnOffValue($settingName, $booleanValue): void\n    {\n        if (!is_bool($booleanValue)) {\n            return;\n        }\n\n        $value = $booleanValue ? 'true' : 'false';\n        $this->settings[$settingName] = ['@attributes' => ['w:val' => $value]];\n    }\n\n    /**\n     * Get protection settings.\n     *\n     * @param \\PhpOffice\\PhpWord\\Metadata\\Protection $documentProtection\n     */\n    private function setDocumentProtection($documentProtection): void\n    {\n        if ($documentProtection->getEditing() !== null) {\n            if ($documentProtection->getPassword() == null) {\n                $this->settings['w:documentProtection'] = [\n                    '@attributes' => [\n                        'w:enforcement' => 1,\n                        'w:edit' => $documentProtection->getEditing(),\n                    ],\n                ];\n            } else {\n                if ($documentProtection->getSalt() == null) {\n                    $documentProtection->setSalt((string) openssl_random_pseudo_bytes(16));\n                }\n                $passwordHash = PasswordEncoder::hashPassword($documentProtection->getPassword(), $documentProtection->getAlgorithm(), $documentProtection->getSalt(), $documentProtection->getSpinCount());\n                $this->settings['w:documentProtection'] = [\n                    '@attributes' => [\n                        'w:enforcement' => 1,\n                        'w:edit' => $documentProtection->getEditing(),\n                        'w:cryptProviderType' => 'rsaFull',\n                        'w:cryptAlgorithmClass' => 'hash',\n                        'w:cryptAlgorithmType' => 'typeAny',\n                        'w:cryptAlgorithmSid' => PasswordEncoder::getAlgorithmId($documentProtection->getAlgorithm()),\n                        'w:cryptSpinCount' => $documentProtection->getSpinCount(),\n                        'w:hash' => $passwordHash,\n                        'w:salt' => base64_encode($documentProtection->getSalt()),\n                    ],\n                ];\n            }\n        }\n    }\n\n    /**\n     * Set the Proof state.\n     */\n    private function setProofState(?ProofState $proofState = null): void\n    {\n        if ($proofState != null && $proofState->getGrammar() !== null && $proofState->getSpelling() !== null) {\n            $this->settings['w:proofState'] = [\n                '@attributes' => [\n                    'w:spelling' => $proofState->getSpelling(),\n                    'w:grammar' => $proofState->getGrammar(),\n                ],\n            ];\n        }\n    }\n\n    /**\n     * Set the Revision View.\n     */\n    private function setRevisionView(?TrackChangesView $trackChangesView = null): void\n    {\n        if ($trackChangesView != null) {\n            $revisionView = [];\n            $revisionView['w:markup'] = $trackChangesView->hasMarkup() ? 'true' : 'false';\n            $revisionView['w:comments'] = $trackChangesView->hasComments() ? 'true' : 'false';\n            $revisionView['w:insDel'] = $trackChangesView->hasInsDel() ? 'true' : 'false';\n            $revisionView['w:formatting'] = $trackChangesView->hasFormatting() ? 'true' : 'false';\n            $revisionView['w:inkAnnotations'] = $trackChangesView->hasInkAnnotations() ? 'true' : 'false';\n\n            $this->settings['w:revisionView'] = ['@attributes' => $revisionView];\n        }\n    }\n\n    /**\n     * Sets the language.\n     */\n    private function setThemeFontLang(?Language $language = null): void\n    {\n        $latinLanguage = ($language == null || $language->getLatin() === null) ? 'en-US' : $language->getLatin();\n        $lang = [];\n        $lang['w:val'] = $latinLanguage;\n        if ($language != null) {\n            $lang['w:eastAsia'] = $language->getEastAsia() === null ? 'x-none' : $language->getEastAsia();\n            $lang['w:bidi'] = $language->getBidirectional() === null ? 'x-none' : $language->getBidirectional();\n        }\n        $this->settings['w:themeFontLang'] = ['@attributes' => $lang];\n    }\n\n    /**\n     * Set the magnification.\n     *\n     * @param mixed $zoom\n     */\n    private function setZoom($zoom = null): void\n    {\n        if ($zoom !== null) {\n            $attr = is_int($zoom) ? 'w:percent' : 'w:val';\n            $this->settings['w:zoom'] = ['@attributes' => [$attr => $zoom]];\n        }\n    }\n\n    /**\n     * @param null|int $consecutiveHyphenLimit\n     */\n    private function setConsecutiveHyphenLimit($consecutiveHyphenLimit): void\n    {\n        if ($consecutiveHyphenLimit === null) {\n            return;\n        }\n\n        $this->settings['w:consecutiveHyphenLimit'] = [\n            '@attributes' => ['w:val' => $consecutiveHyphenLimit],\n        ];\n    }\n\n    /**\n     * @param null|float $hyphenationZone\n     */\n    private function setHyphenationZone($hyphenationZone): void\n    {\n        if ($hyphenationZone === null) {\n            return;\n        }\n\n        $this->settings['w:hyphenationZone'] = [\n            '@attributes' => ['w:val' => $hyphenationZone],\n        ];\n    }\n\n    /**\n     * Get compatibility setting.\n     */\n    private function setCompatibility(): void\n    {\n        $compatibility = $this->getParentWriter()->getPhpWord()->getCompatibility();\n        if ($compatibility->getOoxmlVersion() !== null) {\n            $this->settings['w:compat']['w:compatSetting'] = [\n                '@attributes' => [\n                    'w:name' => 'compatibilityMode',\n                    'w:uri' => 'http://schemas.microsoft.com/office/word',\n                    'w:val' => $compatibility->getOoxmlVersion(),\n                ],\n            ];\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Part/Styles.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Part;\n\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\nuse PhpOffice\\PhpWord\\Style;\nuse PhpOffice\\PhpWord\\Style\\Font as FontStyle;\nuse PhpOffice\\PhpWord\\Style\\Paragraph as ParagraphStyle;\nuse PhpOffice\\PhpWord\\Style\\Table as TableStyle;\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Font as FontStyleWriter;\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Paragraph as ParagraphStyleWriter;\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Table as TableStyleWriter;\n\n/**\n * Word2007 styles part writer: word/styles.xml.\n *\n * @todo Do something with the numbering style introduced in 0.10.0\n *\n * @SuppressWarnings(\"PHPMD.UnusedPrivateMethod\") For writeFontStyle, writeParagraphStyle, and writeTableStyle\n */\nclass Styles extends AbstractPart\n{\n    /**\n     * Write part.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startDocument('1.0', 'UTF-8', 'yes');\n        $xmlWriter->startElement('w:styles');\n        $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');\n        $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main');\n\n        // Write default styles\n        $styles = Style::getStyles();\n        $this->writeDefaultStyles($xmlWriter, $styles);\n\n        // Write styles\n        if (count($styles) > 0) {\n            foreach ($styles as $styleName => $style) {\n                if ($styleName == 'Normal') {\n                    continue;\n                }\n\n                // Get style class and execute if the private method exists\n                $styleClass = substr(get_class($style), strrpos(get_class($style), '\\\\') + 1);\n                $method = \"write{$styleClass}Style\";\n                if (method_exists($this, $method)) {\n                    $this->$method($xmlWriter, $styleName, $style);\n                }\n            }\n        }\n\n        $xmlWriter->endElement(); // w:styles\n\n        return $xmlWriter->getData();\n    }\n\n    /**\n     * Write default font and other default styles.\n     *\n     * @param Style\\AbstractStyle[] $styles\n     */\n    private function writeDefaultStyles(XMLWriter $xmlWriter, $styles): void\n    {\n        $phpWord = $this->getParentWriter()->getPhpWord();\n        $fontName = $phpWord->getDefaultFontName();\n        $asianFontName = $phpWord->getDefaultAsianFontName();\n        $fontSize = $phpWord->getDefaultFontSize();\n        $fontColor = $phpWord->getDefaultFontColor();\n        $language = $phpWord->getSettings()->getThemeFontLang();\n        $latinLanguage = ($language == null || $language->getLatin() === null) ? 'en-US' : $language->getLatin();\n\n        // Default font\n        $xmlWriter->startElement('w:docDefaults');\n        $xmlWriter->startElement('w:rPrDefault');\n        $xmlWriter->startElement('w:rPr');\n        $xmlWriter->startElement('w:rFonts');\n        $xmlWriter->writeAttribute('w:ascii', $fontName);\n        $xmlWriter->writeAttribute('w:hAnsi', $fontName);\n        $xmlWriter->writeAttribute('w:eastAsia', $asianFontName);\n        $xmlWriter->writeAttribute('w:cs', $fontName);\n        $xmlWriter->endElement(); // w:rFonts\n        $xmlWriter->startElement('w:color');\n        $xmlWriter->writeAttribute('w:val', $fontColor);\n        $xmlWriter->endElement();\n        $xmlWriter->startElement('w:sz');\n        $xmlWriter->writeAttribute('w:val', $fontSize * 2);\n        $xmlWriter->endElement(); // w:sz\n        $xmlWriter->startElement('w:szCs');\n        $xmlWriter->writeAttribute('w:val', $fontSize * 2);\n        $xmlWriter->endElement(); // w:szCs\n        $xmlWriter->startElement('w:lang');\n        $xmlWriter->writeAttribute('w:val', $latinLanguage);\n        if ($language != null) {\n            $xmlWriter->writeAttributeIf($language->getEastAsia() !== null, 'w:eastAsia', $language->getEastAsia());\n            $xmlWriter->writeAttributeIf($language->getBidirectional() !== null, 'w:bidi', $language->getBidirectional());\n        }\n        $xmlWriter->endElement(); // w:lang\n        $xmlWriter->endElement(); // w:rPr\n        $xmlWriter->endElement(); // w:rPrDefault\n        $xmlWriter->endElement(); // w:docDefaults\n\n        // Normal style\n        $xmlWriter->startElement('w:style');\n        $xmlWriter->writeAttribute('w:type', 'paragraph');\n        $xmlWriter->writeAttribute('w:default', '1');\n        $xmlWriter->writeAttribute('w:styleId', 'Normal');\n        $xmlWriter->startElement('w:name');\n        $xmlWriter->writeAttribute('w:val', 'Normal');\n        $xmlWriter->endElement(); // w:name\n        if (isset($styles['Normal'])) {\n            $normalStyle = $styles['Normal'];\n            // w:pPr\n            if ($normalStyle instanceof FontStyle && $normalStyle->getParagraph() != null) {\n                $styleWriter = new ParagraphStyleWriter($xmlWriter, $normalStyle->getParagraph());\n                $styleWriter->write();\n            } elseif ($normalStyle instanceof ParagraphStyle) {\n                $styleWriter = new ParagraphStyleWriter($xmlWriter, $normalStyle);\n                $styleWriter->write();\n            }\n\n            // w:rPr\n            $styleWriter = new FontStyleWriter($xmlWriter, $normalStyle);\n            $styleWriter->write();\n        }\n        $xmlWriter->endElement(); // w:style\n\n        // FootnoteReference style\n        if (!isset($styles['FootnoteReference'])) {\n            $xmlWriter->startElement('w:style');\n            $xmlWriter->writeAttribute('w:type', 'character');\n            $xmlWriter->writeAttribute('w:styleId', 'FootnoteReference');\n            $xmlWriter->startElement('w:name');\n            $xmlWriter->writeAttribute('w:val', 'Footnote Reference');\n            $xmlWriter->endElement(); // w:name\n            $xmlWriter->writeElement('w:semiHidden');\n            $xmlWriter->writeElement('w:unhideWhenUsed');\n            $xmlWriter->startElement('w:rPr');\n            $xmlWriter->startElement('w:vertAlign');\n            $xmlWriter->writeAttribute('w:val', 'superscript');\n            $xmlWriter->endElement(); // w:vertAlign\n            $xmlWriter->endElement(); // w:rPr\n            $xmlWriter->endElement(); // w:style\n        }\n    }\n\n    /**\n     * Write font style.\n     *\n     * @param string $styleName\n     */\n    private function writeFontStyle(XMLWriter $xmlWriter, $styleName, FontStyle $style): void\n    {\n        $paragraphStyle = $style->getParagraph();\n        $styleType = $style->getStyleType();\n        $type = ($styleType == 'title') ? 'paragraph' : 'character';\n        if (null !== $paragraphStyle) {\n            $type = 'paragraph';\n        }\n\n        $xmlWriter->startElement('w:style');\n        $xmlWriter->writeAttribute('w:type', $type);\n\n        // Heading style\n        if ($styleType == 'title') {\n            $arrStyle = explode('_', $styleName);\n            if (count($arrStyle) > 1) {\n                $styleId = 'Heading' . $arrStyle[1];\n                $styleName = 'heading ' . $arrStyle[1];\n                $styleLink = 'Heading' . $arrStyle[1] . 'Char';\n            } else {\n                $styleId = $styleName;\n                $styleName = strtolower($styleName);\n                $styleLink = $styleName . 'Char';\n            }\n            $xmlWriter->writeAttribute('w:styleId', $styleId);\n\n            $xmlWriter->startElement('w:link');\n            $xmlWriter->writeAttribute('w:val', $styleLink);\n            $xmlWriter->endElement();\n        } elseif (null !== $paragraphStyle) {\n            // if type is 'paragraph' it should have a styleId\n            $xmlWriter->writeAttribute('w:styleId', $styleName);\n        }\n\n        // Style name\n        $xmlWriter->startElement('w:name');\n        $xmlWriter->writeAttribute('w:val', $styleName);\n        $xmlWriter->endElement();\n\n        // Parent style\n        if (null !== $paragraphStyle) {\n            if ($paragraphStyle->getStyleName() != null) {\n                $xmlWriter->writeElementBlock('w:basedOn', 'w:val', $paragraphStyle->getStyleName());\n            } elseif ($paragraphStyle->getBasedOn() != null) {\n                $xmlWriter->writeElementBlock('w:basedOn', 'w:val', $paragraphStyle->getBasedOn());\n            }\n        }\n\n        // w:pPr\n        if (null !== $paragraphStyle) {\n            $styleWriter = new ParagraphStyleWriter($xmlWriter, $paragraphStyle);\n            $styleWriter->write();\n        }\n\n        // w:rPr\n        $styleWriter = new FontStyleWriter($xmlWriter, $style);\n        $styleWriter->write();\n\n        $xmlWriter->endElement();\n    }\n\n    /**\n     * Write paragraph style.\n     *\n     * @param string $styleName\n     */\n    private function writeParagraphStyle(XMLWriter $xmlWriter, $styleName, ParagraphStyle $style): void\n    {\n        $xmlWriter->startElement('w:style');\n        $xmlWriter->writeAttribute('w:type', 'paragraph');\n        $xmlWriter->writeAttribute('w:customStyle', '1');\n        $xmlWriter->writeAttribute('w:styleId', $styleName);\n        $xmlWriter->startElement('w:name');\n        $xmlWriter->writeAttribute('w:val', $styleName);\n        $xmlWriter->endElement();\n\n        // Parent style\n        $basedOn = $style->getBasedOn();\n        $xmlWriter->writeElementIf(null !== $basedOn, 'w:basedOn', 'w:val', $basedOn);\n\n        // Next paragraph style\n        $next = $style->getNext();\n        $xmlWriter->writeElementIf(null !== $next, 'w:next', 'w:val', $next);\n\n        // w:pPr\n        $styleWriter = new ParagraphStyleWriter($xmlWriter, $style);\n        $styleWriter->write();\n\n        $xmlWriter->endElement();\n    }\n\n    /**\n     * Write table style.\n     *\n     * @param string $styleName\n     */\n    private function writeTableStyle(XMLWriter $xmlWriter, $styleName, TableStyle $style): void\n    {\n        $xmlWriter->startElement('w:style');\n        $xmlWriter->writeAttribute('w:type', 'table');\n        $xmlWriter->writeAttribute('w:customStyle', '1');\n        $xmlWriter->writeAttribute('w:styleId', $styleName);\n        $xmlWriter->startElement('w:name');\n        $xmlWriter->writeAttribute('w:val', $styleName);\n        $xmlWriter->endElement();\n        $xmlWriter->startElement('w:uiPriority');\n        $xmlWriter->writeAttribute('w:val', '99');\n        $xmlWriter->endElement();\n\n        $styleWriter = new TableStyleWriter($xmlWriter, $style);\n        $styleWriter->write();\n\n        $xmlWriter->endElement(); // w:style\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Part/Theme.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Part;\n\n/**\n * Word2007 theme writer: word/theme/theme1.xml.\n *\n * @todo Generate content dynamically\n *\n * @since 0.10.0\n */\nclass Theme extends AbstractPart\n{\n    /**\n     * Write part.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $str = '';\n\n        $str .= '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>';\n        $str .= '<a:theme xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" name=\"Office Theme\">';\n        $str .= '<a:themeElements>';\n        $str .= $this->writeColorScheme();\n        $str .= $this->writeFontScheme();\n        $str .= $this->writeFormatScheme();\n        $str .= '</a:themeElements>';\n        $str .= '<a:objectDefaults />';\n        $str .= '<a:extraClrSchemeLst />';\n        $str .= '</a:theme>';\n\n        return $str;\n    }\n\n    /**\n     * Write color scheme.\n     *\n     * @return string\n     */\n    private function writeColorScheme()\n    {\n        $str = '';\n\n        $str .= '<a:clrScheme name=\"Office\">';\n        $str .= '<a:dk1>';\n        $str .= '<a:sysClr val=\"windowText\" lastClr=\"000000\" />';\n        $str .= '</a:dk1>';\n        $str .= '<a:lt1>';\n        $str .= '<a:sysClr val=\"window\" lastClr=\"FFFFFF\" />';\n        $str .= '</a:lt1>';\n        $str .= '<a:dk2>';\n        $str .= '<a:srgbClr val=\"1F497D\" />';\n        $str .= '</a:dk2>';\n        $str .= '<a:lt2>';\n        $str .= '<a:srgbClr val=\"EEECE1\" />';\n        $str .= '</a:lt2>';\n        $str .= '<a:accent1>';\n        $str .= '<a:srgbClr val=\"4F81BD\" />';\n        $str .= '</a:accent1>';\n        $str .= '<a:accent2>';\n        $str .= '<a:srgbClr val=\"C0504D\" />';\n        $str .= '</a:accent2>';\n        $str .= '<a:accent3>';\n        $str .= '<a:srgbClr val=\"9BBB59\" />';\n        $str .= '</a:accent3>';\n        $str .= '<a:accent4>';\n        $str .= '<a:srgbClr val=\"8064A2\" />';\n        $str .= '</a:accent4>';\n        $str .= '<a:accent5>';\n        $str .= '<a:srgbClr val=\"4BACC6\" />';\n        $str .= '</a:accent5>';\n        $str .= '<a:accent6>';\n        $str .= '<a:srgbClr val=\"F79646\" />';\n        $str .= '</a:accent6>';\n        $str .= '<a:hlink>';\n        $str .= '<a:srgbClr val=\"0000FF\" />';\n        $str .= '</a:hlink>';\n        $str .= '<a:folHlink>';\n        $str .= '<a:srgbClr val=\"800080\" />';\n        $str .= '</a:folHlink>';\n        $str .= '</a:clrScheme>';\n\n        return $str;\n    }\n\n    /**\n     * Write font scheme.\n     *\n     * @return string\n     */\n    private function writeFontScheme()\n    {\n        $str = '';\n\n        $str .= '<a:fontScheme name=\"Office\">';\n\n        $str .= '<a:majorFont>';\n        $str .= '<a:latin typeface=\"Cambria\" />';\n        $str .= '<a:ea typeface=\"\" />';\n        $str .= '<a:cs typeface=\"\" />';\n        $str .= '<a:font script=\"Jpan\" typeface=\"ＭＳ ゴシック\" />';\n        $str .= '<a:font script=\"Hang\" typeface=\"맑은 고딕\" />';\n        $str .= '<a:font script=\"Hans\" typeface=\"宋体\" />';\n        $str .= '<a:font script=\"Hant\" typeface=\"新細明體\" />';\n        $str .= '<a:font script=\"Arab\" typeface=\"Times New Roman\" />';\n        $str .= '<a:font script=\"Hebr\" typeface=\"Times New Roman\" />';\n        $str .= '<a:font script=\"Thai\" typeface=\"Angsana New\" />';\n        $str .= '<a:font script=\"Ethi\" typeface=\"Nyala\" />';\n        $str .= '<a:font script=\"Beng\" typeface=\"Vrinda\" />';\n        $str .= '<a:font script=\"Gujr\" typeface=\"Shruti\" />';\n        $str .= '<a:font script=\"Khmr\" typeface=\"MoolBoran\" />';\n        $str .= '<a:font script=\"Knda\" typeface=\"Tunga\" />';\n        $str .= '<a:font script=\"Guru\" typeface=\"Raavi\" />';\n        $str .= '<a:font script=\"Cans\" typeface=\"Euphemia\" />';\n        $str .= '<a:font script=\"Cher\" typeface=\"Plantagenet Cherokee\" />';\n        $str .= '<a:font script=\"Yiii\" typeface=\"Microsoft Yi Baiti\" />';\n        $str .= '<a:font script=\"Tibt\" typeface=\"Microsoft Himalaya\" />';\n        $str .= '<a:font script=\"Thaa\" typeface=\"MV Boli\" />';\n        $str .= '<a:font script=\"Deva\" typeface=\"Mangal\" />';\n        $str .= '<a:font script=\"Telu\" typeface=\"Gautami\" />';\n        $str .= '<a:font script=\"Taml\" typeface=\"Latha\" />';\n        $str .= '<a:font script=\"Syrc\" typeface=\"Estrangelo Edessa\" />';\n        $str .= '<a:font script=\"Orya\" typeface=\"Kalinga\" />';\n        $str .= '<a:font script=\"Mlym\" typeface=\"Kartika\" />';\n        $str .= '<a:font script=\"Laoo\" typeface=\"DokChampa\" />';\n        $str .= '<a:font script=\"Sinh\" typeface=\"Iskoola Pota\" />';\n        $str .= '<a:font script=\"Mong\" typeface=\"Mongolian Baiti\" />';\n        $str .= '<a:font script=\"Viet\" typeface=\"Times New Roman\" />';\n        $str .= '<a:font script=\"Uigh\" typeface=\"Microsoft Uighur\" />';\n        $str .= '</a:majorFont>';\n\n        $str .= '<a:minorFont>';\n        $str .= '<a:latin typeface=\"Calibri\" />';\n        $str .= '<a:ea typeface=\"\" />';\n        $str .= '<a:cs typeface=\"\" />';\n        $str .= '<a:font script=\"Jpan\" typeface=\"ＭＳ 明朝\" />';\n        $str .= '<a:font script=\"Hang\" typeface=\"맑은 고딕\" />';\n        $str .= '<a:font script=\"Hans\" typeface=\"宋体\" />';\n        $str .= '<a:font script=\"Hant\" typeface=\"新細明體\" />';\n        $str .= '<a:font script=\"Arab\" typeface=\"Arial\" />';\n        $str .= '<a:font script=\"Hebr\" typeface=\"Arial\" />';\n        $str .= '<a:font script=\"Thai\" typeface=\"Cordia New\" />';\n        $str .= '<a:font script=\"Ethi\" typeface=\"Nyala\" />';\n        $str .= '<a:font script=\"Beng\" typeface=\"Vrinda\" />';\n        $str .= '<a:font script=\"Gujr\" typeface=\"Shruti\" />';\n        $str .= '<a:font script=\"Khmr\" typeface=\"DaunPenh\" />';\n        $str .= '<a:font script=\"Knda\" typeface=\"Tunga\" />';\n        $str .= '<a:font script=\"Guru\" typeface=\"Raavi\" />';\n        $str .= '<a:font script=\"Cans\" typeface=\"Euphemia\" />';\n        $str .= '<a:font script=\"Cher\" typeface=\"Plantagenet Cherokee\" />';\n        $str .= '<a:font script=\"Yiii\" typeface=\"Microsoft Yi Baiti\" />';\n        $str .= '<a:font script=\"Tibt\" typeface=\"Microsoft Himalaya\" />';\n        $str .= '<a:font script=\"Thaa\" typeface=\"MV Boli\" />';\n        $str .= '<a:font script=\"Deva\" typeface=\"Mangal\" />';\n        $str .= '<a:font script=\"Telu\" typeface=\"Gautami\" />';\n        $str .= '<a:font script=\"Taml\" typeface=\"Latha\" />';\n        $str .= '<a:font script=\"Syrc\" typeface=\"Estrangelo Edessa\" />';\n        $str .= '<a:font script=\"Orya\" typeface=\"Kalinga\" />';\n        $str .= '<a:font script=\"Mlym\" typeface=\"Kartika\" />';\n        $str .= '<a:font script=\"Laoo\" typeface=\"DokChampa\" />';\n        $str .= '<a:font script=\"Sinh\" typeface=\"Iskoola Pota\" />';\n        $str .= '<a:font script=\"Mong\" typeface=\"Mongolian Baiti\" />';\n        $str .= '<a:font script=\"Viet\" typeface=\"Arial\" />';\n        $str .= '<a:font script=\"Uigh\" typeface=\"Microsoft Uighur\" />';\n        $str .= '</a:minorFont>';\n\n        $str .= '</a:fontScheme>';\n\n        return $str;\n    }\n\n    /**\n     * Write format scheme.\n     *\n     * @return string\n     */\n    private function writeFormatScheme()\n    {\n        $str = '';\n\n        $str .= '<a:fmtScheme name=\"Office\">';\n        $str .= $this->writeFormatFill();\n        $str .= $this->writeFormatLine();\n        $str .= $this->writeFormatEffect();\n        $str .= $this->writeFormatBackground();\n        $str .= '</a:fmtScheme>';\n\n        return $str;\n    }\n\n    /**\n     * Write fill format scheme.\n     *\n     * @return string\n     */\n    private function writeFormatFill()\n    {\n        $str = '';\n\n        $str .= '<a:fillStyleLst>';\n        $str .= '<a:solidFill>';\n        $str .= '<a:schemeClr val=\"phClr\" />';\n        $str .= '</a:solidFill>';\n        $str .= '<a:gradFill rotWithShape=\"1\">';\n        $str .= '<a:gsLst>';\n        $str .= '<a:gs pos=\"0\">';\n        $str .= '<a:schemeClr val=\"phClr\">';\n        $str .= '<a:tint val=\"50000\" />';\n        $str .= '<a:satMod val=\"300000\" />';\n        $str .= '</a:schemeClr>';\n        $str .= '</a:gs>';\n        $str .= '<a:gs pos=\"35000\">';\n        $str .= '<a:schemeClr val=\"phClr\">';\n        $str .= '<a:tint val=\"37000\" />';\n        $str .= '<a:satMod val=\"300000\" />';\n        $str .= '</a:schemeClr>';\n        $str .= '</a:gs>';\n        $str .= '<a:gs pos=\"100000\">';\n        $str .= '<a:schemeClr val=\"phClr\">';\n        $str .= '<a:tint val=\"15000\" />';\n        $str .= '<a:satMod val=\"350000\" />';\n        $str .= '</a:schemeClr>';\n        $str .= '</a:gs>';\n        $str .= '</a:gsLst>';\n        $str .= '<a:lin ang=\"16200000\" scaled=\"1\" />';\n        $str .= '</a:gradFill>';\n        $str .= '<a:gradFill rotWithShape=\"1\">';\n        $str .= '<a:gsLst>';\n        $str .= '<a:gs pos=\"0\">';\n        $str .= '<a:schemeClr val=\"phClr\">';\n        $str .= '<a:shade val=\"51000\" />';\n        $str .= '<a:satMod val=\"130000\" />';\n        $str .= '</a:schemeClr>';\n        $str .= '</a:gs>';\n        $str .= '<a:gs pos=\"80000\">';\n        $str .= '<a:schemeClr val=\"phClr\">';\n        $str .= '<a:shade val=\"93000\" />';\n        $str .= '<a:satMod val=\"130000\" />';\n        $str .= '</a:schemeClr>';\n        $str .= '</a:gs>';\n        $str .= '<a:gs pos=\"100000\">';\n        $str .= '<a:schemeClr val=\"phClr\">';\n        $str .= '<a:shade val=\"94000\" />';\n        $str .= '<a:satMod val=\"135000\" />';\n        $str .= '</a:schemeClr>';\n        $str .= '</a:gs>';\n        $str .= '</a:gsLst>';\n        $str .= '<a:lin ang=\"16200000\" scaled=\"0\" />';\n        $str .= '</a:gradFill>';\n        $str .= '</a:fillStyleLst>';\n\n        return $str;\n    }\n\n    /**\n     * Write line format scheme.\n     *\n     * @return string\n     */\n    private function writeFormatLine()\n    {\n        $str = '';\n\n        $str .= '<a:lnStyleLst>';\n        $str .= '<a:ln w=\"9525\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">';\n        $str .= '<a:solidFill>';\n        $str .= '<a:schemeClr val=\"phClr\">';\n        $str .= '<a:shade val=\"95000\" />';\n        $str .= '<a:satMod val=\"105000\" />';\n        $str .= '</a:schemeClr>';\n        $str .= '</a:solidFill>';\n        $str .= '<a:prstDash val=\"solid\" />';\n        $str .= '</a:ln>';\n        $str .= '<a:ln w=\"25400\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">';\n        $str .= '<a:solidFill>';\n        $str .= '<a:schemeClr val=\"phClr\" />';\n        $str .= '</a:solidFill>';\n        $str .= '<a:prstDash val=\"solid\" />';\n        $str .= '</a:ln>';\n        $str .= '<a:ln w=\"38100\" cap=\"flat\" cmpd=\"sng\" algn=\"ctr\">';\n        $str .= '<a:solidFill>';\n        $str .= '<a:schemeClr val=\"phClr\" />';\n        $str .= '</a:solidFill>';\n        $str .= '<a:prstDash val=\"solid\" />';\n        $str .= '</a:ln>';\n        $str .= '</a:lnStyleLst>';\n\n        return $str;\n    }\n\n    /**\n     * Write effect format scheme.\n     *\n     * @return string\n     */\n    private function writeFormatEffect()\n    {\n        $str = '';\n\n        $str .= '<a:effectStyleLst>';\n        $str .= '<a:effectStyle>';\n        $str .= '<a:effectLst>';\n        $str .= '<a:outerShdw blurRad=\"40000\" dist=\"20000\" dir=\"5400000\" rotWithShape=\"0\">';\n        $str .= '<a:srgbClr val=\"000000\">';\n        $str .= '<a:alpha val=\"38000\" />';\n        $str .= '</a:srgbClr>';\n        $str .= '</a:outerShdw>';\n        $str .= '</a:effectLst>';\n        $str .= '</a:effectStyle>';\n        $str .= '<a:effectStyle>';\n        $str .= '<a:effectLst>';\n        $str .= '<a:outerShdw blurRad=\"40000\" dist=\"23000\" dir=\"5400000\" rotWithShape=\"0\">';\n        $str .= '<a:srgbClr val=\"000000\">';\n        $str .= '<a:alpha val=\"35000\" />';\n        $str .= '</a:srgbClr>';\n        $str .= '</a:outerShdw>';\n        $str .= '</a:effectLst>';\n        $str .= '</a:effectStyle>';\n        $str .= '<a:effectStyle>';\n        $str .= '<a:effectLst>';\n        $str .= '<a:outerShdw blurRad=\"40000\" dist=\"23000\" dir=\"5400000\" rotWithShape=\"0\">';\n        $str .= '<a:srgbClr val=\"000000\">';\n        $str .= '<a:alpha val=\"35000\" />';\n        $str .= '</a:srgbClr>';\n        $str .= '</a:outerShdw>';\n        $str .= '</a:effectLst>';\n        $str .= '<a:scene3d>';\n        $str .= '<a:camera prst=\"orthographicFront\">';\n        $str .= '<a:rot lat=\"0\" lon=\"0\" rev=\"0\" />';\n        $str .= '</a:camera>';\n        $str .= '<a:lightRig rig=\"threePt\" dir=\"t\">';\n        $str .= '<a:rot lat=\"0\" lon=\"0\" rev=\"1200000\" />';\n        $str .= '</a:lightRig>';\n        $str .= '</a:scene3d>';\n        $str .= '<a:sp3d>';\n        $str .= '<a:bevelT w=\"63500\" h=\"25400\" />';\n        $str .= '</a:sp3d>';\n        $str .= '</a:effectStyle>';\n        $str .= '</a:effectStyleLst>';\n\n        return $str;\n    }\n\n    /**\n     * Write background format scheme.\n     *\n     * @return string\n     */\n    private function writeFormatBackground()\n    {\n        $str = '';\n\n        $str .= '<a:bgFillStyleLst>';\n        $str .= '<a:solidFill>';\n        $str .= '<a:schemeClr val=\"phClr\" />';\n        $str .= '</a:solidFill>';\n        $str .= '<a:gradFill rotWithShape=\"1\">';\n        $str .= '<a:gsLst>';\n        $str .= '<a:gs pos=\"0\">';\n        $str .= '<a:schemeClr val=\"phClr\">';\n        $str .= '<a:tint val=\"40000\" />';\n        $str .= '<a:satMod val=\"350000\" />';\n        $str .= '</a:schemeClr>';\n        $str .= '</a:gs>';\n        $str .= '<a:gs pos=\"40000\">';\n        $str .= '<a:schemeClr val=\"phClr\">';\n        $str .= '<a:tint val=\"45000\" />';\n        $str .= '<a:shade val=\"99000\" />';\n        $str .= '<a:satMod val=\"350000\" />';\n        $str .= '</a:schemeClr>';\n        $str .= '</a:gs>';\n        $str .= '<a:gs pos=\"100000\">';\n        $str .= '<a:schemeClr val=\"phClr\">';\n        $str .= '<a:shade val=\"20000\" />';\n        $str .= '<a:satMod val=\"255000\" />';\n        $str .= '</a:schemeClr>';\n        $str .= '</a:gs>';\n        $str .= '</a:gsLst>';\n        $str .= '<a:path path=\"circle\">';\n        $str .= '<a:fillToRect l=\"50000\" t=\"-80000\" r=\"50000\" b=\"180000\" />';\n        $str .= '</a:path>';\n        $str .= '</a:gradFill>';\n        $str .= '<a:gradFill rotWithShape=\"1\">';\n        $str .= '<a:gsLst>';\n        $str .= '<a:gs pos=\"0\">';\n        $str .= '<a:schemeClr val=\"phClr\">';\n        $str .= '<a:tint val=\"80000\" />';\n        $str .= '<a:satMod val=\"300000\" />';\n        $str .= '</a:schemeClr>';\n        $str .= '</a:gs>';\n        $str .= '<a:gs pos=\"100000\">';\n        $str .= '<a:schemeClr val=\"phClr\">';\n        $str .= '<a:shade val=\"30000\" />';\n        $str .= '<a:satMod val=\"200000\" />';\n        $str .= '</a:schemeClr>';\n        $str .= '</a:gs>';\n        $str .= '</a:gsLst>';\n        $str .= '<a:path path=\"circle\">';\n        $str .= '<a:fillToRect l=\"50000\" t=\"50000\" r=\"50000\" b=\"50000\" />';\n        $str .= '</a:path>';\n        $str .= '</a:gradFill>';\n        $str .= '</a:bgFillStyleLst>';\n\n        return $str;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Part/WebSettings.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Part;\n\n/**\n * Word2007 web settings part writer: word/webSettings.xml.\n */\nclass WebSettings extends Settings\n{\n    /**\n     * Write part.\n     *\n     * @return string\n     */\n    public function write()\n    {\n        $settings = [\n            'w:optimizeForBrowser' => '',\n        ];\n\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startDocument('1.0', 'UTF-8', 'yes');\n        $xmlWriter->startElement('w:webSettings');\n        $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');\n        $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main');\n\n        foreach ($settings as $settingKey => $settingValue) {\n            $this->writeSetting($xmlWriter, $settingKey, $settingValue);\n        }\n\n        $xmlWriter->endElement(); // w:settings\n\n        return $xmlWriter->getData();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Style/AbstractStyle.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Style;\n\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\n\n/**\n * Style writer.\n *\n * @since 0.10.0\n */\nabstract class AbstractStyle\n{\n    /**\n     * XML writer.\n     *\n     * @var XMLWriter\n     */\n    private $xmlWriter;\n\n    /**\n     * Style; set protected for a while.\n     *\n     * @var \\PhpOffice\\PhpWord\\Style\\AbstractStyle|string\n     */\n    protected $style;\n\n    /**\n     * Write style.\n     */\n    abstract public function write();\n\n    /**\n     * Create new instance.\n     *\n     * @param \\PhpOffice\\PhpWord\\Style\\AbstractStyle|string $style\n     */\n    public function __construct(XMLWriter $xmlWriter, $style = null)\n    {\n        $this->xmlWriter = $xmlWriter;\n        $this->style = $style;\n    }\n\n    /**\n     * Get XML Writer.\n     *\n     * @return XMLWriter\n     */\n    protected function getXmlWriter()\n    {\n        return $this->xmlWriter;\n    }\n\n    /**\n     * Get Style.\n     *\n     * @return \\PhpOffice\\PhpWord\\Style\\AbstractStyle|string\n     */\n    protected function getStyle()\n    {\n        return $this->style;\n    }\n\n    /**\n     * Convert twip value.\n     *\n     * @param float|int $value\n     * @param int $default (int|float)\n     *\n     * @return float|int\n     */\n    protected function convertTwip($value, $default = 0)\n    {\n        $factors = [\n            Settings::UNIT_CM => 567,\n            Settings::UNIT_MM => 56.7,\n            Settings::UNIT_INCH => 1440,\n            Settings::UNIT_POINT => 20,\n            Settings::UNIT_PICA => 240,\n        ];\n        $unit = Settings::getMeasurementUnit();\n        $factor = 1;\n        if (array_key_exists($unit, $factors) && $value != $default) {\n            $factor = $factors[$unit];\n        }\n\n        return $value * $factor;\n    }\n\n    /**\n     * Write child style.\n     *\n     * @param string $name\n     * @param mixed $value\n     */\n    protected function writeChildStyle(XMLWriter $xmlWriter, $name, $value): void\n    {\n        if ($value !== null) {\n            $class = 'PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007\\\\Style\\\\' . $name;\n\n            /** @var AbstractStyle $writer */\n            $writer = new $class($xmlWriter, $value);\n            $writer->write();\n        }\n    }\n\n    /**\n     * Writes boolean as 0 or 1.\n     *\n     * @param bool $value\n     *\n     * @return null|string\n     */\n    protected function writeOnOf($value = null)\n    {\n        if ($value === null) {\n            return null;\n        }\n\n        return $value ? '1' : '0';\n    }\n\n    /**\n     * Assemble style array into style string.\n     *\n     * @param array $styles\n     *\n     * @return string\n     */\n    protected function assembleStyle($styles = [])\n    {\n        $style = '';\n        foreach ($styles as $key => $value) {\n            if (null !== $value && $value != '') {\n                $style .= \"{$key}:{$value}; \";\n            }\n        }\n\n        return trim($style);\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Style/Cell.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Style;\n\nuse PhpOffice\\PhpWord\\Style\\Cell as CellStyle;\n\n/**\n * Cell style writer.\n *\n * @since 0.10.0\n */\nclass Cell extends AbstractStyle\n{\n    /**\n     * @var int Cell width\n     */\n    private $width;\n\n    /**\n     * Write style.\n     */\n    public function write(): void\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof CellStyle) {\n            return;\n        }\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startElement('w:tcPr');\n\n        // Width\n        if (null !== $this->width || null !== $style->getWidth()) {\n            $width = null === $this->width ? $style->getWidth() : $this->width;\n\n            $xmlWriter->startElement('w:tcW');\n            $xmlWriter->writeAttribute('w:w', $width);\n            $xmlWriter->writeAttribute('w:type', $style->getUnit());\n            $xmlWriter->endElement(); // w:tcW\n        }\n\n        $paddingTop = $style->getPaddingTop();\n        $paddingLeft = $style->getPaddingLeft();\n        $paddingBottom = $style->getPaddingBottom();\n        $paddingRight = $style->getPaddingRight();\n\n        if ($paddingTop !== null || $paddingLeft !== null || $paddingBottom !== null || $paddingRight !== null) {\n            $xmlWriter->startElement('w:tcMar');\n            if ($paddingTop !== null) {\n                $xmlWriter->startElement('w:top');\n                $xmlWriter->writeAttribute('w:w', $paddingTop);\n                $xmlWriter->writeAttribute('w:type', \\PhpOffice\\PhpWord\\SimpleType\\TblWidth::TWIP);\n                $xmlWriter->endElement(); // w:top\n            }\n            if ($paddingLeft !== null) {\n                $xmlWriter->startElement('w:start');\n                $xmlWriter->writeAttribute('w:w', $paddingLeft);\n                $xmlWriter->writeAttribute('w:type', \\PhpOffice\\PhpWord\\SimpleType\\TblWidth::TWIP);\n                $xmlWriter->endElement(); // w:start\n            }\n            if ($paddingBottom !== null) {\n                $xmlWriter->startElement('w:bottom');\n                $xmlWriter->writeAttribute('w:w', $paddingBottom);\n                $xmlWriter->writeAttribute('w:type', \\PhpOffice\\PhpWord\\SimpleType\\TblWidth::TWIP);\n                $xmlWriter->endElement(); // w:bottom\n            }\n            if ($paddingRight !== null) {\n                $xmlWriter->startElement('w:end');\n                $xmlWriter->writeAttribute('w:w', $paddingRight);\n                $xmlWriter->writeAttribute('w:type', \\PhpOffice\\PhpWord\\SimpleType\\TblWidth::TWIP);\n                $xmlWriter->endElement(); // w:end\n            }\n            $xmlWriter->endElement(); // w:tcMar\n        }\n\n        // Text direction\n        $textDir = $style->getTextDirection();\n        $xmlWriter->writeElementIf(null !== $textDir, 'w:textDirection', 'w:val', $textDir);\n\n        // Vertical alignment\n        $vAlign = $style->getVAlign();\n        $xmlWriter->writeElementIf(null !== $vAlign, 'w:vAlign', 'w:val', $vAlign);\n\n        // Border\n        if ($style->hasBorder()) {\n            $xmlWriter->startElement('w:tcBorders');\n\n            $styleWriter = new MarginBorder($xmlWriter);\n            $styleWriter->setSizes($style->getBorderSize());\n            $styleWriter->setColors($style->getBorderColor());\n            $styleWriter->setStyles($style->getBorderStyle());\n            $styleWriter->setAttributes(['defaultColor' => CellStyle::DEFAULT_BORDER_COLOR]);\n            $styleWriter->write();\n\n            $xmlWriter->endElement();\n        }\n\n        // Shading\n        $shading = $style->getShading();\n        if (null !== $shading) {\n            $styleWriter = new Shading($xmlWriter, $shading);\n            $styleWriter->write();\n        }\n\n        // Colspan & rowspan\n        $gridSpan = $style->getGridSpan();\n        $vMerge = $style->getVMerge();\n        $xmlWriter->writeElementIf(null !== $gridSpan, 'w:gridSpan', 'w:val', $gridSpan);\n        $xmlWriter->writeElementIf(null !== $vMerge, 'w:vMerge', 'w:val', $vMerge);\n        $xmlWriter->writeElementIf($style->getNoWrap(), 'w:noWrap');\n\n        $xmlWriter->endElement(); // w:tcPr\n    }\n\n    /**\n     * Set width.\n     *\n     * @param int $value\n     */\n    public function setWidth($value = null): void\n    {\n        $this->width = $value;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Style/Extrusion.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Style;\n\n/**\n * 3D extrusion style writer.\n *\n * @since 0.12.0\n */\nclass Extrusion extends AbstractStyle\n{\n    /**\n     * Write style.\n     */\n    public function write(): void\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof \\PhpOffice\\PhpWord\\Style\\Extrusion) {\n            return;\n        }\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startElement('o:extrusion');\n        $xmlWriter->writeAttribute('on', 't');\n        $xmlWriter->writeAttributeIf($style->getType() !== null, 'type', $style->getType());\n        $xmlWriter->writeAttributeIf($style->getColor() !== null, 'color', $style->getColor());\n        $xmlWriter->endElement();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Style/Fill.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Style;\n\n/**\n * Fill style writer.\n *\n * @since 0.12.0\n */\nclass Fill extends AbstractStyle\n{\n    /**\n     * Write style.\n     */\n    public function write(): void\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof \\PhpOffice\\PhpWord\\Style\\Fill) {\n            return;\n        }\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->writeAttribute('on', 't');\n        $xmlWriter->writeAttributeIf($style->getColor() !== null, 'fillcolor', $style->getColor());\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Style/Font.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Style;\n\n/**\n * Font style writer.\n *\n * @since 0.10.0\n */\nclass Font extends AbstractStyle\n{\n    /**\n     * Is inline in element.\n     *\n     * @var bool\n     */\n    private $isInline = false;\n\n    /**\n     * Write style.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n\n        $isStyleName = $this->isInline && null !== $this->style && is_string($this->style);\n        if ($isStyleName) {\n            $xmlWriter->startElement('w:rPr');\n            $xmlWriter->startElement('w:rStyle');\n            $xmlWriter->writeAttribute('w:val', $this->style);\n            $xmlWriter->endElement();\n            $style = \\PhpOffice\\PhpWord\\Style::getStyle($this->style);\n            if ($style instanceof \\PhpOffice\\PhpWord\\Style\\Font) {\n                $xmlWriter->writeElementIf($style->isRTL(), 'w:rtl');\n            }\n            $xmlWriter->endElement();\n        } else {\n            $this->writeStyle();\n        }\n    }\n\n    /**\n     * Write full style.\n     */\n    private function writeStyle(): void\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof \\PhpOffice\\PhpWord\\Style\\Font) {\n            return;\n        }\n\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startElement('w:rPr');\n\n        // Style name\n        if ($this->isInline === true) {\n            $styleName = $style->getStyleName();\n            $xmlWriter->writeElementIf($styleName !== null, 'w:rStyle', 'w:val', $styleName);\n        }\n\n        // Font name/family\n        $font = $style->getName();\n        $hint = $style->getHint();\n        if ($font !== null) {\n            $xmlWriter->startElement('w:rFonts');\n            $xmlWriter->writeAttribute('w:ascii', $font);\n            $xmlWriter->writeAttribute('w:hAnsi', $font);\n            $xmlWriter->writeAttribute('w:eastAsia', $font);\n            $xmlWriter->writeAttribute('w:cs', $font);\n            $xmlWriter->writeAttributeIf($hint !== null, 'w:hint', $hint);\n            $xmlWriter->endElement();\n        }\n\n        //Language\n        $language = $style->getLang();\n        if ($language != null && ($language->getLatin() !== null || $language->getEastAsia() !== null || $language->getBidirectional() !== null)) {\n            $xmlWriter->startElement('w:lang');\n            $xmlWriter->writeAttributeIf($language->getLatin() !== null, 'w:val', $language->getLatin());\n            $xmlWriter->writeAttributeIf($language->getEastAsia() !== null, 'w:eastAsia', $language->getEastAsia());\n            $xmlWriter->writeAttributeIf($language->getBidirectional() !== null, 'w:bidi', $language->getBidirectional());\n            //if bidi is not set but we are writing RTL, write the latin language in the bidi tag\n            if ($style->isRTL() && $language->getBidirectional() === null && $language->getLatin() !== null) {\n                $xmlWriter->writeAttribute('w:bidi', $language->getLatin());\n            }\n            $xmlWriter->endElement();\n        }\n\n        // Color\n        $color = $style->getColor();\n        $xmlWriter->writeElementIf($color !== null, 'w:color', 'w:val', $color);\n\n        // Size\n        $size = $style->getSize();\n        $xmlWriter->writeElementIf($size !== null, 'w:sz', 'w:val', $size * 2);\n        $xmlWriter->writeElementIf($size !== null, 'w:szCs', 'w:val', $size * 2);\n\n        // Bold, italic\n        $xmlWriter->writeElementIf($style->isBold() !== null, 'w:b', 'w:val', $this->writeOnOf($style->isBold()));\n        $xmlWriter->writeElementIf($style->isBold() !== null, 'w:bCs', 'w:val', $this->writeOnOf($style->isBold()));\n        $xmlWriter->writeElementIf($style->isItalic() !== null, 'w:i', 'w:val', $this->writeOnOf($style->isItalic()));\n        $xmlWriter->writeElementIf($style->isItalic() !== null, 'w:iCs', 'w:val', $this->writeOnOf($style->isItalic()));\n\n        // Strikethrough, double strikethrough\n        $xmlWriter->writeElementIf($style->isStrikethrough(), 'w:strike', 'w:val', $this->writeOnOf($style->isStrikethrough()));\n        $xmlWriter->writeElementIf($style->isDoubleStrikethrough(), 'w:dstrike', 'w:val', $this->writeOnOf($style->isDoubleStrikethrough()));\n\n        // Small caps, all caps\n        $xmlWriter->writeElementIf($style->isSmallCaps() !== null, 'w:smallCaps', 'w:val', $this->writeOnOf($style->isSmallCaps()));\n        $xmlWriter->writeElementIf($style->isAllCaps() !== null, 'w:caps', 'w:val', $this->writeOnOf($style->isAllCaps()));\n\n        //Hidden text\n        $xmlWriter->writeElementIf($style->isHidden(), 'w:vanish', 'w:val', $this->writeOnOf($style->isHidden()));\n\n        // Underline\n        $xmlWriter->writeElementIf($style->getUnderline() != 'none', 'w:u', 'w:val', $style->getUnderline());\n\n        // Foreground-Color\n        $xmlWriter->writeElementIf($style->getFgColor() !== null, 'w:highlight', 'w:val', $style->getFgColor());\n\n        // Superscript/subscript\n        $xmlWriter->writeElementIf($style->isSuperScript(), 'w:vertAlign', 'w:val', 'superscript');\n        $xmlWriter->writeElementIf($style->isSubScript(), 'w:vertAlign', 'w:val', 'subscript');\n\n        // Spacing\n        $xmlWriter->writeElementIf($style->getScale() !== null, 'w:w', 'w:val', $style->getScale());\n        $xmlWriter->writeElementIf($style->getSpacing() !== null, 'w:spacing', 'w:val', $style->getSpacing());\n        $xmlWriter->writeElementIf($style->getKerning() !== null, 'w:kern', 'w:val', $style->getKerning() * 2);\n\n        // noProof\n        $xmlWriter->writeElementIf($style->isNoProof() !== null, 'w:noProof', 'w:val', $this->writeOnOf($style->isNoProof()));\n\n        // Background-Color\n        $shading = $style->getShading();\n        if (null !== $shading) {\n            $styleWriter = new Shading($xmlWriter, $shading);\n            $styleWriter->write();\n        }\n\n        // RTL\n        if ($this->isInline === true) {\n            $styleName = $style->getStyleName();\n            $xmlWriter->writeElementIf($styleName === null && $style->isRTL(), 'w:rtl');\n        }\n\n        // Position\n        $xmlWriter->writeElementIf($style->getPosition() !== null, 'w:position', 'w:val', $style->getPosition());\n\n        $xmlWriter->endElement();\n    }\n\n    /**\n     * Set is inline.\n     *\n     * @param bool $value\n     */\n    public function setIsInline($value): void\n    {\n        $this->isInline = $value;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Style/Frame.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Style;\n\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\nuse PhpOffice\\PhpWord\\Style\\Frame as FrameStyle;\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\ParagraphAlignment;\n\n/**\n * Frame style writer.\n *\n * @since 0.12.0\n */\nclass Frame extends AbstractStyle\n{\n    const PHP_32BIT_INT_MAX = 2147483647;\n\n    /**\n     * Write style.\n     */\n    public function write(): void\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof FrameStyle) {\n            return;\n        }\n        $xmlWriter = $this->getXmlWriter();\n\n        $maxZIndex = min(PHP_INT_MAX, self::PHP_32BIT_INT_MAX);\n        $zIndices = [FrameStyle::WRAP_INFRONT => $maxZIndex, FrameStyle::WRAP_BEHIND => -$maxZIndex];\n\n        $properties = [\n            'width' => 'width',\n            'height' => 'height',\n            'left' => 'margin-left',\n            'top' => 'margin-top',\n            'wrapDistanceTop' => 'mso-wrap-distance-top',\n            'wrapDistanceBottom' => 'mso-wrap-distance-bottom',\n            'wrapDistanceLeft' => 'mso-wrap-distance-left',\n            'wrapDistanceRight' => 'mso-wrap-distance-right',\n        ];\n        $sizeStyles = $this->getStyles($style, $properties, $style->getUnit());\n\n        $properties = [\n            'pos' => 'position',\n            'hPos' => 'mso-position-horizontal',\n            'vPos' => 'mso-position-vertical',\n            'hPosRelTo' => 'mso-position-horizontal-relative',\n            'vPosRelTo' => 'mso-position-vertical-relative',\n        ];\n        $posStyles = $this->getStyles($style, $properties);\n\n        $styles = array_merge($sizeStyles, $posStyles);\n\n        // zIndex for infront & behind wrap\n        $wrap = $style->getWrap();\n        if ($wrap !== null && isset($zIndices[$wrap])) {\n            $styles['z-index'] = $zIndices[$wrap];\n            $wrap = null;\n        }\n\n        // Style attribute\n        $xmlWriter->writeAttribute('style', $this->assembleStyle($styles));\n\n        $this->writeWrap($xmlWriter, $style, $wrap);\n    }\n\n    /**\n     * Write alignment.\n     */\n    public function writeAlignment(): void\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof FrameStyle) {\n            return;\n        }\n\n        $xmlWriter = $this->getXmlWriter();\n        $xmlWriter->startElement('w:pPr');\n\n        if ('' !== $style->getAlignment()) {\n            $paragraphAlignment = new ParagraphAlignment($style->getAlignment());\n            $xmlWriter->startElement($paragraphAlignment->getName());\n            foreach ($paragraphAlignment->getAttributes() as $attributeName => $attributeValue) {\n                $xmlWriter->writeAttribute($attributeName, $attributeValue);\n            }\n            $xmlWriter->endElement();\n        }\n\n        $xmlWriter->endElement();\n    }\n\n    /**\n     * Write wrap.\n     *\n     * @param string $wrap\n     */\n    private function writeWrap(XMLWriter $xmlWriter, FrameStyle $style, $wrap): void\n    {\n        if ($wrap !== null) {\n            $xmlWriter->startElement('w10:wrap');\n            $xmlWriter->writeAttribute('type', $wrap);\n\n            $relativePositions = [\n                FrameStyle::POS_RELTO_MARGIN => 'margin',\n                FrameStyle::POS_RELTO_PAGE => 'page',\n                FrameStyle::POS_RELTO_TMARGIN => 'margin',\n                FrameStyle::POS_RELTO_BMARGIN => 'page',\n                FrameStyle::POS_RELTO_LMARGIN => 'margin',\n                FrameStyle::POS_RELTO_RMARGIN => 'page',\n            ];\n            $pos = $style->getPos();\n            $hPos = $style->getHPosRelTo();\n            $vPos = $style->getVPosRelTo();\n\n            if ($pos == FrameStyle::POS_ABSOLUTE) {\n                $xmlWriter->writeAttribute('anchorx', 'page');\n                $xmlWriter->writeAttribute('anchory', 'page');\n            } elseif ($pos == FrameStyle::POS_RELATIVE) {\n                if (isset($relativePositions[$hPos])) {\n                    $xmlWriter->writeAttribute('anchorx', $relativePositions[$hPos]);\n                }\n                if (isset($relativePositions[$vPos])) {\n                    $xmlWriter->writeAttribute('anchory', $relativePositions[$vPos]);\n                }\n            }\n\n            $xmlWriter->endElement(); // w10:wrap\n        }\n    }\n\n    /**\n     * Get style values in associative array.\n     *\n     * @param array $properties\n     * @param string $suffix\n     *\n     * @return array\n     */\n    private function getStyles(FrameStyle $style, $properties, $suffix = '')\n    {\n        $styles = [];\n\n        foreach ($properties as $key => $property) {\n            $method = \"get{$key}\";\n            $value = $style->$method();\n            if ($value !== null) {\n                $styles[$property] = $style->$method() . $suffix;\n            }\n        }\n\n        return $styles;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Style/Image.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Style;\n\n/**\n * Image style writer.\n *\n * @since 0.10.0\n */\nclass Image extends Frame\n{\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Style/Indentation.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Style;\n\n/**\n * Paragraph indentation style writer.\n *\n * @since 0.10.0\n */\nclass Indentation extends AbstractStyle\n{\n    /**\n     * Write style.\n     */\n    public function write(): void\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof \\PhpOffice\\PhpWord\\Style\\Indentation) {\n            return;\n        }\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startElement('w:ind');\n\n        $xmlWriter->writeAttribute('w:left', $this->convertTwip($style->getLeft()));\n        $xmlWriter->writeAttribute('w:right', $this->convertTwip($style->getRight()));\n\n        $firstLine = $style->getFirstLine();\n        $xmlWriter->writeAttributeIf(null !== $firstLine, 'w:firstLine', $this->convertTwip($firstLine));\n\n        $firstLineChars = $style->getFirstLineChars();\n        $xmlWriter->writeAttributeIf(0 !== $firstLineChars, 'w:firstLineChars', $this->convertTwip($firstLineChars));\n\n        $hanging = $style->getHanging();\n        $xmlWriter->writeAttributeIf(null !== $hanging, 'w:hanging', $this->convertTwip($hanging));\n\n        $xmlWriter->endElement();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Style/Line.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Style;\n\nuse PhpOffice\\PhpWord\\Style\\Line as LineStyle;\n\n/**\n * Line style writer.\n */\nclass Line extends Frame\n{\n    /**\n     * Write Line stroke.\n     *\n     * @todo Merge with `Stroke` style\n     */\n    public function writeStroke(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n        $style = $this->getStyle();\n        if (!$style instanceof LineStyle) {\n            return;\n        }\n\n        $dash = $style->getDash();\n        $dashStyles = [\n            LineStyle::DASH_STYLE_DASH => 'dash',\n            LineStyle::DASH_STYLE_ROUND_DOT => '1 1',\n            LineStyle::DASH_STYLE_SQUARE_DOT => '1 1',\n            LineStyle::DASH_STYLE_DASH_DOT => 'dashDot',\n            LineStyle::DASH_STYLE_LONG_DASH => 'longDash',\n            LineStyle::DASH_STYLE_LONG_DASH_DOT => 'longDashDot',\n            LineStyle::DASH_STYLE_LONG_DASH_DOT_DOT => 'longDashDotDot',\n        ];\n\n        $xmlWriter->startElement('v:stroke');\n\n        $xmlWriter->writeAttributeIf($style->getWeight() !== null, 'weight', $style->getWeight() . 'pt');\n        $xmlWriter->writeAttributeIf($style->getColor() !== null, 'color', $style->getColor());\n        $xmlWriter->writeAttributeIf($style->getBeginArrow() !== null, 'startarrow', $style->getBeginArrow());\n        $xmlWriter->writeAttributeIf($style->getEndArrow() !== null, 'endarrow', $style->getEndArrow());\n\n        if ($dash !== null) {\n            if (isset($dashStyles[$dash])) {\n                $xmlWriter->writeAttribute('dashstyle', $dashStyles[$dash]);\n            }\n            if ($dash == LineStyle::DASH_STYLE_ROUND_DOT) {\n                $xmlWriter->writeAttribute('endcap', 'round');\n            }\n        }\n\n        $xmlWriter->endElement(); //v:stroke\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Style/LineNumbering.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Style;\n\n/**\n * Line numbering style writer.\n *\n * @since 0.10.0\n */\nclass LineNumbering extends AbstractStyle\n{\n    /**\n     * Write style.\n     * The w:start seems to be zero based so we have to decrement by one.\n     */\n    public function write(): void\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof \\PhpOffice\\PhpWord\\Style\\LineNumbering) {\n            return;\n        }\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startElement('w:lnNumType');\n        $xmlWriter->writeAttribute('w:start', $style->getStart() - 1);\n        $xmlWriter->writeAttribute('w:countBy', $style->getIncrement());\n        $xmlWriter->writeAttribute('w:distance', $style->getDistance());\n        $xmlWriter->writeAttribute('w:restart', $style->getRestart());\n        $xmlWriter->endElement();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Style/MarginBorder.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Style;\n\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\n\n/**\n * Margin border style writer.\n *\n * @since 0.10.0\n */\nclass MarginBorder extends AbstractStyle\n{\n    /**\n     * Sizes.\n     *\n     * @var int[]\n     */\n    private $sizes = [];\n\n    /**\n     * Colors.\n     *\n     * @var string[]\n     */\n    private $colors = [];\n\n    /**\n     * Border styles.\n     *\n     * @var string[]\n     */\n    private $styles = [];\n\n    /**\n     * Other attributes.\n     *\n     * @var array\n     */\n    private $attributes = [];\n\n    /**\n     * Write style.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n\n        $sides = ['top', 'left', 'right', 'bottom', 'insideH', 'insideV'];\n\n        foreach ($this->sizes as $i => $size) {\n            if ($size !== null) {\n                $color = null;\n                if (isset($this->colors[$i])) {\n                    $color = $this->colors[$i];\n                }\n                $style = $this->styles[$i] ?? 'single';\n                $this->writeSide($xmlWriter, $sides[$i], $this->sizes[$i], $color, $style);\n            }\n        }\n    }\n\n    /**\n     * Write side.\n     *\n     * @param string $side\n     * @param int $width\n     * @param string $color\n     * @param string $borderStyle\n     */\n    private function writeSide(XMLWriter $xmlWriter, $side, $width, $color = null, $borderStyle = 'solid'): void\n    {\n        $xmlWriter->startElement('w:' . $side);\n        if (!empty($this->colors)) {\n            if ($color === null && !empty($this->attributes)) {\n                if (isset($this->attributes['defaultColor'])) {\n                    $color = $this->attributes['defaultColor'];\n                }\n            }\n            $xmlWriter->writeAttribute('w:val', $borderStyle);\n            $xmlWriter->writeAttribute('w:sz', $width);\n            $xmlWriter->writeAttributeIf($color != null, 'w:color', $color);\n            if (!empty($this->attributes)) {\n                if (isset($this->attributes['space'])) {\n                    $xmlWriter->writeAttribute('w:space', $this->attributes['space']);\n                }\n            }\n        } else {\n            $xmlWriter->writeAttribute('w:w', $width);\n            $xmlWriter->writeAttribute('w:type', 'dxa');\n        }\n        $xmlWriter->endElement();\n    }\n\n    /**\n     * Set sizes.\n     *\n     * @param int[] $value\n     */\n    public function setSizes($value): void\n    {\n        $this->sizes = $value;\n    }\n\n    /**\n     * Set colors.\n     *\n     * @param array<null|string> $value\n     */\n    public function setColors($value): void\n    {\n        $this->colors = $value;\n    }\n\n    /**\n     * Set border styles.\n     *\n     * @param string[] $value\n     */\n    public function setStyles($value): void\n    {\n        $this->styles = $value;\n    }\n\n    /**\n     * Set attributes.\n     *\n     * @param array $value\n     */\n    public function setAttributes($value): void\n    {\n        $this->attributes = $value;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Style/Outline.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Style;\n\n/**\n * Outline style writer.\n *\n * @since 0.12.0\n */\nclass Outline extends AbstractStyle\n{\n    /**\n     * Write style.\n     */\n    public function write(): void\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof \\PhpOffice\\PhpWord\\Style\\Outline) {\n            return;\n        }\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startElement('v:stroke');\n        $xmlWriter->writeAttribute('on', 't');\n        $xmlWriter->writeAttributeIf($style->getColor() !== null, 'color', $style->getColor());\n        $xmlWriter->writeAttributeIf($style->getWeight() !== null, 'weight', $style->getWeight() . $style->getUnit());\n        $xmlWriter->writeAttributeIf($style->getDash() !== null, 'dashstyle', $style->getDash());\n        $xmlWriter->writeAttributeIf($style->getLine() !== null, 'linestyle', $style->getLine());\n        $xmlWriter->writeAttributeIf($style->getEndCap() !== null, 'endcap', $style->getEndCap());\n        $xmlWriter->writeAttributeIf($style->getStartArrow() !== null, 'startarrow', $style->getStartArrow());\n        $xmlWriter->writeAttributeIf($style->getEndArrow() !== null, 'endarrow', $style->getEndArrow());\n        $xmlWriter->endElement();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Style/Paragraph.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Style;\n\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\nuse PhpOffice\\PhpWord\\Style;\nuse PhpOffice\\PhpWord\\Style\\Paragraph as ParagraphStyle;\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\ParagraphAlignment;\n\n/**\n * Paragraph style writer.\n *\n * @since 0.10.0\n */\nclass Paragraph extends AbstractStyle\n{\n    /**\n     * Without w:pPr.\n     *\n     * @var bool\n     */\n    private $withoutPPR = false;\n\n    /**\n     * Is inline in element.\n     *\n     * @var bool\n     */\n    private $isInline = false;\n\n    /**\n     * Write style.\n     */\n    public function write(): void\n    {\n        $xmlWriter = $this->getXmlWriter();\n\n        $isStyleName = $this->isInline && null !== $this->style && is_string($this->style);\n        if ($isStyleName) {\n            if (!$this->withoutPPR) {\n                $xmlWriter->startElement('w:pPr');\n            }\n            $xmlWriter->startElement('w:pStyle');\n            $xmlWriter->writeAttribute('w:val', $this->style);\n            $xmlWriter->endElement();\n            if (!$this->withoutPPR) {\n                $xmlWriter->endElement();\n            }\n        } else {\n            $this->writeStyle();\n        }\n    }\n\n    /**\n     * Write full style.\n     */\n    private function writeStyle(): void\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof ParagraphStyle) {\n            return;\n        }\n        $xmlWriter = $this->getXmlWriter();\n        $styles = $style->getStyleValues();\n\n        if (!$this->withoutPPR) {\n            $xmlWriter->startElement('w:pPr');\n        }\n\n        // Style name\n        if ($this->isInline === true) {\n            $xmlWriter->writeElementIf($styles['name'] !== null, 'w:pStyle', 'w:val', $styles['name']);\n        }\n\n        // Pagination\n        $xmlWriter->writeElementIf($styles['pagination']['widowControl'] === false, 'w:widowControl', 'w:val', '0');\n        $xmlWriter->writeElementIf($styles['pagination']['keepNext'] === true, 'w:keepNext', 'w:val', '1');\n        $xmlWriter->writeElementIf($styles['pagination']['keepLines'] === true, 'w:keepLines', 'w:val', '1');\n        $xmlWriter->writeElementIf($styles['pagination']['pageBreak'] === true, 'w:pageBreakBefore', 'w:val', '1');\n\n        // Paragraph alignment\n        if ('' !== $styles['alignment']) {\n            $paragraphAlignment = new ParagraphAlignment($styles['alignment']);\n            $xmlWriter->startElement($paragraphAlignment->getName());\n            foreach ($paragraphAlignment->getAttributes() as $attributeName => $attributeValue) {\n                $xmlWriter->writeAttribute($attributeName, $attributeValue);\n            }\n            $xmlWriter->endElement();\n        }\n\n        //Right to left\n        $xmlWriter->writeElementIf($styles['bidi'] === true, 'w:bidi');\n\n        //Paragraph contextualSpacing\n        $xmlWriter->writeElementIf($styles['contextualSpacing'] === true, 'w:contextualSpacing');\n\n        //Paragraph textAlignment\n        $xmlWriter->writeElementIf($styles['textAlignment'] !== null, 'w:textAlignment', 'w:val', $styles['textAlignment']);\n\n        // Hyphenation\n        $xmlWriter->writeElementIf($styles['suppressAutoHyphens'] === true, 'w:suppressAutoHyphens');\n\n        // Child style: alignment, indentation, spacing, and shading\n        $this->writeChildStyle($xmlWriter, 'Indentation', $styles['indentation']);\n        $this->writeChildStyle($xmlWriter, 'Spacing', $styles['spacing']);\n        $this->writeChildStyle($xmlWriter, 'Shading', $styles['shading']);\n\n        // Tabs\n        $this->writeTabs($xmlWriter, $styles['tabs']);\n\n        // Numbering\n        $this->writeNumbering($xmlWriter, $styles['numbering']);\n\n        // Border\n        if ($style->hasBorder()) {\n            $xmlWriter->startElement('w:pBdr');\n\n            $styleWriter = new MarginBorder($xmlWriter);\n            $styleWriter->setSizes($style->getBorderSize());\n            $styleWriter->setStyles($style->getBorderStyle());\n            $styleWriter->setColors($style->getBorderColor());\n            $styleWriter->write();\n\n            $xmlWriter->endElement();\n        }\n\n        if (!$this->withoutPPR) {\n            $xmlWriter->endElement(); // w:pPr\n        }\n    }\n\n    /**\n     * Write tabs.\n     *\n     * @param Style\\Tab[] $tabs\n     */\n    private function writeTabs(XMLWriter $xmlWriter, $tabs): void\n    {\n        if (!empty($tabs)) {\n            $xmlWriter->startElement('w:tabs');\n            foreach ($tabs as $tab) {\n                $styleWriter = new Tab($xmlWriter, $tab);\n                $styleWriter->write();\n            }\n            $xmlWriter->endElement();\n        }\n    }\n\n    /**\n     * Write numbering.\n     *\n     * @param array $numbering\n     */\n    private function writeNumbering(XMLWriter $xmlWriter, $numbering): void\n    {\n        $numStyle = $numbering['style'];\n        $numLevel = $numbering['level'];\n\n        /** @var Style\\Numbering $numbering */\n        $numbering = Style::getStyle($numStyle);\n        if ($numStyle !== null && $numbering !== null) {\n            $xmlWriter->startElement('w:numPr');\n            $xmlWriter->startElement('w:numId');\n            $xmlWriter->writeAttribute('w:val', $numbering->getIndex());\n            $xmlWriter->endElement(); // w:numId\n            $xmlWriter->startElement('w:ilvl');\n            $xmlWriter->writeAttribute('w:val', $numLevel);\n            $xmlWriter->endElement(); // w:ilvl\n            $xmlWriter->endElement(); // w:numPr\n\n            $xmlWriter->startElement('w:outlineLvl');\n            $xmlWriter->writeAttribute('w:val', $numLevel);\n            $xmlWriter->endElement(); // w:outlineLvl\n        }\n    }\n\n    /**\n     * Set without w:pPr.\n     *\n     * @param bool $value\n     */\n    public function setWithoutPPR($value): void\n    {\n        $this->withoutPPR = $value;\n    }\n\n    /**\n     * Set is inline.\n     *\n     * @param bool $value\n     */\n    public function setIsInline($value): void\n    {\n        $this->isInline = $value;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Style/Row.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Style;\n\n/**\n * Row style writer.\n *\n * @since 0.11.0\n */\nclass Row extends AbstractStyle\n{\n    /**\n     * @var int Row height\n     */\n    private $height;\n\n    /**\n     * Write style.\n     */\n    public function write(): void\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof \\PhpOffice\\PhpWord\\Style\\Row) {\n            return;\n        }\n\n        $xmlWriter = $this->getXmlWriter();\n        $xmlWriter->startElement('w:trPr');\n\n        if ($this->height !== null) {\n            $xmlWriter->startElement('w:trHeight');\n            $xmlWriter->writeAttribute('w:val', $this->height);\n            $xmlWriter->writeAttribute('w:hRule', ($style->isExactHeight() ? 'exact' : 'atLeast'));\n            $xmlWriter->endElement();\n        }\n        $xmlWriter->writeElementIf($style->isTblHeader(), 'w:tblHeader', 'w:val', '1');\n        $xmlWriter->writeElementIf($style->isCantSplit(), 'w:cantSplit', 'w:val', '1');\n\n        $xmlWriter->endElement(); // w:trPr\n    }\n\n    /**\n     * Set height.\n     *\n     * @param int $value\n     */\n    public function setHeight($value = null): void\n    {\n        $this->height = $value;\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Style/Section.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Style;\n\nuse PhpOffice\\PhpWord\\Style\\Section as SectionStyle;\n\n/**\n * Section style writer.\n *\n * @since 0.10.0\n */\nclass Section extends AbstractStyle\n{\n    /**\n     * Write style.\n     */\n    public function write(): void\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof SectionStyle) {\n            return;\n        }\n        $xmlWriter = $this->getXmlWriter();\n\n        // Break type\n        $breakType = $style->getBreakType();\n        $xmlWriter->writeElementIf(null !== $breakType, 'w:type', 'w:val', $breakType);\n\n        // Page size & orientation\n        $xmlWriter->startElement('w:pgSz');\n        $xmlWriter->writeAttribute('w:orient', $style->getOrientation());\n        $xmlWriter->writeAttribute('w:w', $style->getPageSizeW());\n        $xmlWriter->writeAttribute('w:h', $style->getPageSizeH());\n        $xmlWriter->endElement(); // w:pgSz\n\n        // Vertical alignment\n        $vAlign = $style->getVAlign();\n        $xmlWriter->writeElementIf(null !== $vAlign, 'w:vAlign', 'w:val', $vAlign);\n\n        // Margins\n        $margins = [\n            'w:top' => ['getMarginTop', SectionStyle::DEFAULT_MARGIN],\n            'w:right' => ['getMarginRight', SectionStyle::DEFAULT_MARGIN],\n            'w:bottom' => ['getMarginBottom', SectionStyle::DEFAULT_MARGIN],\n            'w:left' => ['getMarginLeft', SectionStyle::DEFAULT_MARGIN],\n            'w:header' => ['getHeaderHeight', SectionStyle::DEFAULT_HEADER_HEIGHT],\n            'w:footer' => ['getFooterHeight', SectionStyle::DEFAULT_FOOTER_HEIGHT],\n            'w:gutter' => ['getGutter', SectionStyle::DEFAULT_GUTTER],\n        ];\n        $xmlWriter->startElement('w:pgMar');\n        foreach ($margins as $attribute => $value) {\n            [$method, $default] = $value;\n            $xmlWriter->writeAttribute($attribute, $this->convertTwip($style->$method(), $default));\n        }\n        $xmlWriter->endElement();\n\n        // Borders\n        if ($style->hasBorder()) {\n            $xmlWriter->startElement('w:pgBorders');\n            $xmlWriter->writeAttribute('w:offsetFrom', 'page');\n\n            $styleWriter = new MarginBorder($xmlWriter);\n            $styleWriter->setSizes($style->getBorderSize());\n            $styleWriter->setColors($style->getBorderColor());\n            $styleWriter->setAttributes(['space' => '24']);\n            $styleWriter->write();\n\n            $xmlWriter->endElement();\n        }\n\n        // Columns\n        $colsSpace = $style->getColsSpace();\n        $xmlWriter->startElement('w:cols');\n        $xmlWriter->writeAttribute('w:num', $style->getColsNum());\n        $xmlWriter->writeAttribute('w:space', $this->convertTwip($colsSpace, SectionStyle::DEFAULT_COLUMN_SPACING));\n        $xmlWriter->endElement();\n\n        // Page numbering start\n        $pageNum = $style->getPageNumberingStart();\n        $xmlWriter->writeElementIf(null !== $pageNum, 'w:pgNumType', 'w:start', $pageNum);\n\n        // Line numbering\n        $styleWriter = new LineNumbering($xmlWriter, $style->getLineNumbering());\n        $styleWriter->write();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Style/Shading.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Style;\n\n/**\n * Shading style writer.\n *\n * @since 0.10.0\n */\nclass Shading extends AbstractStyle\n{\n    /**\n     * Write style.\n     */\n    public function write(): void\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof \\PhpOffice\\PhpWord\\Style\\Shading) {\n            return;\n        }\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startElement('w:shd');\n        $xmlWriter->writeAttributeIf(null !== $style->getPattern(), 'w:val', $style->getPattern());\n        $xmlWriter->writeAttributeIf(null !== $style->getColor(), 'w:color', $style->getColor());\n        $xmlWriter->writeAttributeIf(null !== $style->getFill(), 'w:fill', $style->getFill());\n        $xmlWriter->endElement();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Style/Shadow.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Style;\n\n/**\n * Shadow style writer.\n *\n * @since 0.12.0\n */\nclass Shadow extends AbstractStyle\n{\n    /**\n     * Write style.\n     */\n    public function write(): void\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof \\PhpOffice\\PhpWord\\Style\\Shadow) {\n            return;\n        }\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startElement('v:shadow');\n        $xmlWriter->writeAttribute('on', 't');\n        $xmlWriter->writeAttributeIf($style->getColor() !== null, 'color', $style->getColor());\n        $xmlWriter->writeAttributeIf($style->getOffset() !== null, 'offset', $style->getOffset());\n        $xmlWriter->endElement();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Style/Shape.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Style;\n\n/**\n * Shape style writer.\n *\n * @since 0.12.0\n */\nclass Shape extends AbstractStyle\n{\n    /**\n     * Write style.\n     */\n    public function write(): void\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof \\PhpOffice\\PhpWord\\Style\\Shape) {\n            return;\n        }\n\n        $xmlWriter = $this->getXmlWriter();\n\n        $childStyles = ['Frame', 'Fill', 'Outline', 'Shadow', 'Extrusion'];\n        foreach ($childStyles as $childStyle) {\n            $method = \"get{$childStyle}\";\n            $this->writeChildStyle($xmlWriter, $childStyle, $style->$method());\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Style/Spacing.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Style;\n\n/**\n * Spacing between lines and above/below paragraph style writer.\n *\n * @since 0.10.0\n */\nclass Spacing extends AbstractStyle\n{\n    /**\n     * Write style.\n     */\n    public function write(): void\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof \\PhpOffice\\PhpWord\\Style\\Spacing) {\n            return;\n        }\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startElement('w:spacing');\n\n        $before = $style->getBefore();\n        $xmlWriter->writeAttributeIf(null !== $before, 'w:before', $this->convertTwip($before));\n\n        $after = $style->getAfter();\n        $xmlWriter->writeAttributeIf(null !== $after, 'w:after', $this->convertTwip($after));\n\n        $line = $style->getLine();\n        //if linerule is auto, the spacing is supposed to include the height of the line itself, which is 240 twips\n        if (null !== $line && 'auto' === $style->getLineRule()) {\n            $line += \\PhpOffice\\PhpWord\\Style\\Paragraph::LINE_HEIGHT;\n        }\n        $xmlWriter->writeAttributeIf(null !== $line, 'w:line', $line);\n\n        $xmlWriter->writeAttributeIf(null !== $line, 'w:lineRule', $style->getLineRule());\n\n        $xmlWriter->endElement();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Style/Tab.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Style;\n\n/**\n * Line numbering style writer.\n *\n * @since 0.10.0\n */\nclass Tab extends AbstractStyle\n{\n    /**\n     * Write style.\n     */\n    public function write(): void\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof \\PhpOffice\\PhpWord\\Style\\Tab) {\n            return;\n        }\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startElement('w:tab');\n        $xmlWriter->writeAttribute('w:val', $style->getType());\n        $xmlWriter->writeAttribute('w:leader', $style->getLeader());\n        $xmlWriter->writeAttribute('w:pos', $this->convertTwip($style->getPosition()));\n        $xmlWriter->endElement();\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Style/Table.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Style;\n\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\nuse PhpOffice\\PhpWord\\SimpleType\\TblWidth;\nuse PhpOffice\\PhpWord\\Style\\Table as TableStyle;\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\TableAlignment;\n\n/**\n * Table style writer.\n *\n * @since 0.10.0\n */\nclass Table extends AbstractStyle\n{\n    /**\n     * @var int Table width\n     */\n    private $width;\n\n    /**\n     * Write style.\n     */\n    public function write(): void\n    {\n        $style = $this->getStyle();\n        $xmlWriter = $this->getXmlWriter();\n\n        if ($style instanceof TableStyle) {\n            $this->writeStyle($xmlWriter, $style);\n        } elseif (is_string($style)) {\n            $xmlWriter->startElement('w:tblPr');\n            $xmlWriter->startElement('w:tblStyle');\n            $xmlWriter->writeAttribute('w:val', $style);\n            $xmlWriter->endElement();\n            if (null !== $this->width) {\n                $this->writeTblWidth($xmlWriter, 'w:tblW', TblWidth::PERCENT, $this->width);\n            }\n            $xmlWriter->endElement();\n        }\n    }\n\n    /**\n     * Write full style.\n     */\n    private function writeStyle(XMLWriter $xmlWriter, TableStyle $style): void\n    {\n        // w:tblPr\n        $xmlWriter->startElement('w:tblPr');\n\n        // Table alignment\n        if ('' !== $style->getAlignment()) {\n            $tableAlignment = new TableAlignment($style->getAlignment());\n            $xmlWriter->startElement($tableAlignment->getName());\n            foreach ($tableAlignment->getAttributes() as $attributeName => $attributeValue) {\n                $xmlWriter->writeAttribute($attributeName, $attributeValue);\n            }\n            $xmlWriter->endElement();\n        }\n\n        $this->writeTblWidth($xmlWriter, 'w:tblW', $style->getUnit(), $style->getWidth());\n        $this->writeTblWidth($xmlWriter, 'w:tblCellSpacing', TblWidth::TWIP, $style->getCellSpacing());\n        $this->writeIndent($xmlWriter, $style);\n        $this->writeLayout($xmlWriter, $style->getLayout());\n\n        // Position\n        $styleWriter = new TablePosition($xmlWriter, $style->getPosition());\n        $styleWriter->write();\n\n        //Right to left\n        $xmlWriter->writeElementIf($style->isBidiVisual() !== null, 'w:bidiVisual', 'w:val', $this->writeOnOf($style->isBidiVisual()));\n\n        $this->writeMargin($xmlWriter, $style);\n        $this->writeBorder($xmlWriter, $style);\n\n        $xmlWriter->endElement(); // w:tblPr\n\n        $this->writeShading($xmlWriter, $style);\n\n        // First row style\n        $firstRow = $style->getFirstRow();\n        if ($firstRow instanceof TableStyle) {\n            $this->writeFirstRow($xmlWriter, $firstRow);\n        }\n    }\n\n    /**\n     * Enable/Disable automatic resizing of the table.\n     *\n     * @param string $layout autofit / fixed\n     */\n    private function writeLayout(XMLWriter $xmlWriter, $layout): void\n    {\n        $xmlWriter->startElement('w:tblLayout');\n        $xmlWriter->writeAttribute('w:type', $layout);\n        $xmlWriter->endElement(); // w:tblLayout\n    }\n\n    /**\n     * Write margin.\n     */\n    private function writeMargin(XMLWriter $xmlWriter, TableStyle $style): void\n    {\n        if ($style->hasMargin()) {\n            $xmlWriter->startElement('w:tblCellMar');\n\n            $styleWriter = new MarginBorder($xmlWriter);\n            $styleWriter->setSizes($style->getCellMargin());\n            $styleWriter->write();\n\n            $xmlWriter->endElement(); // w:tblCellMar\n        }\n    }\n\n    /**\n     * Write border.\n     */\n    private function writeBorder(XMLWriter $xmlWriter, TableStyle $style): void\n    {\n        if ($style->hasBorder()) {\n            $xmlWriter->startElement('w:tblBorders');\n\n            $styleWriter = new MarginBorder($xmlWriter);\n            $styleWriter->setSizes($style->getBorderSize());\n            $styleWriter->setColors($style->getBorderColor());\n            $styleWriter->write();\n\n            $xmlWriter->endElement(); // w:tblBorders\n        }\n    }\n\n    /**\n     * Writes a table width.\n     *\n     * @param string $elementName\n     * @param string $unit\n     * @param null|float|int $width\n     */\n    private function writeTblWidth(XMLWriter $xmlWriter, $elementName, $unit, $width = null): void\n    {\n        if (null === $width) {\n            return;\n        }\n        $xmlWriter->startElement($elementName);\n        $xmlWriter->writeAttribute('w:w', $width);\n        $xmlWriter->writeAttribute('w:type', $unit);\n        $xmlWriter->endElement();\n    }\n\n    /**\n     * Write row style.\n     */\n    private function writeFirstRow(XMLWriter $xmlWriter, TableStyle $style): void\n    {\n        $xmlWriter->startElement('w:tblStylePr');\n        $xmlWriter->writeAttribute('w:type', 'firstRow');\n        $xmlWriter->startElement('w:tcPr');\n\n        $this->writeBorder($xmlWriter, $style);\n        $this->writeShading($xmlWriter, $style);\n\n        $xmlWriter->endElement(); // w:tcPr\n        $xmlWriter->endElement(); // w:tblStylePr\n    }\n\n    /**\n     * Write shading.\n     */\n    private function writeShading(XMLWriter $xmlWriter, TableStyle $style): void\n    {\n        if (null !== $style->getShading()) {\n            $xmlWriter->startElement('w:tcPr');\n\n            $styleWriter = new Shading($xmlWriter, $style->getShading());\n            $styleWriter->write();\n\n            $xmlWriter->endElement();\n        }\n    }\n\n    /**\n     * Set width.\n     *\n     * @param int $value\n     */\n    public function setWidth($value = null): void\n    {\n        $this->width = $value;\n    }\n\n    private function writeIndent(XMLWriter $xmlWriter, TableStyle $style): void\n    {\n        $indent = $style->getIndent();\n\n        if ($indent === null) {\n            return;\n        }\n\n        $this->writeTblWidth($xmlWriter, 'w:tblInd', $indent->getType(), $indent->getValue());\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Style/TablePosition.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Style;\n\n/**\n * TablePosition style writer.\n */\nclass TablePosition extends AbstractStyle\n{\n    /**\n     * Write style.\n     */\n    public function write(): void\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof \\PhpOffice\\PhpWord\\Style\\TablePosition) {\n            return;\n        }\n\n        $values = [];\n        $properties = [\n            'leftFromText',\n            'rightFromText',\n            'topFromText',\n            'bottomFromText',\n            'vertAnchor',\n            'horzAnchor',\n            'tblpXSpec',\n            'tblpX',\n            'tblpYSpec',\n            'tblpY',\n        ];\n        foreach ($properties as $property) {\n            $method = 'get' . $property;\n            if (method_exists($style, $method)) {\n                $values[$property] = $style->$method();\n            }\n        }\n        $values = array_filter($values);\n\n        if ($values) {\n            $xmlWriter = $this->getXmlWriter();\n            $xmlWriter->startElement('w:tblpPr');\n            foreach ($values as $property => $value) {\n                $xmlWriter->writeAttribute('w:' . $property, $value);\n            }\n            $xmlWriter->endElement();\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007/Style/TextBox.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer\\Word2007\\Style;\n\nuse PhpOffice\\PhpWord\\Style\\TextBox as TextBoxStyle;\n\n/**\n * TextBox style writer.\n *\n * @since 0.11.0\n */\nclass TextBox extends Frame\n{\n    /**\n     * Writer inner margin.\n     */\n    public function writeInnerMargin(): void\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof TextBoxStyle || !$style->hasInnerMargins()) {\n            return;\n        }\n\n        $xmlWriter = $this->getXmlWriter();\n        $margins = implode(', ', $style->getInnerMargin());\n\n        $xmlWriter->writeAttribute('inset', $margins);\n    }\n\n    /**\n     * Writer border.\n     */\n    public function writeBorder(): void\n    {\n        $style = $this->getStyle();\n        if (!$style instanceof TextBoxStyle) {\n            return;\n        }\n        $xmlWriter = $this->getXmlWriter();\n\n        $xmlWriter->startElement('v:stroke');\n        $xmlWriter->writeAttributeIf($style->getBorderSize() !== null, 'weight', $style->getBorderSize() . 'pt');\n        $xmlWriter->writeAttributeIf($style->getBorderColor() !== null, 'color', $style->getBorderColor());\n        $xmlWriter->endElement(); // v:stroke\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/Word2007.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer;\n\nuse PhpOffice\\PhpWord\\Element\\Section;\nuse PhpOffice\\PhpWord\\Media;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Shared\\ZipArchive;\n\n/**\n * Word2007 writer.\n */\nclass Word2007 extends AbstractWriter implements WriterInterface\n{\n    /**\n     * Content types values.\n     *\n     * @var array\n     */\n    private $contentTypes = ['default' => [], 'override' => []];\n\n    /**\n     * Document relationship.\n     *\n     * @var array\n     */\n    private $relationships = [];\n\n    /**\n     * Create new Word2007 writer.\n     */\n    public function __construct(?PhpWord $phpWord = null)\n    {\n        // Assign PhpWord\n        $this->setPhpWord($phpWord);\n\n        // Create parts\n        // The first four files need to be in this order for Mimetype detection to work\n        $this->parts = [\n            'ContentTypes' => '[Content_Types].xml',\n            'Rels' => '_rels/.rels',\n            'RelsDocument' => 'word/_rels/document.xml.rels',\n            'Document' => 'word/document.xml',\n            'DocPropsApp' => 'docProps/app.xml',\n            'DocPropsCore' => 'docProps/core.xml',\n            'DocPropsCustom' => 'docProps/custom.xml',\n            'Comments' => 'word/comments.xml',\n            'Styles' => 'word/styles.xml',\n            'Numbering' => 'word/numbering.xml',\n            'Settings' => 'word/settings.xml',\n            'WebSettings' => 'word/webSettings.xml',\n            'FontTable' => 'word/fontTable.xml',\n            'Theme' => 'word/theme/theme1.xml',\n            'RelsPart' => '',\n            'Header' => '',\n            'Footer' => '',\n            'Footnotes' => '',\n            'Endnotes' => '',\n            'Chart' => '',\n        ];\n        foreach (array_keys($this->parts) as $partName) {\n            $partClass = static::class . '\\\\Part\\\\' . $partName;\n            if (class_exists($partClass)) {\n                /** @var Word2007\\Part\\AbstractPart $part Type hint */\n                $part = new $partClass();\n                $part->setParentWriter($this);\n                $this->writerParts[strtolower($partName)] = $part;\n            }\n        }\n\n        // Set package paths\n        $this->mediaPaths = ['image' => 'word/media/', 'object' => 'word/embeddings/'];\n    }\n\n    /**\n     * Save document by name.\n     */\n    public function save(string $filename): void\n    {\n        $filename = $this->getTempFile($filename);\n        $zip = $this->getZipArchive($filename);\n        $phpWord = $this->getPhpWord();\n\n        // Content types\n        $this->contentTypes['default'] = [\n            'rels' => 'application/vnd.openxmlformats-package.relationships+xml',\n            'xml' => 'application/xml',\n        ];\n\n        // Add section media files\n        $sectionMedia = Media::getElements('section');\n        if (!empty($sectionMedia)) {\n            $this->addFilesToPackage($zip, $sectionMedia);\n            $this->registerContentTypes($sectionMedia);\n            foreach ($sectionMedia as $element) {\n                $this->relationships[] = $element;\n            }\n        }\n\n        // Add header/footer media files & relations\n        $this->addHeaderFooterMedia($zip, 'header');\n        $this->addHeaderFooterMedia($zip, 'footer');\n\n        // Add header/footer contents\n        $rId = Media::countElements('section') + 6; //@see Rels::writeDocRels for 6 first elements\n        $sections = $phpWord->getSections();\n        foreach ($sections as $section) {\n            $this->addHeaderFooterContent($section, $zip, 'header', $rId);\n            $this->addHeaderFooterContent($section, $zip, 'footer', $rId);\n        }\n\n        $this->addNotes($zip, $rId, 'footnote');\n        $this->addNotes($zip, $rId, 'endnote');\n        $this->addComments($zip, $rId);\n        $this->addChart($zip, $rId);\n\n        // Write parts\n        foreach ($this->parts as $partName => $fileName) {\n            if ($fileName != '') {\n                $zip->addFromString($fileName, $this->getWriterPart($partName)->write());\n            }\n        }\n\n        // Close zip archive and cleanup temp file\n        $zip->close();\n        $this->cleanupTempFile();\n    }\n\n    /**\n     * Get content types.\n     *\n     * @return array\n     */\n    public function getContentTypes()\n    {\n        return $this->contentTypes;\n    }\n\n    /**\n     * Get content types.\n     *\n     * @return array\n     */\n    public function getRelationships()\n    {\n        return $this->relationships;\n    }\n\n    /**\n     * Add header/footer media files, e.g. footer1.xml.rels.\n     *\n     * @param string $docPart\n     */\n    private function addHeaderFooterMedia(ZipArchive $zip, $docPart): void\n    {\n        $elements = Media::getElements($docPart);\n        if (!empty($elements)) {\n            foreach ($elements as $file => $media) {\n                if (count($media) > 0) {\n                    if (!empty($media)) {\n                        $this->addFilesToPackage($zip, $media);\n                        $this->registerContentTypes($media);\n                    }\n\n                    /** @var Word2007\\Part\\AbstractPart $writerPart Type hint */\n                    $writerPart = $this->getWriterPart('relspart')->setMedia($media);\n                    $zip->addFromString(\"word/_rels/{$file}.xml.rels\", $writerPart->write());\n                }\n            }\n        }\n    }\n\n    /**\n     * Add header/footer content.\n     *\n     * @param string $elmType header|footer\n     * @param int &$rId\n     */\n    private function addHeaderFooterContent(Section &$section, ZipArchive $zip, $elmType, &$rId): void\n    {\n        $getFunction = $elmType == 'header' ? 'getHeaders' : 'getFooters';\n        $elmCount = ($section->getSectionId() - 1) * 3;\n        $elements = $section->$getFunction();\n        /** @var \\PhpOffice\\PhpWord\\Element\\AbstractElement $element Type hint */\n        foreach ($elements as &$element) {\n            ++$elmCount;\n            $element->setRelationId(++$rId);\n            $elmFile = \"{$elmType}{$elmCount}.xml\"; // e.g. footer1.xml\n            $this->contentTypes['override'][\"/word/$elmFile\"] = $elmType;\n            $this->relationships[] = ['target' => $elmFile, 'type' => $elmType, 'rID' => $rId];\n\n            /** @var Word2007\\Part\\AbstractPart $writerPart Type hint */\n            $writerPart = $this->getWriterPart($elmType)->setElement($element);\n            $zip->addFromString(\"word/$elmFile\", $writerPart->write());\n        }\n    }\n\n    /**\n     * Add footnotes/endnotes.\n     *\n     * @param int &$rId\n     * @param string $noteType\n     */\n    private function addNotes(ZipArchive $zip, &$rId, $noteType = 'footnote'): void\n    {\n        $phpWord = $this->getPhpWord();\n        $noteType = ($noteType == 'endnote') ? 'endnote' : 'footnote';\n        $partName = \"{$noteType}s\";\n        $method = 'get' . ucfirst($partName);\n        $collection = $phpWord->$method();\n\n        // Add footnotes media files, relations, and contents\n        if ($collection->countItems() > 0) {\n            $media = Media::getElements($noteType);\n            $this->addFilesToPackage($zip, $media);\n            $this->registerContentTypes($media);\n            $this->contentTypes['override'][\"/word/{$partName}.xml\"] = $partName;\n            $this->relationships[] = ['target' => \"{$partName}.xml\", 'type' => $partName, 'rID' => ++$rId];\n\n            // Write relationships file, e.g. word/_rels/footnotes.xml\n            if (!empty($media)) {\n                /** @var Word2007\\Part\\AbstractPart $writerPart Type hint */\n                $writerPart = $this->getWriterPart('relspart')->setMedia($media);\n                $zip->addFromString(\"word/_rels/{$partName}.xml.rels\", $writerPart->write());\n            }\n\n            // Write content file, e.g. word/footnotes.xml\n            $writerPart = $this->getWriterPart($partName)->setElements($collection->getItems());\n            $zip->addFromString(\"word/{$partName}.xml\", $writerPart->write());\n        }\n    }\n\n    /**\n     * Add comments.\n     *\n     * @param int &$rId\n     */\n    private function addComments(ZipArchive $zip, &$rId): void\n    {\n        $phpWord = $this->getPhpWord();\n        $collection = $phpWord->getComments();\n        $partName = 'comments';\n\n        // Add comment relations and contents\n        if ($collection->countItems() > 0) {\n            $this->relationships[] = ['target' => \"{$partName}.xml\", 'type' => $partName, 'rID' => ++$rId];\n\n            // Write content file, e.g. word/comments.xml\n            $writerPart = $this->getWriterPart($partName)->setElements($collection->getItems());\n            $zip->addFromString(\"word/{$partName}.xml\", $writerPart->write());\n        }\n    }\n\n    /**\n     * Add chart.\n     *\n     * @param int &$rId\n     */\n    private function addChart(ZipArchive $zip, &$rId): void\n    {\n        $phpWord = $this->getPhpWord();\n\n        $collection = $phpWord->getCharts();\n        $index = 0;\n        if ($collection->countItems() > 0) {\n            /** @var \\PhpOffice\\PhpWord\\Element\\Chart $chart */\n            foreach ($collection->getItems() as $chart) {\n                ++$index;\n                ++$rId;\n                $filename = \"charts/chart{$index}.xml\";\n\n                // ContentTypes.xml\n                $this->contentTypes['override'][\"/word/{$filename}\"] = 'chart';\n\n                // word/_rels/document.xml.rel\n                $this->relationships[] = ['target' => $filename, 'type' => 'chart', 'rID' => $rId];\n\n                // word/charts/chartN.xml\n                $chart->setRelationId($rId);\n                $writerPart = $this->getWriterPart('Chart');\n                $writerPart->setElement($chart);\n                $zip->addFromString(\"word/{$filename}\", $writerPart->write());\n            }\n        }\n    }\n\n    /**\n     * Register content types for each media.\n     *\n     * @param array $media\n     */\n    private function registerContentTypes($media): void\n    {\n        foreach ($media as $medium) {\n            $mediumType = $medium['type'];\n            if ($mediumType == 'image') {\n                $extension = $medium['imageExtension'];\n                if (!isset($this->contentTypes['default'][$extension])) {\n                    $this->contentTypes['default'][$extension] = $medium['imageType'];\n                }\n            } elseif ($mediumType == 'object') {\n                if (!isset($this->contentTypes['default']['bin'])) {\n                    $this->contentTypes['default']['bin'] = 'application/vnd.openxmlformats-officedocument.oleObject';\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/WriterInterface.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWord\\Writer;\n\n/**\n * Writer interface.\n */\ninterface WriterInterface\n{\n    /**\n     * Save PhpWord to file.\n     */\n    public function save(string $filename): void;\n}\n"
  },
  {
    "path": "src/PhpWord/Writer/WriterPartInterface.php",
    "content": "<?php\n\nnamespace PhpOffice\\PhpWord\\Writer;\n\ninterface WriterPartInterface\n{\n    public function setParentWriter(AbstractWriter $parentWriter): void;\n\n    public function write(): string;\n}\n"
  },
  {
    "path": "tests/PhpWordTests/AbstractTestReader.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse ZipArchive;\n\n/**\n * Base class for Word2007 reader tests.\n */\nabstract class AbstractTestReader extends \\PHPUnit\\Framework\\TestCase\n{\n    private $parts = [\n        'styles' => ['class' => 'PhpOffice\\PhpWord\\Reader\\Word2007\\Styles',      'xml' => '<w:styles xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\"><w:docDefaults><w:rPrDefault><w:rPr><w:sz w:val=\"24\"/></w:rPr></w:rPrDefault></w:docDefaults>{toReplace}</w:styles>'],\n        'document' => ['class' => 'PhpOffice\\PhpWord\\Reader\\Word2007\\Document',    'xml' => '<w:document xmlns:v=\"urn:schemas-microsoft-com:vml\" xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\"><w:body>{toReplace}</w:body></w:document>'],\n        'footnotes' => ['class' => 'PhpOffice\\PhpWord\\Reader\\Word2007\\Footnotes',   'xml' => '<w:footnotes xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\">{toReplace}</w:footnotes>'],\n        'endnotes' => ['class' => 'PhpOffice\\PhpWord\\Reader\\Word2007\\Endnotes',    'xml' => '<w:endnotes xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\">{toReplace}</w:endnotes>'],\n        'settings' => ['class' => 'PhpOffice\\PhpWord\\Reader\\Word2007\\Settings',    'xml' => '<w:comments xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\">{toReplace}</w:comments>'],\n    ];\n\n    /**\n     * Builds a PhpWord instance based on the xml passed.\n     *\n     * @return PhpWord\n     */\n    protected function getDocumentFromString(array $partXmls = [])\n    {\n        $file = __DIR__ . '/_files/temp.docx';\n        $zip = new ZipArchive();\n        $zip->open($file, ZipArchive::CREATE | ZipArchive::OVERWRITE);\n        foreach ($this->parts as $partName => $part) {\n            if (array_key_exists($partName, $partXmls)) {\n                $zip->addFromString(\"{$partName}.xml\", str_replace('{toReplace}', $partXmls[$partName], $this->parts[$partName]['xml']));\n            }\n        }\n        $zip->close();\n\n        $phpWord = new PhpWord();\n        foreach ($this->parts as $partName => $part) {\n            if (array_key_exists($partName, $partXmls)) {\n                $className = $this->parts[$partName]['class'];\n                $reader = new $className($file, \"{$partName}.xml\");\n                $reader->read($phpWord);\n            }\n        }\n        unlink($file);\n\n        return $phpWord;\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/AbstractWebServerEmbedded.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests;\n\nuse Symfony\\Component\\Process\\Process;\n\nabstract class AbstractWebServerEmbedded extends \\PHPUnit\\Framework\\TestCase\n{\n    private static $httpServer;\n\n    public static function setUpBeforeClass(): void\n    {\n        $commandLine = 'php -S localhost:8080 -t tests/PhpWordTests/_files';\n\n        self::$httpServer = Process::fromShellCommandline($commandLine);\n        self::$httpServer->start();\n        while (!self::$httpServer->isRunning()) {\n            usleep(1000);\n        }\n    }\n\n    public static function tearDownAfterClass(): void\n    {\n        self::$httpServer->stop();\n    }\n\n    protected static function getBaseUrl()\n    {\n        return 'http://localhost:8080';\n    }\n\n    protected static function getRemoteImageUrl()\n    {\n        if (self::$httpServer) {\n            return self::getBaseUrl() . '/images/new-php-logo.png';\n        }\n\n        return 'http://php.net/images/logos/new-php-logo.png';\n    }\n\n    protected static function getRemoteImageUrlWithoutExtension(): string\n    {\n        if (self::$httpServer) {\n            return self::getBaseUrl() . '/images/new-php-logo';\n        }\n\n        return 'http://placekitten.com/200/300';\n    }\n\n    protected static function getRemoteGifImageUrl()\n    {\n        if (self::$httpServer) {\n            return self::getBaseUrl() . '/images/mario.gif';\n        }\n\n        return 'http://php.net/images/logos/php-med-trans-light.gif';\n    }\n\n    protected static function getRemoteBmpImageUrl()\n    {\n        if (self::$httpServer) {\n            return self::getBaseUrl() . '/images/duke_nukem.bmp';\n        }\n\n        return 'https://samples.libav.org/image-samples/RACECAR.BMP';\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/AutoloaderTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests;\n\nuse PhpOffice\\PhpWord\\Autoloader;\nuse PHPUnit\\Framework\\TestCase;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Autoloader.\n */\nclass AutoloaderTest extends TestCase\n{\n    public function testRegister(): void\n    {\n        Autoloader::register();\n        $splFunctions = spl_autoload_functions();\n        // @phpstan-ignore-next-line spl_autoload_functions return false < PHP 8.0\n        if ($splFunctions === false) {\n            $splFunctions = [];\n        }\n\n        self::assertContains(\n            ['PhpOffice\\\\PhpWord\\\\Autoloader', 'autoload'],\n            $splFunctions\n        );\n    }\n\n    public function testAutoload(): void\n    {\n        $declared = get_declared_classes();\n        $declaredCount = count($declared);\n        Autoloader::autoload('Foo');\n        self::assertCount(\n            $declaredCount,\n            get_declared_classes(),\n            'PhpOffice\\\\PhpWord\\\\Autoloader::autoload() is trying to load ' .\n            'classes outside of the PhpOffice\\\\PhpWord namespace'\n        );\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Collection/CollectionTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Collection;\n\nuse PhpOffice\\PhpWord\\Collection\\Footnotes;\nuse PhpOffice\\PhpWord\\Element\\Footnote;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Collection subnamespace.\n *\n * Using concrete class Footnotes instead of AbstractCollection\n */\nclass CollectionTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test collection.\n     */\n    public function testCollection(): void\n    {\n        $object = new Footnotes();\n        $object->addItem(new Footnote()); // addItem #1\n\n        self::assertEquals(1, $object->addItem(new Footnote())); // addItem #2. Should returns new item index\n        self::assertCount(2, $object->getItems()); // getItems returns array\n        self::assertInstanceOf(Footnote::class, $object->getItem(1)); // getItem returns object\n        self::assertNull($object->getItem(3)); // getItem returns null when invalid index is referenced\n\n        $object->setItem(2, null); // Set item #2 to null\n\n        self::assertNull($object->getItem(2)); // Check if it's null\n    }\n\n    public function testCollectionSetItem(): void\n    {\n        $object = new Footnotes();\n        $object->addItem(new Footnote());\n        self::assertCount(1, $object->getItems());\n\n        $object->setItem(0, new Footnote());\n        self::assertCount(1, $object->getItems());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/ComplexType/FootnotePropertiesTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\ComplexType;\n\nuse InvalidArgumentException;\nuse PhpOffice\\PhpWord\\ComplexType\\FootnoteProperties;\nuse PhpOffice\\PhpWord\\SimpleType\\NumberFormat;\n\n/**\n * Test class for PhpOffice\\PhpWord\\ComplexType\\FootnoteProperties.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\ComplexType\\FootnoteProperties\n *\n * @runTestsInSeparateProcesses\n */\nclass FootnotePropertiesTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test setting style with normal value.\n     */\n    public function testSetGetNormal(): void\n    {\n        $footnoteProp = new FootnoteProperties();\n        $footnoteProp->setPos(FootnoteProperties::POSITION_DOC_END);\n        $footnoteProp->setNumFmt(NumberFormat::LOWER_ROMAN);\n        $footnoteProp->setNumStart(2);\n        $footnoteProp->setNumRestart(FootnoteProperties::RESTART_NUMBER_EACH_PAGE);\n\n        self::assertEquals(FootnoteProperties::POSITION_DOC_END, $footnoteProp->getPos());\n        self::assertEquals(NumberFormat::LOWER_ROMAN, $footnoteProp->getNumFmt());\n        self::assertEquals(2, $footnoteProp->getNumStart());\n        self::assertEquals(FootnoteProperties::RESTART_NUMBER_EACH_PAGE, $footnoteProp->getNumRestart());\n    }\n\n    /**\n     * Test throws exception if wrong position given.\n     */\n    public function testWrongPos(): void\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $footnoteProp = new FootnoteProperties();\n        $footnoteProp->setPos(NumberFormat::LOWER_ROMAN);\n    }\n\n    /**\n     * Test throws exception if wrong number format given.\n     */\n    public function testWrongNumFmt(): void\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $footnoteProp = new FootnoteProperties();\n        $footnoteProp->setNumFmt(FootnoteProperties::POSITION_DOC_END);\n    }\n\n    /**\n     * Test throws exception if wrong number restart given.\n     */\n    public function testWrongNumRestart(): void\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $footnoteProp = new FootnoteProperties();\n        $footnoteProp->setNumRestart(NumberFormat::LOWER_ROMAN);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/ComplexType/ProofStateTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\ComplexType;\n\nuse InvalidArgumentException;\nuse PhpOffice\\PhpWord\\ComplexType\\ProofState;\n\n/**\n * Test class for PhpOffice\\PhpWord\\ComplexType\\ProofState.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\ComplexType\\ProofState\n */\nclass ProofStateTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Tests the getters and setters.\n     */\n    public function testGetSet(): void\n    {\n        $pState = new ProofState();\n        $pState->setGrammar(ProofState::CLEAN);\n        $pState->setSpelling(ProofState::DIRTY);\n\n        self::assertEquals(ProofState::CLEAN, $pState->getGrammar());\n        self::assertEquals(ProofState::DIRTY, $pState->getSpelling());\n    }\n\n    /**\n     * Test throws exception if wrong grammar proof state value given.\n     */\n    public function testWrongGrammar(): void\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $pState = new ProofState();\n        $pState->setGrammar('Wrong');\n    }\n\n    /**\n     * Test throws exception if wrong spelling proof state value given.\n     */\n    public function testWrongSpelling(): void\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $pState = new ProofState();\n        $pState->setSpelling('Wrong');\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/ComplexType/RubyPropertiesTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\ComplexType;\n\nuse InvalidArgumentException;\nuse PhpOffice\\PhpWord\\ComplexType\\RubyProperties;\n\n/**\n * Test class for PhpOffice\\PhpWord\\ComplexType\\RubyProperties.\n *\n * @runTestsInSeparateProcesses\n */\nclass RubyPropertiesTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test new instance.\n     */\n    public function testConstruct(): void\n    {\n        $properties = new RubyProperties();\n\n        self::assertIsString($properties->getAlignment());\n        self::assertNotEmpty($properties->getAlignment());\n        self::assertIsFloat($properties->getFontFaceSize());\n        self::assertIsFloat($properties->getFontPointsAboveBaseText());\n        self::assertIsFloat($properties->getFontSizeForBaseText());\n        self::assertIsString($properties->getLanguageId());\n        self::assertTrue($properties->getLanguageId() !== '');\n    }\n\n    /**\n     * Get/set alignment.\n     */\n    public function testAlignment(): void\n    {\n        $properties = new RubyProperties();\n        self::assertIsString($properties->getAlignment());\n        self::assertNotEmpty($properties->getAlignment());\n        $properties->setAlignment(RubyProperties::ALIGNMENT_RIGHT_VERTICAL);\n        self::assertEquals(RubyProperties::ALIGNMENT_RIGHT_VERTICAL, $properties->getAlignment());\n    }\n\n    /**\n     * Set valid alignments. Make sure we can set all valid types - should not throw exception.\n     */\n    public function testValidAlignments(): void\n    {\n        $properties = new RubyProperties();\n        $types = [\n            RubyProperties::ALIGNMENT_CENTER,\n            RubyProperties::ALIGNMENT_DISTRIBUTE_LETTER,\n            RubyProperties::ALIGNMENT_DISTRIBUTE_SPACE,\n            RubyProperties::ALIGNMENT_LEFT,\n            RubyProperties::ALIGNMENT_RIGHT,\n            RubyProperties::ALIGNMENT_RIGHT_VERTICAL,\n        ];\n        foreach ($types as $type) {\n            $properties->setAlignment($type);\n            self::assertEquals($type, $properties->getAlignment());\n        }\n    }\n\n    /**\n     * Test throws exception on invalid alignment type.\n     */\n    public function testInvalidAlignment(): void\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $properties = new RubyProperties();\n        $properties->setAlignment('invalid alignment type');\n    }\n\n    /**\n     * Get/set font face size.\n     */\n    public function testFontFaceSize(): void\n    {\n        $properties = new RubyProperties();\n\n        self::assertTrue($properties->getFontFaceSize() > 0);\n        $properties->setFontFaceSize(42.42);\n        self::assertEqualsWithDelta(42.42, $properties->getFontFaceSize(), 0.00001); // use delta as it is a float compare\n        self::assertIsFloat($properties->getFontFaceSize());\n    }\n\n    /**\n     * Get/set font points above base text.\n     */\n    public function testFontPointsAboveBaseText(): void\n    {\n        $properties = new RubyProperties();\n\n        self::assertTrue($properties->getFontPointsAboveBaseText() > 0);\n        $properties->setFontPointsAboveBaseText(43.42);\n        self::assertEqualsWithDelta(43.42, $properties->getFontPointsAboveBaseText(), 0.00001); // use delta as it is a float compare\n        self::assertIsFloat($properties->getFontPointsAboveBaseText());\n    }\n\n    /**\n     * Get/set font size for base text.\n     */\n    public function testFontSizeForBaseText(): void\n    {\n        $properties = new RubyProperties();\n\n        self::assertTrue($properties->getFontSizeForBaseText() > 0);\n        $properties->setFontSizeForBaseText(45.42);\n        self::assertEqualsWithDelta(45.42, $properties->getFontSizeForBaseText(), 0.00001); // use delta as it is a float compare\n        self::assertIsFloat($properties->getFontSizeForBaseText());\n    }\n\n    /**\n     * Get/set language id.\n     */\n    public function testLanguageId(): void\n    {\n        $properties = new RubyProperties();\n\n        self::assertNotEmpty($properties->getLanguageId());\n        $properties->setLanguageId('en-US');\n        self::assertIsString($properties->getLanguageId());\n        self::assertEquals('en-US', $properties->getLanguageId());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Element/AbstractElementTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\AbstractElement;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Element\\AbstractElement.\n */\nclass AbstractElementTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test set/get element index.\n     */\n    public function testElementIndex(): void\n    {\n        // @phpstan-ignore-next-line\n        if (method_exists($this, 'getMockForAbstractClass')) {\n            $stub = $this->getMockForAbstractClass(AbstractElement::class);\n        } else {\n            /** @var AbstractElement $stub */\n            $stub = new class() extends AbstractElement {\n            };\n        }\n        $ival = mt_rand(0, 100);\n        $stub->setElementIndex($ival);\n        self::assertEquals($ival, $stub->getElementIndex());\n    }\n\n    /**\n     * Test set/get element unique Id.\n     */\n    public function testElementId(): void\n    {\n        // @phpstan-ignore-next-line\n        if (method_exists($this, 'getMockForAbstractClass')) {\n            $stub = $this->getMockForAbstractClass(AbstractElement::class);\n        } else {\n            /** @var AbstractElement $stub */\n            $stub = new class() extends AbstractElement {\n            };\n        }\n        $stub->setElementId();\n        self::assertEquals(6, strlen($stub->getElementId()));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Element/BookmarkTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\Bookmark;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Element\\Footer.\n *\n * @runTestsInSeparateProcesses\n */\nclass BookmarkTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * New instance.\n     */\n    public function testConstruct(): void\n    {\n        $bookmarkName = 'test';\n        $oBookmark = new Bookmark($bookmarkName);\n\n        self::assertEquals($bookmarkName, $oBookmark->getName());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Element/CellTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Element;\n\nuse BadMethodCallException;\nuse PhpOffice\\PhpWord\\Element\\Cell;\nuse PhpOffice\\PhpWordTests\\AbstractWebServerEmbedded;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Element\\Cell.\n *\n * @runTestsInSeparateProcesses\n */\nclass CellTest extends AbstractWebServerEmbedded\n{\n    /**\n     * New instance.\n     */\n    public function testConstruct(): void\n    {\n        $oCell = new Cell();\n\n        self::assertNull($oCell->getWidth());\n    }\n\n    /**\n     * New instance with array.\n     */\n    public function testConstructWithStyleArray(): void\n    {\n        $oCell = new Cell(null, ['valign' => 'center']);\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Cell', $oCell->getStyle());\n        self::assertNull($oCell->getWidth());\n    }\n\n    /**\n     * Add text.\n     */\n    public function testAddText(): void\n    {\n        $oCell = new Cell();\n        $element = $oCell->addText('text');\n\n        self::assertCount(1, $oCell->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Text', $element);\n    }\n\n    /**\n     * Add non-UTF8.\n     */\n    public function testAddTextNotUTF8(): void\n    {\n        $oCell = new Cell();\n        $element = $oCell->addText(utf8decode('ééé'));\n\n        self::assertCount(1, $oCell->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Text', $element);\n        self::assertEquals('ééé', $element->getText());\n    }\n\n    /**\n     * Add link.\n     */\n    public function testAddLink(): void\n    {\n        $oCell = new Cell();\n        $element = $oCell->addLink(utf8decode('ééé'), utf8decode('ééé'));\n\n        self::assertCount(1, $oCell->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Link', $element);\n    }\n\n    /**\n     * Add text break.\n     */\n    public function testAddTextBreak(): void\n    {\n        $oCell = new Cell();\n        $oCell->addTextBreak();\n\n        self::assertCount(1, $oCell->getElements());\n    }\n\n    /**\n     * Add list item.\n     */\n    public function testAddListItem(): void\n    {\n        $oCell = new Cell();\n        $element = $oCell->addListItem('text');\n\n        self::assertCount(1, $oCell->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\ListItem', $element);\n        self::assertEquals('text', $element->getTextObject()->getText());\n    }\n\n    /**\n     * Add list item non-UTF8.\n     */\n    public function testAddListItemNotUTF8(): void\n    {\n        $oCell = new Cell();\n        $element = $oCell->addListItem(utf8decode('ééé'));\n\n        self::assertCount(1, $oCell->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\ListItem', $element);\n        self::assertEquals('ééé', $element->getTextObject()->getText());\n    }\n\n    /**\n     * Add image section.\n     */\n    public function testAddImageSection(): void\n    {\n        $src = __DIR__ . '/../_files/images/earth.jpg';\n        $oCell = new Cell();\n        $element = $oCell->addImage($src);\n\n        self::assertCount(1, $oCell->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Image', $element);\n    }\n\n    /**\n     * Add image header.\n     */\n    public function testAddImageHeader(): void\n    {\n        $src = __DIR__ . '/../_files/images/earth.jpg';\n        $oCell = new Cell('header', 1);\n        $element = $oCell->addImage($src);\n\n        self::assertCount(1, $oCell->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Image', $element);\n    }\n\n    /**\n     * Add image footer.\n     */\n    public function testAddImageFooter(): void\n    {\n        $src = __DIR__ . '/../_files/images/earth.jpg';\n        $oCell = new Cell('footer', 1);\n        $element = $oCell->addImage($src);\n\n        self::assertCount(1, $oCell->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Image', $element);\n    }\n\n    /**\n     * Add image section by URL.\n     */\n    public function testAddImageSectionByUrl(): void\n    {\n        $oCell = new Cell();\n        $element = $oCell->addImage(self::getRemoteGifImageUrl());\n\n        self::assertCount(1, $oCell->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Image', $element);\n    }\n\n    /**\n     * Add object.\n     */\n    public function testAddObjectXLS(): void\n    {\n        $src = __DIR__ . '/../_files/documents/sheet.xls';\n        $oCell = new Cell();\n        $element = $oCell->addObject($src);\n\n        self::assertCount(1, $oCell->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\OLEObject', $element);\n    }\n\n    /**\n     * Test add object exception.\n     */\n    public function testAddObjectException(): void\n    {\n        $this->expectException(\\PhpOffice\\PhpWord\\Exception\\InvalidObjectException::class);\n        $src = __DIR__ . '/../_files/xsl/passthrough.xsl';\n        $oCell = new Cell();\n        $oCell->addObject($src);\n    }\n\n    /**\n     * Add preserve text.\n     */\n    public function testAddPreserveText(): void\n    {\n        $oCell = new Cell();\n        $oCell->setDocPart('Header', 1);\n        $element = $oCell->addPreserveText('text');\n\n        self::assertCount(1, $oCell->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\PreserveText', $element);\n    }\n\n    /**\n     * Add preserve text non-UTF8.\n     */\n    public function testAddPreserveTextNotUTF8(): void\n    {\n        $oCell = new Cell();\n        $oCell->setDocPart('Header', 1);\n        $element = $oCell->addPreserveText(utf8decode('ééé'));\n\n        self::assertCount(1, $oCell->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\PreserveText', $element);\n        self::assertEquals(['ééé'], $element->getText());\n    }\n\n    /**\n     * Add preserve text exception.\n     */\n    public function testAddPreserveTextException(): void\n    {\n        $this->expectException(BadMethodCallException::class);\n        $oCell = new Cell();\n        $oCell->setDocPart('TextRun', 1);\n        $oCell->addPreserveText('text');\n    }\n\n    /**\n     * Add text run.\n     */\n    public function testCreateTextRun(): void\n    {\n        $oCell = new Cell();\n        $element = $oCell->addTextRun();\n\n        self::assertCount(1, $oCell->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\TextRun', $element);\n    }\n\n    /**\n     * Add check box.\n     */\n    public function testAddCheckBox(): void\n    {\n        $oCell = new Cell();\n        $element = $oCell->addCheckBox(utf8decode('ééé'), utf8decode('ééé'));\n\n        self::assertCount(1, $oCell->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\CheckBox', $element);\n    }\n\n    /**\n     * Get elements.\n     */\n    public function testGetElements(): void\n    {\n        $oCell = new Cell();\n\n        self::assertIsArray($oCell->getElements());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Element/CheckBoxTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\CheckBox;\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\nuse PhpOffice\\PhpWord\\Style\\Font;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Element\\CheckBox.\n *\n * @runTestsInSeparateProcesses\n */\nclass CheckBoxTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Construct.\n     */\n    public function testConstruct(): void\n    {\n        $oCheckBox = new CheckBox();\n\n        self::assertNull($oCheckBox->getText());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Font', $oCheckBox->getFontStyle());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph', $oCheckBox->getParagraphStyle());\n    }\n\n    /**\n     * Get name and text.\n     */\n    public function testCheckBox(): void\n    {\n        $oCheckBox = new CheckBox('chkBox', 'CheckBox');\n\n        self::assertEquals('chkBox', $oCheckBox->getName());\n        self::assertEquals('CheckBox', $oCheckBox->getText());\n    }\n\n    /**\n     * Get font style.\n     */\n    public function testFont(): void\n    {\n        $oCheckBox = new CheckBox('chkBox', 'CheckBox', 'fontStyle');\n        self::assertEquals('fontStyle', $oCheckBox->getFontStyle());\n\n        $oCheckBox->setFontStyle(['bold' => true, 'italic' => true, 'size' => 16]);\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Font', $oCheckBox->getFontStyle());\n    }\n\n    /**\n     * Font style as object.\n     */\n    public function testFontObject(): void\n    {\n        $font = new Font();\n        $oCheckBox = new CheckBox('chkBox', 'CheckBox', $font);\n        self::assertEquals($font, $oCheckBox->getFontStyle());\n    }\n\n    /**\n     * Get paragraph style.\n     */\n    public function testParagraph(): void\n    {\n        $oCheckBox = new CheckBox('chkBox', 'CheckBox', 'fontStyle', 'paragraphStyle');\n        self::assertEquals('paragraphStyle', $oCheckBox->getParagraphStyle());\n\n        $oCheckBox->setParagraphStyle(['alignment' => Jc::CENTER, 'spaceAfter' => 100]);\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph', $oCheckBox->getParagraphStyle());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Element/CommentTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Element;\n\nuse DateTime;\nuse InvalidArgumentException;\nuse PhpOffice\\PhpWord\\Element\\Comment;\nuse PhpOffice\\PhpWord\\Element\\Section;\nuse PhpOffice\\PhpWord\\Element\\Text;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Element\\Header.\n *\n * @runTestsInSeparateProcesses\n */\nclass CommentTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * New instance.\n     */\n    public function testConstructDefault(): void\n    {\n        $author = 'Test User';\n        $date = new DateTime('2000-01-01');\n        $initials = 'default_user';\n        $oComment = new Comment($author, $date, $initials);\n\n        $oText = new Text('dummy text');\n        $oComment->setStartElement($oText);\n        $oComment->setEndElement($oText);\n\n        self::assertEquals($author, $oComment->getAuthor());\n        self::assertEquals($date, $oComment->getDate());\n        self::assertEquals($initials, $oComment->getInitials());\n        self::assertEquals($oText, $oComment->getStartElement());\n        self::assertEquals($oText, $oComment->getEndElement());\n    }\n\n    /**\n     * Two comments on same text.\n     */\n    public function testTwoCommentsOnSameText(): void\n    {\n        $section = new Section(0);\n        $text = $section->addText('Text');\n\n        $comment1 = new Comment('Author1', new DateTime(), 'A1');\n        $comment1->addText('Comment1');\n\n        $comment2 = new Comment('Author2', new DateTime(), 'A2');\n        $comment2->addText('Comment2');\n\n        $comment1->setStartElement($text);\n        $comment2->setStartElement($text);\n\n        $text->setCommentRangeStart($comment1);\n        $text->setCommentRangeEnd($comment1);\n\n        $text->setCommentRangeStart($comment2);\n        $text->setCommentRangeEnd($comment2);\n\n        self::assertEquals(2, $text->getCommentsRangeStart()->countItems());\n        self::assertEquals(2, $text->getCommentsRangeEnd()->countItems());\n\n        self::assertEquals($text->getCommentsRangeStart()->getItem(0)->getElementId(), $comment1->getElementId());\n        self::assertEquals($text->getCommentsRangeEnd()->getItem(0)->getElementId(), $comment1->getElementId());\n\n        self::assertEquals($text->getCommentsRangeStart()->getItem(1)->getElementId(), $comment2->getElementId());\n        self::assertEquals($text->getCommentsRangeEnd()->getItem(1)->getElementId(), $comment2->getElementId());\n    }\n\n    /**\n     * Add text.\n     */\n    public function testAddText(): void\n    {\n        $oComment = new Comment('Test User', new DateTime(), 'my_initials');\n        $element = $oComment->addText('text');\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Text', $element);\n        self::assertCount(1, $oComment->getElements());\n        self::assertEquals('text', $element->getText());\n    }\n\n    /**\n     * Get elements.\n     */\n    public function testGetElements(): void\n    {\n        $oComment = new Comment('Test User', new DateTime(), 'my_initials');\n\n        self::assertIsArray($oComment->getElements());\n    }\n\n    /**\n     * Set/get relation Id.\n     */\n    public function testRelationId(): void\n    {\n        $oComment = new Comment('Test User', new DateTime(), 'my_initials');\n\n        $iVal = mt_rand(1, 1000);\n        $oComment->setRelationId($iVal);\n        self::assertEquals($iVal, $oComment->getRelationId());\n    }\n\n    public function testExceptionOnCommentStartOnComment(): void\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $dummyComment = new Comment('Test User', new DateTime(), 'my_initials');\n        $oComment = new Comment('Test User', new DateTime(), 'my_initials');\n        $oComment->setCommentRangeStart($dummyComment);\n    }\n\n    public function testExceptionOnCommentEndOnComment(): void\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $dummyComment = new Comment('Test User', new DateTime(), 'my_initials');\n        $oComment = new Comment('Test User', new DateTime(), 'my_initials');\n        $oComment->setCommentRangeEnd($dummyComment);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Element/FieldTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Element;\n\nuse InvalidArgumentException;\nuse PhpOffice\\PhpWord\\Element\\Field;\nuse PhpOffice\\PhpWord\\Element\\TextRun;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Element\\Field.\n *\n * @runTestsInSeparateProcesses\n */\nclass FieldTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * New instance with type.\n     */\n    public function testConstructWithType(): void\n    {\n        $oField = new Field('DATE');\n\n        self::assertEquals('DATE', $oField->getType());\n    }\n\n    /**\n     * New instance with type and properties.\n     */\n    public function testConstructWithTypeProperties(): void\n    {\n        $oField = new Field('DATE', ['dateformat' => 'd-M-yyyy']);\n\n        self::assertEquals('DATE', $oField->getType());\n        self::assertEquals(['dateformat' => 'd-M-yyyy'], $oField->getProperties());\n    }\n\n    /**\n     * New instance with type and properties and options.\n     */\n    public function testConstructWithTypePropertiesOptions(): void\n    {\n        $oField = new Field('DATE', ['dateformat' => 'd-M-yyyy'], ['SakaEraCalendar', 'PreserveFormat']);\n\n        self::assertEquals('DATE', $oField->getType());\n        self::assertEquals(['dateformat' => 'd-M-yyyy'], $oField->getProperties());\n        self::assertEquals(['SakaEraCalendar', 'PreserveFormat'], $oField->getOptions());\n    }\n\n    /**\n     * New instance with type and properties and options and text.\n     */\n    public function testConstructWithTypePropertiesOptionsText(): void\n    {\n        $oField = new Field('XE', [], ['Bold', 'Italic'], 'FieldValue');\n\n        self::assertEquals('XE', $oField->getType());\n        self::assertEquals([], $oField->getProperties());\n        self::assertEquals(['Bold', 'Italic'], $oField->getOptions());\n        self::assertEquals('FieldValue', $oField->getText());\n    }\n\n    /**\n     * New instance with type and properties and options and text as TextRun.\n     */\n    public function testConstructWithTypePropertiesOptionsTextAsTextRun(): void\n    {\n        $textRun = new TextRun();\n        $textRun->addText('test string');\n\n        $oField = new Field('XE', [], ['Bold', 'Italic'], $textRun);\n\n        self::assertEquals('XE', $oField->getType());\n        self::assertEquals([], $oField->getProperties());\n        self::assertEquals(['Bold', 'Italic'], $oField->getOptions());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\TextRun', $oField->getText());\n    }\n\n    public function testConstructWithOptionValue(): void\n    {\n        $oField = new Field('INDEX', [], ['\\\\c \"3\" \\\\h \"A\"']);\n\n        self::assertEquals('INDEX', $oField->getType());\n        self::assertEquals([], $oField->getProperties());\n        self::assertEquals(['\\\\c \"3\" \\\\h \"A\"'], $oField->getOptions());\n    }\n\n    /**\n     * Test setType exception.\n     */\n    public function testSetTypeException(): void\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $this->expectExceptionMessage('Invalid type');\n        $object = new Field();\n        $object->setType('foo');\n    }\n\n    /**\n     * Test setProperties exception.\n     */\n    public function testSetPropertiesException(): void\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $this->expectExceptionMessage('Invalid property');\n        $object = new Field('PAGE');\n        $object->setProperties(['foo' => 'bar']);\n    }\n\n    /**\n     * Test setOptions exception.\n     */\n    public function testSetOptionsException(): void\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $this->expectExceptionMessage('Invalid option');\n        $object = new Field('PAGE');\n        $object->setOptions(['foo' => 'bar']);\n    }\n\n    /**\n     * Test setText exception.\n     */\n    public function testSetTextException(): void\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $this->expectExceptionMessage('Invalid text');\n        $object = new Field('XE');\n        $object->setText([]);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Element/FooterTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\Footer;\nuse PhpOffice\\PhpWordTests\\AbstractWebServerEmbedded;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Element\\Footer.\n *\n * @runTestsInSeparateProcesses\n */\nclass FooterTest extends AbstractWebServerEmbedded\n{\n    /**\n     * New instance.\n     */\n    public function testConstruct(): void\n    {\n        $iVal = mt_rand(1, 1000);\n        $oFooter = new Footer($iVal);\n\n        self::assertEquals($iVal, $oFooter->getSectionId());\n    }\n\n    /**\n     * Add text.\n     */\n    public function testAddText(): void\n    {\n        $oFooter = new Footer(1);\n        $element = $oFooter->addText('text');\n\n        self::assertCount(1, $oFooter->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Text', $element);\n    }\n\n    /**\n     * Add text non-UTF8.\n     */\n    public function testAddTextNotUTF8(): void\n    {\n        $oFooter = new Footer(1);\n        $element = $oFooter->addText(utf8decode('ééé'));\n\n        self::assertCount(1, $oFooter->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Text', $element);\n        self::assertEquals('ééé', $element->getText());\n    }\n\n    /**\n     * Add text break.\n     */\n    public function testAddTextBreak(): void\n    {\n        $oFooter = new Footer(1);\n        $iVal = mt_rand(1, 1000);\n        $oFooter->addTextBreak($iVal);\n\n        self::assertCount($iVal, $oFooter->getElements());\n    }\n\n    /**\n     * Add text run.\n     */\n    public function testCreateTextRun(): void\n    {\n        $oFooter = new Footer(1);\n        $element = $oFooter->addTextRun();\n\n        self::assertCount(1, $oFooter->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\TextRun', $element);\n    }\n\n    /**\n     * Add table.\n     */\n    public function testAddTable(): void\n    {\n        $oFooter = new Footer(1);\n        $element = $oFooter->addTable();\n\n        self::assertCount(1, $oFooter->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Table', $element);\n    }\n\n    /**\n     * Add image.\n     */\n    public function testAddImage(): void\n    {\n        $src = __DIR__ . '/../_files/images/earth.jpg';\n        $oFooter = new Footer(1);\n        $element = $oFooter->addImage($src);\n\n        self::assertCount(1, $oFooter->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Image', $element);\n    }\n\n    /**\n     * Add image by URL.\n     */\n    public function testAddImageByUrl(): void\n    {\n        $oFooter = new Footer(1);\n        $element = $oFooter->addImage(self::getRemoteGifImageUrl());\n\n        self::assertCount(1, $oFooter->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Image', $element);\n    }\n\n    /**\n     * Add preserve text.\n     */\n    public function testAddPreserveText(): void\n    {\n        $oFooter = new Footer(1);\n        $element = $oFooter->addPreserveText('text');\n\n        self::assertCount(1, $oFooter->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\PreserveText', $element);\n    }\n\n    /**\n     * Add preserve text non-UTF8.\n     */\n    public function testAddPreserveTextNotUTF8(): void\n    {\n        $oFooter = new Footer(1);\n        $element = $oFooter->addPreserveText(utf8decode('ééé'));\n\n        self::assertCount(1, $oFooter->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\PreserveText', $element);\n        self::assertEquals(['ééé'], $element->getText());\n    }\n\n    /**\n     * Get elements.\n     */\n    public function testGetElements(): void\n    {\n        $oFooter = new Footer(1);\n\n        self::assertIsArray($oFooter->getElements());\n    }\n\n    /**\n     * Set/get relation Id.\n     */\n    public function testRelationID(): void\n    {\n        $oFooter = new Footer(0);\n\n        $iVal = mt_rand(1, 1000);\n        $oFooter->setRelationId($iVal);\n\n        self::assertEquals($iVal, $oFooter->getRelationId());\n        self::assertEquals(Footer::AUTO, $oFooter->getType());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Element/FootnoteTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\Footnote;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Element\\Footnote.\n *\n * @runTestsInSeparateProcesses\n */\nclass FootnoteTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * New instance without parameter.\n     */\n    public function testConstruct(): void\n    {\n        $oFootnote = new Footnote();\n\n        self::assertCount(0, $oFootnote->getElements());\n        self::assertNull($oFootnote->getParagraphStyle());\n    }\n\n    /**\n     * New instance with string parameter.\n     */\n    public function testConstructString(): void\n    {\n        $oFootnote = new Footnote('pStyle');\n\n        self::assertEquals('pStyle', $oFootnote->getParagraphStyle());\n    }\n\n    /**\n     * New instance with array parameter.\n     */\n    public function testConstructArray(): void\n    {\n        $oFootnote = new Footnote(['spacing' => 100]);\n\n        self::assertInstanceOf(\n            'PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph',\n            $oFootnote->getParagraphStyle()\n        );\n    }\n\n    /**\n     * Add text element.\n     */\n    public function testAddText(): void\n    {\n        $oFootnote = new Footnote();\n        $element = $oFootnote->addText('text');\n\n        self::assertCount(1, $oFootnote->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Text', $element);\n    }\n\n    /**\n     * Add text break element.\n     */\n    public function testAddTextBreak(): void\n    {\n        $oFootnote = new Footnote();\n        $oFootnote->addTextBreak(2);\n\n        self::assertCount(2, $oFootnote->getElements());\n    }\n\n    /**\n     * Add link element.\n     */\n    public function testAddLink(): void\n    {\n        $oFootnote = new Footnote();\n        $element = $oFootnote->addLink('https://github.com/PHPOffice/PHPWord');\n\n        self::assertCount(1, $oFootnote->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Link', $element);\n    }\n\n    /**\n     * Set/get reference Id.\n     */\n    public function testReferenceId(): void\n    {\n        $oFootnote = new Footnote();\n\n        $iVal = mt_rand(1, 1000);\n        $oFootnote->setRelationId($iVal);\n        self::assertEquals($iVal, $oFootnote->getRelationId());\n    }\n\n    /**\n     * Get elements.\n     */\n    public function testGetElements(): void\n    {\n        $oFootnote = new Footnote();\n        self::assertIsArray($oFootnote->getElements());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Element/FormulaTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Element;\n\nuse PhpOffice\\Math\\Element;\nuse PhpOffice\\Math\\Math;\nuse PhpOffice\\PhpWord\\Element\\Formula;\nuse PhpOffice\\PhpWordTests\\AbstractWebServerEmbedded;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Element\\Formula.\n *\n * @runTestsInSeparateProcesses\n */\nclass FormulaTest extends AbstractWebServerEmbedded\n{\n    /**\n     * @covers \\PhpOffice\\PhpWord\\Element\\Formula::getMath\n     * @covers \\PhpOffice\\PhpWord\\Element\\Formula::setMath\n     */\n    public function testMath(): void\n    {\n        $math = new Math();\n        $math->add(new Element\\Fraction(\n            new Element\\Numeric(2),\n            new Element\\Identifier('π')\n        ));\n\n        $element = new Formula(new Math());\n\n        self::assertEquals(new Math(), $element->getMath());\n        self::assertNotEquals($math, $element->getMath());\n\n        $element->setMath($math);\n        self::assertNotEquals(new Math(), $element->getMath());\n        self::assertEquals($math, $element->getMath());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Element/HeaderTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Element;\n\nuse BadMethodCallException;\nuse PhpOffice\\PhpWord\\Element\\Header;\nuse PhpOffice\\PhpWordTests\\AbstractWebServerEmbedded;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Element\\Header.\n *\n * @runTestsInSeparateProcesses\n */\nclass HeaderTest extends AbstractWebServerEmbedded\n{\n    /**\n     * New instance.\n     */\n    public function testConstructDefault(): void\n    {\n        $iVal = mt_rand(1, 1000);\n        $oHeader = new Header($iVal);\n\n        self::assertEquals($iVal, $oHeader->getSectionId());\n        self::assertEquals(Header::AUTO, $oHeader->getType());\n    }\n\n    /**\n     * Add text.\n     */\n    public function testAddText(): void\n    {\n        $oHeader = new Header(1);\n        $element = $oHeader->addText('text');\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Text', $element);\n        self::assertCount(1, $oHeader->getElements());\n        self::assertEquals('text', $element->getText());\n    }\n\n    /**\n     * Add text non-UTF8.\n     */\n    public function testAddTextNotUTF8(): void\n    {\n        $oHeader = new Header(1);\n        $element = $oHeader->addText(utf8decode('ééé'));\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Text', $element);\n        self::assertCount(1, $oHeader->getElements());\n        self::assertEquals('ééé', $element->getText());\n    }\n\n    /**\n     * Add text break.\n     */\n    public function testAddTextBreak(): void\n    {\n        $oHeader = new Header(1);\n        $oHeader->addTextBreak();\n        self::assertCount(1, $oHeader->getElements());\n    }\n\n    /**\n     * Add text break with params.\n     */\n    public function testAddTextBreakWithParams(): void\n    {\n        $oHeader = new Header(1);\n        $iVal = mt_rand(1, 1000);\n        $oHeader->addTextBreak($iVal);\n        self::assertCount($iVal, $oHeader->getElements());\n    }\n\n    /**\n     * Add text run.\n     */\n    public function testCreateTextRun(): void\n    {\n        $oHeader = new Header(1);\n        $element = $oHeader->addTextRun();\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\TextRun', $element);\n        self::assertCount(1, $oHeader->getElements());\n    }\n\n    /**\n     * Add table.\n     */\n    public function testAddTable(): void\n    {\n        $oHeader = new Header(1);\n        $element = $oHeader->addTable();\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Table', $element);\n        self::assertCount(1, $oHeader->getElements());\n    }\n\n    /**\n     * Add image.\n     */\n    public function testAddImage(): void\n    {\n        $src = __DIR__ . '/../_files/images/earth.jpg';\n        $oHeader = new Header(1);\n        $element = $oHeader->addImage($src);\n\n        self::assertCount(1, $oHeader->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Image', $element);\n    }\n\n    /**\n     * Add image by URL.\n     */\n    public function testAddImageByUrl(): void\n    {\n        $oHeader = new Header(1);\n        $element = $oHeader->addImage(self::getRemoteGifImageUrl());\n\n        self::assertCount(1, $oHeader->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Image', $element);\n    }\n\n    /**\n     * Add preserve text.\n     */\n    public function testAddPreserveText(): void\n    {\n        $oHeader = new Header(1);\n        $element = $oHeader->addPreserveText('text');\n\n        self::assertCount(1, $oHeader->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\PreserveText', $element);\n    }\n\n    /**\n     * Add preserve text non-UTF8.\n     */\n    public function testAddPreserveTextNotUTF8(): void\n    {\n        $oHeader = new Header(1);\n        $element = $oHeader->addPreserveText(utf8decode('ééé'));\n\n        self::assertCount(1, $oHeader->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\PreserveText', $element);\n        self::assertEquals(['ééé'], $element->getText());\n    }\n\n    /**\n     * Add watermark.\n     */\n    public function testAddWatermark(): void\n    {\n        $src = __DIR__ . '/../_files/images/earth.jpg';\n        $oHeader = new Header(1);\n        $element = $oHeader->addWatermark($src);\n\n        self::assertCount(1, $oHeader->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Image', $element);\n    }\n\n    /**\n     * Get elements.\n     */\n    public function testGetElements(): void\n    {\n        $oHeader = new Header(1);\n\n        self::assertIsArray($oHeader->getElements());\n    }\n\n    /**\n     * Set/get relation Id.\n     */\n    public function testRelationId(): void\n    {\n        $oHeader = new Header(1);\n\n        $iVal = mt_rand(1, 1000);\n        $oHeader->setRelationId($iVal);\n        self::assertEquals($iVal, $oHeader->getRelationId());\n    }\n\n    /**\n     * Reset type.\n     */\n    public function testResetType(): void\n    {\n        $oHeader = new Header(1);\n        $oHeader->firstPage();\n        $oHeader->resetType();\n\n        self::assertEquals(Header::AUTO, $oHeader->getType());\n    }\n\n    /**\n     * First page.\n     */\n    public function testFirstPage(): void\n    {\n        $oHeader = new Header(1);\n        $oHeader->firstPage();\n\n        self::assertEquals(Header::FIRST, $oHeader->getType());\n    }\n\n    /**\n     * Even page.\n     */\n    public function testEvenPage(): void\n    {\n        $oHeader = new Header(1);\n        $oHeader->evenPage();\n\n        self::assertEquals(Header::EVEN, $oHeader->getType());\n    }\n\n    /**\n     * Add footnote exception.\n     */\n    public function testAddFootnoteException(): void\n    {\n        $this->expectException(BadMethodCallException::class);\n        $header = new Header(1);\n        $header->addFootnote();\n    }\n\n    /**\n     * Set/get type.\n     */\n    public function testSetGetType(): void\n    {\n        $object = new Header(1);\n        self::assertEquals(Header::AUTO, $object->getType());\n\n        $object->setType('ODD');\n        self::assertEquals(Header::AUTO, $object->getType());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Element/ImageTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\Image;\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\nuse PhpOffice\\PhpWordTests\\AbstractWebServerEmbedded;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Element\\Image.\n */\nclass ImageTest extends AbstractWebServerEmbedded\n{\n    /**\n     * New instance.\n     */\n    public function testConstruct(): void\n    {\n        $src = __DIR__ . '/../_files/images/firefox.png';\n        $oImage = new Image($src);\n\n        self::assertEquals($src, $oImage->getSource());\n        self::assertEquals(md5($src), $oImage->getMediaId());\n        self::assertFalse($oImage->isWatermark());\n        self::assertEquals(Image::SOURCE_LOCAL, $oImage->getSourceType());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Image', $oImage->getStyle());\n    }\n\n    /**\n     * New instance with style.\n     */\n    public function testConstructWithStyle(): void\n    {\n        $src = __DIR__ . '/../_files/images/firefox.png';\n        $oImage = new Image(\n            $src,\n            [\n                'width' => 210,\n                'height' => 210,\n                'alignment' => Jc::CENTER,\n                'wrappingStyle' => \\PhpOffice\\PhpWord\\Style\\Image::WRAPPING_STYLE_BEHIND,\n            ]\n        );\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Image', $oImage->getStyle());\n    }\n\n    /**\n     * Valid image types.\n     *\n     * @dataProvider providerImages\n     */\n    public function testImages($source, $type, $extension, $createFunction, $imageFunction, $imageQuality): void\n    {\n        $nam = ucfirst((string) strtok($source, '.'));\n        $source = __DIR__ . \"/../_files/images/{$source}\";\n        $image = new Image($source, null, null, $nam);\n        self::assertEquals($source, $image->getSource());\n        self::assertEquals($nam, $image->getName());\n        self::assertEquals(md5($source), $image->getMediaId());\n        self::assertEquals($type, $image->getImageType());\n        self::assertEquals($extension, $image->getImageExtension());\n        self::assertEquals($createFunction, $image->getImageCreateFunction());\n        if ($imageFunction) {\n            self::assertNotNull($image->getImageFunction());\n        } else {\n            self::assertNull($image->getImageFunction());\n        }\n        self::assertEquals($imageQuality, $image->getImageQuality());\n        self::assertFalse($image->isMemImage());\n        self::assertNotNull($image->getImageStringData());\n    }\n\n    public static function providerImages(): array\n    {\n        return [\n            ['mars.jpg', 'image/jpeg', 'jpg', 'imagecreatefromjpeg', true, 100],\n            ['mario.gif', 'image/gif', 'gif', 'imagecreatefromgif', true, null],\n            ['firefox.png', 'image/png', 'png', 'imagecreatefrompng', true, -1],\n            ['duke_nukem.bmp', 'image/bmp', 'bmp', null, false, null],\n            ['angela_merkel.tif', 'image/tiff', 'tif', null, false, null],\n        ];\n    }\n\n    /**\n     * Get style.\n     */\n    public function testStyle(): void\n    {\n        $oImage = new Image(\n            __DIR__ . '/../_files/images/earth.jpg',\n            ['height' => 210, 'alignment' => Jc::CENTER]\n        );\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Image', $oImage->getStyle());\n    }\n\n    /**\n     * Test invalid local image.\n     */\n    public function testInvalidImageLocal(): void\n    {\n        $this->expectException(\\PhpOffice\\PhpWord\\Exception\\InvalidImageException::class);\n        new Image(__DIR__ . '/../_files/images/thisisnotarealimage');\n    }\n\n    /**\n     * Test invalid PHP Image.\n     */\n    public function testInvalidImagePhp(): void\n    {\n        $this->expectException(\\PhpOffice\\PhpWord\\Exception\\InvalidImageException::class);\n        $object = new Image('test.php');\n        $source = $object->getSource();\n    }\n\n    /**\n     * Test unsupported image.\n     */\n    public function testUnsupportedImage(): void\n    {\n        $this->expectException(\\PhpOffice\\PhpWord\\Exception\\UnsupportedImageTypeException::class);\n        //disable ssl verification, never do this in real application, you should pass the certificiate instead!!!\n        $arrContextOptions = [\n            'ssl' => [\n                'verify_peer' => false,\n                'verify_peer_name' => false,\n            ],\n        ];\n        stream_context_set_default($arrContextOptions);\n        $object = new Image(self::getRemoteBmpImageUrl());\n        $source = $object->getSource();\n    }\n\n    /**\n     * Get relation Id.\n     */\n    public function testRelationID(): void\n    {\n        $oImage = new Image(__DIR__ . '/../_files/images/earth.jpg', ['width' => 100]);\n        $iVal = mt_rand(1, 1000);\n        $oImage->setRelationId($iVal);\n        self::assertEquals($iVal, $oImage->getRelationId());\n    }\n\n    /**\n     * Test archived image.\n     */\n    public function testArchivedImage(): void\n    {\n        $archiveFile = __DIR__ . '/../_files/documents/reader.docx';\n        $imageFile = 'word/media/image1.jpeg';\n        $image = new Image(\"zip://{$archiveFile}#{$imageFile}\");\n        self::assertEquals('image/jpeg', $image->getImageType());\n    }\n\n    /**\n     * Test getting image as string.\n     */\n    public function testImageAsStringFromFile(): void\n    {\n        $image = new Image(__DIR__ . '/../_files/images/earth.jpg');\n\n        self::assertNotNull($image->getImageStringData());\n        self::assertNotNull($image->getImageStringData(true));\n    }\n\n    /**\n     * Test getting image from zip as string.\n     */\n    public function testImageAsStringFromZip(): void\n    {\n        $archiveFile = __DIR__ . '/../_files/documents/reader.docx';\n        $imageFile = 'word/media/image1.jpeg';\n        $image = new Image(\"zip://{$archiveFile}#{$imageFile}\");\n\n        self::assertNotNull($image->getImageStringData());\n        self::assertNotNull($image->getImageStringData(true));\n    }\n\n    /**\n     * Test construct from string.\n     */\n    public function testConstructFromString(): void\n    {\n        $source = file_get_contents(__DIR__ . '/../_files/images/earth.jpg');\n\n        $image = new Image($source);\n        self::assertEquals($source, $image->getSource());\n        self::assertEquals(md5((string) $source), $image->getMediaId());\n        self::assertEquals('image/jpeg', $image->getImageType());\n        self::assertEquals('jpg', $image->getImageExtension());\n        self::assertEquals('imagecreatefromstring', $image->getImageCreateFunction());\n        self::assertNotNull($image->getImageFunction());\n        self::assertEquals(100, $image->getImageQuality());\n        self::assertTrue($image->isMemImage());\n\n        self::assertNotNull($image->getImageStringData());\n        self::assertNotNull($image->getImageStringData(true));\n    }\n\n    /**\n     * Test construct from GD.\n     */\n    public function testConstructFromGd(): void\n    {\n        $source = self::getRemoteImageUrl();\n\n        $image = new Image($source);\n        self::assertEquals($source, $image->getSource());\n        self::assertEquals(md5($source), $image->getMediaId());\n        self::assertEquals('image/png', $image->getImageType());\n        self::assertEquals('png', $image->getImageExtension());\n        self::assertEquals('imagecreatefrompng', $image->getImageCreateFunction());\n        self::assertNotNull($image->getImageFunction());\n        self::assertEquals(-1, $image->getImageQuality());\n        self::assertTrue($image->isMemImage());\n\n        self::assertNotNull($image->getImageStringData());\n        self::assertNotNull($image->getImageStringData(true));\n    }\n\n    /**\n     * Test invalid string image.\n     */\n    public function testInvalidImageString(): void\n    {\n        $this->expectException(\\PhpOffice\\PhpWord\\Exception\\InvalidImageException::class);\n        $object = new Image('this_is-a_non_valid_image');\n        $source = $object->getSource();\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Element/LineTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\Line;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Element\\Line.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Element\\Line\n *\n * @runTestsInSeparateProcesses\n */\nclass LineTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Create new instance.\n     */\n    public function testConstruct(): void\n    {\n        $oLine = new Line();\n\n        self::assertNull($oLine->getStyle());\n    }\n\n    /**\n     * Get style name.\n     */\n    public function testStyleText(): void\n    {\n        $oLine = new Line('lineStyle');\n\n        self::assertEquals('lineStyle', $oLine->getStyle());\n    }\n\n    /**\n     * Get style array.\n     */\n    public function testStyleArray(): void\n    {\n        $oLine = new Line(\n            [\n                'width' => \\PhpOffice\\PhpWord\\Shared\\Converter::cmToPixel(14),\n                'height' => \\PhpOffice\\PhpWord\\Shared\\Converter::cmToPixel(4),\n                'positioning' => 'absolute',\n                'posHorizontalRel' => 'page',\n                'posVerticalRel' => 'page',\n                'flip' => true,\n                'marginLeft' => \\PhpOffice\\PhpWord\\Shared\\Converter::cmToPixel(5),\n                'marginTop' => \\PhpOffice\\PhpWord\\Shared\\Converter::cmToPixel(3),\n                'wrappingStyle' => \\PhpOffice\\PhpWord\\Style\\Image::WRAPPING_STYLE_SQUARE,\n                'beginArrow' => \\PhpOffice\\PhpWord\\Style\\Line::ARROW_STYLE_BLOCK,\n                'endArrow' => \\PhpOffice\\PhpWord\\Style\\Line::ARROW_STYLE_OVAL,\n                'dash' => \\PhpOffice\\PhpWord\\Style\\Line::DASH_STYLE_LONG_DASH_DOT_DOT,\n                'weight' => 10,\n            ]\n        );\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Line', $oLine->getStyle());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Element/LinkTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\Link;\nuse PhpOffice\\PhpWord\\Style\\Font;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Element\\Link.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Element\\Link\n *\n * @runTestsInSeparateProcesses\n */\nclass LinkTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Create new instance.\n     */\n    public function testConstructDefault(): void\n    {\n        $oLink = new Link('https://github.com/PHPOffice/PHPWord');\n\n        self::assertEquals('https://github.com/PHPOffice/PHPWord', $oLink->getSource());\n        self::assertEquals($oLink->getSource(), $oLink->getText());\n        self::assertNull($oLink->getFontStyle());\n        self::assertNull($oLink->getParagraphStyle());\n    }\n\n    /**\n     * Create new instance with array.\n     */\n    public function testConstructWithParamsArray(): void\n    {\n        $oLink = new Link(\n            'https://github.com/PHPOffice/PHPWord',\n            'PHPWord on GitHub',\n            ['color' => '0000FF', 'underline' => Font::UNDERLINE_SINGLE],\n            ['marginLeft' => 600, 'marginRight' => 600, 'marginTop' => 600, 'marginBottom' => 600]\n        );\n\n        self::assertEquals('https://github.com/PHPOffice/PHPWord', $oLink->getSource());\n        self::assertEquals('PHPWord on GitHub', $oLink->getText());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Font', $oLink->getFontStyle());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph', $oLink->getParagraphStyle());\n    }\n\n    /**\n     * Create new instance with style name string.\n     */\n    public function testConstructWithParamsString(): void\n    {\n        $oLink = new Link('https://github.com/PHPOffice/PHPWord', null, 'fontStyle', 'paragraphStyle');\n\n        self::assertEquals('fontStyle', $oLink->getFontStyle());\n        self::assertEquals('paragraphStyle', $oLink->getParagraphStyle());\n    }\n\n    /**\n     * Set/get relation Id.\n     */\n    public function testRelationId(): void\n    {\n        $oLink = new Link('https://github.com/PHPOffice/PHPWord');\n\n        $iVal = mt_rand(1, 1000);\n        $oLink->setRelationId($iVal);\n        self::assertEquals($iVal, $oLink->getRelationId());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Element/ListItemRunTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\ListItemRun;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Element\\ListItemRun.\n *\n * @runTestsInSeparateProcesses\n */\nclass ListItemRunTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * New instance.\n     */\n    public function testConstruct(): void\n    {\n        $oListItemRun = new ListItemRun();\n\n        self::assertCount(0, $oListItemRun->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph', $oListItemRun->getParagraphStyle());\n    }\n\n    /**\n     * New instance with string.\n     */\n    public function testConstructString(): void\n    {\n        $oListItemRun = new ListItemRun(0, null, 'pStyle');\n\n        self::assertCount(0, $oListItemRun->getElements());\n        self::assertEquals('pStyle', $oListItemRun->getParagraphStyle());\n    }\n\n    /**\n     * New instance with string.\n     */\n    public function testConstructListString(): void\n    {\n        $oListItemRun = new ListItemRun(0, 'numberingStyle');\n\n        self::assertCount(0, $oListItemRun->getElements());\n    }\n\n    /**\n     * New instance with array.\n     */\n    public function testConstructArray(): void\n    {\n        $oListItemRun = new ListItemRun(0, null, ['spacing' => 100]);\n\n        self::assertCount(0, $oListItemRun->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph', $oListItemRun->getParagraphStyle());\n    }\n\n    /**\n     * Get style.\n     */\n    public function testStyle(): void\n    {\n        $oListItemRun = new ListItemRun(1, ['listType' => \\PhpOffice\\PhpWord\\Style\\ListItem::TYPE_NUMBER]);\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\ListItem', $oListItemRun->getStyle());\n        self::assertEquals(\\PhpOffice\\PhpWord\\Style\\ListItem::TYPE_NUMBER, $oListItemRun->getStyle()->getListType());\n    }\n\n    /**\n     * getDepth.\n     */\n    public function testDepth(): void\n    {\n        $iVal = mt_rand(1, 1000);\n        $oListItemRun = new ListItemRun($iVal);\n\n        self::assertEquals($iVal, $oListItemRun->getDepth());\n    }\n\n    /**\n     * Add text.\n     */\n    public function testAddText(): void\n    {\n        $oListItemRun = new ListItemRun();\n        $element = $oListItemRun->addText('text');\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Text', $element);\n        self::assertCount(1, $oListItemRun->getElements());\n        self::assertEquals('text', $element->getText());\n    }\n\n    /**\n     * Add text non-UTF8.\n     */\n    public function testAddTextNotUTF8(): void\n    {\n        $oListItemRun = new ListItemRun();\n        $element = $oListItemRun->addText(utf8decode('ééé'));\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Text', $element);\n        self::assertCount(1, $oListItemRun->getElements());\n        self::assertEquals('ééé', $element->getText());\n    }\n\n    /**\n     * Add link.\n     */\n    public function testAddLink(): void\n    {\n        $oListItemRun = new ListItemRun();\n        $element = $oListItemRun->addLink('https://github.com/PHPOffice/PHPWord');\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Link', $element);\n        self::assertCount(1, $oListItemRun->getElements());\n        self::assertEquals('https://github.com/PHPOffice/PHPWord', $element->getSource());\n    }\n\n    /**\n     * Add link with name.\n     */\n    public function testAddLinkWithName(): void\n    {\n        $oListItemRun = new ListItemRun();\n        $element = $oListItemRun->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub');\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Link', $element);\n        self::assertCount(1, $oListItemRun->getElements());\n        self::assertEquals('https://github.com/PHPOffice/PHPWord', $element->getSource());\n        self::assertEquals('PHPWord on GitHub', $element->getText());\n    }\n\n    /**\n     * Add text break.\n     */\n    public function testAddTextBreak(): void\n    {\n        $oListItemRun = new ListItemRun();\n        $oListItemRun->addTextBreak(2);\n\n        self::assertCount(2, $oListItemRun->getElements());\n    }\n\n    /**\n     * Add image.\n     */\n    public function testAddImage(): void\n    {\n        $src = __DIR__ . '/../_files/images/earth.jpg';\n\n        $oListItemRun = new ListItemRun();\n        $element = $oListItemRun->addImage($src);\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Image', $element);\n        self::assertCount(1, $oListItemRun->getElements());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Element/ListItemTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\ListItem;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Element\\ListItem.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Element\\ListItem\n *\n * @runTestsInSeparateProcesses\n */\nclass ListItemTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Get text object.\n     */\n    public function testText(): void\n    {\n        $oListItem = new ListItem('text');\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Text', $oListItem->getTextObject());\n    }\n\n    /**\n     * Get style.\n     */\n    public function testStyle(): void\n    {\n        $oListItem = new ListItem('text', 1, null, ['listType' => \\PhpOffice\\PhpWord\\Style\\ListItem::TYPE_NUMBER]);\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\ListItem', $oListItem->getStyle());\n        self::assertEquals(\\PhpOffice\\PhpWord\\Style\\ListItem::TYPE_NUMBER, $oListItem->getStyle()->getListType());\n    }\n\n    /**\n     * Get depth.\n     */\n    public function testDepth(): void\n    {\n        $iVal = mt_rand(1, 1000);\n        $oListItem = new ListItem('text', $iVal);\n\n        self::assertEquals($iVal, $oListItem->getDepth());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Element/ObjectTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\OLEObject;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Element\\OLEObject.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Element\\OLEObject\n *\n * @runTestsInSeparateProcesses\n */\nclass ObjectTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Create new instance with supported files, 4 character extention.\n     */\n    public function testConstructWithSupportedFiles(): void\n    {\n        $src = __DIR__ . '/../_files/documents/reader.docx';\n        $oObject = new OLEObject($src);\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Image', $oObject->getStyle());\n        self::assertEquals($src, $oObject->getSource());\n    }\n\n    /**\n     * Create new instance with supported files.\n     */\n    public function testConstructWithSupportedFilesLong(): void\n    {\n        $src = __DIR__ . '/../_files/documents/sheet.xls';\n        $oObject = new OLEObject($src);\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Image', $oObject->getStyle());\n        self::assertEquals($src, $oObject->getSource());\n    }\n\n    /**\n     * Create new instance with non-supported files.\n     */\n    public function testConstructWithNotSupportedFiles(): void\n    {\n        $this->expectException(\\PhpOffice\\PhpWord\\Exception\\InvalidObjectException::class);\n        $src = __DIR__ . '/../_files/xsl/passthrough.xsl';\n        $oObject = new OLEObject($src);\n        $source = $oObject->getSource();\n    }\n\n    /**\n     * Create with style.\n     */\n    public function testConstructWithSupportedFilesAndStyle(): void\n    {\n        $src = __DIR__ . '/../_files/documents/sheet.xls';\n        $oObject = new OLEObject($src, ['width' => '230px']);\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Image', $oObject->getStyle());\n        self::assertEquals($src, $oObject->getSource());\n    }\n\n    /**\n     * Set/get relation Id.\n     */\n    public function testRelationId(): void\n    {\n        $src = __DIR__ . '/../_files/documents/sheet.xls';\n        $oObject = new OLEObject($src);\n\n        $iVal = mt_rand(1, 1000);\n        $oObject->setRelationId($iVal);\n        self::assertEquals($iVal, $oObject->getRelationId());\n    }\n\n    /**\n     * Set/get image relation Id.\n     */\n    public function testImageRelationId(): void\n    {\n        $src = __DIR__ . '/../_files/documents/sheet.xls';\n        $oObject = new OLEObject($src);\n\n        $iVal = mt_rand(1, 1000);\n        $oObject->setImageRelationId($iVal);\n        self::assertEquals($iVal, $oObject->getImageRelationId());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Element/PreserveTextTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\PreserveText;\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Element\\PreserveText.\n *\n * @runTestsInSeparateProcesses\n */\nclass PreserveTextTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Create new instance.\n     */\n    public function testConstruct(): void\n    {\n        $oPreserveText = new PreserveText();\n\n        self::assertNull($oPreserveText->getText());\n        self::assertNull($oPreserveText->getFontStyle());\n        self::assertNull($oPreserveText->getParagraphStyle());\n    }\n\n    /**\n     * Create new instance with style name.\n     */\n    public function testConstructWithString(): void\n    {\n        $oPreserveText = new PreserveText('text', 'styleFont', 'styleParagraph');\n        self::assertEquals(['text'], $oPreserveText->getText());\n        self::assertEquals('styleFont', $oPreserveText->getFontStyle());\n        self::assertEquals('styleParagraph', $oPreserveText->getParagraphStyle());\n    }\n\n    /**\n     * Create new instance with array.\n     */\n    public function testConstructWithArray(): void\n    {\n        $oPreserveText = new PreserveText('text', ['size' => 16, 'color' => '1B2232'], ['alignment' => Jc::CENTER]);\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Font', $oPreserveText->getFontStyle());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph', $oPreserveText->getParagraphStyle());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Element/RowTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\Row;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Element\\Row.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Element\\Row\n *\n * @runTestsInSeparateProcesses\n */\nclass RowTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Create new instance.\n     */\n    public function testConstruct(): void\n    {\n        $oRow = new Row();\n\n        self::assertNull($oRow->getHeight());\n        self::assertIsArray($oRow->getCells());\n        self::assertCount(0, $oRow->getCells());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Row', $oRow->getStyle());\n    }\n\n    /**\n     * Create new instance with parameters.\n     */\n    public function testConstructWithParams(): void\n    {\n        $iVal = mt_rand(1, 1000);\n        $oRow = new Row($iVal, ['borderBottomSize' => 18, 'borderBottomColor' => '0000FF', 'bgColor' => '66BBFF']);\n\n        self::assertEquals($iVal, $oRow->getHeight());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Row', $oRow->getStyle());\n    }\n\n    /**\n     * Add cell.\n     */\n    public function testAddCell(): void\n    {\n        $oRow = new Row();\n        $element = $oRow->addCell();\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Cell', $element);\n        self::assertCount(1, $oRow->getCells());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Element/RubyTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Element;\n\nuse PhpOffice\\PhpWord\\ComplexType\\RubyProperties;\nuse PhpOffice\\PhpWord\\Element\\Ruby;\nuse PhpOffice\\PhpWord\\Element\\TextRun;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Element\\Text.\n *\n * @runTestsInSeparateProcesses\n */\nclass RubyTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test new instance.\n     */\n    public function testConstruct(): void\n    {\n        $ruby = new Ruby(new TextRun(), new TextRun(), new RubyProperties());\n\n        self::assertEquals('', $ruby->getBaseTextRun()->getText());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph', $ruby->getBaseTextRun()->getParagraphStyle());\n        self::assertEquals('', $ruby->getRubyTextRun()->getText());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph', $ruby->getRubyTextRun()->getParagraphStyle());\n        self::assertEquals(RubyProperties::ALIGNMENT_DISTRIBUTE_SPACE, $ruby->getProperties()->getAlignment());\n    }\n\n    /**\n     * Get/set base text.\n     */\n    public function testBaseText(): void\n    {\n        $ruby = new Ruby(new TextRun(), new TextRun(), new RubyProperties());\n\n        self::assertEquals('', $ruby->getBaseTextRun()->getText());\n        $tr = new TextRun();\n        $tr->addText('Hello, world');\n        $ruby->setBaseTextRun($tr);\n        self::assertEquals('Hello, world', $ruby->getBaseTextRun()->getText());\n    }\n\n    /**\n     * Get/set ruby text.\n     */\n    public function testRubyText(): void\n    {\n        $ruby = new Ruby(new TextRun(), new TextRun(), new RubyProperties());\n\n        self::assertEquals('', $ruby->getRubyTextRun()->getText());\n        $tr = new TextRun();\n        $tr->addText('Hello, ruby');\n        $ruby->setRubyTextRun($tr);\n        self::assertEquals('Hello, ruby', $ruby->getRubyTextRun()->getText());\n    }\n\n    /**\n     * Get/set ruby properties.\n     */\n    public function testRubyProperties(): void\n    {\n        $ruby = new Ruby(new TextRun(), new TextRun(), new RubyProperties());\n\n        self::assertEquals(RubyProperties::ALIGNMENT_DISTRIBUTE_SPACE, $ruby->getProperties()->getAlignment());\n\n        $properties = new RubyProperties();\n        $properties->setAlignment(RubyProperties::ALIGNMENT_RIGHT_VERTICAL);\n        $properties->setFontFaceSize(1);\n        $properties->setFontPointsAboveBaseText(2);\n        $properties->setFontSizeForBaseText(3);\n        $properties->setLanguageId('en-US');\n        $ruby->setProperties($properties);\n\n        self::assertEquals(RubyProperties::ALIGNMENT_RIGHT_VERTICAL, $ruby->getProperties()->getAlignment());\n        self::assertEquals(1, $ruby->getProperties()->getFontFaceSize());\n        self::assertEquals(2, $ruby->getProperties()->getFontPointsAboveBaseText());\n        self::assertEquals(3, $ruby->getProperties()->getFontSizeForBaseText());\n        self::assertEquals('en-US', $ruby->getProperties()->getLanguageId());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Element/SDTTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Element;\n\nuse InvalidArgumentException;\nuse PhpOffice\\PhpWord\\Element\\SDT;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Element\\SDT.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Element\\SDT\n */\nclass SDTTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Create new instance.\n     */\n    public function testConstruct(): void\n    {\n        $types = ['plainText', 'comboBox', 'dropDownList', 'date'];\n        $type = $types[mt_rand(0, 3)];\n        $value = mt_rand(0, 100);\n        $alias = 'alias';\n        $tag = 'my_tag';\n        $object = new SDT($type);\n        $object->setValue($value);\n        $object->setListItems($types);\n        $object->setAlias($alias);\n        $object->setTag($tag);\n\n        self::assertEquals($type, $object->getType());\n        self::assertEquals($types, $object->getListItems());\n        self::assertEquals($value, $object->getValue());\n        self::assertEquals($alias, $object->getAlias());\n        self::assertEquals($tag, $object->getTag());\n    }\n\n    /**\n     * Test set type exception.\n     */\n    public function testSetTypeException(): void\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $this->expectExceptionMessage('Invalid style value');\n        $object = new SDT('comboBox');\n        $object->setType('foo');\n    }\n\n    /**\n     * Test set type.\n     */\n    public function testSetTypeNull(): void\n    {\n        $object = new SDT('comboBox');\n        $object->setType(' ');\n\n        self::assertEquals('comboBox', $object->getType());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Element/SectionTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Element;\n\nuse Exception;\nuse PhpOffice\\PhpWord\\Element\\Header;\nuse PhpOffice\\PhpWord\\Element\\Section;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Style;\nuse PhpOffice\\PhpWord\\Style\\Section as SectionStyle;\n\n/**\n * @covers \\PhpOffice\\PhpWord\\Element\\Section\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Element\\Section\n *\n * @runTestsInSeparateProcesses\n */\nclass SectionTest extends \\PHPUnit\\Framework\\TestCase\n{\n    public function testConstructorWithDefaultStyle(): void\n    {\n        $section = new Section(0);\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Section', $section->getStyle());\n    }\n\n    public function testConstructorWithArrayStyle(): void\n    {\n        $section = new Section(0, ['orientation' => 'landscape']);\n        $style = $section->getStyle();\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Section', $style);\n        self::assertEquals('landscape', $style->getOrientation());\n    }\n\n    public function testConstructorWithObjectStyle(): void\n    {\n        $style = new SectionStyle();\n        $section = new Section(0, $style);\n        self::assertSame($style, $section->getStyle());\n    }\n\n    /**\n     * @covers ::setStyle\n     */\n    public function testSetStyle(): void\n    {\n        $expected = 'landscape';\n        $object = new Section(0);\n        $object->setStyle(['orientation' => $expected, 'foo' => null]);\n        self::assertEquals($expected, $object->getStyle()->getOrientation());\n    }\n\n    /**\n     * @coversNothing\n     */\n    public function testAddElements(): void\n    {\n        $objectSource = __DIR__ . '/../_files/documents/reader.docx';\n        $imageSource = __DIR__ . '/../_files/images/PhpWord.png';\n\n        $section = new Section(0);\n        $section->setPhpWord(new PhpWord());\n        $section->addText(utf8decode('ä'));\n        $section->addLink(utf8decode('http://äää.com'), utf8decode('ä'));\n        $section->addTextBreak();\n        $section->addPageBreak();\n        $section->addTable();\n        $section->addListItem(utf8decode('ä'));\n        $section->addObject($objectSource);\n        $section->addImage($imageSource);\n        $section->addTitle(utf8decode('ä'), 1);\n        $section->addTextRun();\n        $section->addFootnote();\n        $section->addCheckBox(utf8decode('chkä'), utf8decode('Contentä'));\n        $section->addTOC();\n\n        $elementCollection = $section->getElements();\n        $elementTypes = [\n            'Text',\n            'Link',\n            'TextBreak',\n            'PageBreak',\n            'Table',\n            'ListItem',\n            'OLEObject',\n            'Image',\n            'Title',\n            'TextRun',\n            'Footnote',\n            'CheckBox',\n            'TOC',\n        ];\n        $elmCount = 0;\n        foreach ($elementTypes as $elementType) {\n            self::assertInstanceOf(\"PhpOffice\\\\PhpWord\\\\Element\\\\{$elementType}\", $elementCollection[$elmCount]);\n            ++$elmCount;\n        }\n    }\n\n    /**\n     * @coversNothing\n     */\n    public function testAddObjectException(): void\n    {\n        $this->expectException(\\PhpOffice\\PhpWord\\Exception\\InvalidObjectException::class);\n        $source = __DIR__ . '/_files/xsl/passthrough.xsl';\n        $section = new Section(0);\n        $section->addObject($source);\n    }\n\n    /**\n     * Add title with predefined style.\n     *\n     * @coversNothing\n     */\n    public function testAddTitleWithStyle(): void\n    {\n        Style::addTitleStyle(1, ['size' => 14]);\n        $section = new Section(0);\n        $section->setPhpWord(new PhpWord());\n        $section->addTitle('Test', 1);\n        $elementCollection = $section->getElements();\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Title', $elementCollection[0]);\n    }\n\n    /**\n     * @covers ::addFooter\n     * @covers ::addHeader\n     * @covers ::hasDifferentFirstPage\n     */\n    public function testAddHeaderFooter(): void\n    {\n        $object = new Section(0);\n        $elements = ['Header', 'Footer'];\n\n        foreach ($elements as $element) {\n            $method = \"add{$element}\";\n            self::assertInstanceOf(\"PhpOffice\\\\PhpWord\\\\Element\\\\{$element}\", $object->$method());\n        }\n        self::assertFalse($object->hasDifferentFirstPage());\n    }\n\n    /**\n     * @covers ::addHeader\n     * @covers ::hasDifferentFirstPage\n     */\n    public function testHasDifferentFirstPageFooter(): void\n    {\n        $object = new Section(1);\n        $object->addFooter(Header::FIRST);\n        self::assertTrue($object->hasDifferentFirstPage());\n    }\n\n    /**\n     * @covers ::addHeader\n     * @covers ::hasDifferentFirstPage\n     */\n    public function testHasDifferentFirstPage(): void\n    {\n        $object = new Section(1);\n        $header = $object->addHeader();\n        $header->setType(Header::FIRST);\n        self::assertTrue($object->hasDifferentFirstPage());\n    }\n\n    /**\n     * @covers ::addHeader\n     */\n    public function testAddHeaderException(): void\n    {\n        $this->expectException(Exception::class);\n        $this->expectExceptionMessage('Invalid header/footer type.');\n        $object = new Section(1);\n        $object->addHeader('ODD');\n    }\n\n    /**\n     * @covers \\PhpOffice\\PhpWord\\Element\\AbstractContainer::removeElement\n     */\n    public function testRemoveElementByIndex(): void\n    {\n        $section = new Section(1);\n        $section->addText('firstText');\n        $section->addText('secondText');\n\n        self::assertEquals(2, $section->countElements());\n        $section->removeElement(1);\n\n        self::assertEquals(1, $section->countElements());\n    }\n\n    /**\n     * @covers \\PhpOffice\\PhpWord\\Element\\AbstractContainer::removeElement\n     */\n    public function testRemoveElementByElement(): void\n    {\n        $section = new Section(1);\n        $firstText = $section->addText('firstText');\n        $secondText = $section->addText('secondText');\n\n        self::assertEquals(2, $section->countElements());\n        $section->removeElement($firstText);\n\n        self::assertEquals(1, $section->countElements());\n        self::assertEquals($secondText->getElementId(), $section->getElement(1)->getElementId());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Element/TOCTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\Title;\nuse PhpOffice\\PhpWord\\Element\\TOC;\nuse PhpOffice\\PhpWord\\PhpWord;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Element\\TOC.\n *\n * @runTestsInSeparateProcesses\n */\nclass TOCTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Construct with font and TOC style in array format.\n     */\n    public function testConstructWithStyleArray(): void\n    {\n        $expected = [\n            'position' => 9062,\n            'leader' => \\PhpOffice\\PhpWord\\Style\\Tab::TAB_LEADER_DOT,\n            'indent' => 200,\n        ];\n        $object = new TOC(['size' => 11], ['position' => $expected['position']]);\n        $tocStyle = $object->getStyleTOC();\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\TOC', $tocStyle);\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Font', $object->getStyleFont());\n\n        foreach ($expected as $key => $value) {\n            $method = \"get{$key}\";\n            self::assertEquals($value, $tocStyle->$method());\n        }\n    }\n\n    /**\n     * Construct with named font style.\n     */\n    public function testConstructWithStyleName(): void\n    {\n        $object = new TOC('Font Style');\n        // $tocStyle = $object->getStyleTOC();\n\n        self::assertEquals('Font Style', $object->getStyleFont());\n    }\n\n    /**\n     * Test when no PHPWord object is assigned:.\n     */\n    public function testNoPhpWord(): void\n    {\n        $object = new TOC();\n\n        self::assertEmpty($object->getTitles());\n        self::assertNull($object->getPhpWord());\n    }\n\n    /**\n     * Set/get minDepth and maxDepth.\n     */\n    public function testSetGetMinMaxDepth(): void\n    {\n        $titles = [\n            'Heading 1' => 1,\n            'Heading 2' => 2,\n            'Heading 3' => 3,\n            'Heading 4' => 4,\n        ];\n\n        $phpWord = new PhpWord();\n        foreach ($titles as $text => $depth) {\n            $phpWord->addTitle(new Title($text, $depth));\n        }\n        $toc = new TOC();\n        $toc->setPhpWord($phpWord);\n        self::assertEquals(1, $toc->getMinDepth());\n        self::assertEquals(9, $toc->getMaxDepth());\n\n        $toc->setMinDepth(2);\n        $toc->setMaxDepth(3);\n        $toc->getTitles();\n\n        self::assertEquals(2, $toc->getMinDepth());\n        self::assertEquals(3, $toc->getMaxDepth());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Element/TableTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\Table;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Element\\Table.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Element\\Table\n *\n * @runTestsInSeparateProcesses\n */\nclass TableTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Create new instance.\n     */\n    public function testConstruct(): void\n    {\n        $oTable = new Table();\n\n        self::assertNull($oTable->getStyle());\n        self::assertNull($oTable->getWidth());\n        self::assertEquals([], $oTable->getRows());\n        self::assertCount(0, $oTable->getRows());\n    }\n\n    /**\n     * Get style name.\n     */\n    public function testStyleText(): void\n    {\n        $oTable = new Table('tableStyle');\n\n        self::assertEquals('tableStyle', $oTable->getStyle());\n    }\n\n    /**\n     * Get style array.\n     */\n    public function testStyleArray(): void\n    {\n        $oTable = new Table(['borderSize' => 6, 'borderColor' => '006699', 'cellMargin' => 80]);\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Table', $oTable->getStyle());\n    }\n\n    /**\n     * Set/get width.\n     */\n    public function testWidth(): void\n    {\n        $oTable = new Table();\n        $iVal = mt_rand(1, 1000);\n        $oTable->setWidth($iVal);\n        self::assertEquals($iVal, $oTable->getWidth());\n    }\n\n    /**\n     * Add/get row.\n     */\n    public function testRow(): void\n    {\n        $oTable = new Table();\n        $element = $oTable->addRow();\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Row', $element);\n        self::assertCount(1, $oTable->getRows());\n    }\n\n    /**\n     * Add cell.\n     */\n    public function testCell(): void\n    {\n        $oTable = new Table();\n        $oTable->addRow();\n        $element = $oTable->addCell();\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Cell', $element);\n    }\n\n    /**\n     * Add cell.\n     */\n    public function testCountColumns(): void\n    {\n        $oTable = new Table();\n        $oTable->addRow();\n        $oTable->addCell();\n        self::assertEquals($oTable->countColumns(), 1);\n        $oTable->addCell();\n        $oTable->addCell();\n        self::assertEquals($oTable->countColumns(), 3);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Element/TextBoxTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\TextBox;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Element\\TextBox.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Element\\TextBox\n *\n * @runTestsInSeparateProcesses\n */\nclass TextBoxTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Create new instance.\n     */\n    public function testConstruct(): void\n    {\n        $oTextBox = new TextBox();\n\n        self::assertNull($oTextBox->getStyle());\n    }\n\n    /**\n     * Get style name.\n     */\n    public function testStyleText(): void\n    {\n        $oTextBox = new TextBox('textBoxStyle');\n\n        self::assertEquals('textBoxStyle', $oTextBox->getStyle());\n    }\n\n    /**\n     * Get style array.\n     */\n    public function testStyleArray(): void\n    {\n        $oTextBox = new TextBox(\n            [\n                'width' => \\PhpOffice\\PhpWord\\Shared\\Converter::cmToPixel(4.5),\n                'height' => \\PhpOffice\\PhpWord\\Shared\\Converter::cmToPixel(17.5),\n                'positioning' => 'absolute',\n                'marginLeft' => \\PhpOffice\\PhpWord\\Shared\\Converter::cmToPixel(15.4),\n                'marginTop' => \\PhpOffice\\PhpWord\\Shared\\Converter::cmToPixel(9.9),\n                'stroke' => 0,\n                'innerMargin' => 0,\n                'borderSize' => 1,\n                'borderColor' => '',\n            ]\n        );\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\TextBox', $oTextBox->getStyle());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Element/TextBreakTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\TextBreak;\nuse PhpOffice\\PhpWord\\Style\\Font;\nuse PhpOffice\\PhpWord\\Style\\Paragraph;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Element\\TextBreak.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Element\\TextBreak\n *\n * @runTestsInSeparateProcesses\n */\nclass TextBreakTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Construct with empty value.\n     */\n    public function testConstruct(): void\n    {\n        $object = new TextBreak();\n        self::assertNull($object->getFontStyle());\n        self::assertNull($object->getParagraphStyle());\n    }\n\n    /**\n     * Construct with style object.\n     */\n    public function testConstructWithStyleObject(): void\n    {\n        $fStyle = new Font();\n        $pStyle = new Paragraph();\n        $object = new TextBreak($fStyle, $pStyle);\n        self::assertEquals($fStyle, $object->getFontStyle());\n        self::assertEquals($pStyle, $object->getParagraphStyle());\n    }\n\n    /**\n     * Construct with style array.\n     */\n    public function testConstructWithStyleArray(): void\n    {\n        $fStyle = ['size' => 12];\n        $pStyle = ['spacing' => 240];\n        $object = new TextBreak($fStyle, $pStyle);\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Font', $object->getFontStyle());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph', $object->getParagraphStyle());\n    }\n\n    /**\n     * Construct with style name.\n     */\n    public function testConstructWithStyleName(): void\n    {\n        $fStyle = 'fStyle';\n        $pStyle = 'pStyle';\n        $object = new TextBreak($fStyle, $pStyle);\n        self::assertEquals($fStyle, $object->getFontStyle());\n        self::assertEquals($pStyle, $object->getParagraphStyle());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Element/TextRunTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Element;\n\nuse PhpOffice\\PhpWord\\ComplexType\\RubyProperties;\nuse PhpOffice\\PhpWord\\Element\\TextRun;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\nuse PhpOffice\\PhpWord\\Style\\Paragraph;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Element\\TextRun.\n *\n * @runTestsInSeparateProcesses\n */\nclass TextRunTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * New instance.\n     */\n    public function testConstruct(): void\n    {\n        $oTextRun = new TextRun();\n\n        self::assertCount(0, $oTextRun->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph', $oTextRun->getParagraphStyle());\n    }\n\n    /**\n     * New instance with string.\n     */\n    public function testConstructString(): void\n    {\n        $oTextRun = new TextRun('pStyle');\n\n        self::assertCount(0, $oTextRun->getElements());\n        self::assertEquals('pStyle', $oTextRun->getParagraphStyle());\n    }\n\n    /**\n     * New instance with array.\n     */\n    public function testConstructArray(): void\n    {\n        $oTextRun = new TextRun(['spacing' => 100]);\n\n        self::assertCount(0, $oTextRun->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph', $oTextRun->getParagraphStyle());\n    }\n\n    /**\n     * New instance with object.\n     */\n    public function testConstructObject(): void\n    {\n        $oParagraphStyle = new Paragraph();\n        $oParagraphStyle->setAlignment(Jc::BOTH);\n        $oTextRun = new TextRun($oParagraphStyle);\n\n        self::assertCount(0, $oTextRun->getElements());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph', $oTextRun->getParagraphStyle());\n        self::assertEquals(Jc::BOTH, $oTextRun->getParagraphStyle()->getAlignment());\n    }\n\n    /**\n     * Add text.\n     */\n    public function testAddText(): void\n    {\n        $oTextRun = new TextRun();\n        $element = $oTextRun->addText('text');\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Text', $element);\n        self::assertCount(1, $oTextRun->getElements());\n        self::assertEquals('text', $element->getText());\n    }\n\n    /**\n     * Add text non-UTF8.\n     */\n    public function testAddTextNotUTF8(): void\n    {\n        $oTextRun = new TextRun();\n        $element = $oTextRun->addText(utf8decode('ééé'));\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Text', $element);\n        self::assertCount(1, $oTextRun->getElements());\n        self::assertEquals('ééé', $element->getText());\n    }\n\n    /**\n     * Add link.\n     */\n    public function testAddLink(): void\n    {\n        $oTextRun = new TextRun();\n        $element = $oTextRun->addLink('https://github.com/PHPOffice/PHPWord');\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Link', $element);\n        self::assertCount(1, $oTextRun->getElements());\n        self::assertEquals('https://github.com/PHPOffice/PHPWord', $element->getSource());\n    }\n\n    /**\n     * Add link with name.\n     */\n    public function testAddLinkWithName(): void\n    {\n        $oTextRun = new TextRun();\n        $element = $oTextRun->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub');\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Link', $element);\n        self::assertCount(1, $oTextRun->getElements());\n        self::assertEquals('https://github.com/PHPOffice/PHPWord', $element->getSource());\n        self::assertEquals('PHPWord on GitHub', $element->getText());\n    }\n\n    /**\n     * Add text break.\n     */\n    public function testAddTextBreak(): void\n    {\n        $oTextRun = new TextRun();\n        $oTextRun->addTextBreak(2);\n\n        self::assertCount(2, $oTextRun->getElements());\n    }\n\n    /**\n     * Add image.\n     */\n    public function testAddImage(): void\n    {\n        $src = __DIR__ . '/../_files/images/earth.jpg';\n\n        $oTextRun = new TextRun();\n        $element = $oTextRun->addImage($src);\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Image', $element);\n        self::assertCount(1, $oTextRun->getElements());\n    }\n\n    /**\n     * Add footnote.\n     */\n    public function testCreateFootnote(): void\n    {\n        $oTextRun = new TextRun();\n        $oTextRun->setPhpWord(new PhpWord());\n        $element = $oTextRun->addFootnote();\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Footnote', $element);\n        self::assertCount(1, $oTextRun->getElements());\n    }\n\n    /**\n     * Get paragraph style.\n     */\n    public function testParagraph(): void\n    {\n        $oText = new TextRun('paragraphStyle');\n        self::assertEquals('paragraphStyle', $oText->getParagraphStyle());\n\n        $oText->setParagraphStyle(['alignment' => Jc::CENTER, 'spaceAfter' => 100]);\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph', $oText->getParagraphStyle());\n    }\n\n    /**\n     * Add ruby element and get raw text.\n     */\n    public function testRubyElementGetText(): void\n    {\n        $oTextRun = new TextRun();\n        $oTextRun->setPhpWord(new PhpWord());\n\n        $properties = new RubyProperties();\n        $baseTextRun = new TextRun(null);\n        $baseTextRun->addText('私');\n        $rubyTextRun = new TextRun(null);\n        $rubyTextRun->addText('わたし');\n        $element = $oTextRun->addRuby($baseTextRun, $rubyTextRun, $properties);\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Element\\\\Ruby', $element);\n        self::assertCount(1, $oTextRun->getElements());\n        self::assertEquals('私 (わたし)', $oTextRun->getText());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Element/TextTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\Text;\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\nuse PhpOffice\\PhpWord\\Style\\Font;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Element\\Text.\n *\n * @runTestsInSeparateProcesses\n */\nclass TextTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * New instance.\n     */\n    public function testConstruct(): void\n    {\n        $oText = new Text();\n\n        self::assertNull($oText->getText());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Font', $oText->getFontStyle());\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph', $oText->getParagraphStyle());\n    }\n\n    /**\n     * Get text.\n     */\n    public function testText(): void\n    {\n        $oText = new Text('text');\n\n        self::assertEquals('text', $oText->getText());\n    }\n\n    /**\n     * Get font style.\n     */\n    public function testFont(): void\n    {\n        $oText = new Text('text', 'fontStyle');\n        self::assertEquals('fontStyle', $oText->getFontStyle());\n\n        $oText->setFontStyle(['bold' => true, 'italic' => true, 'size' => 16]);\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Font', $oText->getFontStyle());\n    }\n\n    /**\n     * Get font style as object.\n     */\n    public function testFontObject(): void\n    {\n        $font = new Font();\n        $oText = new Text('text', $font);\n        self::assertEquals($font, $oText->getFontStyle());\n    }\n\n    /**\n     * Get paragraph style.\n     */\n    public function testParagraph(): void\n    {\n        $oText = new Text('text', 'fontStyle', 'paragraphStyle');\n        self::assertEquals('paragraphStyle', $oText->getParagraphStyle());\n\n        $oText->setParagraphStyle(['alignment' => Jc::CENTER, 'spaceAfter' => 100]);\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph', $oText->getParagraphStyle());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Element/TitleTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\ndeclare(strict_types=1);\n\nnamespace PhpOffice\\PhpWordTests\\Element;\n\nuse InvalidArgumentException;\nuse PhpOffice\\PhpWord\\Element\\PageBreak;\nuse PhpOffice\\PhpWord\\Element\\TextRun;\nuse PhpOffice\\PhpWord\\Element\\Title;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Element\\Title.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Element\\Title\n *\n * @runTestsInSeparateProcesses\n */\nclass TitleTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Create new instance with string.\n     */\n    public function testConstruct(): void\n    {\n        $title = new Title('text');\n\n        self::assertEquals('text', $title->getText());\n        self::assertEquals(1, $title->getDepth());\n        self::assertNull($title->getPageNumber());\n        self::assertNull($title->getStyle());\n    }\n\n    /**\n     * Create new instance with TextRun.\n     */\n    public function testConstructWithTextRun(): void\n    {\n        $textRun = new TextRun();\n        $textRun->addText('text');\n        $title = new Title($textRun);\n\n        self::assertInstanceOf(TextRun::class, $title->getText());\n        self::assertEquals(1, $title->getDepth());\n        self::assertNull($title->getPageNumber());\n        self::assertNull($title->getStyle());\n    }\n\n    public function testConstructWithInvalidArgument(): void\n    {\n        $this->expectException(InvalidArgumentException::class);\n\n        new Title(new PageBreak());\n    }\n\n    public function testConstructWithPageNumber(): void\n    {\n        $title = new Title('text', 1, 0);\n\n        self::assertEquals('text', $title->getText());\n        self::assertEquals(0, $title->getPageNumber());\n        self::assertNull($title->getStyle());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Element/TrackChangeTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Element;\n\nuse DateTime;\nuse PhpOffice\\PhpWord\\Element\\Text;\nuse PhpOffice\\PhpWord\\Element\\TrackChange;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Element\\TrackChange.\n *\n * @runTestsInSeparateProcesses\n */\nclass TrackChangeTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * New instance.\n     */\n    public function testConstructDefault(): void\n    {\n        $author = 'Test User';\n        $date = new DateTime('2000-01-01');\n        $oTrackChange = new TrackChange(TrackChange::INSERTED, $author, $date);\n\n        $oText = new Text('dummy text');\n        $oText->setTrackChange($oTrackChange);\n\n        self::assertEquals($author, $oTrackChange->getAuthor());\n        self::assertEquals($date, $oTrackChange->getDate());\n        self::assertEquals(TrackChange::INSERTED, $oTrackChange->getChangeType());\n    }\n\n    /**\n     * New instance with invalid \\DateTime (produced by \\DateTime::createFromFormat(...)).\n     */\n    public function testConstructDefaultWithInvalidDate(): void\n    {\n        $author = 'Test User';\n        $date = false;\n        $oTrackChange = new TrackChange(TrackChange::INSERTED, $author, $date);\n\n        $oText = new Text('dummy text');\n        $oText->setTrackChange($oTrackChange);\n\n        self::assertEquals($author, $oTrackChange->getAuthor());\n        self::assertEquals($date, null);\n        self::assertEquals(TrackChange::INSERTED, $oTrackChange->getChangeType());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Escaper/RtfEscaper2Test.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Escaper;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Escaper\\RTF.\n */\nclass RtfEscaper2Test extends \\PHPUnit\\Framework\\TestCase\n{\n    const HEADER = '\\\\pard\\\\nowidctlpar {\\\\cf0\\\\f0 ';\n    const TRAILER = '}\\\\par';\n\n    public function escapestring($str)\n    {\n        \\PhpOffice\\PhpWord\\Settings::setOutputEscapingEnabled(true);\n        $parentWriter = new \\PhpOffice\\PhpWord\\Writer\\RTF();\n        $element = new \\PhpOffice\\PhpWord\\Element\\Text($str);\n        $txt = new \\PhpOffice\\PhpWord\\Writer\\RTF\\Element\\Text($parentWriter, $element);\n        $txt2 = trim($txt->write());\n\n        return $txt2;\n    }\n\n    public function expect($str)\n    {\n        return self::HEADER . $str . self::TRAILER;\n    }\n\n    /**\n     * Test special characters which require escaping.\n     */\n    public function testSpecial(): void\n    {\n        $str = 'Special characters { open brace } close brace \\\\ backslash';\n        $expect = $this->expect('Special characters \\\\{ open brace \\\\} close brace \\\\\\\\ backslash');\n        self::assertEquals($expect, $this->escapestring($str));\n    }\n\n    /**\n     * Test accented character.\n     */\n    public function testAccent(): void\n    {\n        $str = 'Voilà - string with accented char';\n        $expect = $this->expect('Voil\\\\uc0{\\\\u224} - string with accented char');\n        self::assertEquals($expect, $this->escapestring($str));\n    }\n\n    /**\n     * Test Hebrew.\n     */\n    public function testHebrew(): void\n    {\n        $str = 'Hebrew - שלום';\n        $expect = $this->expect('Hebrew - \\\\uc0{\\\\u1513}\\\\uc0{\\\\u1500}\\\\uc0{\\\\u1493}\\\\uc0{\\\\u1501}');\n        self::assertEquals($expect, $this->escapestring($str));\n    }\n\n    /**\n     * Test tab.\n     */\n    public function testTab(): void\n    {\n        $str = \"Here's a tab\\tfollowed by more characters.\";\n        $expect = $this->expect(\"Here's a tab{\\\\tab}followed by more characters.\");\n        self::assertEquals($expect, $this->escapestring($str));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Escaper/RtfEscaper3Test.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Escaper;\n\nuse PhpOffice\\PhpWord\\Settings;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Escaper\\RTF.\n */\nclass RtfEscaper3Test extends \\PHPUnit\\Framework\\TestCase\n{\n    const HEADER = '\\\\pard\\\\nowidctlpar \\ql{\\\\cf0\\\\f0 ';\n    const HEADER_RTL = '\\\\pard\\\\nowidctlpar \\qr{\\\\rtlch\\\\cf0\\\\f0 ';\n    const TRAILER = '}\\\\par';\n\n    protected function tearDown(): void\n    {\n        Settings::setDefaultRtl(null);\n    }\n\n    public function escapestring(string $str): string\n    {\n        Settings::setOutputEscapingEnabled(true);\n        $parentWriter = new \\PhpOffice\\PhpWord\\Writer\\RTF();\n        $element = new \\PhpOffice\\PhpWord\\Element\\Text($str);\n        $txt = new \\PhpOffice\\PhpWord\\Writer\\RTF\\Element\\Text($parentWriter, $element);\n        $txt2 = trim($txt->write());\n\n        return $txt2;\n    }\n\n    public function expect(string $str, bool $rtl = false): string\n    {\n        return ($rtl ? self:: HEADER_RTL : self::HEADER) . $str . self::TRAILER;\n    }\n\n    /**\n     * Test special characters which require escaping.\n     */\n    public function testSpecial(): void\n    {\n        Settings::setDefaultRtl(false);\n        $str = 'Special characters { open brace } close brace \\\\ backslash';\n        $expect = $this->expect('Special characters \\\\{ open brace \\\\} close brace \\\\\\\\ backslash');\n        self::assertEquals($expect, $this->escapestring($str));\n    }\n\n    /**\n     * Test accented character.\n     */\n    public function testAccent(): void\n    {\n        Settings::setDefaultRtl(false);\n        $str = 'Voilà - string with accented char';\n        $expect = $this->expect('Voil\\\\uc0{\\\\u224} - string with accented char');\n        self::assertEquals($expect, $this->escapestring($str));\n    }\n\n    /**\n     * Test Hebrew.\n     */\n    public function testHebrew(): void\n    {\n        Settings::setDefaultRtl(true);\n        $str = 'Hebrew - שלום';\n        $expect = $this->expect('Hebrew - \\\\uc0{\\\\u1513}\\\\uc0{\\\\u1500}\\\\uc0{\\\\u1493}\\\\uc0{\\\\u1501}', true);\n        self::assertEquals($expect, $this->escapestring($str));\n    }\n\n    /**\n     * Test tab.\n     */\n    public function testTab(): void\n    {\n        Settings::setDefaultRtl(false);\n        $str = \"Here's a tab\\tfollowed by more characters.\";\n        $expect = $this->expect(\"Here's a tab{\\\\tab}followed by more characters.\");\n        self::assertEquals($expect, $this->escapestring($str));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Exception/CopyFileExceptionTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Exception;\n\nuse PhpOffice\\PhpWord\\Exception\\CopyFileException;\n\n/**\n * @covers \\PhpOffice\\PhpWord\\Exception\\CopyFileException\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Exception\\CopyFileException\n */\nclass CopyFileExceptionTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * CopyFileException can be thrown.\n     */\n    public function testCopyFileExceptionCanBeThrown(): void\n    {\n        $this->expectException(CopyFileException::class);\n\n        throw new CopyFileException('C:\\source\\dummy.txt', 'C:\\destination\\dummy.txt');\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Exception/CreateTemporaryFileExceptionTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Exception;\n\nuse PhpOffice\\PhpWord\\Exception\\CreateTemporaryFileException;\n\n/**\n * @covers \\PhpOffice\\PhpWord\\Exception\\CreateTemporaryFileException\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Exception\\CreateTemporaryFileException\n */\nclass CreateTemporaryFileExceptionTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * CreateTemporaryFileException can be thrown.\n     */\n    public function testCreateTemporaryFileExceptionCanBeThrown(): void\n    {\n        $this->expectException(CreateTemporaryFileException::class);\n\n        throw new CreateTemporaryFileException();\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Exception/ExceptionTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Exception;\n\nuse PhpOffice\\PhpWord\\Exception\\Exception;\nuse PHPUnit\\Framework\\TestCase;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Exception\\Exception.\n *\n * @coversDefaultClass \\Exception\n *\n * @runTestsInSeparateProcesses\n */\nclass ExceptionTest extends TestCase\n{\n    /**\n     * Throw new exception.\n     *\n     * @covers            \\PhpOffice\\PhpWord\\Exception\\Exception\n     */\n    public function testThrowException(): void\n    {\n        $this->expectException(Exception::class);\n\n        throw new Exception();\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Exception/InvalidImageExceptionTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Exception;\n\nuse PhpOffice\\PhpWord\\Exception\\InvalidImageException;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Exception\\InvalidImageException.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Exception\\InvalidImageException\n *\n * @runTestsInSeparateProcesses\n */\nclass InvalidImageExceptionTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Throw new exception.\n     *\n     * @covers            \\PhpOffice\\PhpWord\\Exception\\InvalidImageException\n     */\n    public function testThrowException(): void\n    {\n        $this->expectException(InvalidImageException::class);\n\n        throw new InvalidImageException();\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Exception/InvalidStyleExceptionTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Exception;\n\nuse PhpOffice\\PhpWord\\Exception\\InvalidStyleException;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Exception\\InvalidStyleException.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Exception\\InvalidStyleException\n *\n * @runTestsInSeparateProcesses\n */\nclass InvalidStyleExceptionTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Throw new exception.\n     *\n     * @covers            \\PhpOffice\\PhpWord\\Exception\\InvalidStyleException\n     */\n    public function testThrowException(): void\n    {\n        $this->expectException(InvalidStyleException::class);\n\n        throw new InvalidStyleException();\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Exception/UnsupportedImageTypeExceptionTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Exception;\n\nuse PhpOffice\\PhpWord\\Exception\\UnsupportedImageTypeException;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Exception\\UnsupportedImageTypeExceptionTest.\n *\n * @runTestsInSeparateProcesses\n */\nclass UnsupportedImageTypeExceptionTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Throw new exception.\n     *\n     * @covers            \\PhpOffice\\PhpWord\\Exception\\UnsupportedImageTypeException\n     */\n    public function testThrowException(): void\n    {\n        $this->expectException(UnsupportedImageTypeException::class);\n\n        throw new UnsupportedImageTypeException();\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/IOFactoryTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests;\n\nuse PhpOffice\\PhpWord\\Exception\\Exception;\nuse PhpOffice\\PhpWord\\IOFactory;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Writer\\HTML;\nuse PhpOffice\\PhpWord\\Writer\\ODText;\nuse PhpOffice\\PhpWord\\Writer\\PDF;\nuse PhpOffice\\PhpWord\\Writer\\RTF;\nuse PhpOffice\\PhpWord\\Writer\\Word2007;\nuse PHPUnit\\Framework\\TestCase;\n\n/**\n * Test class for PhpOffice\\PhpWord\\IOFactory.\n *\n * @runTestsInSeparateProcesses\n */\nclass IOFactoryTest extends TestCase\n{\n    protected function setUp(): void\n    {\n        $rendererName = Settings::PDF_RENDERER_DOMPDF;\n        $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/dompdf/dompdf');\n        Settings::setPdfRenderer($rendererName, $rendererLibraryPath);\n    }\n\n    /**\n     * Create all possible writers.\n     *\n     * @dataProvider providerCreateWriter\n     */\n    public function testCreateWriter(string $name, string $expected): void\n    {\n        $phpWord = new PhpWord();\n        $actual = IOFactory::createWriter($phpWord, $name);\n        self::assertInstanceOf($expected, $actual);\n    }\n\n    public static function providerCreateWriter(): iterable\n    {\n        return [\n            ['ODText', ODText::class],\n            ['RTF', RTF::class],\n            ['Word2007', Word2007::class],\n            ['HTML', HTML::class],\n            ['PDF', PDF::class],\n        ];\n    }\n\n    /**\n     * Create existing writer.\n     */\n    public function testExistingWriterCanBeCreated(): void\n    {\n        self::assertInstanceOf(\n            'PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007',\n            IOFactory::createWriter(new PhpWord(), 'Word2007')\n        );\n    }\n\n    /**\n     * Create non-existing writer.\n     */\n    public function testNonexistentWriterCanNotBeCreated(): void\n    {\n        $this->expectException(Exception::class);\n        IOFactory::createWriter(new PhpWord(), 'Word2006');\n    }\n\n    /**\n     * Create existing reader.\n     */\n    public function testExistingReaderCanBeCreated(): void\n    {\n        self::assertInstanceOf(\n            'PhpOffice\\\\PhpWord\\\\Reader\\\\Word2007',\n            IOFactory::createReader('Word2007')\n        );\n    }\n\n    /**\n     * Create non-existing reader.\n     */\n    public function testNonexistentReaderCanNotBeCreated(): void\n    {\n        $this->expectException(Exception::class);\n        IOFactory::createReader('Word2006');\n    }\n\n    /**\n     * Load document.\n     */\n    public function testLoad(): void\n    {\n        $file = __DIR__ . '/_files/templates/blank.docx';\n        self::assertInstanceOf(\n            'PhpOffice\\\\PhpWord\\\\PhpWord',\n            IOFactory::load($file)\n        );\n    }\n\n    /**\n     * Test for extractVariables method.\n     */\n    public function testExtractVariables(): void\n    {\n        $file = __DIR__ . '/_files/templates/extract-variable.docx';\n        $extractedVariables = IOFactory::extractVariables($file, 'Word2007');\n\n        $expectedVariables = ['date', 'A1', 'B1'];\n\n        self::assertEquals($expectedVariables, $extractedVariables, 'Extracted variables do not match expected variables.');\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/MediaTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests;\n\nuse Exception;\nuse PhpOffice\\PhpWord\\Element\\Image;\nuse PhpOffice\\PhpWord\\Media;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Media.\n *\n * @runTestsInSeparateProcesses\n */\nclass MediaTest extends AbstractWebServerEmbedded\n{\n    /**\n     * Get section media elements.\n     */\n    public function testGetSectionMediaElementsWithNull(): void\n    {\n        self::assertEquals([], Media::getElements('section'));\n    }\n\n    /**\n     * Get header media elements.\n     */\n    public function testGetHeaderMediaElementsWithNull(): void\n    {\n        self::assertEquals([], Media::getElements('header'));\n    }\n\n    /**\n     * Get footer media elements.\n     */\n    public function testGetFooterMediaElementsWithNull(): void\n    {\n        self::assertEquals([], Media::getElements('footer'));\n    }\n\n    /**\n     * Count section media elements.\n     */\n    public function testCountSectionMediaElementsWithNull(): void\n    {\n        self::assertEquals(0, Media::countElements('section'));\n    }\n\n    /**\n     * Add section media element.\n     */\n    public function testAddSectionMediaElement(): void\n    {\n        $local = __DIR__ . '/_files/images/mars.jpg';\n        $object = __DIR__ . '/_files/documents/sheet.xls';\n        $remote = self::getRemoteImageUrl();\n        Media::addElement('section', 'image', $local, new Image($local));\n        Media::addElement('section', 'image', $local, new Image($local));\n        Media::addElement('section', 'image', $remote, new Image($local));\n        Media::addElement('section', 'object', $object);\n        Media::addElement('section', 'object', $object);\n\n        self::assertCount(3, Media::getElements('section'));\n    }\n\n    /**\n     * Add section link.\n     */\n    public function testAddSectionLinkElement(): void\n    {\n        $expected = Media::countElements('section') + 1;\n        $actual = Media::addElement('section', 'link', 'http://test.com');\n\n        self::assertEquals($expected, $actual);\n        self::assertCount(1, Media::getElements('section', 'link'));\n    }\n\n    /**\n     * Add header media element.\n     */\n    public function testAddHeaderMediaElement(): void\n    {\n        $local = __DIR__ . '/_files/images/mars.jpg';\n        $remote = self::getRemoteImageUrl();\n        Media::addElement('header1', 'image', $local, new Image($local));\n        Media::addElement('header1', 'image', $local, new Image($local));\n        Media::addElement('header1', 'image', $remote, new Image($remote));\n\n        self::assertCount(2, Media::getElements('header1'));\n        self::assertEmpty(Media::getElements('header2'));\n    }\n\n    /**\n     * Add footer media element and reset media.\n     */\n    public function testAddFooterMediaElement(): void\n    {\n        $local = __DIR__ . '/_files/images/mars.jpg';\n        $remote = self::getRemoteImageUrl();\n        Media::addElement('footer1', 'image', $local, new Image($local));\n        Media::addElement('footer1', 'image', $local, new Image($local));\n        Media::addElement('footer1', 'image', $remote, new Image($remote));\n\n        self::assertCount(2, Media::getElements('footer1'));\n\n        Media::resetElements();\n        self::assertCount(0, Media::getElements('footer1'));\n    }\n\n    /**\n     * Add image element exception.\n     */\n    public function testAddElementImageException(): void\n    {\n        $this->expectException(Exception::class);\n        $this->expectExceptionMessage('Image object not assigned.');\n        Media::addElement('section', 'image', __DIR__ . '/_files/images/mars.jpg');\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Metadata/DocInfoTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Metadata;\n\nuse PhpOffice\\PhpWord\\Metadata\\DocInfo;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Metadata\\DocInfo.\n *\n * @runTestsInSeparateProcesses\n */\nclass DocInfoTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Creator.\n     */\n    public function testCreator(): void\n    {\n        $oProperties = new DocInfo();\n        $oProperties->setCreator();\n        self::assertEquals('', $oProperties->getCreator());\n\n        $oProperties->setCreator('AAA');\n        self::assertEquals('AAA', $oProperties->getCreator());\n    }\n\n    /**\n     * Last modified by.\n     */\n    public function testLastModifiedBy(): void\n    {\n        $oProperties = new DocInfo();\n        $oProperties->setLastModifiedBy();\n        self::assertEquals('', $oProperties->getLastModifiedBy());\n\n        $oProperties->setLastModifiedBy('AAA');\n        self::assertEquals('AAA', $oProperties->getLastModifiedBy());\n    }\n\n    /**\n     * Created.\n     */\n    public function testCreated(): void\n    {\n        $oProperties = new DocInfo();\n        $oProperties->setCreated();\n        self::assertEquals(time(), $oProperties->getCreated());\n\n        $iTime = time() + 3600;\n        $oProperties->setCreated($iTime);\n        self::assertEquals($iTime, $oProperties->getCreated());\n    }\n\n    /**\n     * Modified.\n     */\n    public function testModified(): void\n    {\n        $oProperties = new DocInfo();\n        $oProperties->setModified();\n        self::assertEquals(time(), $oProperties->getModified());\n\n        $iTime = time() + 3600;\n        $oProperties->setModified($iTime);\n        self::assertEquals($iTime, $oProperties->getModified());\n    }\n\n    /**\n     * Title.\n     */\n    public function testTitle(): void\n    {\n        $oProperties = new DocInfo();\n        $oProperties->setTitle();\n        self::assertEquals('', $oProperties->getTitle());\n\n        $oProperties->setTitle('AAA');\n        self::assertEquals('AAA', $oProperties->getTitle());\n    }\n\n    /**\n     * Description.\n     */\n    public function testDescription(): void\n    {\n        $oProperties = new DocInfo();\n        $oProperties->setDescription();\n        self::assertEquals('', $oProperties->getDescription());\n\n        $oProperties->setDescription('AAA');\n        self::assertEquals('AAA', $oProperties->getDescription());\n    }\n\n    /**\n     * Subject.\n     */\n    public function testSubject(): void\n    {\n        $oProperties = new DocInfo();\n        $oProperties->setSubject();\n        self::assertEquals('', $oProperties->getSubject());\n\n        $oProperties->setSubject('AAA');\n        self::assertEquals('AAA', $oProperties->getSubject());\n    }\n\n    /**\n     * Keywords.\n     */\n    public function testKeywords(): void\n    {\n        $oProperties = new DocInfo();\n        $oProperties->setKeywords();\n        self::assertEquals('', $oProperties->getKeywords());\n\n        $oProperties->setKeywords('AAA');\n        self::assertEquals('AAA', $oProperties->getKeywords());\n    }\n\n    /**\n     * Category.\n     */\n    public function testCategory(): void\n    {\n        $oProperties = new DocInfo();\n        $oProperties->setCategory();\n        self::assertEquals('', $oProperties->getCategory());\n\n        $oProperties->setCategory('AAA');\n        self::assertEquals('AAA', $oProperties->getCategory());\n    }\n\n    /**\n     * Company.\n     */\n    public function testCompany(): void\n    {\n        $oProperties = new DocInfo();\n        $oProperties->setCompany();\n        self::assertEquals('', $oProperties->getCompany());\n\n        $oProperties->setCompany('AAA');\n        self::assertEquals('AAA', $oProperties->getCompany());\n    }\n\n    /**\n     * Manager.\n     */\n    public function testManager(): void\n    {\n        $oProperties = new DocInfo();\n        $oProperties->setManager();\n        self::assertEquals('', $oProperties->getManager());\n\n        $oProperties->setManager('AAA');\n        self::assertEquals('AAA', $oProperties->getManager());\n    }\n\n    /**\n     * Custom properties.\n     */\n    public function testCustomProperty(): void\n    {\n        $oProperties = new DocInfo();\n        $oProperties->setCustomProperty('key1', null);\n        $oProperties->setCustomProperty('key2', true);\n        $oProperties->setCustomProperty('key3', 3);\n        $oProperties->setCustomProperty('key4', 4.4);\n        $oProperties->setCustomProperty('key5', 'value5');\n        self::assertEquals(DocInfo::PROPERTY_TYPE_STRING, $oProperties->getCustomPropertyType('key1'));\n        self::assertEquals(DocInfo::PROPERTY_TYPE_BOOLEAN, $oProperties->getCustomPropertyType('key2'));\n        self::assertEquals(DocInfo::PROPERTY_TYPE_INTEGER, $oProperties->getCustomPropertyType('key3'));\n        self::assertEquals(DocInfo::PROPERTY_TYPE_FLOAT, $oProperties->getCustomPropertyType('key4'));\n        self::assertEquals(DocInfo::PROPERTY_TYPE_STRING, $oProperties->getCustomPropertyType('key5'));\n        self::assertNull($oProperties->getCustomPropertyType('key6'));\n        self::assertNull($oProperties->getCustomPropertyValue('key1'));\n        self::assertTrue($oProperties->getCustomPropertyValue('key2'));\n        self::assertEquals(3, $oProperties->getCustomPropertyValue('key3'));\n        self::assertEquals(4.4, $oProperties->getCustomPropertyValue('key4'));\n        self::assertEquals('value5', $oProperties->getCustomPropertyValue('key5'));\n        self::assertNull($oProperties->getCustomPropertyValue('key6'));\n        self::assertTrue($oProperties->isCustomPropertySet('key5'));\n        self::assertNotTrue($oProperties->isCustomPropertySet('key6'));\n        self::assertEquals(['key1', 'key2', 'key3', 'key4', 'key5'], $oProperties->getCustomProperties());\n    }\n\n    /**\n     * Convert property.\n     */\n    public function testConvertProperty(): void\n    {\n        self::assertEquals('', DocInfo::convertProperty('a', 'empty'));\n        self::assertNull(DocInfo::convertProperty('a', 'null'));\n        self::assertEquals(8, DocInfo::convertProperty('8', 'int'));\n        self::assertEquals(8, DocInfo::convertProperty('8.3', 'uint'));\n        self::assertEquals(8.3, DocInfo::convertProperty('8.3', 'decimal'));\n        self::assertEquals('8.3', DocInfo::convertProperty('8.3', 'lpstr'));\n        self::assertEquals(strtotime('10/11/2013'), DocInfo::convertProperty('10/11/2013', 'date'));\n        self::assertTrue(DocInfo::convertProperty('true', 'bool'));\n        self::assertNotTrue(DocInfo::convertProperty('1', 'bool'));\n        self::assertEquals('1', DocInfo::convertProperty('1', 'array'));\n        self::assertEquals('1', DocInfo::convertProperty('1', ''));\n\n        self::assertEquals(DocInfo::PROPERTY_TYPE_INTEGER, DocInfo::convertPropertyType('int'));\n        self::assertEquals(DocInfo::PROPERTY_TYPE_INTEGER, DocInfo::convertPropertyType('uint'));\n        self::assertEquals(DocInfo::PROPERTY_TYPE_FLOAT, DocInfo::convertPropertyType('decimal'));\n        self::assertEquals(DocInfo::PROPERTY_TYPE_STRING, DocInfo::convertPropertyType('lpstr'));\n        self::assertEquals(DocInfo::PROPERTY_TYPE_DATE, DocInfo::convertPropertyType('date'));\n        self::assertEquals(DocInfo::PROPERTY_TYPE_BOOLEAN, DocInfo::convertPropertyType('bool'));\n        self::assertEquals(DocInfo::PROPERTY_TYPE_UNKNOWN, DocInfo::convertPropertyType('array'));\n        self::assertEquals(DocInfo::PROPERTY_TYPE_UNKNOWN, DocInfo::convertPropertyType(''));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Metadata/SettingsTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Metadata;\n\nuse InvalidArgumentException;\nuse PhpOffice\\PhpWord\\ComplexType\\ProofState;\nuse PhpOffice\\PhpWord\\Metadata\\Protection;\nuse PhpOffice\\PhpWord\\Metadata\\Settings;\nuse PhpOffice\\PhpWord\\SimpleType\\Zoom;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Metadata\\Settings.\n *\n * @runTestsInSeparateProcesses\n */\nclass SettingsTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * EvenAndOddHeaders.\n     */\n    public function testSetEvenAndOddHeaders(): void\n    {\n        $oSettings = new Settings();\n        $oSettings->setEvenAndOddHeaders(true);\n        self::assertTrue($oSettings->hasEvenAndOddHeaders());\n    }\n\n    /**\n     * HideGrammaticalErrors.\n     */\n    public function testHideGrammaticalErrors(): void\n    {\n        $oSettings = new Settings();\n        $oSettings->setHideGrammaticalErrors(true);\n        self::assertTrue($oSettings->hasHideGrammaticalErrors());\n    }\n\n    /**\n     * HideSpellingErrors.\n     */\n    public function testHideSpellingErrors(): void\n    {\n        $oSettings = new Settings();\n        $oSettings->setHideSpellingErrors(true);\n        self::assertTrue($oSettings->hasHideSpellingErrors());\n    }\n\n    /**\n     * DocumentProtection.\n     */\n    public function testDocumentProtection(): void\n    {\n        $oSettings = new Settings();\n        $oSettings->setDocumentProtection(new Protection('trackedChanges'));\n        self::assertNotNull($oSettings->getDocumentProtection());\n\n        self::assertEquals('trackedChanges', $oSettings->getDocumentProtection()->getEditing());\n    }\n\n    /**\n     * Test setting an invalid salt.\n     */\n    public function testInvalidSalt(): void\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $protection = new Protection();\n        $protection->setSalt('123');\n    }\n\n    /**\n     * TrackRevistions.\n     */\n    public function testTrackRevisions(): void\n    {\n        $oSettings = new Settings();\n        $oSettings->setTrackRevisions(true);\n        self::assertTrue($oSettings->hasTrackRevisions());\n    }\n\n    /**\n     * DoNotTrackFormatting.\n     */\n    public function testDoNotTrackFormatting(): void\n    {\n        $oSettings = new Settings();\n        $oSettings->setDoNotTrackFormatting(true);\n        self::assertTrue($oSettings->hasDoNotTrackFormatting());\n    }\n\n    /**\n     * DoNotTrackMoves.\n     */\n    public function testDoNotTrackMoves(): void\n    {\n        $oSettings = new Settings();\n        $oSettings->setDoNotTrackMoves(true);\n        self::assertTrue($oSettings->hasDoNotTrackMoves());\n    }\n\n    /**\n     * ProofState.\n     */\n    public function testProofState(): void\n    {\n        $proofState = new ProofState();\n        $proofState->setGrammar(ProofState::CLEAN);\n        $proofState->setSpelling(ProofState::DIRTY);\n\n        $oSettings = new Settings();\n        $oSettings->setProofState($proofState);\n        self::assertNotNull($oSettings->getProofState());\n        self::assertEquals(ProofState::CLEAN, $oSettings->getProofState()->getGrammar());\n        self::assertEquals(ProofState::DIRTY, $oSettings->getProofState()->getSpelling());\n    }\n\n    public function testWrongProofStateGrammar(): void\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $proofState = new ProofState();\n        $proofState->setGrammar('wrong');\n    }\n\n    public function testWrongProofStateSpelling(): void\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $proofState = new ProofState();\n        $proofState->setSpelling('wrong');\n    }\n\n    /**\n     * Zoom as percentage.\n     */\n    public function testZoomPercentage(): void\n    {\n        $oSettings = new Settings();\n        $oSettings->setZoom(75);\n        self::assertEquals(75, $oSettings->getZoom());\n    }\n\n    /**\n     * Zoom as string.\n     */\n    public function testZoomEnum(): void\n    {\n        $oSettings = new Settings();\n        $oSettings->setZoom(Zoom::FULL_PAGE);\n        self::assertEquals('fullPage', $oSettings->getZoom());\n    }\n\n    /**\n     * Test Update Fields on update.\n     */\n    public function testUpdateFields(): void\n    {\n        $oSettings = new Settings();\n        $oSettings->setUpdateFields(true);\n        self::assertTrue($oSettings->hasUpdateFields());\n    }\n\n    public function testAutoHyphenation(): void\n    {\n        $oSettings = new Settings();\n        $oSettings->setAutoHyphenation(true);\n        self::assertTrue($oSettings->hasAutoHyphenation());\n    }\n\n    public function testDefaultAutoHyphenation(): void\n    {\n        $oSettings = new Settings();\n        self::assertNull($oSettings->hasAutoHyphenation());\n    }\n\n    public function testConsecutiveHyphenLimit(): void\n    {\n        $consecutiveHypenLimit = 2;\n        $oSettings = new Settings();\n        $oSettings->setConsecutiveHyphenLimit($consecutiveHypenLimit);\n        self::assertSame($consecutiveHypenLimit, $oSettings->getConsecutiveHyphenLimit());\n    }\n\n    public function testDefaultConsecutiveHyphenLimit(): void\n    {\n        $oSettings = new Settings();\n        self::assertNull($oSettings->getConsecutiveHyphenLimit());\n    }\n\n    public function testHyphenationZone(): void\n    {\n        $hyphenationZoneInTwip = 100;\n        $oSettings = new Settings();\n        $oSettings->setHyphenationZone($hyphenationZoneInTwip);\n        self::assertSame($hyphenationZoneInTwip, $oSettings->getHyphenationZone());\n    }\n\n    public function testDefaultHyphenationZone(): void\n    {\n        $oSettings = new Settings();\n        self::assertNull($oSettings->getHyphenationZone());\n    }\n\n    public function testDoNotHyphenateCaps(): void\n    {\n        $oSettings = new Settings();\n        $oSettings->setDoNotHyphenateCaps(true);\n        self::assertTrue($oSettings->hasDoNotHyphenateCaps());\n    }\n\n    public function testDefaultDoNotHyphenateCaps(): void\n    {\n        $oSettings = new Settings();\n        self::assertNull($oSettings->hasDoNotHyphenateCaps());\n    }\n\n    public function testBookFoldPrinting(): void\n    {\n        $oSettings = new Settings();\n\n        $oSettings->setBookFoldPrinting(true);\n        self::assertTrue($oSettings->hasBookFoldPrinting());\n\n        $oSettings->setBookFoldPrinting(false);\n        self::assertFalse($oSettings->hasBookFoldPrinting());\n    }\n\n    public function testDefaultBookFoldPrinting(): void\n    {\n        $oSettings = new Settings();\n        self::assertFalse($oSettings->hasBookFoldPrinting());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/PhpWordTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests;\n\nuse BadMethodCallException;\nuse DateTimeImmutable;\nuse PhpOffice\\PhpWord\\Metadata\\DocInfo;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Style;\n\n/**\n * Test class for PhpOffice\\PhpWord\\PhpWord.\n *\n * @runTestsInSeparateProcesses\n */\nclass PhpWordTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test object creation.\n     */\n    public function testConstruct(): void\n    {\n        do {\n            $dtStart = new DateTimeImmutable();\n            $startSecond = $dtStart->format('s');\n            $phpWord = new PhpWord();\n            $docInfo = new DocInfo();\n            $endSecond = (new DateTimeImmutable('now'))->format('s');\n        } while ($startSecond !== $endSecond);\n        self::assertEquals($docInfo, $phpWord->getDocInfo());\n        self::assertEquals(Settings::DEFAULT_FONT_NAME, $phpWord->getDefaultFontName());\n        self::assertEquals(Settings::DEFAULT_FONT_SIZE, $phpWord->getDefaultFontSize());\n    }\n\n    /**\n     * Test create/get section.\n     */\n    public function testCreateGetSections(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->addSection();\n        self::assertCount(1, $phpWord->getSections());\n    }\n\n    /**\n     * Test set/get default font name.\n     */\n    public function testSetGetDefaultFontName(): void\n    {\n        $phpWord = new PhpWord();\n        $fontName = 'Times New Roman';\n        self::assertEquals(Settings::DEFAULT_FONT_NAME, $phpWord->getDefaultFontName());\n        $phpWord->setDefaultFontName($fontName);\n        self::assertEquals($fontName, $phpWord->getDefaultFontName());\n    }\n\n    /**\n     * Test set/get default font size.\n     */\n    public function testSetGetDefaultFontSize(): void\n    {\n        $phpWord = new PhpWord();\n        $fontSize = 16;\n        self::assertEquals(Settings::DEFAULT_FONT_SIZE, $phpWord->getDefaultFontSize());\n        $phpWord->setDefaultFontSize($fontSize);\n        self::assertEquals($fontSize, $phpWord->getDefaultFontSize());\n    }\n\n    /**\n     * Test set/get default asian font name.\n     */\n    public function testSetGetDefaultAsianFontName(): void\n    {\n        $phpWord = new PhpWord();\n        $fontName = 'Times New Roman';\n        self::assertEquals(Settings::DEFAULT_FONT_NAME, $phpWord->getDefaultAsianFontName());\n        $phpWord->setDefaultAsianFontName($fontName);\n        self::assertEquals($fontName, $phpWord->getDefaultAsianFontName());\n    }\n\n    /**\n     * Test set/get default font color.\n     */\n    public function testSetGetDefaultFontColor(): void\n    {\n        $phpWord = new PhpWord();\n        $fontColor = 'FF0000';\n        self::assertEquals(Settings::DEFAULT_FONT_COLOR, $phpWord->getDefaultFontColor());\n        $phpWord->setDefaultFontColor($fontColor);\n        self::assertEquals($fontColor, $phpWord->getDefaultFontColor());\n    }\n\n    /**\n     * Test set default paragraph style.\n     */\n    public function testSetDefaultParagraphStyle(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->setDefaultParagraphStyle([]);\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph', Style::getStyle('Normal'));\n    }\n\n    /**\n     * Test add styles.\n     */\n    public function testAddStyles(): void\n    {\n        $phpWord = new PhpWord();\n        $styles = [\n            'Paragraph' => 'Paragraph',\n            'Font' => 'Font',\n            'Table' => 'Table',\n            'Link' => 'Font',\n        ];\n        foreach ($styles as $key => $value) {\n            $method = \"add{$key}Style\";\n            $styleId = \"{$key} Style\";\n            $phpWord->$method($styleId, []);\n            self::assertInstanceOf(\"PhpOffice\\\\PhpWord\\\\Style\\\\{$value}\", Style::getStyle($styleId));\n        }\n    }\n\n    /**\n     * Test add title style.\n     */\n    public function testAddTitleStyle(): void\n    {\n        $phpWord = new PhpWord();\n        $titleLevel = 1;\n        $titleName = \"Heading_{$titleLevel}\";\n        $phpWord->addTitleStyle($titleLevel, []);\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Font', Style::getStyle($titleName));\n    }\n\n    /**\n     * Test save.\n     */\n    public function testSave(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $section->addText('Hello world!');\n        ob_start();\n        self::assertTrue($phpWord->save('test.docx', 'Word2007', true));\n        $contents = ob_get_contents();\n        self::assertTrue(ob_end_clean());\n        self::assertNotEmpty($contents);\n    }\n\n    /**\n     * Test calling undefined method.\n     */\n    public function testCallUndefinedMethod(): void\n    {\n        $this->expectException(BadMethodCallException::class);\n        $this->expectExceptionMessage('is not defined');\n        $phpWord = new PhpWord();\n        $phpWord->undefinedMethod();\n    }\n\n    /**\n     * @covers \\PhpOffice\\PhpWord\\PhpWord::getSection\n     */\n    public function testGetNotExistingSection(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->getSection(0);\n\n        self::assertNull($section);\n    }\n\n    /**\n     * @covers \\PhpOffice\\PhpWord\\PhpWord::getSection\n     */\n    public function testGetSection(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->addSection();\n        $section = $phpWord->getSection(0);\n\n        self::assertNotNull($section);\n    }\n\n    /**\n     * @covers \\PhpOffice\\PhpWord\\PhpWord::sortSections\n     */\n    public function testSortSections(): void\n    {\n        $phpWord = new PhpWord();\n        $section1 = $phpWord->addSection();\n        $section1->addText('test1');\n        $section2 = $phpWord->addSection();\n        $section2->addText('test2');\n        $section2->addText('test3');\n\n        self::assertEquals(1, $phpWord->getSection(0)->countElements());\n        self::assertEquals(2, $phpWord->getSection(1)->countElements());\n\n        $phpWord->sortSections(function ($a, $b) {\n            $numElementsInA = $a->countElements();\n            $numElementsInB = $b->countElements();\n            if ($numElementsInA === $numElementsInB) {\n                return 0;\n            } elseif ($numElementsInA > $numElementsInB) {\n                return -1;\n            }\n\n            return 1;\n        });\n\n        self::assertEquals(2, $phpWord->getSection(0)->countElements());\n        self::assertEquals(1, $phpWord->getSection(1)->countElements());\n    }\n\n    /**\n     * @covers \\PhpOffice\\PhpWord\\PhpWord::getSettings\n     */\n    public function testGetSettings(): void\n    {\n        $phpWord = new PhpWord();\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Metadata\\\\Settings', $phpWord->getSettings());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Reader/HTMLTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Reader;\n\nuse Exception;\nuse PhpOffice\\PhpWord\\IOFactory;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Reader\\HTML.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Reader\\HTML\n *\n * @runTestsInSeparateProcesses\n */\nclass HTMLTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test load.\n     */\n    public function testLoad(): void\n    {\n        $filename = __DIR__ . '/../_files/documents/reader.html';\n        $phpWord = IOFactory::load($filename, 'HTML');\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\PhpWord', $phpWord);\n    }\n\n    /**\n     * Test load exception.\n     */\n    public function testLoadException(): void\n    {\n        $this->expectException(Exception::class);\n        $this->expectExceptionMessage('Cannot read');\n        $filename = __DIR__ . '/../_files/documents/foo.html';\n        IOFactory::load($filename, 'HTML');\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Reader/MsDocTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Reader;\n\nuse Exception;\nuse PhpOffice\\PhpWord\\Element\\Text;\nuse PhpOffice\\PhpWord\\IOFactory;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Reader\\MsDoc;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Reader\\MsDoc.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Reader\\MsDoc\n *\n * @runTestsInSeparateProcesses\n */\nclass MsDocTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test canRead() method.\n     */\n    public function testCanRead(): void\n    {\n        $object = new MsDoc();\n        $filename = __DIR__ . '/../_files/documents/reader.doc';\n        self::assertTrue($object->canRead($filename));\n    }\n\n    /**\n     * Can read exception.\n     */\n    public function testCanReadFailed(): void\n    {\n        $object = new MsDoc();\n        $filename = __DIR__ . '/../_files/documents/foo.doc';\n        self::assertFalse($object->canRead($filename));\n    }\n\n    public function testLoadBasic(): void\n    {\n        $filename = __DIR__ . '/../_files/documents/reader.doc';\n        $phpWord = IOFactory::load($filename, 'MsDoc');\n        self::assertInstanceOf(PhpWord::class, $phpWord);\n\n        $sections = $phpWord->getSections();\n        self::assertCount(1, $sections);\n        $elements = $sections[0]->getElements();\n        self::assertArrayHasKey(0, $elements);\n        /** @var Text $element0 */\n        $element0 = $elements[0];\n        self::assertInstanceOf(Text::class, $element0);\n        self::assertEquals('Welcome to PhpWord', $element0->getText());\n    }\n\n    public function testLoadHalfPointFont(): void\n    {\n        $filename = __DIR__ . '/../_files/documents/reader.font-halfpoint.doc';\n        $phpWord = IOFactory::load($filename, 'MsDoc');\n        $sections = $phpWord->getSections();\n        self::assertCount(1, $sections);\n        $elements = $sections[0]->getElements();\n        self::assertArrayHasKey(0, $elements);\n        $element0 = $elements[0];\n        if (method_exists($element0, 'getFontStyle')) {\n            self::assertSame(19.5, $element0->getFontStyle()->getSize());\n        } else {\n            self::fail('Unexpected no font style for first element');\n        }\n    }\n\n    public function testLoadChinese(): void\n    {\n        $filename = __DIR__ . '/../_files/documents/docChinese.doc';\n        $phpWord = IOFactory::load($filename, 'MsDoc');\n        self::assertInstanceOf(PhpWord::class, $phpWord);\n\n        $sections = $phpWord->getSections();\n        self::assertCount(1, $sections);\n        $elements = $sections[0]->getElements();\n        self::assertArrayHasKey(0, $elements);\n        /** @var Text $element0 */\n        $element0 = $elements[0];\n        self::assertInstanceOf(Text::class, $element0);\n        self::assertEquals('OKKI AI 客户案例', $element0->getText());\n    }\n\n    public function testLoadCzech(): void\n    {\n        $filename = __DIR__ . '/../_files/documents/docCzech.doc';\n        $phpWord = IOFactory::load($filename, 'MsDoc');\n        self::assertInstanceOf(PhpWord::class, $phpWord);\n\n        $sections = $phpWord->getSections();\n        self::assertCount(1, $sections);\n        $elements = $sections[0]->getElements();\n        self::assertArrayHasKey(0, $elements);\n        /** @var Text $element0 */\n        $element0 = $elements[0];\n        self::assertInstanceOf(Text::class, $element0);\n        self::assertEquals('Příliš žluťoučký kůň pěl ďábelské ódy', $element0->getText());\n    }\n\n    public function testLoadSlovak(): void\n    {\n        $filename = __DIR__ . '/../_files/documents/docSlovak.doc';\n        $phpWord = IOFactory::load($filename, 'MsDoc');\n        self::assertInstanceOf(PhpWord::class, $phpWord);\n\n        $sections = $phpWord->getSections();\n        self::assertCount(1, $sections);\n        $elements = $sections[0]->getElements();\n        self::assertArrayHasKey(0, $elements);\n        /** @var Text $element0 */\n        $element0 = $elements[0];\n        self::assertInstanceOf(Text::class, $element0);\n        self::assertEquals('Pondelok', $element0->getText());\n    }\n\n    /**\n     * Test exception on not existing file.\n     */\n    public function testFailIfFileNotReadable(): void\n    {\n        $this->expectException(Exception::class);\n        $filename = __DIR__ . '/../_files/documents/not_existing_reader.doc';\n        IOFactory::load($filename, 'MsDoc');\n    }\n\n    /**\n     * Test exception on non OLE document.\n     */\n    public function testFailIfFileNotOle(): void\n    {\n        $this->expectException(Exception::class);\n        $filename = __DIR__ . '/../_files/documents/reader.odt';\n        IOFactory::load($filename, 'MsDoc');\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Reader/ODText/ODTextSectionTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Reader\\ODText;\n\nuse PhpOffice\\PhpWord\\IOFactory;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Settings;\n\nclass ODTextSectionTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /** @var string */\n    private $filename = '';\n\n    protected function tearDown(): void\n    {\n        if ($this->filename !== '') {\n            unlink($this->filename);\n            $this->filename = '';\n        }\n    }\n\n    public function testWriteThenReadSection(): void\n    {\n        $dir = 'tests/PhpWordTests/_files';\n        Settings::setOutputEscapingEnabled(true);\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $inputText = ['days', 'monday', 'tuesday'];\n        $inputText[] = \"Tab\\tthen two spaces  then done.\";\n        foreach ($inputText as $text) {\n            $section->addText($text);\n        }\n        $writer = IOFactory::createWriter($phpWord, 'ODText');\n        $this->filename = \"$dir/sectiontest.odt\";\n        $writer->save($this->filename);\n\n        $reader = IOFactory::createReader('ODText');\n        $phpWord2 = $reader->load($this->filename);\n        $outputText = [];\n        foreach ($phpWord2->getSections() as $section) {\n            foreach ($section->getElements() as $element) {\n                if (is_object($element) && method_exists($element, 'getText')) {\n                    $outputText[] = $element->getText();\n                }\n            }\n        }\n        self::assertSame($inputText, $outputText);\n    }\n\n    public function testReadNoSections(): void\n    {\n        $dir = 'tests/PhpWordTests/_files/documents';\n        $inputText = ['days', 'monday', 'tuesday'];\n\n        $reader = IOFactory::createReader('ODText');\n        $filename = \"$dir/word.2493.nosection.odt\";\n        $phpWord2 = $reader->load($filename);\n        $outputText = [];\n        foreach ($phpWord2->getSections() as $section) {\n            foreach ($section->getElements() as $element) {\n                if (is_object($element) && method_exists($element, 'getText')) {\n                    $outputText[] = $element->getText();\n                }\n            }\n        }\n        self::assertSame($inputText, $outputText);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Reader/ODTextTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Reader;\n\nuse PhpOffice\\Math\\Element;\nuse PhpOffice\\PhpWord\\Element\\Formula;\nuse PhpOffice\\PhpWord\\Element\\Section;\nuse PhpOffice\\PhpWord\\IOFactory;\nuse PhpOffice\\PhpWord\\PhpWord;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Reader\\ODText.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Reader\\ODText\n *\n * @runTestsInSeparateProcesses\n */\nclass ODTextTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Load.\n     */\n    public function testLoad(): void\n    {\n        $phpWord = IOFactory::load(dirname(__DIR__, 1) . '/_files/documents/reader.odt', 'ODText');\n        self::assertInstanceOf(PhpWord::class, $phpWord);\n    }\n\n    public function testLoadFormula(): void\n    {\n        $phpWord = IOFactory::load(dirname(__DIR__, 1) . '/_files/documents/reader-formula.odt', 'ODText');\n\n        self::assertInstanceOf(PhpWord::class, $phpWord);\n\n        $sections = $phpWord->getSections();\n        self::assertCount(1, $sections);\n\n        $section = $sections[0];\n        self::assertInstanceOf(Section::class, $section);\n\n        $elements = $section->getElements();\n        self::assertCount(1, $elements);\n\n        $element = $elements[0];\n        self::assertInstanceOf(Formula::class, $element);\n\n        $elements = $element->getMath()->getElements();\n        self::assertCount(1, $elements);\n\n        self::assertInstanceOf(Element\\Semantics::class, $elements[0]);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Reader/RTFTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Reader;\n\nuse Exception;\nuse PhpOffice\\PhpWord\\IOFactory;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Reader\\RTF.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Reader\\RTF\n *\n * @runTestsInSeparateProcesses\n */\nclass RTFTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test load.\n     */\n    public function testLoad(): void\n    {\n        $filename = __DIR__ . '/../_files/documents/reader.rtf';\n        $phpWord = IOFactory::load($filename, 'RTF');\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\PhpWord', $phpWord);\n    }\n\n    /**\n     * Test load exception.\n     */\n    public function testLoadException(): void\n    {\n        $this->expectException(Exception::class);\n        $this->expectExceptionMessage('Cannot read');\n        $filename = __DIR__ . '/../_files/documents/foo.rtf';\n        IOFactory::load($filename, 'RTF');\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Reader/Word2007/ElementTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Reader\\Word2007;\n\nuse PhpOffice\\PhpWord\\ComplexType\\RubyProperties;\nuse PhpOffice\\PhpWord\\Element\\Ruby;\nuse PhpOffice\\PhpWord\\Element\\Text;\nuse PhpOffice\\PhpWord\\Element\\TrackChange;\nuse PhpOffice\\PhpWord\\Style\\Font;\nuse PhpOffice\\PhpWordTests\\AbstractTestReader;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Reader\\Word2007\\Element subnamespace.\n */\nclass ElementTest extends AbstractTestReader\n{\n    /**\n     * Test reading of alternate content value.\n     */\n    public function testReadAlternateContent(): void\n    {\n        $documentXml = '<w:p>\n            <w:r>\n                <mc:AlternateContent>\n                    <mc:Choice Requires=\"wps\"></mc:Choice>\n                    <mc:Fallback>\n                        <w:pict>\n                            <v:rect>\n                                <v:textbox>\n                                    <w:txbxContent>\n                                        <w:p>\n                                            <w:pPr>\n                                                <w:jc w:val=\"center\"/>\n                                            </w:pPr>\n                                            <w:r>\n                                                <w:t>Test node value</w:t>\n                                            </w:r>\n                                        </w:p>\n                                    </w:txbxContent>\n                                </v:textbox>\n                            </v:rect>\n                        </w:pict>\n                    </mc:Fallback>\n                </mc:AlternateContent>\n            </w:r>\n        </w:p>';\n\n        $phpWord = $this->getDocumentFromString(['document' => $documentXml]);\n\n        $elements = $phpWord->getSection(0)->getElements();\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $elements[0]);\n        self::assertInstanceOf(Text::class, $elements[0]->getElement(0));\n        $text = $elements[0];\n        self::assertEquals('Test node value', trim($text->getElement(0)->getText()));\n    }\n\n    /**\n     * Test reading of textbreak.\n     */\n    public function testReadTextBreak(): void\n    {\n        $documentXml = '<w:p>\n            <w:r>\n                <w:br/>\n                <w:t xml:space=\"preserve\">test string</w:t>\n            </w:r>\n        </w:p>';\n\n        $phpWord = $this->getDocumentFromString(['document' => $documentXml]);\n\n        $elements = $phpWord->getSection(0)->getElements();\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $elements[0]);\n        /** @var \\PhpOffice\\PhpWord\\Element\\TextRun $textRun */\n        $textRun = $elements[0];\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextBreak', $textRun->getElement(0));\n        self::assertInstanceOf(Text::class, $textRun->getElement(1));\n        self::assertEquals('test string', $textRun->getElement(1)->getText());\n    }\n\n    /**\n     * Test reading content inside w:smartTag.\n     */\n    public function testSmartTag(): void\n    {\n        $documentXml = '<w:p>\n            <w:smartTag>\n                <w:r>\n                    <w:t xml:space=\"preserve\">test string</w:t>\n                </w:r>\n            </w:smartTag>\n        </w:p>';\n\n        $phpWord = $this->getDocumentFromString(['document' => $documentXml]);\n\n        $elements = $phpWord->getSection(0)->getElements();\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $elements[0]);\n        /** @var \\PhpOffice\\PhpWord\\Element\\TextRun $textRun */\n        $textRun = $elements[0];\n        self::assertInstanceOf(Text::class, $textRun->getElement(0));\n        self::assertEquals('test string', $textRun->getElement(0)->getText());\n    }\n\n    /**\n     * Test reading of textbreak.\n     */\n    public function testReadListItemRunWithFormatting(): void\n    {\n        $documentXml = '<w:p>\n            <w:pPr>\n                <w:numPr>\n                    <w:ilvl w:val=\"0\"/>\n                    <w:numId w:val=\"11\"/>\n                </w:numPr>\n            </w:pPr>\n            <w:r>\n                <w:t>Two</w:t>\n            </w:r>\n            <w:r>\n                <w:t xml:space=\"preserve\"> with </w:t>\n            </w:r>\n            <w:r>\n                <w:rPr>\n                    <w:b/>\n                </w:rPr>\n                <w:t>bold</w:t>\n            </w:r>\n        </w:p>';\n\n        $phpWord = $this->getDocumentFromString(['document' => $documentXml]);\n\n        $sections = $phpWord->getSection(0);\n        self::assertNull($sections->getElement(999));\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\ListItemRun', $sections->getElement(0));\n        self::assertEquals(0, $sections->getElement(0)->getDepth());\n\n        $listElements = $sections->getElement(0)->getElements();\n        /** @var Text $listElement0 */\n        $listElement0 = $listElements[0];\n        self::assertInstanceOf(Text::class, $listElement0);\n        self::assertEquals('Two', $listElement0->getText());\n        /** @var Text $listElement1 */\n        $listElement1 = $listElements[1];\n        self::assertEquals(' with ', $listElement1->getText());\n        /** @var Text $listElement2 */\n        $listElement2 = $listElements[2];\n        self::assertEquals('bold', $listElement2->getText());\n        /** @var Font $listElement2FontStyle */\n        $listElement2FontStyle = $listElement2->getFontStyle();\n        self::assertInstanceOf(Font::class, $listElement2FontStyle);\n        self::assertTrue($listElement2FontStyle->isBold());\n    }\n\n    /**\n     * Test reading track changes.\n     */\n    public function testReadTrackChange(): void\n    {\n        $documentXml = '<w:p>\n            <w:r>\n                <w:t>One </w:t>\n            </w:r>\n            <w:del w:author=\"Barney\" w:date=\"2018-03-14T10:57:05Z\">\n                <w:r>\n                    <w:delText>two</w:delText>\n                </w:r>\n            </w:del>\n            <w:ins w:author=\"Fred\" w:date=\"2018-03-14T10:57:05Z\">\n                \t<w:r>\n                    <w:t>three</w:t>\n                \t</w:r>\n            </w:ins>\n        </w:p>';\n\n        $phpWord = $this->getDocumentFromString(['document' => $documentXml]);\n\n        $elements = $phpWord->getSection(0)->getElements();\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $elements[0]);\n        /** @var \\PhpOffice\\PhpWord\\Element\\TextRun $elements */\n        $textRun = $elements[0];\n\n        self::assertEquals('One ', $textRun->getElement(0)->getText());\n\n        self::assertEquals('two', $textRun->getElement(1)->getText());\n        self::assertNotNull($textRun->getElement(1)->getTrackChange());\n        /** @var TrackChange $trackChange */\n        $trackChange = $textRun->getElement(1)->getTrackChange();\n        self::assertEquals(TrackChange::DELETED, $trackChange->getChangeType());\n\n        self::assertEquals('three', $textRun->getElement(2)->getText());\n        self::assertNotNull($textRun->getElement(2)->getTrackChange());\n        /** @var TrackChange $trackChange */\n        $trackChange = $textRun->getElement(2)->getTrackChange();\n        self::assertEquals(TrackChange::INSERTED, $trackChange->getChangeType());\n    }\n\n    /**\n     * Test reading of tab.\n     */\n    public function testReadTab(): void\n    {\n        $documentXml = '<w:p>\n            <w:r>\n                <w:t>One</w:t>\n                <w:tab/>\n                <w:t>Two</w:t>\n            </w:r>\n        </w:p>';\n\n        $phpWord = $this->getDocumentFromString(['document' => $documentXml]);\n\n        $elements = $phpWord->getSection(0)->getElements();\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $elements[0]);\n        /** @var \\PhpOffice\\PhpWord\\Element\\TextRun $textRun */\n        $textRun = $elements[0];\n        self::assertInstanceOf(Text::class, $textRun->getElement(0));\n        self::assertEquals('One', $textRun->getElement(0)->getText());\n        self::assertInstanceOf(Text::class, $textRun->getElement(1));\n        self::assertEquals(\"\\t\", $textRun->getElement(1)->getText());\n        self::assertInstanceOf(Text::class, $textRun->getElement(2));\n        self::assertEquals('Two', $textRun->getElement(2)->getText());\n    }\n\n    /**\n     * Test reading Title style.\n     */\n    public function testReadTitleStyle(): void\n    {\n        $documentXml = '<w:p>\n            <w:pPr>\n                <w:pStyle w:val=\"Title\"/>\n            </w:pPr>\n            <w:r>\n                <w:t>This is a non formatted title</w:t>\n            </w:r>\n        </w:p>\n        <w:p>\n            <w:pPr>\n                <w:pStyle w:val=\"Title\"/>\n            </w:pPr>\n            <w:r>\n                <w:t>This is a </w:t>\n            </w:r>\n            <w:r>\n                <w:rPr>\n                    <w:b/>\n                </w:rPr>\n                <w:t>bold</w:t>\n            </w:r>\n            <w:r>\n                <w:t> title</w:t>\n            </w:r>\n        </w:p>';\n\n        $stylesXml = '<w:style w:type=\"paragraph\" w:styleId=\"Title\">\n            <w:name w:val=\"Title\"/>\n            <w:link w:val=\"TitleChar\"/>\n            <w:rPr>\n                <w:i/>\n            </w:rPr>\n        </w:style>';\n\n        $phpWord = $this->getDocumentFromString(['document' => $documentXml, 'styles' => $stylesXml]);\n\n        $elements = $phpWord->getSection(0)->getElements();\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Title', $elements[0]);\n        /** @var \\PhpOffice\\PhpWord\\Element\\Title $title */\n        $title = $elements[0];\n        self::assertEquals('Title', $title->getStyle());\n        self::assertEquals('This is a non formatted title', $title->getText());\n\n        self::assertInstanceOf(\\PhpOffice\\PhpWord\\Element\\Title::class, $elements[1]);\n        /** @var \\PhpOffice\\PhpWord\\Element\\Title $formattedTitle */\n        $formattedTitle = $elements[1];\n        self::assertEquals('Title', $formattedTitle->getStyle());\n        self::assertInstanceOf(\\PhpOffice\\PhpWord\\Element\\TextRun::class, $formattedTitle->getText());\n    }\n\n    /**\n     * Test reading of nested table.\n     */\n    public function testReadNestedTable(): void\n    {\n        $documentXml = '<w:tbl>\n          <w:tr>\n            <w:tc>\n              <w:tbl>\n                <w:tr>\n                  <w:tc>\n                    <w:p>\n                      <w:t>${Field}</w:t>\n                    </w:p>\n                  </w:tc>\n                </w:tr>\n              </w:tbl>\n              <w:p />\n            </w:tc>\n          </w:tr>\n        </w:tbl>';\n\n        $phpWord = $this->getDocumentFromString(['document' => $documentXml]);\n\n        $section = $phpWord->getSection(0);\n        $table = $section->getElement(0);\n        $rows = $table->getRows();\n        $cells = $rows[0]->getCells();\n        $nestedTable = $cells[0]->getElement(0);\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table', $nestedTable);\n    }\n\n    /**\n     * Test reading Drawing.\n     */\n    public function testReadDrawing(): void\n    {\n        $documentXml = '<w:p>\n            <w:r>\n                <w:drawing xmlns:wp=\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\">\n                    <wp:inline distT=\"0\" distB=\"0\" distL=\"0\" distR=\"0\">\n                        <wp:extent cx=\"5727700\" cy=\"6621145\"/>\n                        <wp:docPr id=\"1\" name=\"Picture 1\"/>\n                        <a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">\n                            <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">\n                                <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">\n                                    <pic:nvPicPr>\n                                        <pic:cNvPr id=\"1\" name=\"file_name.jpg\"/>\n                                        <pic:cNvPicPr/>\n                                    </pic:nvPicPr>\n                                    <pic:blipFill>\n                                        <a:blip r:embed=\"rId4\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">\n                                        </a:blip>\n                                    </pic:blipFill>\n                                </pic:pic>\n                            </a:graphicData>\n                        </a:graphic>\n                    </wp:inline>\n                </w:drawing>\n            </w:r>\n        </w:p>';\n\n        $phpWord = $this->getDocumentFromString(['document' => $documentXml]);\n\n        $elements = $phpWord->getSection(0)->getElements();\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $elements[0]);\n    }\n\n    /**\n     * Test reading FormField - DROPDOWN.\n     */\n    public function testReadFormFieldDropdown(): void\n    {\n        $documentXml = '<w:p>\n            <w:r>\n                <w:t>Reference</w:t>\n            </w:r>\n            <w:r>\n                <w:fldChar w:fldCharType=\"begin\">\n                    <w:ffData>\n                        <w:name w:val=\"DropDownList1\"/>\n                        <w:enabled/>\n                        <w:calcOnExit w:val=\"0\"/>\n                        <w:ddList>\n                            <w:result w:val=\"2\"/>\n                            <w:listEntry w:val=\"TBD\"/>\n                            <w:listEntry w:val=\"Option One\"/>\n                            <w:listEntry w:val=\"Option Two\"/>\n                            <w:listEntry w:val=\"Option Three\"/>\n                            <w:listEntry w:val=\"Other\"/>\n                        </w:ddList>\n                    </w:ffData>\n                </w:fldChar>\n            </w:r>\n            <w:r>\n                <w:instrText xml:space=\"preserve\"> FORMDROPDOWN </w:instrText>\n            </w:r>\n            <w:r>\n                <w:rPr>\n                    <w:lang w:val=\"en-GB\"/>\n                </w:rPr>\n            </w:r>\n            <w:r>\n                <w:rPr>\n                    <w:lang w:val=\"en-GB\"/>\n                </w:rPr>\n                <w:fldChar w:fldCharType=\"separate\"/>\n            </w:r>\n            <w:r>\n                <w:rPr>\n                    <w:lang w:val=\"en-GB\"/>\n                </w:rPr>\n                <w:fldChar w:fldCharType=\"end\"/>\n            </w:r>\n        </w:p>';\n\n        $phpWord = $this->getDocumentFromString(['document' => $documentXml]);\n\n        $elements = $phpWord->getSection(0)->getElements();\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $elements[0]);\n\n        $subElements = $elements[0]->getElements();\n\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $subElements[0]);\n        self::assertEquals('Reference', $subElements[0]->getText());\n\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\FormField', $subElements[1]);\n        self::assertEquals('dropdown', $subElements[1]->getType());\n        self::assertEquals('DropDownList1', $subElements[1]->getName());\n        self::assertEquals('2', $subElements[1]->getValue());\n        self::assertEquals('Option Two', $subElements[1]->getText());\n        self::assertEquals(['TBD', 'Option One', 'Option Two', 'Option Three', 'Other'], $subElements[1]->getEntries());\n    }\n\n    /**\n     * Test reading FormField - textinput.\n     */\n    public function testReadFormFieldTextinput(): void\n    {\n        $documentXml = '<w:p>\n            <w:r>\n                <w:t>Fieldname</w:t>\n            </w:r>\n            <w:r>\n                <w:fldChar w:fldCharType=\"begin\">\n                    <w:ffData>\n                        <w:name w:val=\"TextInput2\"/>\n                        <w:enabled/>\n                        <w:calcOnExit w:val=\"0\"/>\n                        <w:textInput>\n                            <w:default w:val=\"TBD\"/>\n                            <w:maxLength w:val=\"200\"/>\n                        </w:textInput>\n                    </w:ffData>\n                </w:fldChar>\n            </w:r>\n            <w:r>\n                <w:instrText xml:space=\"preserve\"> FORMTEXT </w:instrText>\n            </w:r>\n            <w:r>\n                <w:rPr>\n                    <w:lang w:val=\"en-GB\"/>\n                </w:rPr>\n            </w:r>\n            <w:r>\n                <w:rPr>\n                    <w:lang w:val=\"en-GB\"/>\n                </w:rPr>\n                <w:fldChar w:fldCharType=\"separate\"/>\n            </w:r>\n            <w:r w:rsidR=\"00807709\">\n                <w:rPr>\n                    <w:noProof/>\n                    <w:lang w:val=\"en-GB\"/>\n                </w:rPr>\n                <w:t>This is some sample text</w:t>\n            </w:r>\n            <w:r>\n                <w:rPr>\n                    <w:lang w:val=\"en-GB\"/>\n                </w:rPr>\n                <w:fldChar w:fldCharType=\"end\"/>\n            </w:r>\n        </w:p>';\n\n        $phpWord = $this->getDocumentFromString(['document' => $documentXml]);\n\n        $elements = $phpWord->getSection(0)->getElements();\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $elements[0]);\n\n        $subElements = $elements[0]->getElements();\n\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $subElements[0]);\n        self::assertEquals('Fieldname', $subElements[0]->getText());\n\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\FormField', $subElements[1]);\n        self::assertEquals('textinput', $subElements[1]->getType());\n        self::assertEquals('TextInput2', $subElements[1]->getName());\n        self::assertEquals('This is some sample text', $subElements[1]->getValue());\n        self::assertEquals('This is some sample text', $subElements[1]->getText());\n    }\n\n    /**\n     * Test reading FormField - checkbox.\n     */\n    public function testReadFormFieldCheckbox(): void\n    {\n        $documentXml = '<w:p>\n\t\t\t<w:pPr/>\n\t\t\t<w:r>\n\t\t\t\t<w:fldChar w:fldCharType=\"begin\">\n\t\t\t\t\t<w:ffData>\n\t\t\t\t\t\t<w:enabled w:val=\"1\"/>\n\t\t\t\t\t\t<w:name w:val=\"SomeCheckbox\"/>\n\t\t\t\t\t\t<w:calcOnExit w:val=\"0\"/>\n\t\t\t\t\t\t<w:checkBox>\n\t\t\t\t\t\t\t<w:sizeAuto w:val=\"\"/>\n\t\t\t\t\t\t\t<w:default w:val=\"0\"/>\n\t\t\t\t\t\t\t<w:checked w:val=\"0\"/>\n\t\t\t\t\t\t</w:checkBox>\n\t\t\t\t\t</w:ffData>\n\t\t\t\t</w:fldChar>\n\t\t\t</w:r>\n\t\t\t<w:r>\n\t\t\t\t<w:rPr/>\n\t\t\t\t<w:instrText xml:space=\"preserve\">FORMCHECKBOX</w:instrText>\n\t\t\t</w:r>\n\t\t\t<w:r>\n\t\t\t\t<w:rPr/>\n\t\t\t\t<w:fldChar w:fldCharType=\"separate\"/>\n\t\t\t</w:r>\n\t\t\t<w:r>\n\t\t\t\t<w:rPr/>\n\t\t\t\t<w:t xml:space=\"preserve\">                              </w:t>\n\t\t\t</w:r>\n\t\t\t<w:r>\n\t\t\t\t<w:rPr/>\n\t\t\t\t<w:fldChar w:fldCharType=\"end\"/>\n\t\t\t</w:r>\n\t\t</w:p>';\n\n        $phpWord = $this->getDocumentFromString(['document' => $documentXml]);\n\n        $elements = $phpWord->getSection(0)->getElements();\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $elements[0]);\n\n        $subElements = $elements[0]->getElements();\n\n//        $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $subElements[0]);\n//        $this->assertEquals('Fieldname', $subElements[0]->getText());\n\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\FormField', $subElements[0]);\n        self::assertEquals('checkbox', $subElements[0]->getType());\n        self::assertEquals('SomeCheckbox', $subElements[0]->getName());\n    }\n\n    /**\n     * Test reading of ruby.\n     */\n    public function testReadRuby(): void\n    {\n        $documentXml = '<w:p>\n            <w:r>\n                <w:ruby>\n                    <w:rubyPr>\n                        <w:rubyAlign w:val=\"distributeSpace\" />\n                        <w:hps w:val=\"12\" />\n                        <w:hpsRaise w:val=\"22\" />\n                        <w:hpsBaseText w:val=\"24\" />\n                        <w:lid w:val=\"ja-JP\" />\n                    </w:rubyPr>\n                    <w:rt>\n                        <w:r w:rsidR=\"00984B5D\"\n                             w:rsidRPr=\"00984B5D\">\n                            <w:rPr>\n                                <w:rFonts w:ascii=\"Yu Gothic\"\n                                          w:eastAsia=\"Yu Gothic\"\n                                          w:hAnsi=\"Yu Gothic\"\n                                          w:hint=\"eastAsia\" />\n                                <w:sz w:val=\"12\" />\n                            </w:rPr>\n                            <w:t>わたし</w:t>\n                        </w:r>\n                    </w:rt>\n                    <w:rubyBase>\n                        <w:r w:rsidR=\"00984B5D\">\n                            <w:rPr>\n                                <w:rFonts w:hint=\"eastAsia\" />\n                            </w:rPr>\n                            <w:t>私</w:t>\n                        </w:r>\n                    </w:rubyBase>\n                </w:ruby>\n            </w:r>\n        </w:p>';\n\n        $phpWord = $this->getDocumentFromString(['document' => $documentXml]);\n        $elements = $phpWord->getSection(0)->getElements();\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $elements[0]);\n        $subElements = $elements[0]->getElements(); // <w:ruby>\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Ruby', $subElements[0]);\n        /** @var RubyProperties $rubyProperties */\n        $rubyProperties = $subElements[0]->getProperties();\n        self::assertEquals(RubyProperties::ALIGNMENT_DISTRIBUTE_SPACE, $rubyProperties->getAlignment());\n        self::assertEquals(12, $rubyProperties->getFontFaceSize());\n        self::assertEquals(22, $rubyProperties->getFontPointsAboveBaseText());\n        self::assertEquals(24, $rubyProperties->getFontSizeForBaseText());\n        self::assertEquals('ja-JP', $rubyProperties->getLanguageId());\n        /** @var \\PhpOffice\\PhpWord\\Element\\TextRun $textRun */\n        $textRun = $subElements[0]->getBaseTextRun();\n        self::assertEquals('私', $textRun->getText());\n        $textRun = $subElements[0]->getRubyTextRun();\n        self::assertEquals('わたし', $textRun->getText());\n    }\n\n    /**\n     * Test reading of ruby title.\n     */\n    public function testReadRubyTitle(): void\n    {\n        $documentXml = '<w:p\n             w:rsidR=\"00CB4855\"\n             w:rsidRDefault=\"00AA542C\"\n             w:rsidP=\"00AA542C\">\n            <w:pPr>\n                <w:pStyle w:val=\"Heading1\" />\n            </w:pPr>\n            <w:r>\n                <w:ruby>\n                    <w:rubyPr>\n                        <w:rubyAlign w:val=\"distributeSpace\" />\n                        <w:hps w:val=\"20\" />\n                        <w:hpsRaise w:val=\"38\" />\n                        <w:hpsBaseText w:val=\"40\" />\n                        <w:lid w:val=\"ja-JP\" />\n                    </w:rubyPr>\n                    <w:rt>\n                        <w:r w:rsidR=\"00AA542C\"\n                             w:rsidRPr=\"00AA542C\">\n                            <w:rPr>\n                                <w:rFonts w:ascii=\"Yu Gothic Light\"\n                                          w:eastAsia=\"Yu Gothic Light\"\n                                          w:hAnsi=\"Yu Gothic Light\"\n                                          w:hint=\"eastAsia\" />\n                                <w:sz w:val=\"20\" />\n                            </w:rPr>\n                            <w:t>かみ</w:t>\n                        </w:r>\n                    </w:rt>\n                    <w:rubyBase>\n                        <w:r w:rsidR=\"00AA542C\">\n                            <w:rPr>\n                                <w:rFonts w:hint=\"eastAsia\" />\n                            </w:rPr>\n                            <w:t>神</w:t>\n                        </w:r>\n                    </w:rubyBase>\n                </w:ruby>\n            </w:r>\n        </w:p>';\n\n        $phpWord = $this->getDocumentFromString(['document' => $documentXml]);\n        $elements = $phpWord->getSection(0)->getElements();\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Title', $elements[0]);\n        /** @var \\PhpOffice\\PhpWord\\Element\\Title $title */\n        $title = $elements[0];\n        /** @var \\PhpOffice\\PhpWord\\Element\\TextRun $textRun */\n        $textRun = $title->getText();\n        $subElements = $textRun->getElements(); // <w:ruby>\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Ruby', $subElements[0]);\n        /** @var Ruby $ruby */\n        $ruby = $subElements[0];\n        /** @var RubyProperties $rubyProperties */\n        $rubyProperties = $ruby->getProperties();\n        self::assertEquals(RubyProperties::ALIGNMENT_DISTRIBUTE_SPACE, $rubyProperties->getAlignment());\n        self::assertEquals(20, $rubyProperties->getFontFaceSize());\n        self::assertEquals(38, $rubyProperties->getFontPointsAboveBaseText());\n        self::assertEquals(40, $rubyProperties->getFontSizeForBaseText());\n        self::assertEquals('ja-JP', $rubyProperties->getLanguageId());\n        /** @var \\PhpOffice\\PhpWord\\Element\\TextRun $textRun */\n        $textRun = $ruby->getBaseTextRun();\n        self::assertEquals('神', $textRun->getText());\n        $textRun = $ruby->getRubyTextRun();\n        self::assertEquals('かみ', $textRun->getText());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Reader/Word2007/PartTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Reader\\Word2007;\n\nuse PhpOffice\\PhpWordTests\\AbstractTestReader;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Reader\\Word2007 subnamespace.\n */\nclass PartTest extends AbstractTestReader\n{\n    /**\n     * Test reading Footnotes.\n     */\n    public function testReadFootnote(): void\n    {\n        $documentXml = '<w:p>\n                <w:r>\n                    <w:t>This is a test</w:t>\n                </w:r>\n                <w:r>\n                    <w:rPr>\n                        <w:rStyle w:val=\"FootnoteReference\"/>\n                    </w:rPr>\n                    <w:footnoteReference w:id=\"1\"/>\n                </w:r>\n            </w:p>\n            <w:p>\n                <w:r>\n                    <w:t>And another one</w:t>\n                </w:r>\n                <w:r>\n                    <w:rPr>\n                        <w:rStyle w:val=\"EndnoteReference\"/>\n                    </w:rPr>\n                    <w:endnoteReference w:id=\"2\"/>\n                </w:r>\n            </w:p>';\n\n        $footnotesXml = '<w:footnote w:type=\"separator\" w:id=\"-1\">\n                <w:p>\n                    <w:r>\n                        <w:separator/>\n                    </w:r>\n                </w:p>\n            </w:footnote>\n            <w:footnote w:id=\"1\">\n                <w:p>\n                    <w:pPr>\n                        <w:pStyle w:val=\"FootnoteText\"/>\n                    </w:pPr>\n                    <w:r>\n                        <w:rPr>\n                            <w:rStyle w:val=\"FootnoteReference\"/>\n                        </w:rPr>\n                        <w:footnoteRef/>\n                    </w:r>\n                    <w:r>\n                        <w:rPr>\n                            <w:lang w:val=\"nl-NL\"/>\n                        </w:rPr>\n                        <w:t>footnote text</w:t>\n                    </w:r>\n                </w:p>\n            </w:footnote>';\n\n        $endnotesXml = '<w:endnote w:type=\"separator\" w:id=\"-1\">\n                <w:p>\n                    <w:r>\n                        <w:separator/>\n                    </w:r>\n                </w:p>\n            </w:endnote>\n            <w:endnote w:type=\"continuationNotice\" w:id=\"1\">\n                <w:p>\n                    <w:r>\n                        <w:separator/>\n                    </w:r>\n                </w:p>\n            </w:endnote>\n            <w:endnote w:id=\"2\">\n                <w:p>\n                    <w:pPr>\n                        <w:pStyle w:val=\"EndnoteText\"/>\n                    </w:pPr>\n                    <w:r>\n                        <w:rPr>\n                            <w:rStyle w:val=\"EndnoteReference\"/>\n                        </w:rPr>\n                        <w:endnoteRef/>\n                    </w:r>\n                    <w:r>\n                        <w:rPr>\n                            <w:lang w:val=\"nl-NL\"/>\n                        </w:rPr>\n                        <w:t>This is an endnote</w:t>\n                    </w:r>\n                </w:p>\n            </w:endnote>';\n\n        $phpWord = $this->getDocumentFromString(['document' => $documentXml, 'footnotes' => $footnotesXml, 'endnotes' => $endnotesXml]);\n\n        $elements = $phpWord->getSection(0)->getElements();\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $elements[0]);\n        /** @var \\PhpOffice\\PhpWord\\Element\\TextRun $textRun */\n        $textRun = $elements[0];\n\n        //test the text in the first paragraph\n        /** @var \\PhpOffice\\PhpWord\\Element\\Text $text */\n        $text = $elements[0]->getElement(0);\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $text);\n        self::assertEquals('This is a test', $text->getText());\n\n        //test the presence of the footnote in the document.xml\n        /** @var \\PhpOffice\\PhpWord\\Element\\Footnote $footnote */\n        $documentFootnote = $textRun->getElement(1);\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Footnote', $documentFootnote);\n        self::assertEquals(1, $documentFootnote->getRelationId());\n\n        //test the presence of the footnote in the footnote.xml\n        /** @var \\PhpOffice\\PhpWord\\Element\\Footnote $footnote */\n        $footnote = $phpWord->getFootnotes()->getItem(1);\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Footnote', $footnote);\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $footnote->getElement(0));\n        self::assertEquals('footnote text', $footnote->getElement(0)->getText());\n        self::assertEquals(1, $footnote->getRelationId());\n\n        //test the text in the second paragraph\n        /** @var \\PhpOffice\\PhpWord\\Element\\Text $text */\n        $text = $elements[1]->getElement(0);\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $text);\n        self::assertEquals('And another one', $text->getText());\n\n        //test the presence of the endnote in the document.xml\n        /** @var \\PhpOffice\\PhpWord\\Element\\Endnote $endnote */\n        $documentEndnote = $elements[1]->getElement(1);\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Endnote', $documentEndnote);\n        self::assertEquals(2, $documentEndnote->getRelationId());\n\n        //test the presence of the endnote in the endnote.xml\n        /** @var \\PhpOffice\\PhpWord\\Element\\Endnote $endnote */\n        $endnote = $phpWord->getEndnotes()->getItem(1);\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Endnote', $endnote);\n        self::assertEquals(2, $endnote->getRelationId());\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $endnote->getElement(0));\n        self::assertEquals('This is an endnote', $endnote->getElement(0)->getText());\n    }\n\n    public function testReadHeadingWithOverriddenStyle(): void\n    {\n        $documentXml = '<w:p>\n            <w:pPr>\n                <w:pStyle w:val=\"Heading1\"/>\n            </w:pPr>\n            <w:r>\n                <w:t>This is a bold </w:t>\n            </w:r>\n            <w:r w:rsidRPr=\"00377798\">\n                <w:rPr>\n                    <w:b w:val=\"0\"/>\n                </w:rPr>\n                <w:t>heading</w:t>\n            </w:r>\n            <w:r>\n                <w:t xml:space=\"preserve\"> but with parts not in bold</w:t>\n            </w:r>\n            </w:p>';\n\n        $stylesXml = '<w:style w:type=\"paragraph\" w:default=\"1\" w:styleId=\"Normal\">\n                <w:name w:val=\"Normal\"/>\n                <w:qFormat/>\n            </w:style>\n            <w:style w:type=\"paragraph\" w:styleId=\"Heading1\">\n                <w:name w:val=\"heading 1\"/>\n                <w:basedOn w:val=\"Normal\"/>\n                <w:next w:val=\"Normal\"/>\n                <w:link w:val=\"Heading1Char\"/>\n                <w:uiPriority w:val=\"9\"/>\n                <w:qFormat/>\n                <w:rsid w:val=\"00377798\"/>\n                <w:pPr>\n                    <w:keepNext/>\n                    <w:keepLines/>\n                    <w:spacing w:before=\"240\"/>\n                    <w:outlineLvl w:val=\"0\"/>\n                </w:pPr>\n                <w:rPr>\n                    <w:rFonts w:asciiTheme=\"majorHAnsi\" w:eastAsiaTheme=\"majorEastAsia\" w:hAnsiTheme=\"majorHAnsi\" w:cstheme=\"majorBidi\"/>\n                    <w:b/>\n                    <w:color w:val=\"2F5496\" w:themeColor=\"accent1\" w:themeShade=\"BF\"/>\n                    <w:sz w:val=\"32\"/>\n                    <w:szCs w:val=\"32\"/>\n                </w:rPr>\n            </w:style>';\n\n        $phpWord = $this->getDocumentFromString(['document' => $documentXml, 'styles' => $stylesXml]);\n\n        $elements = $phpWord->getSection(0)->getElements();\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Title', $elements[0]);\n        /** @var \\PhpOffice\\PhpWord\\Element\\Title $title */\n        $title = $elements[0];\n        self::assertEquals('Heading1', $title->getStyle());\n\n        /** @var \\PhpOffice\\PhpWord\\Element\\Text $text */\n        $text = $title->getText()->getElement(0);\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $text);\n        self::assertEquals('This is a bold ', $text->getText());\n\n        /** @var \\PhpOffice\\PhpWord\\Element\\Text $text */\n        $text = $title->getText()->getElement(1);\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $text);\n        self::assertEquals('heading', $text->getText());\n        self::assertFalse($text->getFontStyle()->isBold());\n\n        /** @var \\PhpOffice\\PhpWord\\Element\\Text $text */\n        $text = $title->getText()->getElement(2);\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $text);\n        self::assertEquals(' but with parts not in bold', $text->getText());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Reader/Word2007/StyleTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Reader\\Word2007;\n\nuse Generator;\nuse PhpOffice\\PhpWord\\Element\\TextRun;\nuse PhpOffice\\PhpWord\\SimpleType\\Border;\nuse PhpOffice\\PhpWord\\SimpleType\\TblWidth;\nuse PhpOffice\\PhpWord\\SimpleType\\VerticalJc;\nuse PhpOffice\\PhpWord\\Style;\nuse PhpOffice\\PhpWord\\Style\\Table;\nuse PhpOffice\\PhpWord\\Style\\TablePosition;\nuse PhpOffice\\PhpWordTests\\AbstractTestReader;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Reader\\Word2007\\Styles.\n */\nclass StyleTest extends AbstractTestReader\n{\n    /**\n     * Test reading of table layout.\n     */\n    public function testReadTableLayout(): void\n    {\n        $documentXml = '<w:tbl>\n            <w:tblPr>\n                <w:tblLayout w:type=\"fixed\"/>\n            </w:tblPr>\n        </w:tbl>';\n\n        $phpWord = $this->getDocumentFromString(['document' => $documentXml]);\n\n        $elements = $phpWord->getSection(0)->getElements();\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table', $elements[0]);\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Table', $elements[0]->getStyle());\n        self::assertEquals(Table::LAYOUT_FIXED, $elements[0]->getStyle()->getLayout());\n    }\n\n    /**\n     * Test reading of table position.\n     */\n    public function testReadTablePosition(): void\n    {\n        $documentXml = '<w:tbl>\n            <w:tblPr>\n                <w:tblpPr w:leftFromText=\"10\" w:rightFromText=\"20\" w:topFromText=\"30\" w:bottomFromText=\"40\" w:vertAnchor=\"page\" w:horzAnchor=\"margin\" w:tblpXSpec=\"center\" w:tblpX=\"50\" w:tblpYSpec=\"top\" w:tblpY=\"60\"/>\n            </w:tblPr>\n        </w:tbl>';\n\n        $phpWord = $this->getDocumentFromString(['document' => $documentXml]);\n\n        $elements = $phpWord->getSection(0)->getElements();\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table', $elements[0]);\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Table', $elements[0]->getStyle());\n        self::assertNotNull($elements[0]->getStyle()->getPosition());\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\TablePosition', $elements[0]->getStyle()->getPosition());\n        /** @var TablePosition $tableStyle */\n        $tableStyle = $elements[0]->getStyle()->getPosition();\n        self::assertEquals(10, $tableStyle->getLeftFromText());\n        self::assertEquals(20, $tableStyle->getRightFromText());\n        self::assertEquals(30, $tableStyle->getTopFromText());\n        self::assertEquals(40, $tableStyle->getBottomFromText());\n        self::assertEquals(TablePosition::VANCHOR_PAGE, $tableStyle->getVertAnchor());\n        self::assertEquals(TablePosition::HANCHOR_MARGIN, $tableStyle->getHorzAnchor());\n        self::assertEquals(TablePosition::XALIGN_CENTER, $tableStyle->getTblpXSpec());\n        self::assertEquals(50, $tableStyle->getTblpX());\n        self::assertEquals(TablePosition::YALIGN_TOP, $tableStyle->getTblpYSpec());\n        self::assertEquals(60, $tableStyle->getTblpY());\n    }\n\n    public function testReadTableCellNoWrap(): void\n    {\n        $documentXml = '<w:tbl>\n          <w:tr>\n            <w:tc>\n              <w:tcPr>\n                <w:noWrap />\n              </w:tcPr>\n            </w:tc>\n          </w:tr>\n        </w:tbl>';\n\n        $phpWord = $this->getDocumentFromString(['document' => $documentXml]);\n\n        $elements = $phpWord->getSection(0)->getElements();\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table', $elements[0]);\n        $rows = $elements[0]->getRows();\n        $cells = $rows[0]->getCells();\n        self::assertTrue($cells[0]->getStyle()->getNoWrap());\n    }\n\n    /**\n     * Test reading of cell spacing.\n     */\n    public function testReadTableCellSpacing(): void\n    {\n        $documentXml = '<w:tbl>\n            <w:tblPr>\n                <w:tblCellSpacing w:w=\"10.5\" w:type=\"dxa\"/>\n            </w:tblPr>\n        </w:tbl>';\n\n        $phpWord = $this->getDocumentFromString(['document' => $documentXml]);\n\n        $elements = $phpWord->getSection(0)->getElements();\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table', $elements[0]);\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Table', $elements[0]->getStyle());\n        /** @var Table $tableStyle */\n        $tableStyle = $elements[0]->getStyle();\n        self::assertEquals(TblWidth::AUTO, $tableStyle->getUnit());\n        self::assertEquals(10.5, $tableStyle->getCellSpacing());\n    }\n\n    public function testReadTableCellStyle(): void\n    {\n        $documentXml = '<w:tbl>\n          <w:tr>\n            <w:tc>\n              <w:tcPr>\n                <w:tcBorders>\n                  <w:top w:val=\"single\" w:sz=\"4\" w:space=\"0\" w:color=\"auto\"/>\n                  <w:bottom w:val=\"double\" w:sz=\"4\" w:space=\"0\" w:color=\"auto\"/>\n                </w:tcBorders>\n                <w:tcMar>\n                  <w:top w:w=\"720\" w:type=\"dxa\"/>\n                  <w:start w:w=\"720\" w:type=\"dxa\"/>\n                  <w:bottom w:w=\"0\" w:type=\"dxa\"/>\n                  <w:end w:w=\"720\" w:type=\"dxa\"/>\n                </w:tcMar>\n              </w:tcPr>\n            </w:tc>\n          </w:tr>\n        </w:tbl>';\n\n        $phpWord = $this->getDocumentFromString(['document' => $documentXml]);\n\n        $elements = $phpWord->getSection(0)->getElements();\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table', $elements[0]);\n        $rows = $elements[0]->getRows();\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Row', $rows[0]);\n        $cells = $rows[0]->getCells();\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Cell', $cells[0]);\n        $styleCell = $cells[0]->getStyle();\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Cell', $styleCell);\n\n        self::assertEquals(4, $styleCell->getBorderTopSize());\n        self::assertEquals(Border::SINGLE, $styleCell->getBorderTopStyle());\n        self::assertEquals('auto', $styleCell->getBorderTopColor());\n\n        self::assertEquals(4, $styleCell->getBorderBottomSize());\n        self::assertEquals(Border::DOUBLE, $styleCell->getBorderBottomStyle());\n        self::assertEquals('auto', $styleCell->getBorderBottomColor());\n    }\n\n    public function testReadTableCellsWithVerticalMerge(): void\n    {\n        $documentXml = '<w:tbl>\n          <w:tr>\n            <w:tc>\n              <w:tcPr>\n                <w:vMerge w:val=\"restart\" />\n              </w:tcPr>\n            </w:tc>\n          </w:tr>\n          <w:tr>\n            <w:tc>\n              <w:tcPr>\n                <w:vMerge />\n              </w:tcPr>\n            </w:tc>\n          </w:tr>\n          <w:tr>\n            <w:tc />\n          </w:tr>\n        </w:tbl>';\n\n        $phpWord = $this->getDocumentFromString(['document' => $documentXml]);\n\n        $table = $phpWord->getSection(0)->getElements()[0];\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table', $table);\n\n        $rows = $table->getRows();\n        self::assertCount(3, $rows);\n        foreach ($rows as $row) {\n            self::assertCount(1, $row->getCells());\n        }\n\n        self::assertSame('restart', $rows[0]->getCells()[0]->getStyle()->getVMerge());\n        self::assertSame('continue', $rows[1]->getCells()[0]->getStyle()->getVMerge());\n        self::assertNull($rows[2]->getCells()[0]->getStyle()->getVMerge());\n    }\n\n    /**\n     * Test reading of position.\n     */\n    public function testReadPosition(): void\n    {\n        $documentXml = '<w:p>\n            <w:r>\n                <w:rPr>\n                    <w:position w:val=\"15\"/>\n                </w:rPr>\n                <w:t xml:space=\"preserve\">This text is lowered</w:t>\n            </w:r>\n        </w:p>';\n\n        $phpWord = $this->getDocumentFromString(['document' => $documentXml]);\n\n        $elements = $phpWord->getSection(0)->getElements();\n        /** @var TextRun $elements */\n        $textRun = $elements[0];\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $textRun);\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $textRun->getElement(0));\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $textRun->getElement(0)->getFontStyle());\n        /** @var Style\\Font $fontStyle */\n        $fontStyle = $textRun->getElement(0)->getFontStyle();\n        self::assertEquals(15, $fontStyle->getPosition());\n    }\n\n    public function testReadIndent(): void\n    {\n        $documentXml = '<w:tbl>\n            <w:tblPr>\n                <w:tblInd w:w=\"2160\" w:type=\"dxa\"/>\n            </w:tblPr>\n        </w:tbl>';\n\n        $phpWord = $this->getDocumentFromString(['document' => $documentXml]);\n\n        $elements = $phpWord->getSection(0)->getElements();\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table', $elements[0]);\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Table', $elements[0]->getStyle());\n        /** @var Table $tableStyle */\n        $tableStyle = $elements[0]->getStyle();\n        self::assertSame(TblWidth::TWIP, $tableStyle->getIndent()->getType());\n        self::assertSame(2160, $tableStyle->getIndent()->getValue());\n    }\n\n    public function testReadTableRTL(): void\n    {\n        $documentXml = '<w:tbl>\n            <w:tblPr>\n                <w:bidiVisual w:val=\"1\"/>\n            </w:tblPr>\n        </w:tbl>';\n\n        $phpWord = $this->getDocumentFromString(['document' => $documentXml]);\n\n        $elements = $phpWord->getSection(0)->getElements();\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table', $elements[0]);\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Table', $elements[0]->getStyle());\n        /** @var Table $tableStyle */\n        $tableStyle = $elements[0]->getStyle();\n        self::assertTrue($tableStyle->isBidiVisual());\n    }\n\n    public function testReadHidden(): void\n    {\n        $documentXml = '<w:p>\n            <w:r>\n                <w:rPr>\n                    <w:vanish/>\n                </w:rPr>\n                <w:t xml:space=\"preserve\">This text is hidden</w:t>\n            </w:r>\n        </w:p>';\n\n        $phpWord = $this->getDocumentFromString(['document' => $documentXml]);\n\n        $elements = $phpWord->getSection(0)->getElements();\n        /** @var TextRun $elements */\n        $textRun = $elements[0];\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $textRun);\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $textRun->getElement(0));\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $textRun->getElement(0)->getFontStyle());\n        /** @var Style\\Font $fontStyle */\n        $fontStyle = $textRun->getElement(0)->getFontStyle();\n        self::assertTrue($fontStyle->isHidden());\n    }\n\n    public function testReadHeading(): void\n    {\n        Style::resetStyles();\n\n        $documentXml = '<w:style w:type=\"paragraph\" w:styleId=\"Ttulo1\">\n            <w:name w:val=\"heading 1\"/>\n            <w:basedOn w:val=\"Normal\"/>\n            <w:uiPriority w:val=\"1\"/>\n            <w:qFormat/>\n            <w:pPr>\n                <w:outlineLvl w:val=\"0\"/>\n            </w:pPr>\n            <w:rPr>\n                <w:rFonts w:ascii=\"Times New Roman\" w:eastAsia=\"Times New Roman\" w:hAnsi=\"Times New Roman\"/>\n                <w:b/>\n                <w:bCs/>\n            </w:rPr>\n        </w:style>';\n\n        $name = 'Heading_1';\n\n        $this->getDocumentFromString(['styles' => $documentXml]);\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Font', Style::getStyle($name));\n    }\n\n    public function testPageVerticalAlign(): void\n    {\n        $documentXml = '<w:sectPr>\n            <w:vAlign w:val=\"center\"/>\n        </w:sectPr>';\n\n        $phpWord = $this->getDocumentFromString(['document' => $documentXml]);\n\n        $sectionStyle = $phpWord->getSection(0)->getStyle();\n        self::assertEquals(VerticalJc::CENTER, $sectionStyle->getVAlign());\n    }\n\n    /**\n     * @dataProvider providerIndentation\n     */\n    public function testIndentation(\n        string $indent,\n        float $left,\n        float $right,\n        ?float $hanging,\n        float $firstLine,\n        int $firstLineChars\n    ): void {\n        $documentXml = \"<w:p>\n            <w:pPr>\n                $indent\n            </w:pPr>\n            <w:r>\n                <w:t>1.</w:t>\n            </w:r>\n        </w:p>\";\n\n        $phpWord = $this->getDocumentFromString(['document' => $documentXml]);\n\n        $section = $phpWord->getSection(0);\n        $textRun = $section->getElements()[0];\n        self::assertInstanceOf(TextRun::class, $textRun);\n\n        $paragraphStyle = $textRun->getParagraphStyle();\n        self::assertInstanceOf(Style\\Paragraph::class, $paragraphStyle);\n\n        $indentation = $paragraphStyle->getIndentation();\n        self::assertSame($left, $indentation->getLeft());\n        self::assertSame($right, $indentation->getRight());\n        self::assertSame($hanging, $indentation->getHanging());\n        self::assertSame($firstLine, $indentation->getFirstLine());\n        self::assertSame($firstLineChars, $indentation->getFirstLineChars());\n    }\n\n    /**\n     * @return Generator<array{0:string, 1:float, 2:float, 3:null|float, 4: float, 5: int}>\n     */\n    public static function providerIndentation()\n    {\n        yield [\n            '<w:ind w:left=\"709\" w:right=\"488\" w:hanging=\"10\" w:firstLine=\"490\" w:firstLineChars=\"140\"/>',\n            709.00,\n            488.00,\n            10.0,\n            490.00,\n            140,\n        ];\n        yield [\n            '<w:ind w:left=\"709\" w:right=\"488\" w:hanging=\"10\" w:firstLine=\"490\"/>',\n            709.00,\n            488.00,\n            10.0,\n            490.00,\n            0,\n        ];\n        yield [\n            '<w:ind w:hanging=\"10\" w:firstLine=\"490\"/>',\n            0,\n            0,\n            10.0,\n            490.00,\n            0,\n        ];\n        yield [\n            '<w:ind w:left=\"709\"/>',\n            709.00,\n            0,\n            0,\n            0,\n            0,\n        ];\n        yield [\n            '<w:ind w:right=\"488\"/>',\n            0,\n            488.00,\n            0,\n            0,\n            0,\n        ];\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Reader/Word2007Test.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Reader;\n\nuse DateTime;\nuse PhpOffice\\Math\\Element;\nuse PhpOffice\\PhpWord\\Element\\Comment;\nuse PhpOffice\\PhpWord\\Element\\Formula;\nuse PhpOffice\\PhpWord\\Element\\Image;\nuse PhpOffice\\PhpWord\\Element\\Section;\nuse PhpOffice\\PhpWord\\Element\\Text;\nuse PhpOffice\\PhpWord\\Element\\TextRun;\nuse PhpOffice\\PhpWord\\IOFactory;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Reader\\Word2007;\nuse PhpOffice\\PhpWord\\Style\\Font;\nuse PhpOffice\\PhpWord\\Style\\Paragraph;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Reader\\Word2007.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Reader\\Word2007\n *\n * @runTestsInSeparateProcesses\n */\nclass Word2007Test extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Tear down after each test.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    /**\n     * Test canRead() method.\n     */\n    public function testCanRead(): void\n    {\n        $object = new Word2007();\n        self::assertTrue($object->canRead(dirname(__DIR__, 1) . '/_files/documents/reader.docx'));\n    }\n\n    /**\n     * Can read exception.\n     */\n    public function testCanReadFailed(): void\n    {\n        $object = new Word2007();\n        self::assertFalse($object->canRead(dirname(__DIR__, 1) . '/_files/documents/foo.docx'));\n    }\n\n    /**\n     * Load.\n     */\n    public function testLoad(): void\n    {\n        $phpWord = IOFactory::load(dirname(__DIR__, 1) . '/_files/documents/reader.docx', 'Word2007');\n\n        self::assertInstanceOf(PhpWord::class, $phpWord);\n        self::assertTrue($phpWord->getSettings()->hasDoNotTrackMoves());\n        self::assertFalse($phpWord->getSettings()->hasDoNotTrackFormatting());\n        self::assertEquals(100, $phpWord->getSettings()->getZoom());\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n        self::assertEquals('0', $doc->getElementAttribute('/w:document/w:body/w:p/w:r[w:t/node()=\"italics\"]/w:rPr/w:b', 'w:val'));\n    }\n\n    public function testLoadStyles(): void\n    {\n        $phpWord = IOFactory::load(dirname(__DIR__, 1) . '/_files/documents/reader-styles.docx', 'Word2007');\n\n        self::assertInstanceOf(PhpWord::class, $phpWord);\n\n        $section2 = $phpWord->getSection(2);\n        self::assertInstanceOf(Section::class, $section2);\n\n        $element2e31 = $section2->getElement(31);\n        self::assertInstanceOf(TextRun::class, $element2e31);\n        self::assertEquals('This is a paragraph with border differents', $element2e31->getText());\n\n        /** @var Paragraph $element2e31pStyle */\n        $element2e31pStyle = $element2e31->getParagraphStyle();\n        self::assertInstanceOf(Paragraph::class, $element2e31pStyle);\n\n        // Top\n        self::assertEquals('FFFF00', $element2e31pStyle->getBorderTopColor());\n        self::assertEquals('10', $element2e31pStyle->getBorderTopSize());\n        self::assertEquals('dotted', $element2e31pStyle->getBorderTopStyle());\n        // Right\n        self::assertEquals('00A933', $element2e31pStyle->getBorderRightColor());\n        self::assertEquals('4', $element2e31pStyle->getBorderRightSize());\n        self::assertEquals('dashed', $element2e31pStyle->getBorderRightStyle());\n        // Bottom\n        self::assertEquals('F10D0C', $element2e31pStyle->getBorderBottomColor());\n        self::assertEquals('8', $element2e31pStyle->getBorderBottomSize());\n        self::assertEquals('dashSmallGap', $element2e31pStyle->getBorderBottomStyle());\n        // Left\n        self::assertEquals('3465A4', $element2e31pStyle->getBorderLeftColor());\n        self::assertEquals('8', $element2e31pStyle->getBorderLeftSize());\n        self::assertEquals('dashed', $element2e31pStyle->getBorderLeftStyle());\n    }\n\n    /**\n     * Load a Word 2011 file.\n     */\n    public function testLoadWord2011(): void\n    {\n        $reader = new Word2007();\n        $phpWord = $reader->load(dirname(__DIR__, 1) . '/_files/documents/reader-2011.docx');\n\n        self::assertInstanceOf(PhpWord::class, $phpWord);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p[3]/w:r/w:pict/v:shape/v:imagedata'));\n    }\n\n    /**\n     * Load a Word without/withoutImages.\n     *\n     * @dataProvider providerSettingsImageLoading\n     */\n    public function testLoadWord2011SettingsImageLoading(bool $hasImageLoading): void\n    {\n        $reader = new Word2007();\n        $reader->setImageLoading($hasImageLoading);\n        $phpWord = $reader->load(dirname(__DIR__, 1) . '/_files/documents/reader-2011.docx');\n\n        self::assertInstanceOf(PhpWord::class, $phpWord);\n\n        $sections = $phpWord->getSections();\n        self::assertCount(1, $sections);\n        $section = $sections[0];\n        $elements = $section->getElements();\n        self::assertCount(3, $elements);\n        $element = $elements[2];\n        self::assertInstanceOf(TextRun::class, $element);\n        $subElements = $element->getElements();\n        if ($hasImageLoading) {\n            self::assertCount(1, $subElements);\n            $subElement = $subElements[0];\n            self::assertInstanceOf(Image::class, $subElement);\n        } else {\n            self::assertCount(0, $subElements);\n        }\n    }\n\n    public static function providerSettingsImageLoading(): iterable\n    {\n        return [\n            [true],\n            [false],\n        ];\n    }\n\n    public function testLoadComments(): void\n    {\n        $phpWord = IOFactory::load(dirname(__DIR__, 1) . '/_files/documents/reader-comments.docx');\n\n        self::assertInstanceOf(PhpWord::class, $phpWord);\n\n        self::assertEquals(2, $phpWord->getComments()->countItems());\n\n        /** @var Comment $comment */\n        $comment = $phpWord->getComments()->getItem(0);\n        self::assertInstanceOf(Comment::class, $comment);\n        self::assertEquals('shaedrich', $comment->getAuthor());\n        self::assertEquals(new DateTime('2021-10-28T13:56:55Z'), $comment->getDate());\n        self::assertEquals('SH', $comment->getInitials());\n        self::assertCount(1, $comment->getElements());\n        self::assertInstanceOf(Text::class, $comment->getElement(0));\n        self::assertEquals('This this be lowercase', $comment->getElement(0)->getText());\n        /** @var Font $fontStyle */\n        $fontStyle = $comment->getElement(0)->getFontStyle();\n        self::assertInstanceOf(Font::class, $fontStyle);\n        self::assertEquals('de-DE', $fontStyle->getLang()->getLatin());\n\n        /** @var Comment $comment */\n        $comment = $phpWord->getComments()->getItem(1);\n        self::assertInstanceOf(Comment::class, $comment);\n        self::assertEquals('shaedrich', $comment->getAuthor());\n        self::assertEquals(new DateTime('2021-11-02T19:10:00Z'), $comment->getDate());\n        self::assertEquals('SH', $comment->getInitials());\n        self::assertCount(1, $comment->getElements());\n        self::assertInstanceOf(Text::class, $comment->getElement(0));\n        self::assertEquals('But this should be uppercase', $comment->getElement(0)->getText());\n        /** @var Font $fontStyle */\n        $fontStyle = $comment->getElement(0)->getFontStyle();\n        self::assertInstanceOf(Font::class, $fontStyle);\n        self::assertEquals('de-DE', $fontStyle->getLang()->getLatin());\n    }\n\n    public function testLoadFormula(): void\n    {\n        $phpWord = IOFactory::load(dirname(__DIR__, 1) . '/_files/documents/reader-formula.docx');\n\n        self::assertInstanceOf(PhpWord::class, $phpWord);\n\n        $sections = $phpWord->getSections();\n        self::assertCount(1, $sections);\n\n        $section = $sections[0];\n        self::assertInstanceOf(Section::class, $section);\n\n        $elements = $section->getElements();\n        self::assertCount(1, $elements);\n\n        $element = $elements[0];\n        self::assertInstanceOf(Formula::class, $element);\n\n        $elements = $element->getMath()->getElements();\n        self::assertCount(5, $elements);\n\n        /** @var Element\\Fraction $element */\n        $element = $elements[0];\n        self::assertInstanceOf(Element\\Fraction::class, $element);\n        /** @var Element\\Identifier $numerator */\n        $numerator = $element->getNumerator();\n        self::assertInstanceOf(Element\\Identifier::class, $numerator);\n        self::assertEquals('π', $numerator->getValue());\n        /** @var Element\\Numeric $denominator */\n        $denominator = $element->getDenominator();\n        self::assertInstanceOf(Element\\Numeric::class, $denominator);\n        self::assertEquals(2, $denominator->getValue());\n\n        /** @var Element\\Operator $element */\n        $element = $elements[1];\n        self::assertInstanceOf(Element\\Operator::class, $element);\n        self::assertEquals('+', $element->getValue());\n\n        /** @var Element\\Identifier $element */\n        $element = $elements[2];\n        self::assertInstanceOf(Element\\Identifier::class, $element);\n        self::assertEquals('a', $element->getValue());\n\n        /** @var Element\\Operator $element */\n        $element = $elements[3];\n        self::assertInstanceOf(Element\\Operator::class, $element);\n        self::assertEquals('∗', $element->getValue());\n\n        /** @var Element\\Numeric $element */\n        $element = $elements[4];\n        self::assertInstanceOf(Element\\Numeric::class, $element);\n        self::assertEquals(2, $element->getValue());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/SettingsTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Settings;\nuse PHPUnit\\Framework\\TestCase;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Settings.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Settings\n *\n * @runTestsInSeparateProcesses\n */\nclass SettingsTest extends TestCase\n{\n    private $compatibility;\n\n    /** @var string */\n    private $defaultFontColor;\n\n    private $defaultFontSize;\n\n    private $defaultFontName;\n\n    private $defaultPaper;\n\n    private $measurementUnit;\n\n    private $outputEscapingEnabled;\n\n    private $pdfRendererName;\n\n    /**\n     * @var array\n     */\n    private $pdfRendererOptions;\n\n    private $pdfRendererPath;\n\n    private $tempDir;\n\n    private $zipClass;\n\n    /** @var bool */\n    private $defaultRtl;\n\n    protected function setUp(): void\n    {\n        $this->compatibility = Settings::hasCompatibility();\n        $this->defaultFontColor = Settings::getDefaultFontColor();\n        $this->defaultFontSize = Settings::getDefaultFontSize();\n        $this->defaultFontName = Settings::getDefaultFontName();\n        $this->defaultPaper = Settings::getDefaultPaper();\n        $this->measurementUnit = Settings::getMeasurementUnit();\n        $this->outputEscapingEnabled = Settings::isOutputEscapingEnabled();\n        $this->pdfRendererName = Settings::getPdfRendererName();\n        $this->pdfRendererOptions = Settings::getPdfRendererOptions();\n        $this->pdfRendererPath = Settings::getPdfRendererPath();\n        $this->tempDir = Settings::getTempDir();\n        $this->zipClass = Settings::getZipClass();\n        $this->defaultRtl = Settings::isDefaultRtl();\n    }\n\n    protected function tearDown(): void\n    {\n        Settings::setCompatibility($this->compatibility);\n        Settings::setDefaultFontColor($this->defaultFontColor);\n        Settings::setDefaultFontSize($this->defaultFontSize);\n        Settings::setDefaultFontName($this->defaultFontName);\n        Settings::setDefaultPaper($this->defaultPaper);\n        Settings::setMeasurementUnit($this->measurementUnit);\n        Settings::setOutputEscapingEnabled($this->outputEscapingEnabled);\n        Settings::setPdfRendererName($this->pdfRendererName);\n        Settings::setPdfRendererOptions($this->pdfRendererOptions);\n        Settings::setPdfRendererPath($this->pdfRendererPath);\n        Settings::setTempDir($this->tempDir);\n        Settings::setZipClass($this->zipClass);\n        Settings::setDefaultRtl($this->defaultRtl);\n    }\n\n    /**\n     * Test set/get compatibity option.\n     */\n    public function testSetGetCompatibility(): void\n    {\n        self::assertTrue(Settings::hasCompatibility());\n        self::assertTrue(Settings::setCompatibility(false));\n        self::assertFalse(Settings::hasCompatibility());\n    }\n\n    /**\n     * Test set/get outputEscapingEnabled option.\n     */\n    public function testSetGetOutputEscapingEnabled(): void\n    {\n        self::assertFalse(Settings::isOutputEscapingEnabled());\n        Settings::setOutputEscapingEnabled(true);\n        self::assertTrue(Settings::isOutputEscapingEnabled());\n    }\n\n    public function testSetGetDefaultRtl(): void\n    {\n        self::assertNull(Settings::isDefaultRtl());\n        Settings::setDefaultRtl(true);\n        self::assertTrue(Settings::isDefaultRtl());\n        Settings::setDefaultRtl(false);\n        self::assertFalse(Settings::isDefaultRtl());\n        Settings::setDefaultRtl(null);\n        self::assertNull(Settings::isDefaultRtl());\n    }\n\n    /**\n     * Test set/get zip class.\n     */\n    public function testSetGetZipClass(): void\n    {\n        self::assertEquals(Settings::ZIPARCHIVE, Settings::getZipClass());\n        self::assertFalse(Settings::setZipClass('foo'));\n        self::assertEquals(Settings::ZIPARCHIVE, Settings::getZipClass());\n        self::assertTrue(Settings::setZipClass(Settings::PCLZIP));\n        self::assertEquals(Settings::getZipClass(), Settings::PCLZIP);\n        self::assertFalse(Settings::setZipClass('foo'));\n        self::assertEquals(Settings::getZipClass(), Settings::PCLZIP);\n    }\n\n    /**\n     * Test set/get PDF renderer.\n     */\n    public function testSetGetPdfRenderer(): void\n    {\n        $domPdfPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/dompdf/dompdf');\n\n        self::assertFalse(Settings::setPdfRenderer('FOO', 'dummy/path'));\n        self::assertTrue(Settings::setPdfRenderer(Settings::PDF_RENDERER_DOMPDF, $domPdfPath));\n        self::assertEquals(Settings::PDF_RENDERER_DOMPDF, Settings::getPdfRendererName());\n        self::assertEquals($domPdfPath, Settings::getPdfRendererPath());\n        self::assertFalse(Settings::setPdfRendererPath('dummy/path'));\n        self::assertEquals($domPdfPath, Settings::getPdfRendererPath());\n    }\n\n    /**\n     * Test set/get PDF renderer.\n     */\n    public function testSetGetPdfOptions(): void\n    {\n        $domPdfPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/dompdf/dompdf');\n\n        self::assertEquals([], Settings::getPdfRendererOptions());\n\n        Settings::setPdfRendererOptions([\n            'font' => 'Arial',\n        ]);\n        self::assertEquals([\n            'font' => 'Arial',\n        ], Settings::getPdfRendererOptions());\n    }\n\n    /**\n     * Test set/get measurement unit.\n     */\n    public function testSetGetMeasurementUnit(): void\n    {\n        self::assertEquals(Settings::UNIT_TWIP, Settings::getMeasurementUnit());\n        self::assertFalse(Settings::setMeasurementUnit('foo'));\n        self::assertEquals(Settings::UNIT_TWIP, Settings::getMeasurementUnit());\n        self::assertTrue(Settings::setMeasurementUnit(Settings::UNIT_INCH));\n        self::assertEquals(Settings::UNIT_INCH, Settings::getMeasurementUnit());\n        self::assertFalse(Settings::setMeasurementUnit('foo'));\n        self::assertEquals(Settings::UNIT_INCH, Settings::getMeasurementUnit());\n    }\n\n    /**\n     * @covers ::getTempDir\n     */\n    public function testPhpTempDirIsUsedByDefault(): void\n    {\n        self::assertEquals(sys_get_temp_dir(), Settings::getTempDir());\n    }\n\n    /**\n     * @covers ::getTempDir\n     * @covers ::setTempDir\n     *\n     * @depends testPhpTempDirIsUsedByDefault\n     */\n    public function testTempDirCanBeSet(): void\n    {\n        $userDefinedTempDir = 'C:\\PhpWordTemp';\n        Settings::setTempDir($userDefinedTempDir);\n        $currentTempDir = Settings::getTempDir();\n        self::assertEquals($userDefinedTempDir, $currentTempDir);\n        self::assertNotEquals(sys_get_temp_dir(), $currentTempDir);\n    }\n\n    /**\n     * Test set/get default font name.\n     */\n    public function testSetGetDefaultFontName(): void\n    {\n        self::assertEquals(Settings::DEFAULT_FONT_NAME, Settings::getDefaultFontName());\n        self::assertFalse(Settings::setDefaultFontName(' '));\n        self::assertEquals(Settings::DEFAULT_FONT_NAME, Settings::getDefaultFontName());\n        self::assertTrue(Settings::setDefaultFontName('Times New Roman'));\n        self::assertEquals('Times New Roman', Settings::getDefaultFontName());\n        self::assertFalse(Settings::setDefaultFontName(' '));\n        self::assertEquals('Times New Roman', Settings::getDefaultFontName());\n    }\n\n    /**\n     * Test set/get default font name.\n     */\n    public function testSetGetDefaultAsianFontName(): void\n    {\n        self::assertEquals(Settings::DEFAULT_FONT_NAME, Settings::getDefaultAsianFontName());\n        self::assertFalse(Settings::setDefaultAsianFontName(' '));\n        self::assertEquals(Settings::DEFAULT_FONT_NAME, Settings::getDefaultAsianFontName());\n        self::assertTrue(Settings::setDefaultAsianFontName('Times New Roman'));\n        self::assertEquals('Times New Roman', Settings::getDefaultAsianFontName());\n        self::assertFalse(Settings::setDefaultAsianFontName(' '));\n        self::assertEquals('Times New Roman', Settings::getDefaultAsianFontName());\n    }\n\n    /**\n     * Test set/get default font size.\n     */\n    public function testSetGetDefaultFontSize(): void\n    {\n        self::assertEquals(Settings::DEFAULT_FONT_SIZE, Settings::getDefaultFontSize());\n        self::assertFalse(Settings::setDefaultFontSize(null));\n        self::assertEquals(Settings::DEFAULT_FONT_SIZE, Settings::getDefaultFontSize());\n        self::assertTrue(Settings::setDefaultFontSize(12));\n        self::assertEquals(12, Settings::getDefaultFontSize());\n        self::assertFalse(Settings::setDefaultFontSize(null));\n        self::assertEquals(12, Settings::getDefaultFontSize());\n        self::assertTrue(Settings::setDefaultFontSize(12.5));\n        self::assertEquals(12.5, Settings::getDefaultFontSize());\n        self::assertFalse(Settings::setDefaultFontSize(0.5));\n        self::assertEquals(12.5, Settings::getDefaultFontSize());\n        self::assertFalse(Settings::setDefaultFontSize(0));\n        self::assertEquals(12.5, Settings::getDefaultFontSize());\n    }\n\n    /**\n     * Test set/get default font color.\n     */\n    public function testSetGetDefaultFontColor(): void\n    {\n        self::assertEquals(Settings::DEFAULT_FONT_COLOR, Settings::getDefaultFontColor());\n        self::assertFalse(Settings::setDefaultFontColor(' '));\n        self::assertEquals(Settings::DEFAULT_FONT_COLOR, Settings::getDefaultFontColor());\n        self::assertTrue(Settings::setDefaultFontColor('FF0000'));\n        self::assertEquals('FF0000', Settings::getDefaultFontColor());\n        self::assertFalse(Settings::setDefaultFontColor(' '));\n        self::assertEquals('FF0000', Settings::getDefaultFontColor());\n    }\n\n    /**\n     * Test set/get default paper.\n     */\n    public function testSetGetDefaultPaper(): void\n    {\n        $dflt = Settings::DEFAULT_PAPER;\n        $chng = 'A4';\n        $doc = new PhpWord();\n        self::assertEquals($dflt, Settings::getDefaultPaper());\n        $sec1 = $doc->addSection();\n        self::assertEquals($dflt, $sec1->getStyle()->getPaperSize());\n        self::assertFalse(Settings::setDefaultPaper(''));\n        self::assertEquals($dflt, Settings::getDefaultPaper());\n        self::assertTrue(Settings::setDefaultPaper($chng));\n        self::assertEquals($chng, Settings::getDefaultPaper());\n        $sec2 = $doc->addSection();\n        self::assertEquals($chng, $sec2->getStyle()->getPaperSize());\n        $sec3 = $doc->addSection(['paperSize' => 'Legal']);\n        self::assertEquals('Legal', $sec3->getStyle()->getPaperSize());\n        self::assertFalse(Settings::setDefaultPaper(''));\n        self::assertEquals($chng, Settings::getDefaultPaper());\n    }\n\n    /**\n     * Test load config.\n     */\n    public function testLoadConfig(): void\n    {\n        $expected = [\n            'compatibility' => true,\n            'zipClass' => 'ZipArchive',\n            'pdfRendererName' => 'DomPDF',\n            'pdfRendererPath' => '',\n            'defaultFontName' => 'Arial',\n            'defaultFontSize' => 10,\n            'defaultFontColor' => '000000',\n            'outputEscapingEnabled' => false,\n            'defaultPaper' => 'A4',\n        ];\n\n        // Test default value\n        self::assertEquals($expected, Settings::loadConfig());\n\n        // Test with valid file\n        self::assertEquals($expected, Settings::loadConfig(__DIR__ . '/../../phpword.ini.dist'));\n        foreach ($expected as $key => $value) {\n            if ($key === 'compatibility') {\n                $meth = 'hasCompatibility';\n            } elseif ($key === 'outputEscapingEnabled') {\n                $meth = 'isOutputEscapingEnabled';\n            } else {\n                $meth = 'get' . ucfirst($key);\n            }\n            self::assertEquals(Settings::$meth(), $value);\n        }\n\n        // Test with invalid file\n        self::assertEmpty(Settings::loadConfig(__DIR__ . '/../../phpunit.xml.dist'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Shared/ConverterTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Shared;\n\nuse PhpOffice\\PhpWord\\Shared\\Converter;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Shared\\Converter.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Shared\\Converter\n */\nclass ConverterTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test unit conversion functions with various numbers.\n     */\n    public function testUnitConversions(): void\n    {\n        $values = [];\n        $values[] = 0; // zero value\n        $values[] = mt_rand(1, 100) / 100; // fraction number\n        $values[] = mt_rand(1, 100); // integer\n\n        foreach ($values as $value) {\n            $result = Converter::cmToTwip($value);\n            self::assertEqualsWithDelta($value / 2.54 * 1440, $result, 0.00001);\n\n            $result = Converter::cmToInch($value);\n            self::assertEqualsWithDelta($value / 2.54, $result, 0.00001);\n\n            $result = Converter::cmToPixel($value);\n            self::assertEqualsWithDelta($value / 2.54 * 96, $result, 0.00001);\n\n            $result = Converter::cmToPoint($value);\n            self::assertEqualsWithDelta($value / 2.54 * 72, $result, 0.00001);\n\n            $result = Converter::cmToEmu($value);\n            self::assertEqualsWithDelta(round($value / 2.54 * 96 * 9525), $result, 0.00001);\n\n            $result = Converter::inchToTwip($value);\n            self::assertEqualsWithDelta($value * 1440, $result, 0.00001);\n\n            $result = Converter::inchToCm($value);\n            self::assertEqualsWithDelta($value * 2.54, $result, 0.00001);\n\n            $result = Converter::inchToPixel($value);\n            self::assertEqualsWithDelta($value * 96, $result, 0.00001);\n\n            $result = Converter::inchToPoint($value);\n            self::assertEqualsWithDelta($value * 72, $result, 0.00001);\n\n            $result = Converter::inchToEmu($value);\n            self::assertEqualsWithDelta(round($value * 96 * 9525), $result, 0.00001);\n\n            $result = Converter::pixelToTwip($value);\n            self::assertEqualsWithDelta($value / 96 * 1440, $result, 0.00001);\n\n            $result = Converter::pixelToCm($value);\n            self::assertEqualsWithDelta($value / 96 * 2.54, $result, 0.00001);\n\n            $result = Converter::pixelToPoint($value);\n            self::assertEqualsWithDelta($value / 96 * 72, $result, 0.00001);\n\n            $result = Converter::pixelToEmu($value);\n            self::assertEqualsWithDelta(round($value * 9525), $result, 0.00001);\n\n            $result = Converter::pointToTwip($value);\n            self::assertEqualsWithDelta($value * 20, $result, 0.00001);\n\n            $result = Converter::pointToCm($value);\n            self::assertEqualsWithDelta($value * 0.035277778, $result, 0.00001);\n\n            $result = Converter::pointToPixel($value);\n            self::assertEqualsWithDelta($value / 72 * 96, $result, 0.00001);\n\n            $result = Converter::pointToEmu($value);\n            self::assertEqualsWithDelta(round($value / 72 * 96 * 9525), $result, 0.00001);\n\n            $result = Converter::emuToPixel($value);\n            self::assertEqualsWithDelta(round($value / 9525), $result, 0.00001);\n\n            $result = Converter::picaToPoint($value);\n            self::assertEqualsWithDelta($value / 6 * 72, $result, 0.00001);\n\n            $result = Converter::degreeToAngle($value);\n            self::assertEqualsWithDelta((int) round($value * 60000), $result, 0.00001);\n\n            $result = Converter::angleToDegree($value);\n            self::assertEqualsWithDelta(round($value / 60000), $result, 0.00001);\n        }\n    }\n\n    /**\n     * Test htmlToRGB().\n     */\n    public function testHtmlToRGB(): void\n    {\n        $flse = false;\n        self::assertEquals([255, 153, 221], Converter::htmlToRgb('#FF99DD')); // With #\n        self::assertEquals([224, 170, 29], Converter::htmlToRgb('E0AA1D')); // 6 characters\n        self::assertEquals([102, 119, 136], Converter::htmlToRgb('678')); // 3 characters\n        self::assertEquals($flse, Converter::htmlToRgb('0F9D')); // 4 characters\n        self::assertEquals([0, 0, 0], Converter::htmlToRgb('unknow')); // 6 characters, invalid\n        self::assertEquals([139, 0, 139], Converter::htmlToRgb(\\PhpOffice\\PhpWord\\Style\\Font::FGCOLOR_DARKMAGENTA)); // Constant\n    }\n\n    /**\n     * Test css size to point.\n     */\n    public function testCssSizeParser(): void\n    {\n        self::assertNull(Converter::cssToPoint('10em'));\n        self::assertEquals(0, Converter::cssToPoint('0'));\n        self::assertEquals(10, Converter::cssToPoint('10pt'));\n        self::assertEquals(7.5, Converter::cssToPoint('10px'));\n        self::assertEquals(720, Converter::cssToPoint('10in'));\n        self::assertEquals(7.2, Converter::cssToPoint('0.1in'));\n        self::assertEquals(120, Converter::cssToPoint('10pc'));\n        self::assertEqualsWithDelta(28.346457, Converter::cssToPoint('10mm'), 0.000001);\n        self::assertEqualsWithDelta(283.464567, Converter::cssToPoint('10cm'), 0.000001);\n        self::assertEquals(40, Converter::cssToPixel('30pt'));\n        self::assertEquals(1.27, Converter::cssToCm('36pt'));\n        self::assertEquals(127000, Converter::cssToEmu('10pt'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Shared/CssTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Shared;\n\nuse PhpOffice\\PhpWord\\Shared\\Css;\nuse PHPUnit\\Framework\\TestCase;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Shared\\Css.\n */\nclass CssTest extends TestCase\n{\n    public function testEmptyCss(): void\n    {\n        $css = new Css('');\n        $css->process();\n\n        self::assertEquals([], $css->getStyles());\n    }\n\n    public function testBasicCss(): void\n    {\n        $cssContent = '.pStyle {\n          font-size:15px;\n        }';\n\n        $css = new Css($cssContent);\n        $css->process();\n\n        self::assertEquals([\n            '.pStyle' => [\n                'font-size' => '15px',\n            ],\n        ], $css->getStyles());\n        self::assertEquals([\n            'font-size' => '15px',\n        ], $css->getStyle('.pStyle'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Shared/DrawingTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Shared;\n\nuse PhpOffice\\PhpWord\\Shared\\Drawing;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Shared\\Drawing.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Shared\\Drawing\n */\nclass DrawingTest extends \\PHPUnit\\Framework\\TestCase\n{\n    public function testDegreesAngle(): void\n    {\n        $value = mt_rand(1, 100);\n\n        self::assertEquals(0, Drawing::degreesToAngle());\n        self::assertEquals((int) round($value * 60000), Drawing::degreesToAngle($value));\n        self::assertEquals(0, Drawing::angleToDegrees());\n        self::assertEquals(round($value / 60000), Drawing::angleToDegrees($value));\n    }\n\n    public function testPixelsCentimeters(): void\n    {\n        $value = mt_rand(1, 100);\n\n        self::assertEquals(0, Drawing::pixelsToCentimeters());\n        self::assertEquals($value / Drawing::DPI_96 * 2.54, Drawing::pixelsToCentimeters($value));\n        self::assertEquals(0, Drawing::centimetersToPixels());\n        self::assertEquals($value / 2.54 * Drawing::DPI_96, Drawing::centimetersToPixels($value));\n    }\n\n    public function testPixelsEMU(): void\n    {\n        $value = mt_rand(1, 100);\n\n        self::assertEquals(0, Drawing::pixelsToEmu());\n        self::assertEquals(round($value * 9525), Drawing::pixelsToEmu($value));\n        self::assertEquals(0, Drawing::emuToPixels());\n        self::assertEquals(round($value / 9525), Drawing::emuToPixels($value));\n    }\n\n    public function testPixelsPoints(): void\n    {\n        $value = mt_rand(1, 100);\n\n        self::assertEquals(0, Drawing::pixelsToPoints());\n        self::assertEquals($value * 0.67777777, Drawing::pixelsToPoints($value));\n        self::assertEquals(0, Drawing::pointsToPixels());\n        self::assertEquals($value * 1.333333333, Drawing::pointsToPixels($value));\n    }\n\n    public function testPointsCentimeters(): void\n    {\n        $value = mt_rand(1, 100);\n\n        self::assertEquals(0, Drawing::pointsToCentimeters());\n        self::assertEquals($value * 1.333333333 / Drawing::DPI_96 * 2.54, Drawing::pointsToCentimeters($value));\n    }\n\n    public function testTwips(): void\n    {\n        $value = mt_rand(1, 100);\n\n        // Centimeters\n        self::assertEquals(0, Drawing::centimetersToTwips());\n        self::assertEquals($value * 566.928, Drawing::centimetersToTwips($value));\n\n        self::assertEquals(0, Drawing::twipsToCentimeters());\n        self::assertEquals($value / 566.928, Drawing::twipsToCentimeters($value));\n\n        // Inches\n        self::assertEquals(0, Drawing::inchesToTwips());\n        self::assertEquals($value * 1440, Drawing::inchesToTwips($value));\n\n        self::assertEquals(0, Drawing::twipsToInches());\n        self::assertEquals($value / 1440, Drawing::twipsToInches($value));\n\n        // Pixels\n        self::assertEquals(0, Drawing::twipsToPixels());\n        self::assertEquals(round($value / 15.873984), Drawing::twipsToPixels($value));\n    }\n\n    public function testHTML(): void\n    {\n        self::assertFalse(Drawing::htmlToRGB('0'));\n        self::assertFalse(Drawing::htmlToRGB('00'));\n        self::assertFalse(Drawing::htmlToRGB('0000'));\n        self::assertFalse(Drawing::htmlToRGB('00000'));\n\n        self::assertIsArray(Drawing::htmlToRGB('ABCDEF'));\n        self::assertCount(3, Drawing::htmlToRGB('ABCDEF'));\n        self::assertEquals([0xAB, 0xCD, 0xEF], Drawing::htmlToRGB('ABCDEF'));\n        self::assertEquals([0xAB, 0xCD, 0xEF], Drawing::htmlToRGB('#ABCDEF'));\n        self::assertEquals([0xAA, 0xBB, 0xCC], Drawing::htmlToRGB('ABC'));\n        self::assertEquals([0xAA, 0xBB, 0xCC], Drawing::htmlToRGB('#ABC'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Shared/HtmlTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Shared;\n\nuse Exception;\nuse PhpOffice\\PhpWord\\ComplexType\\RubyProperties;\nuse PhpOffice\\PhpWord\\Element\\Section;\nuse PhpOffice\\PhpWord\\Element\\Table;\nuse PhpOffice\\PhpWord\\Element\\Text;\nuse PhpOffice\\PhpWord\\Element\\TextRun;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Shared\\Converter;\nuse PhpOffice\\PhpWord\\Shared\\Html;\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\nuse PhpOffice\\PhpWord\\SimpleType\\LineSpacingRule;\nuse PhpOffice\\PhpWord\\SimpleType\\TblWidth;\nuse PhpOffice\\PhpWord\\Style\\Font;\nuse PhpOffice\\PhpWord\\Style\\Paragraph;\nuse PhpOffice\\PhpWordTests\\AbstractWebServerEmbedded;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Shared\\Html.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Shared\\Html\n */\nclass HtmlTest extends AbstractWebServerEmbedded\n{\n    /**\n     * Tear down after each test.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    /**\n     * Test unit conversion functions with various numbers.\n     */\n    public function testAddHtml(): void\n    {\n        $content = '';\n\n        // Default\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        self::assertCount(0, $section->getElements());\n\n        // Heading\n        $styles = ['strong', 'em', 'sup', 'sub'];\n        for ($level = 1; $level <= 6; ++$level) {\n            $content .= \"<h{$level}>Heading {$level}</h{$level}>\";\n        }\n\n        // Styles\n        $content .= '<p style=\"text-decoration: underline; text-decoration: line-through; '\n                  . 'text-align: center; color: #999; background-color: #000; font-weight: bold; font-style: italic;\">';\n        foreach ($styles as $style) {\n            $content .= \"<{$style}>{$style}</{$style}>\";\n        }\n        $content .= '</p>';\n\n        // Add HTML\n        Html::addHtml($section, $content);\n        self::assertCount(7, $section->getElements());\n\n        // Other parts\n        $section = $phpWord->addSection();\n        $content = '';\n        $content .= '<table><tr><th>Header</th><td>Content</td></tr></table>';\n        $content .= '<ul><li>Bullet</li><ul><li>Bullet</li></ul></ul>';\n        $content .= '<ol><li>Bullet</li></ol>';\n        $content .= \"'Single Quoted Text'\";\n        $content .= '\"Double Quoted Text\"';\n        $content .= '& Ampersand';\n        $content .= '&lt;&gt;&ldquo;&lsquo;&rsquo;&laquo;&raquo;&lsaquo;&rsaquo;';\n        $content .= '&amp;&bull;&deg;&hellip;&trade;&copy;&reg;&mdash;';\n        $content .= '&ndash;&nbsp;&emsp;&ensp;&sup2;&sup3;&frac14;&frac12;&frac34;';\n        Html::addHtml($section, $content);\n    }\n\n    /**\n     * Test that html already in body element can be read.\n     *\n     * @ignore\n     */\n    public function testParseFullHtml(): void\n    {\n        $section = new Section(1);\n        Html::addHtml($section, '<body><p>test paragraph1</p><p>test paragraph2</p></body>', true);\n\n        self::assertCount(2, $section->getElements());\n    }\n\n    public function testParseHeader(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        Html::addHtml($section, '<h1>Text</h1>');\n\n        self::assertCount(1, $section->getElements());\n        $element = $section->getElement(0);\n        self::assertInstanceOf(TextRun::class, $element);\n        self::assertInstanceOf(Paragraph::class, $element->getParagraphStyle());\n        self::assertEquals('Heading1', $element->getParagraphStyle()->getStyleName());\n        self::assertEquals('', $element->getParagraphStyle()->getAlignment());\n        self::assertEquals('Text', $element->getText());\n        self::assertCount(1, $element->getElements());\n        $subElement = $element->getElement(0);\n        self::assertInstanceOf(Text::class, $subElement);\n        self::assertInstanceOf(Font::class, $subElement->getFontStyle());\n        self::assertNull($subElement->getFontStyle()->getColor());\n        self::assertEquals('Text', $subElement->getText());\n    }\n\n    public function testParseHeaderStyle(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        Html::addHtml($section, '<h1 style=\"color: #ff0000; text-align:center\">Text</h1>');\n\n        self::assertCount(1, $section->getElements());\n        $element = $section->getElement(0);\n        self::assertInstanceOf(TextRun::class, $element);\n        self::assertInstanceOf(Paragraph::class, $element->getParagraphStyle());\n        self::assertEquals('Heading1', $element->getParagraphStyle()->getStyleName());\n        self::assertEquals('center', $element->getParagraphStyle()->getAlignment());\n        self::assertEquals('Text', $element->getText());\n        self::assertCount(1, $element->getElements());\n        $subElement = $element->getElement(0);\n        self::assertInstanceOf(Text::class, $subElement);\n        self::assertInstanceOf(Font::class, $subElement->getFontStyle());\n        self::assertEquals('ff0000', $subElement->getFontStyle()->getColor());\n        self::assertEquals('Text', $subElement->getText());\n    }\n\n    /**\n     * Test HTML entities.\n     */\n    public function testParseHtmlEntities(): void\n    {\n        \\PhpOffice\\PhpWord\\Settings::setOutputEscapingEnabled(true);\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        Html::addHtml($section, 'text with entities &lt;my text&gt;');\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:r/w:t'));\n        self::assertEquals('text with entities <my text>', $doc->getElement('/w:document/w:body/w:p[1]/w:r/w:t')->nodeValue);\n    }\n\n    public function testParseStyle(): void\n    {\n        $html = '<style type=\"text/css\">\n        .pStyle {\n          font-size:15px;\n        }\n        .tableStyle {\n          width:100%;\n          background-color:red;\n        }\n        </style>\n        \n        <p class=\"pStyle\">Calculator</p>';\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        Html::addHtml($section, $html);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p[2]'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p[2]/w:r'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p[2]/w:r/w:t'));\n        self::assertEquals('Calculator', $doc->getElement('/w:document/w:body/w:p[2]/w:r/w:t')->nodeValue);\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p[2]/w:r/w:rPr'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p[2]/w:r/w:rPr/w:sz'));\n        self::assertEquals('22.5', $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:r/w:rPr/w:sz', 'w:val'));\n    }\n\n    public function testParseStyleTableClassName(): void\n    {\n        $html = '<style type=\"text/css\">.pStyle { font-size:15px; }</style><table class=\"pStyle\"><tr><td></td></tr></table>';\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        Html::addHtml($section, $html);\n\n        self::assertInstanceOf(Table::class, $section->getElement(0));\n        self::assertEquals('pStyle', $section->getElement(0)->getStyle()->getStyleName());\n    }\n\n    /**\n     * Test text-decoration style.\n     */\n    public function testParseTextDecoration(): void\n    {\n        $html = '<span style=\"text-decoration: underline;\">test</span>';\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        Html::addHtml($section, $html);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:u'));\n        self::assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:rPr/w:u', 'w:val'));\n    }\n\n    /**\n     * Test underline.\n     */\n    public function testParseUnderline(): void\n    {\n        $html = '<u>test</u>';\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        Html::addHtml($section, $html);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:u'));\n        self::assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:rPr/w:u', 'w:val'));\n    }\n\n    /**\n     * Test width.\n     *\n     * @dataProvider providerParseWidth\n     */\n    public function testParseWidth(string $htmlSize, float $docxSize, string $docxUnit): void\n    {\n        $html = '<table width=\"' . $htmlSize . '\"><tr><td>A</td></tr></table>';\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        Html::addHtml($section, $html);\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n        $xpath = '/w:document/w:body/w:tbl/w:tblPr/w:tblW';\n        self::assertTrue($doc->elementExists($xpath));\n        self::assertEquals($docxSize, $doc->getElement($xpath)->getAttribute('w:w'));\n        self::assertEquals($docxUnit, $doc->getElement($xpath)->getAttribute('w:type'));\n    }\n\n    /**\n     * Test font-variant style.\n     */\n    public function testParseFontVariant(): void\n    {\n        $html = '<span style=\"font-variant: small-caps;\">test</span>';\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        Html::addHtml($section, $html);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:smallCaps'));\n        self::assertEquals('1', $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:rPr/w:smallCaps', 'w:val'));\n    }\n\n    /**\n     * Test font.\n     */\n    public function testParseFont(): void\n    {\n        $html = '<font style=\"font-family: Arial;\">test</font>';\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        Html::addHtml($section, $html);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr'));\n        //TODO check style\n    }\n\n    /**\n     * Test line-height style.\n     */\n    public function testParseLineHeight(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        Html::addHtml($section, '<p style=\"line-height: 1.5;\">test</p>');\n        Html::addHtml($section, '<p style=\"line-height: 15pt;\">test</p>');\n        Html::addHtml($section, '<p style=\"line-height: 120%;\">test</p>');\n        Html::addHtml($section, '<p style=\"line-height: 0.17in;\">test</p>');\n        Html::addHtml($section, '<p style=\"line-height: normal;\">test</p>');\n        Html::addHtml($section, '<p style=\"line-height: inherit;\">test</p>');\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:pPr/w:spacing'));\n        self::assertEquals(Paragraph::LINE_HEIGHT * 1.5, $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:spacing', 'w:line'));\n        self::assertEquals(LineSpacingRule::AUTO, $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:spacing', 'w:lineRule'));\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p[2]/w:pPr/w:spacing'));\n        self::assertEquals(300, $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:pPr/w:spacing', 'w:line'));\n        self::assertEquals(LineSpacingRule::EXACT, $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:pPr/w:spacing', 'w:lineRule'));\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p[3]/w:pPr/w:spacing'));\n        self::assertEquals(Paragraph::LINE_HEIGHT * 1.2, $doc->getElementAttribute('/w:document/w:body/w:p[3]/w:pPr/w:spacing', 'w:line'));\n        self::assertEquals(LineSpacingRule::AUTO, $doc->getElementAttribute('/w:document/w:body/w:p[3]/w:pPr/w:spacing', 'w:lineRule'));\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p[4]/w:pPr/w:spacing'));\n        self::assertEquals(244.8, $doc->getElementAttribute('/w:document/w:body/w:p[4]/w:pPr/w:spacing', 'w:line'));\n        self::assertEquals(LineSpacingRule::EXACT, $doc->getElementAttribute('/w:document/w:body/w:p[4]/w:pPr/w:spacing', 'w:lineRule'));\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p[5]/w:pPr/w:spacing'));\n        self::assertEquals(Paragraph::LINE_HEIGHT, $doc->getElementAttribute('/w:document/w:body/w:p[5]/w:pPr/w:spacing', 'w:line'));\n        self::assertEquals(LineSpacingRule::AUTO, $doc->getElementAttribute('/w:document/w:body/w:p[5]/w:pPr/w:spacing', 'w:lineRule'));\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p[6]/w:pPr/w:spacing'));\n        self::assertEquals(Paragraph::LINE_HEIGHT, $doc->getElementAttribute('/w:document/w:body/w:p[6]/w:pPr/w:spacing', 'w:line'));\n        self::assertEquals(LineSpacingRule::AUTO, $doc->getElementAttribute('/w:document/w:body/w:p[6]/w:pPr/w:spacing', 'w:lineRule'));\n    }\n\n    public function testParseCellPaddingStyle(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        $top = 10;\n        $right = 11;\n        $bottom = 12;\n        $left = 13;\n\n        $testValTop = Converter::pixelToTwip($top);\n        $testValRight = Converter::pixelToTwip($right);\n        $testValBottom = Converter::pixelToTwip($bottom);\n        $testValLeft = Converter::pixelToTwip($left);\n\n        $html = '<table>\n            <tbody>\n                <tr>\n                    <td style=\"padding:' . $top . 'px ' . $right . 'px ' . $bottom . 'px ' . $left . 'px;\">full</td>\n                    <td style=\"padding:' . $top . 'px 0px ' . $bottom . 'px ' . $left . 'px;padding-right:' . $right . 'px;\">mix</td>\n                    <td style=\"padding-top:' . $top . 'px;\">top</td>\n                    <td style=\"padding-bottom:' . $bottom . 'px;\">bottom</td>\n                    <td style=\"padding-left:' . $left . 'px;\">left</td>\n                </tr>\n            </tbody>\n        </table>';\n        Html::addHtml($section, $html);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $path = '/w:document/w:body/w:tbl/w:tr/w:tc[1]/w:tcPr/w:tcMar/w:top';\n        self::assertTrue($doc->elementExists($path));\n        $path = '/w:document/w:body/w:tbl/w:tr/w:tc[1]/w:tcPr/w:tcMar/w:bottom';\n        self::assertTrue($doc->elementExists($path));\n        $path = '/w:document/w:body/w:tbl/w:tr/w:tc[1]/w:tcPr/w:tcMar/w:end';\n        self::assertTrue($doc->elementExists($path));\n        $path = '/w:document/w:body/w:tbl/w:tr/w:tc[1]/w:tcPr/w:tcMar/w:start';\n        self::assertTrue($doc->elementExists($path));\n\n        $path = '/w:document/w:body/w:tbl/w:tr/w:tc[2]/w:tcPr/w:tcMar/w:end';\n        self::assertTrue($doc->elementExists($path));\n        self::assertEquals($testValRight, $doc->getElementAttribute($path, 'w:w'));\n        self::assertEquals(TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type'));\n\n        $path = '/w:document/w:body/w:tbl/w:tr/w:tc[3]/w:tcPr/w:tcMar/w:top';\n        self::assertTrue($doc->elementExists($path));\n        self::assertEquals($testValTop, $doc->getElementAttribute($path, 'w:w'));\n        self::assertEquals(TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type'));\n\n        $path = '/w:document/w:body/w:tbl/w:tr/w:tc[4]/w:tcPr/w:tcMar/w:bottom';\n        self::assertTrue($doc->elementExists($path));\n        self::assertEquals($testValBottom, $doc->getElementAttribute($path, 'w:w'));\n        self::assertEquals(TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type'));\n\n        $path = '/w:document/w:body/w:tbl/w:tr/w:tc[5]/w:tcPr/w:tcMar/w:start';\n        self::assertTrue($doc->elementExists($path));\n        self::assertEquals($testValLeft, $doc->getElementAttribute($path, 'w:w'));\n        self::assertEquals(TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type'));\n    }\n\n    /**\n     * Test text-indent style.\n     */\n    public function testParseTextIndent(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        Html::addHtml($section, '<p style=\"text-indent: 50px;\">test</p>');\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:ind'));\n        self::assertEquals(750, $doc->getElementAttribute('/w:document/w:body/w:p/w:pPr/w:ind', 'w:firstLine'));\n    }\n\n    /**\n     * Test text-align style.\n     */\n    public function testParseTextAlign(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        Html::addHtml($section, '<p style=\"text-align: left;\">test</p>');\n        Html::addHtml($section, '<p style=\"text-align: right;\">test</p>');\n        Html::addHtml($section, '<p style=\"text-align: center;\">test</p>');\n        Html::addHtml($section, '<p style=\"text-align: justify;\">test</p>');\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:jc'));\n        self::assertEquals(Jc::START, $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:jc', 'w:val'));\n        self::assertEquals(Jc::END, $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:pPr/w:jc', 'w:val'));\n        self::assertEquals(Jc::CENTER, $doc->getElementAttribute('/w:document/w:body/w:p[3]/w:pPr/w:jc', 'w:val'));\n        self::assertEquals(Jc::BOTH, $doc->getElementAttribute('/w:document/w:body/w:p[4]/w:pPr/w:jc', 'w:val'));\n    }\n\n    /**\n     * Test font-size style.\n     */\n    public function testParseFontSize(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        Html::addHtml($section, '<span style=\"font-size: 10pt;\">test</span>');\n        Html::addHtml($section, '<span style=\"font-size: 10px;\">test</span>');\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:sz'));\n        self::assertEquals('20', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:r/w:rPr/w:sz', 'w:val'));\n        self::assertEquals('15', $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:r/w:rPr/w:sz', 'w:val'));\n    }\n\n    /**\n     * Test direction style.\n     */\n    public function testParseTextDirection(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        Html::addHtml($section, '<span style=\"direction: rtl\">test</span>');\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:rtl'));\n    }\n\n    /**\n     * Test html lang.\n     */\n    public function testParseLang(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        Html::addHtml($section, '<span lang=\"fr-BE\">test</span>');\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:lang'));\n        self::assertEquals('fr-BE', $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:rPr/w:lang', 'w:val'));\n    }\n\n    /**\n     * Test font-family style.\n     */\n    public function testParseFontFamily(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        Html::addHtml($section, '<span style=\"font-family: Arial\">test</span>');\n        Html::addHtml($section, '<span style=\"font-family: Times New Roman;\">test</span>');\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:rFonts'));\n        self::assertEquals('Arial', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:r/w:rPr/w:rFonts', 'w:ascii'));\n        self::assertEquals('Times New Roman', $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:r/w:rPr/w:rFonts', 'w:ascii'));\n    }\n\n    /**\n     * Test parsing paragraph and span styles.\n     */\n    public function testParseParagraphAndSpanStyle(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        Html::addHtml($section, '<p style=\"text-align: center; margin-top: 15px; margin-bottom: 15px;\"><span style=\"text-decoration: underline;\">test</span></p>');\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:jc'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:spacing'));\n        self::assertEquals(Jc::CENTER, $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:jc', 'w:val'));\n        self::assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:r/w:rPr/w:u', 'w:val'));\n    }\n\n    /**\n     * Test parsing paragraph with `page-break-after` style.\n     */\n    public function testParseParagraphWithPageBreak(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        Html::addHtml($section, '<p style=\"page-break-after:always;\"></p>');\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:br'));\n        self::assertEquals('page', $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:br', 'w:type'));\n    }\n\n    /**\n     * Test parsing table.\n     */\n    public function testParseTable(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $html = '<table align=\"left\" style=\"width: 50%; border: 12px #0000FF double\">\n                <thead>\n                    <tr style=\"background-color: #FF0000; text-align: center; color: #FFFFFF; font-weight: bold\">\n                        <th style=\"width: 50pt\"><p>header a</p></th>\n                        <th style=\"width: 50; border-color: #00EE00; border-width: 3px\"><span>header b</span></th>\n                        <th style=\"border-color: #00AA00 #00BB00 #00CC00 #00DD00; border-width: 3px\">header c</th>\n                    </tr>\n                </thead>\n                <tbody>\n                    <tr><td style=\"border-style: dotted;\">1</td><td colspan=\"2\">2</td></tr>\n                    <tr><td>This is <b>bold</b> text</td><td>5</td><td><p>6</p></td></tr>\n                </tbody>\n            </table>';\n        Html::addHtml($section, $html);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr/w:tc'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tblPr/w:jc'));\n        self::assertEquals(Jc::START, $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tblPr/w:jc', 'w:val'));\n\n        //check border colors\n        self::assertEquals('00EE00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]/w:tcPr/w:tcBorders/w:top', 'w:color'));\n        self::assertEquals('00EE00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]/w:tcPr/w:tcBorders/w:right', 'w:color'));\n        self::assertEquals('00EE00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]/w:tcPr/w:tcBorders/w:bottom', 'w:color'));\n        self::assertEquals('00EE00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]/w:tcPr/w:tcBorders/w:left', 'w:color'));\n\n        self::assertEquals('00AA00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:top', 'w:color'));\n        self::assertEquals('00BB00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:right', 'w:color'));\n        self::assertEquals('00CC00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:bottom', 'w:color'));\n        self::assertEquals('00DD00', $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]/w:tcPr/w:tcBorders/w:left', 'w:color'));\n\n        //check borders are not propagated inside cells\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc[1]/w:p'));\n        self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc[1]/w:p/w:pPr/w:pBdr'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]/w:p'));\n        self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]/w:p/w:pPr/w:pBdr'));\n    }\n\n    /**\n     * Parse widths in tables and cells, which also allows for controlling column width.\n     */\n    public function testParseTableAndCellWidth(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection([\n            'orientation' => \\PhpOffice\\PhpWord\\Style\\Section::ORIENTATION_LANDSCAPE,\n        ]);\n\n        // borders & backgrounds are here just for better visual comparison\n        $html = <<<HTML\n<table style=\"border: 1px #000000 solid; width: 100%;\">\n    <tr>\n        <td style=\"width: 25%; border: 1px #000000 solid; text-align: center;\">25%</td>\n        <td>\n            <table width=\"400\" style=\"border: 1px #000000 solid; background-color: #EEEEEE;\">\n                <tr>\n                    <th colspan=\"3\" style=\"border: 1px #000000 solid;\">400px</th>\n                </tr>\n                <tr>\n                    <th>T2.R2.C1</th>\n                    <th style=\"width: 50pt; border: 1px #FF0000 dashed; background-color: #FFFFFF\">50pt</th>\n                    <th>T2.R2.C3</th>\n                </tr>\n                <tr>\n                    <th width=\"300\" colspan=\"2\" style=\"border: 1px #000000 solid;\">300px</th>\n                    <th style=\"border: 1px #000000 solid;\">T2.R3.C3</th>\n                </tr>\n            </table>\n        </td>\n    </tr>\n</table>\nHTML;\n\n        Html::addHtml($section, $html);\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        // outer table grid\n        $xpath = '/w:document/w:body/w:tbl/w:tblGrid/w:gridCol';\n        self::assertTrue($doc->elementExists($xpath));\n        self::assertEquals(25 * 50, $doc->getElement($xpath)->getAttribute('w:w'));\n        self::assertEquals(TblWidth::TWIP, $doc->getElement($xpath)->getAttribute('w:type'));\n\n        // <td style=\"width: 25%; ...\n        $xpath = '/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr/w:tcW';\n        self::assertTrue($doc->elementExists($xpath));\n        self::assertEquals(25 * 50, $doc->getElement($xpath)->getAttribute('w:w'));\n        self::assertEquals(TblWidth::PERCENT, $doc->getElement($xpath)->getAttribute('w:type'));\n\n        // <table width=\"400\" .. 400px = 6000 twips (400 / 96 * 1440)\n        $xpath = '/w:document/w:body/w:tbl/w:tr/w:tc/w:tbl/w:tr/w:tc/w:tcPr/w:tcW';\n        self::assertTrue($doc->elementExists($xpath));\n        self::assertEquals(6000, $doc->getElement($xpath)->getAttribute('w:w'));\n        self::assertEquals(TblWidth::TWIP, $doc->getElement($xpath)->getAttribute('w:type'));\n\n        // <th style=\"width: 50pt; .. 50pt = 750 twips (50 / 72 * 1440)\n        $xpath = '/w:document/w:body/w:tbl/w:tr/w:tc/w:tbl/w:tr[2]/w:tc[2]/w:tcPr/w:tcW';\n        self::assertTrue($doc->elementExists($xpath));\n        self::assertEquals(1000, $doc->getElement($xpath)->getAttribute('w:w'));\n        self::assertEquals(TblWidth::TWIP, $doc->getElement($xpath)->getAttribute('w:type'));\n\n        // <th width=\"300\" .. 300px = 4500 twips (300 / 96 * 1440)\n        $xpath = '/w:document/w:body/w:tbl/w:tr/w:tc/w:tbl/w:tr[3]/w:tc/w:tcPr/w:tcW';\n        self::assertTrue($doc->elementExists($xpath));\n        self::assertEquals(4500, $doc->getElement($xpath)->getAttribute('w:w'));\n        self::assertEquals(TblWidth::TWIP, $doc->getElement($xpath)->getAttribute('w:type'));\n    }\n\n    /**\n     * Parse heights in rows, which also allows for controlling column height.\n     */\n    public function testParseTableRowHeight(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection([\n            'orientation' => \\PhpOffice\\PhpWord\\Style\\Section::ORIENTATION_LANDSCAPE,\n        ]);\n\n        $html = <<<HTML\n<table>\n    <tr style=\"height: 100px;\">\n        <td>100px</td>\n    </tr>\n    <tr style=\"height: 200pt;\">\n        <td>200pt</td>\n    </tr>\n    <tr>\n        <td>\n            <table>\n                <tr style=\"height: 300px;\">\n                    <td>300px</td>\n                </tr>\n            </table>\n        </td>\n    </tr>\n</table>\nHTML;\n\n        Html::addHtml($section, $html);\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        // <tr style=\"height: 100; ... 100px = 1500 twips (100 / 96 * 1440)\n        $xpath = '/w:document/w:body/w:tbl/w:tr/w:trPr/w:trHeight';\n        self::assertTrue($doc->elementExists($xpath));\n        self::assertEquals(1500, $doc->getElement($xpath)->getAttribute('w:val'));\n        self::assertEquals('exact', $doc->getElement($xpath)->getAttribute('w:hRule'));\n\n        // <tr style=\"height: 200pt; ... 200pt = 4000 twips (200 / 72 * 1440)\n        $xpath = '/w:document/w:body/w:tbl/w:tr[2]/w:trPr/w:trHeight';\n        self::assertTrue($doc->elementExists($xpath));\n        self::assertEquals(4000, $doc->getElement($xpath)->getAttribute('w:val'));\n        self::assertEquals('exact', $doc->getElement($xpath)->getAttribute('w:hRule'));\n\n        // <tr style=\"width: 300; .. 300px = 4500 twips (300 / 72 * 1440)\n        $xpath = '/w:document/w:body/w:tbl/w:tr[3]/w:tc/w:tbl/w:tr/w:trPr/w:trHeight';\n        self::assertTrue($doc->elementExists($xpath));\n        self::assertEquals(4500, $doc->getElement($xpath)->getAttribute('w:val'));\n        self::assertEquals('exact', $doc->getElement($xpath)->getAttribute('w:hRule'));\n    }\n\n    /**\n     * Test parsing table (attribute border).\n     */\n    public function testParseTableAttributeBorder(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $html = '<table border=\"10\">\n                <thead>\n                    <tr>\n                        <th>Header</th>\n                    </tr>\n                </thead>\n                <tbody>\n                    <tr><td>Cell 1</td></tr>\n                    <tr><td>Cell 2</td></tr>\n                </tbody>\n            </table>';\n        Html::addHtml($section, $html);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tblPr'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tblPr/w:tblBorders'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tblPr/w:tblBorders/w:top'));\n        // 10 pixels = 150 twips\n        self::assertEquals(150, $doc->getElementAttribute('/w:document/w:body/w:tbl/w:tblPr/w:tblBorders/w:top', 'w:sz'));\n    }\n\n    /**\n     * Test parsing background color for table rows and table cellspacing.\n     */\n    public function testParseTableCellspacingRowBgColor(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection([\n            'orientation' => \\PhpOffice\\PhpWord\\Style\\Section::ORIENTATION_LANDSCAPE,\n        ]);\n\n        // borders & backgrounds are here just for better visual comparison\n        $html = <<<HTML\n<table cellspacing=\"3\" bgColor=\"lightgreen\" width=\"50%\" align=\"center\">\n    <tr>\n        <td>A</td>\n        <td>B</td>\n    </tr>\n    <tr bgcolor=\"#FF0000\">\n        <td>C</td>\n        <td>D</td>\n    </tr>\n</table>\nHTML;\n\n        Html::addHtml($section, $html);\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $xpath = '/w:document/w:body/w:tbl/w:tblPr/w:tblCellSpacing';\n        self::assertTrue($doc->elementExists($xpath));\n        self::assertEquals(3 * 15, $doc->getElement($xpath)->getAttribute('w:w'));\n        self::assertEquals(TblWidth::TWIP, $doc->getElement($xpath)->getAttribute('w:type'));\n\n        $xpath = '/w:document/w:body/w:tbl/w:tr[1]/w:tc[1]/w:tcPr/w:shd';\n        self::assertTrue($doc->elementExists($xpath));\n        self::assertEquals('lightgreen', $doc->getElement($xpath)->getAttribute('w:fill'));\n\n        $xpath = '/w:document/w:body/w:tbl/w:tr[2]/w:tc[1]/w:tcPr/w:shd';\n        self::assertTrue($doc->elementExists($xpath));\n        self::assertEquals('FF0000', $doc->getElement($xpath)->getAttribute('w:fill'));\n    }\n\n    /**\n     * Test parsing background color for table rows and table cellspacing.\n     */\n    public function testParseTableStyleAttributeInlineStyle(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection([\n            'orientation' => \\PhpOffice\\PhpWord\\Style\\Section::ORIENTATION_LANDSCAPE,\n        ]);\n\n        $html = '<table style=\"background-color:red;width:100%;\" bgColor=\"lightgreen\" width=\"50%\">\n            <tr>\n                <td>A</td>\n            </tr>\n        </table>';\n\n        Html::addHtml($section, $html);\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $xpath = '/w:document/w:body/w:tbl/w:tblPr/w:tblW';\n        self::assertTrue($doc->elementExists($xpath));\n        self::assertEquals(100 * 50, $doc->getElement($xpath)->getAttribute('w:w'));\n        self::assertEquals(TblWidth::PERCENT, $doc->getElement($xpath)->getAttribute('w:type'));\n\n        $xpath = '/w:document/w:body/w:tbl/w:tr[1]/w:tc[1]/w:tcPr/w:shd';\n        self::assertTrue($doc->elementExists($xpath));\n        self::assertEquals('red', $doc->getElement($xpath)->getAttribute('w:fill'));\n    }\n\n    /**\n     * Tests parsing of ul/li.\n     */\n    public function testParseList(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $html = '<ul>\n                <li>\n                    <span style=\"font-family: arial,helvetica,sans-serif;\">\n                        <span style=\"font-size: 12px;\">list item1</span>\n                    </span>\n                </li>\n                <li>\n                    <span style=\"font-family: arial,helvetica,sans-serif;\">\n                        <span style=\"font-size: 10px; font-weight: bold;\">list item2</span>\n                    </span>\n                </li>\n            </ul>';\n        Html::addHtml($section, $html, false, false);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:numPr/w:numId'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:t'));\n        self::assertEquals('list item1', $doc->getElement('/w:document/w:body/w:p[1]/w:r/w:t')->nodeValue);\n        self::assertEquals('list item2', $doc->getElement('/w:document/w:body/w:p[2]/w:r/w:t')->nodeValue);\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:b'));\n    }\n\n    /**\n     * Tests parsing of ul/li.\n     */\n    public function testOrderedListNumbering(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $html = '<ol>\n                <li>List 1 item 1</li>\n                <li>List 1 item 2</li>\n            </ol>\n            <p>Some Text</p>\n            <ol>\n                <li>List 2 item 1</li>\n                <li>List 2 item 2</li>\n            </ol>';\n        Html::addHtml($section, $html, false, false);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:numPr/w:numId'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:t'));\n\n        self::assertEquals('List 1 item 1', $doc->getElement('/w:document/w:body/w:p[1]/w:r/w:t')->nodeValue);\n        self::assertEquals('List 2 item 1', $doc->getElement('/w:document/w:body/w:p[4]/w:r/w:t')->nodeValue);\n\n        $firstListnumId = $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:numPr/w:numId', 'w:val');\n        $secondListnumId = $doc->getElementAttribute('/w:document/w:body/w:p[4]/w:pPr/w:numPr/w:numId', 'w:val');\n\n        self::assertNotEquals($firstListnumId, $secondListnumId);\n    }\n\n    /**\n     * Tests parsing of nested ul/li.\n     */\n    public function testOrderedNestedListNumbering(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $html = '<ol>\n                <li>List 1 item 1</li>\n                <li>List 1 item 2</li>\n            </ol>\n            <p>Some Text</p>\n            <ol>\n                <li>List 2 item 1</li>\n                <li>\n                    <ol>\n                        <li>sub list 1</li>\n                        <li>sub list 2</li>\n                    </ol>\n                </li>\n            </ol>';\n        Html::addHtml($section, $html, false, false);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:numPr/w:numId'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:t'));\n\n        self::assertEquals('List 1 item 1', $doc->getElement('/w:document/w:body/w:p[1]/w:r/w:t')->nodeValue);\n        self::assertEquals('List 2 item 1', $doc->getElement('/w:document/w:body/w:p[4]/w:r/w:t')->nodeValue);\n\n        $firstListnumId = $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:numPr/w:numId', 'w:val');\n        $secondListnumId = $doc->getElementAttribute('/w:document/w:body/w:p[4]/w:pPr/w:numPr/w:numId', 'w:val');\n\n        self::assertNotEquals($firstListnumId, $secondListnumId);\n    }\n\n    /**\n     * Tests parsing of ul/li.\n     */\n    public function testParseListWithFormat(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $html = preg_replace('/\\s+/', ' ', '<ul>\n                <li>Some text before\n                    <span style=\"font-family: arial,helvetica,sans-serif;\">\n                        <span style=\"font-size: 12px;\">list item1 <b>bold</b> with text after bold</span>\n                    </span>\n                    and some after\n                </li>\n                <li>\n                    <span style=\"font-family: arial,helvetica,sans-serif;\">\n                        <span style=\"font-size: 12px;\">list item2</span>\n                    </span>\n                </li>\n            </ul>');\n        Html::addHtml($section, $html, false, false);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:numPr/w:numId'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:t'));\n        self::assertEquals('list item2', $doc->getElement('/w:document/w:body/w:p[2]/w:r/w:t')->nodeValue);\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:r[3]/w:rPr/w:b'));\n        self::assertEquals('bold', $doc->getElement('/w:document/w:body/w:p[1]/w:r[3]/w:t')->nodeValue);\n    }\n\n    /**\n     * Tests parsing of br.\n     */\n    public function testParseLineBreak(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $html = '<p>This is some text<br/>with a linebreak.</p>';\n        Html::addHtml($section, $html);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:br'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:t'));\n        self::assertEquals('This is some text', $doc->getElement('/w:document/w:body/w:p/w:r[1]/w:t')->nodeValue);\n        self::assertEquals('with a linebreak.', $doc->getElement('/w:document/w:body/w:p/w:r[2]/w:t')->nodeValue);\n    }\n\n    /**\n     * Test parsing of img.\n     */\n    public function testParseImage(): void\n    {\n        $src = __DIR__ . '/../_files/images/firefox.png';\n\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $html = '<p><img src=\"' . $src . '\" width=\"150\" height=\"200\" style=\"float: right;\"/><img src=\"' . $src . '\" style=\"float: left;\"/></p>';\n        Html::addHtml($section, $html);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $baseXpath = '/w:document/w:body/w:p/w:r';\n        self::assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape'));\n        self::assertStringMatchesFormat('%Swidth:150px%S', $doc->getElementAttribute($baseXpath . '[1]/w:pict/v:shape', 'style'));\n        self::assertStringMatchesFormat('%Sheight:200px%S', $doc->getElementAttribute($baseXpath . '[1]/w:pict/v:shape', 'style'));\n        self::assertStringMatchesFormat('%Smso-position-horizontal:right%S', $doc->getElementAttribute($baseXpath . '[1]/w:pict/v:shape', 'style'));\n        self::assertStringMatchesFormat('%Smso-position-horizontal:left%S', $doc->getElementAttribute($baseXpath . '[2]/w:pict/v:shape', 'style'));\n    }\n\n    /**\n     * Test parsing of img.\n     */\n    public function testParseImageSizeInPixels(): void\n    {\n        $src = __DIR__ . '/../_files/images/firefox.png';\n\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $html = '<p><img src=\"' . $src . '\" width=\"150px\" height=\"200px\" /></p>';\n        Html::addHtml($section, $html);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $baseXpath = '/w:document/w:body/w:p/w:r';\n        self::assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape'));\n        self::assertStringMatchesFormat('%Swidth:150px%S', $doc->getElementAttribute($baseXpath . '[1]/w:pict/v:shape', 'style'));\n        self::assertStringMatchesFormat('%Sheight:200px%S', $doc->getElementAttribute($baseXpath . '[1]/w:pict/v:shape', 'style'));\n    }\n\n    /**\n     * Test parsing of img.\n     */\n    public function testParseImageSizeInPoints(): void\n    {\n        $src = __DIR__ . '/../_files/images/firefox.png';\n\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $html = '<p><img src=\"' . $src . '\" width=\"150pt\" height=\"200pt\" /></p>';\n        Html::addHtml($section, $html);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $baseXpath = '/w:document/w:body/w:p/w:r';\n        self::assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape'));\n        self::assertStringMatchesFormat('%Swidth:200px%S', $doc->getElementAttribute($baseXpath . '[1]/w:pict/v:shape', 'style'));\n        self::assertStringMatchesFormat('%Sheight:266.66666666667%S', $doc->getElementAttribute($baseXpath . '[1]/w:pict/v:shape', 'style'));\n    }\n\n    /**\n     * Test parsing of img.\n     */\n    public function testParseImageSizeWithoutUnits(): void\n    {\n        $src = __DIR__ . '/../_files/images/firefox.png';\n\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $html = '<p><img src=\"' . $src . '\" width=\"150\" height=\"200\" /></p>';\n        Html::addHtml($section, $html);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $baseXpath = '/w:document/w:body/w:p/w:r';\n        self::assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape'));\n        self::assertStringMatchesFormat('%Swidth:150px%S', $doc->getElementAttribute($baseXpath . '[1]/w:pict/v:shape', 'style'));\n        self::assertStringMatchesFormat('%Sheight:200px%S', $doc->getElementAttribute($baseXpath . '[1]/w:pict/v:shape', 'style'));\n    }\n\n    /**\n     * Test parsing of remote img.\n     */\n    public function testParseRemoteImage(): void\n    {\n        $src = self::getRemoteImageUrl();\n\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $html = '<p><img src=\"' . $src . '\" width=\"150\" height=\"200\" style=\"float: right;\"/><img src=\"' . $src . '\" style=\"float: left;\"/></p>';\n        Html::addHtml($section, $html);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $baseXpath = '/w:document/w:body/w:p/w:r';\n        self::assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape'));\n    }\n\n    /**\n     * Test parsing of remote img without extension.\n     */\n    public function testParseRemoteImageWithoutExtension(): void\n    {\n        $src = self::getRemoteImageUrlWithoutExtension();\n\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $html = '<p><img src=\"' . $src . '\" width=\"150\" height=\"200\" style=\"float: right;\"/><img src=\"' . $src . '\" style=\"float: left;\"/></p>';\n        Html::addHtml($section, $html);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $baseXpath = '/w:document/w:body/w:p/w:r';\n        self::assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape'));\n    }\n\n    /**\n     * Test parsing embedded image.\n     */\n    public function testParseEmbeddedImage(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $html = '<p><img src=\"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEJ7AnsAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wgARCAH0AfQDASIAAhEBAxEB/8QAGwABAAIDAQEAAAAAAAAAAAAAAAMEAQIFBgf/xAAZAQEBAQEBAQAAAAAAAAAAAAAAAQIDBAX/2gAMAwEAAhADEAAAAfn4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADO1aJcpCnwQpcEbbEuAAAAAAAAAAAAAAAAAAAAAAADJhY6O5yJvR3tzzFzuQ7lWS3lKe2+VRdDTN5+l7WOXB19I4UHegl4OvXr5c9ZhjQSgAAAAAAAAAAAAAAAAAMzdbpOb3PQ3d5oWtdyxpFJm8zn9yvrMcliXOqGOtucPe8inR63DiWnDpVneG+caDo1YqR3Y1oxW9IqYswxoJQAAAAAAAAAAAAABLWnSvdf0c4OrUj3m1Ut8/DoXeJ1uepqlrXNqaXpStHa3XWfmbR1M8zpFfmW+YcjFi+nMvw9G3iIoks6xbLDDbiipiWJdIbGKrt9MUAAAAAAAAAAAAWrNfRSdT0847OI8zG6bN2tQ8/GuvNycRdjiiXpcvTnp3IOfXlsRwap6Lo8Si13eWiS1c5PTNZJNKr+f63PKdnWOsRWo4owdWoUkmq6Ry5qqliwBQAAAAAAAABNW3o83PXyu5pMTfrVs89SOdqkcunQymqV5M9NYbesQayYl1huwy1dLMdVMz4TEmb9R26VlNeX1easEN4c/F2tZrJrmo45IiKCaMi03yRwzYqqkjxQAAAAAAAANvSUfQernHiCX0Zxer7ee3uHYi1mKWSDc6uK9bw9L9OCn6Ofc6tqx5PTyoL7Fr63KE1pHnNa4ubaxUuW5dTmdOPSteHb50s0OomrYEesmi66SRWVNdotZjxtHEkeM6K82SszjFAAAAAAAWYPX9J1a3rPJd80YtXoxYn5nX8+reZ4vJ0mo77SVIOtSijyrVT28fadGDTwepjbXG3OsVbmLGvd1jm25sal2STGlfk3a2Nctdjlp6z41KuuapZ102IK9iKyttvNrNCK9W1IYrNeXOcLNIrEMuozQAAAABkv8A03zPs+0eB9/47TlY9f470Y1NNS76nj+v+f3oR34fN04uZGs8GD1e/XlX0uwcO2jOZca6wm21LffO/wBulf6ZxqrLzIZIsaiitwVJFvCleLSMixiHWLleXq2waX61lCnc5xFDLDqbYarthmoG2vOgAAAALlT0/Sex6MM2em0kVrnNeV2Y8vCS+n36yCfE3m760elqxzKHTgWvLrtpvFnQ3q3ZI5UfVgk58trrbxw/QcLpazb4fU4CzZ582db5xBVuWCpc6c/0NmzyM/erWUOhJX0zzJeYaR51kjgmi01YzazjNYinhywM0AAACT6P4T6p2k02N/P03xpphZi2ZnnYq0fqeqxTseTtLvFLl4nfp+L9/l9tnbHi9FWzFLqW68dhNqdirmyaLDPItX4NZpyyyaziv3KurxtOjHLDD0o7NbGM2Uud1uWXK2sNVqHVopz8SRmkM8Wkec62tsZMx75K4xQAABk9H9I8f6/snpdKp59ybYl5aVp6ied5vb8v7efrOnS6Pk7Ybb8rB8++neb9Hn+edH11bra/S+fa19Fx4mbL1+3C9Ryus2ZcWWGav0zQtyV4t7RVK3gnkKlnGbI6jjlyv0YzlZtRENW1RsgqXKppDrndkisaRBjOaxJHtUGNtedAAASR2dT6V3udd0twWK3n6b7Yzz1rHrm3ieY9N4P28fonT43V8fWWTSbkxDZppX1tbN+d8L7Twvv89vHd6255Hpz0z103C63m10KccWbbp16R0LHHlS/a5Fau5y/N1e2fT1Of1ubq7czWW7pvrpyKlngalitLFprNDKs0UtXLXbSSss6GkcsWQSgAL9Dp9M/T5d46uQ0LvOyb7UuPeSKGRNvCfR/M+jle6XA7HHdvCv5+lyJzdZ7PA4flPXxRbvTm50ebaxrsY51nDPrub1MqEtqDjqpBauRyNutwbKXnJuf3mN9d9yf0nlvRYK0kfBb0p4t6PDuyacBPB0mJ4bi6071bKHJW+ddjWCxXyCUAB1eV1umfqtC7T1mOfSlmdeHndzn0xbk1l15nX4RxOz1Y7anG83zNu7wZ9e2K2ksGkksU0ZuQaZeg6vlvUYvQnho4dTHI7uLQodbk89eb5Sv6cSY3k3K+M6lrued72btXupIoLXN5JdodZc82/Q6Tboc+bVxrqy0jk0rO2uRBPBAZoADqcvo9M/Q81Xfn1NexV8++BfqyzPR6nnehjfQ4HZialqX8rwvOe4oZ381npwe/hLBlLLtHLG89KxlP6byvfzer5ruw5c32fF6+TzN3h+fXDr5z7MzZztZWxvISdjmegxYtLOscrndbhWd+pzZI2r77VnTbVcN9MsRSRmdtVbV7NbIJQAFynPqfSbPJt+rn6WbjdLy750XTqyUrHOlmvRVZK01NBPQz008v6LwPSVo99fZw03ztLJXmgyjmksGnsvM+y5Wte5EWXWi386XOBdrRSm6fHTsV9ot2SxFROl1fPzR2adzWOHUtwyc5JrtvrnJpmxBltHtFLmPKs4zkxBLFkEoADbVXr+x57se/jY6vAn871fEvwcdwxVtj0Oedc59ufHLxbOZxbVT28tZYpK1zJnNgxctxW7lenh6GTl75t7ndvmxiaL0J5CX0FuPKcT2/nipD1OjXkrPS3qhH0erHn+hPzcu55+XlSa1rNTSTGk9QSTR4Q6SYt1jkxWdtd5K2m2soSgAAdf0/i/Ye3lLFNpmYtV9Odtem8v6Xlqfh9jhTXl456fsxDBJitJpM5vfl7bheBy9eZt2I+VfPQac23i9OGmjqdLzHXju48/Uj0Xn+joVJkhU58lqqPVt0S157p0CjU2izN4bMNlS1rDq26+Ycm0GVznTNSY11IhigAAAZ9X5Prd8eq0s1u2dYpNObfscmxy32vL9Pz/SRxzVO8imisxe4l2jm3/Z/O7WXU5/pPSc78/09945eVZ5+NTrT8uaNejxB35fKzS+zl81ay7HEq9sp6dGgSbwhxoatSYis2Ynpbc0ekuNI9ZI5cMgbGIpYIDNAAAATQq9xZ8z6/wBnOjpar4Y6VDfndKdjoJyOd3+J3VYbUelmnYzlzsbYro+n8Tvz17O/4OTD3HB5OF2g3jshz1qpUi6m8cqbtyy0LfGkS7x7FNbNrlTppWmiqTSWtGDBtjGMsa7ay5NhvnWIo84zQAAAAAJvZ+G63fPs69jG5W6vMsYtuO1JzcnhdjkenOuXQOTTtR1U3x0CrjaOV1eXazexRq65aXefEel5XOkFvmTFyOK/GnSzbxeXzPVcCs78/opx4LdDTOgYEMNc3BmMyNoxDJXlwIAAAAAAbaj13oPnXtfVi3IYsNLueX3mzWp9HrM9Kp2fJ08pT6u3oxz03PXpzcXeOnU3giWarDL0I6wTVBYxHJGJN54sXuHJm9aLm2C9FHDEFHsYTzGOpytMa7amMZZuJWc0RGmhkAAAAAAAA6fMzqfSOz839n2nf4vao4eG060vrxX7dWXydOfx/R8DviharSaSy7aZu2d98q8c9ck2g3ljxbwUc9CeOXp2sxyVyArpIDGqudXPHR2udHYjna26kYkbZuqSAxBnEoQAAAAAAAABt2uHnc+j9f536Hvi5zOnvpDmOkXeB1+zL4ff0XL1K28G5csVb+LXwxEO+20tbWbYxnO0V8TihvvDW0G0caba5Na8mYgki0iSJvltnMcuarEBKAAAAAAAAAABnp8tqeuv+N7nrx0N+tSjnTwQ6de35nOXoPNdvq4vgt/U8XcpW6UdXLHKt5tyOLENdkR40nImY5cZ12MR76Qgmjyj1k1jG2sUu0LGQSgAAAAAAAAAAAAJI1dz1Pzux1z7mhTu9sw6751Ic6TS9K/5/GL3OfRtRzK3rtTzVL0HMqlvjSzoQQT5umNUZ03hlziLEZ1zrlnTTTNzqZoAAAAAAAAAAAAAAAAGbFZZ3ej5KTrPZVuB0+mbO+JqrxzVK2sU8R3LPk8ZvpqFG7m06nSoWNdYc3aLTTKXSHXNk0wzQAAAAAAAAAAAAAAAAAAAAAN5IFl2XmtOnnlrOnrzheUUt2KujfXDNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG5ouZ6Sku5KK1vFJayVFjcqLm1UVzWKqzKUVxVNa3iktbFNa2KYxQAAAAAAAAAAAAAAAAAAAM4KbEagAyDAAAAAMhMBf/8QALBAAAgICAQMCBgMBAQEBAAAAAQIAAxESBBATISIxBRQgMDJBI0BQM0JwYP/aAAgBAQABBQL/AOr4mpmhnbM7c7Zmk1mJj/SwYKjF4zGJwyYOEoHYrExUkXDQpiYUw1idgGHjiHjiGiGozX/NWomV8RmicIxalSEw2RdTPYMEyLEnbJGmJ23nkQ+5hxGxMAxkEKTH+QlJaUfD2aV8JUgqGe2DO2uLsLNC8RPGkbi9wjjKksYiIbDCGj5SHyM4LGMsKsYVM1hExNf8RKy0q48o4eAWq48bk7RXCrsHsKrhu2szXMET0oBgjSOomMBsy57RO8ZsZmI2a7WIJy81MIhHQiEf4AGZVx8mvjQGqhW5bmb+qs7EE47iCNb6i6tDYizuq6mtrZWO3O7gq4eEQmMuwsQqVM/XlambyH8bZmMwrCOpEx/dRCxo4swqxmGB6oyLpAxBTMcHU0lql4wEPHrwlaVTRte4qG0rbVVshDZj7LHs0mC7rRiMuDpsliFG2g8nzD0PTM94R/brrLnj8cDoqCahj+MXjs8HCrwKqknnNqtsuqs9wEblusS/IfkZLvO+0oTurlVlgGzLmU4AyIyAwDxZWHllGhCTQRl86ZjKRMfQR/ZqqLmrj6iumPYEPlz23aIq1M/LYRr3MW1kr+beKwYF/BYT8rD7n3g8FuXhUtIbuzbeJ7gePaM4EtsM2LMQ0HvnaYhGYUmJjqR/Xrr3NNesXxDaYYlelTWeO0+jnJpoe5tKqSX2boT4GAds9MQ9RMbGnCzdY1nh2YsFDMVnnEGcnoTCIYZ7dCP6qJuaKMLsojt6hKkDB3xBcrM9mSqbsbTSmS0TGO8upHjWaTSFcTExNZrAmTWpSEMpWnItrKhgc5mfWyZjLgjoYRCcQ9TPeEf0wMni8fw9mRUPNZzYFm6otlpc1uENe1jghJY6vZ7BbFyOGchPDgKFXuH/AM+lxpNIawAFBVU89t9VGbMS44GQGbDDwGbBUqJjoYY3v0z194R/S4tGxfCLnxWwQIoVRYrG7+Q9oYTh3PGDqwrwmcG1zrU/buQragWXsRKl9LeA0JxAREC4RNwlWGt8VpjWy5UF96mN7YmcwwknoBGhMaZ+jPQ+f6NNe7cXia13U6zC9vy7XHxVWdEqBhTE+ZsRXPcPbOAJbV/Hgk8dLEdjsjIDBkRzLGAm0TwRbhfOtSBVMaXpmdvE1mMfVriYhmIfczEMHQj748z4bxd2x45l62NFbU+8WxRXSdVOctklEyT4sK6mxzYc+oDFQfYnofUbPAXJlPFUhlqraxHMVcKw9LXTuQ+YZ+yCC03KzuA9TAhM0IDCa+T4hgn7h+9xq9m4tPZpb8LFKPA2CYo2J3LVU7L2FI7OkHh3T0NS1ZCb292y2YzMtjzAMx6yx/5xWLRai1gXUb5awelgcnxCTPeAYVrCY3mMgxgwT9a5YJgGOJ+3P0n7o8n4ZxxkdOTU55r/AA2scdhqQMkzgccFvAn7LBo//QHaKqsBWomkKkxQR0yRNjhnyKjuyFVGcwribMZbZYzecHEPiZbNgMLYm8Y+TK2iIsMIlpnsT7/SfucdNn4lQq48Hv2k7mJy+DXyVPAYW1/CrQ3ZUCY8+VstQGYKkjwvifowEav7k+MZLJhu3Yh+YKspDKzahr+226zzj9mK2DndTVktS07TGDjMJ2NoB4ZvD29DDD9J+58No3sPssGTd+4fELFH7m7A+Rjoy5DBUnIEVsTwDmfutMxlUgoJ4Q1sO+SNe9q9GDXa3peexDeCZt4UDtDIYeSVBXUZZgTiewLbR/eE5hh+o/aQbN8Mp1T3GMQDAJx0f2+I3GocS3PHVPBgMzPjDOL/AIZZvVjyfKhiGYeaz6WYCanBXdgMWW2F52ziqwoDYLIBtPlkjpgss9GyqCMAEeqfpgRF9Rz4tzoCBGHnoYfpEb7XFXNnHTt0nxPZVJn/AL8xvKfFf+fw8543zBMAhi4M+McbuU8fkvxn499d9VhUREBYpYsDYLBYXncNaZssCKBNPLhcmtIgAYAMrocMonywzpDSJqFGcR/IH5O3p8tWq+hl1Zh5/bTGSeuYPdvtfDatrIZks8xmH2sfx8UwOP8ADnWIF2UT94weUpbi/EeOnHdXZDal/wAvTyeO9emZ2WE8zts0ZMKnqAXzWssqWdpVi1jOQk2WOpd2OGB36Osc4ln4gZhQ7wYjsCbB4h9l9yIRB1/X2fhNfqX1PAuLII0YBZz1W3jcEE8umskY8DEx05XwpORfx/hVNFvxKo3h6rK4rMpPN5Mr5d2a+TYrlhbWi4A/JiYbfJ9t8Hw0cTdhNQwxMhJezzubXa7DXEb1F11GBHEzG8TM/Z6H6D9hBlvhSYoT2jRB0B8tOcwXj/DrFTl7HAiiD3jnAyY9YZbeHvXZX23SncGkpAWA49vbdbjMme6tEAWXvFsaJfmNdtEt8PdG5E75eVIz3pYI3T3jnR7bgkD5h6AiGHoBMdG+xSM2cL0cFW9UJyf1Mw/jzajZx8TjkvWCTBMQ+z+YEhHjnc4V1CcSjI7OqcmsYCYHGvILOwjW+GbWG7WbZLZYL6QTgWWaVnmNgXvOM+WHhi2CbjFbKn35Tepjkj8eizMPRYeh+xxR/JV44Se9jaCeclvBMz5avEtGnJ4Ffa4w8tnE2z019U5vxCmmWWGwxeQ4FfMfNvLrNpv3nDrD2hRjsmMxmi9y2sxKroV1NtgSu25rOijJXKMrG8Mp2YGVXaxr8s1qPL6tD1UZhEPv0E/Z+xw/zVf4xhTa5Y0tlW9tox8is7sDq3BDXIO21TByfAUgEtifP0Y5vxPaMxdsTWKs7Ox7BArVpxkAeyE7BxFyrd5Ug5lbHn8nR7eVY89zFfWbHNfOOjWQvvMz3OYw3LoVPStY0I6ifs/Y4f5A+jJdrPAouCxLAzsrdwVmBIZbbvTxns7ypYim4EW/EaVa74lZYnQxffPndot1ma7TZCPHHGocgSk7IVM20N92ZdyNI9hs+n2nERDTbQ0rpfNlXbmPBm3i3BEWAjVj0boPc+/2OF+VZzVnEOWRBmIdXrZzX+lMMp9LhFL8h+1x7me+z2KDaWYyykdBNZoJkiUlQeMFcL6JzLyJVb3HEasML3BTkDF4ghH0UgihnbCcjVuRZsq3KQ3pPvG8CCZmfMP0fr6+H+Vb6BfWliHtVpqjv5o5ETlBiPbHlmD2p+F9RsS7hoaF+EYsuAr5C8llpM/fvP0pzKx5cCk/Drf4nVEe0NYUwoH/ACd/TfZk8g7XRIxmOihQFr2ViwAUsbvTStYxUKjTkSx8mfr6z7fXxP8Ap+aVvozD+Pt/xvVg/L5AC0rUWZC2Ai1hB5BXMPiXW9uqxzY5mZ7ibATKiBmaDLzjBVpqS5nt7fJbh0BIzajlM+TG8P7xK2MsACRPBADSpcVOJV6X5W10MDkANhZr1x49p7Dq32OOf5eH6pYqwNlV9uQnkXEh3GvFf1a+CAkTdQ13nuPn4pyC7MMHoIojHzBY4lDu1lVDa/Lqs+VoeBVRuTcdNu9TyLVw1foouFZfs471Yg45ud+Mqw1VqVIDOomurF92NKiAT95zCeg8zPRvob7FRxZxLtQLDW3HsVilg7nIwErVVG2bdyr4LVH37ixq9JdalVTnMPQQCYmpldXcgVg3GRBc5LV8i21ZwXsVrdGPIUFlYVL8sbI9DLSUUGkKtSWrXDzXi3EstxiXbBDlT5HIp1BX0MMQDoq7MQqT2hn76frEb7C+9J/jY7JS/abj2q0sHdqLMjXaA7bWVv6F/Mhu/a38nK5Autb8oghHkQzVpTjL0Ix46qGsC0RqajXXtVYE2svuG3yQL9pkNhtso+XscnjuEag5/lwnGZia96qaCYHZJW2RqCvIH8tuIpnnOCZjofMEPt1b7PDOyofQ0pftnjuBWulnIbDxK2LJmIABuFv5N6vwx6h0T8mBaDE7SvF4YaKqUTY2WBe2OO9ljfJtenJ2Q8ahNK6adG4akpQFHMGlViqkoV7K14wqFjWSpbYww1ecWJtM9tn5RVfVn8oQRCcyv3f3h94ev6P2eG2Cfy/Q8MXeBzTc5BXif8WwYzWVtc1hve02hvHTHhRBwWsA+H0vL+Lx+Ii2tLOT4W5sVp3E9SunMAG9N0SviqKRtAJmPYFFlfedKrQCfFhzFrTuDJNe0cZNqZN3lc+EEtTWGL4XPpPUnqftUNrYh2r6Z1jPuykY4hXsFTjl3tVx9msU+ITBgnU9tD25RfvU1RYcsst2SYFaV1+K1Rnfj2kV8S5Ja/Yi8pCy82kS/wCIBYbGtma2r/jrQVMYyKkc1Ma3WYUR3CndpYxaXMdVOVDYLITDqRmA5hPTPnqftD34j5BBHQz2M49us5F+i3Wi6LYao52LSinvPaqaSnlNU3C/lTm8YV8jtWGDiWGHZEDgn550ickubjUVIRZRow+UQmo10sbe7ABWPKh7DyGSnQYOa38jtEsRhr2YhsTc7ZhcisnJmfrP2+JZg53r6YnvKxiP5GoEu9RhBlIAs9RjDVgcEXlTxkTkJXUEnIoax+Whcsjk/LWTUJCy1191ixtwveaLfYDXfdax5L7G+3kNTVXUCvrc5HcGmNZyH3s1JJiUMynwc7DHkLCP6VbatxX2BEPRSQbmU1uSzfLtt2GqDEMMz2YOXSxTtMzjck1ynlhSfiG8W2mwW08YTlpvDxyssXwKWM+VMCosJm5iVNZFIqi3tGv9LXkxL7SDYVWyzz+1TYs7N1yZn62+7xLZ+aETExHLTysWzRb3ayuxN0Q6sfJVjUbbe4sxmIdW7pMS0gLY2C74G2TnXWUVPlqbmYcRxUnDLROEqW8mxNcGJTLjiHxM4i1Fo+sAxM4o+wOh+9W2rcW3YEeCIpGzVIwuQRK8U3VVqmhQUUG9Xq1rt9Y1wD7hDqK1EajEqCbdmsWLRUBa6I5s9TWYsD6yxu7BdbUWsdItptDLEXLNWdbOE8WrZvlkUWWVrNYfcnx9B+pj9/i3YKNvWV6UuVPptVFU13KiPdcdqOT2EpUciWqeNduHAxql6JVba9p1ttipYpT1xrLFinuAjSbNh73cjlMs32myzOJUa2RWGNhXCS85VerJ3HnYKqVJ+0B0J/oKcHh8jp4LMqCDJsbkWC2+xbRyKcP8tXrx11nM9Vq1Fx8o2i0orKyVP3VJe7BN+YtiRjUFPZwzUz+Fz2q8kVLCtE9DEU6BJsDDZHUNBhVYjUVeq+iD3Y5b6QOpP9GqzRuJfuHXwtRaGvM5ClbR4J5e1db5Wv01Occo4SHk+pj3GxidsiLgQa7HGNQZ2cg0YjV4AQQooKqBNVmiwprFvKw8jJrtyGbwHAOfMup+nH0Mf6fHv1NF4dahgFFaczjp2dcwoRKU1Wl/RzMJHtyg99SJrgL4n5wKCSgWexXG22JljNSJiCtpo02InqMDsIWWACEmb4i2ho10L5VgD0Mx9BP9Xi8jU8fkgEMDLxkKPLMrJQgFJUJO4MX4FpEDYg1aHEU46H8cYmoMAmvQLB4UGHBhqqnYMZXEwGmrQ56bRX6WDoOpP9YHE43IxKLpb6q7aGcKXrevloptvwuwuRyCceFMxmZxKVzDUIFnZhTzrNTM+VPgs0Pch7ghZoLDGsMyJ5B2BBUGEY6bxm+hjCf64OJxuUVI5DsKuSWjXptrx2DgrKEJZ+NTZLPhxnJ4jVAe3clbhYxGMzYzYzzCTPce3TYCdwRyD1J8THiE5h6joWhP9qnkYldoMetnny7mJZZSbHXZbmwvKsxXzdhfw67BbQ9RmxE7rRbQEF03abzuGZYlmmwM29W6ZPTxCYYfqJ/u13FZTyNTWy2JcpSWBcY8eQVtIlXLzM1Wi/gbx+FckKnqLMwMBPTDM5UNhhnBAgxA0zDD0Pv0zCf76uVlHLKGrlpcttYAJXLDMAE7eYtmoq5LYHMQztUXx/hxlvGauARgprmTFbyACpVoozNYRqP3mFoWPUmZ/wAJLSso55EJrtnlIHwNzn3AAh2gaJyrUK8xGjUVWA8N1L8ZgdDMQOQBZ6fSZt5LAzJx1Jhb/GW4iJyzEsqcdpWjVFZ6lmTDpCBPUJXyNCvNUwWI8epWhr1jVAzQzQTAh8ddoW/yg5EXkEReaYOTU0HbaMkZT0ZMTJmSIvJdZ3Vsjw5yTC0LzaZ/z9jO6YL2E+ZM787s7s7k3E7uIbzO4ZtM/wDz1Rk9tIalz2lyK68dtZ2gB21yUXGo27Qx21naURUQg1gQICBWmRWs7SztrO2s0E7SztjJqUH/APAf/8QAJhEAAgIBAwMFAAMAAAAAAAAAAAEQEQIhMUADEiAiMEFQURMyYP/aAAgBAwEBPwH/ABVll8xvwqK5LyLhcxuyijTmN3PchaiUUUUV4VwW5esIa7nqY4rEpt8djSShFIaO0u2JKilDmuFj+nUQ8ajDH5KRR/ArsqXN8FmI4XTVmw/JwuF8wkUX6hMaNsrLUIbNxqL4OP6IYkZf2EWZIWDrU7juEy+GzHYxijPRiMjHcyyRlksnpN6eNsXuvaExOzLMy1MIuhv8Ekprh5bT3QhOh9Qu/JQ/Cvcy2ioTlYLfkuFCQjFa6nVyr0r2PjhfInHTz7o7y795+5lvOGKxWg+ZlK++y+h2hwkuY1DhbD5jX0LRVTfOrwvnUV4XzqKKK+jsssuLLLLLi/ov/8QAKBEAAgIBBAIBBAMBAQAAAAAAAAECERADEiAhMDETIjJAQQRQUUJx/9oACAECAQE/Af62jazaymV+SoNnxo286K/EjptlJeht4U6NxuZfOvwErIadex+i0vQ8X468yViioobG/wAD35ErIR2oYza/Q8Mssvjf4Olp/sa66J9vohtj2z6Zeh9M04/TZOTfvzvw6cb7ZpzlKXQzUTUaQ2y3jTi4x7JPsvCzZfBcWvBP6Y0fx5dshqRn6Ga8+6RbLPnklXBZrivJprsm77H0KTi7Q9edDfKxCYy81xWXyX0w/wDRjxtXx2OOEvk0qRTusPFiEUVzWXy1OqReEQ702iQ0aGoo+x68d3Q9FP0fAzU02hLx14I9s1e2x50VcGiXRY1QjQjJLscj2OPeLLEfGSVF4iuT4af3EhoaFE0XTNX2UKLkaeh+3h4bKxX+EIViSynyfDS+4/YxrLW5kf4y/ZGKj0uDxJDIRSV5Z+qNuI8Xw0vvJoseGXR8svSK4PEhsXSy8RHHk+EPuNROxrDwz+Pp29z4ywhQp2QlfT4+uy8Pg+L+qFkliUawoORFKKpDxeUM3CLLLx7Ij4vjou4UMaJEY2xYZuYkVlorlJfsixleHQlToeJGklhiJRs3UKVlIoooo9ZrG2iy8vknQ3avFEXQn/vBxscBRxZZZQvC+elL/ljHiJJ17w8MooorDE/wU96xppMar0Sb/Yn0djWK40Vi/PGW1jVq0Q6ZuJ+yA+Vl8K4vxwntNql2jtdG1Mvabk8Pyt+WMnEjNSLvplIcEW4m5MoaK8LfnToWpfsTy4opr0bv9E1zv8NNoWr/AKKZeXE9Flll/kWzez5GfIbzcX/Q/Gz42fGzYxQbPjZsdWKDZ8bPjZsZsf8ARf/EADoQAAIBAwIEBQMCBQMCBwAAAAABEQIhMRASIkFRYQMgMnGBQFCRE6EjMGKxwUJS0SSCM0NgcHKA8f/aAAgBAQAGPwL/AOimHpxVHp/cvQjhoUa4PSY+5Y0sqS+kZOFScX7IhUov+xZXLvyYMfbb8PuWUvucTntp/wAHCpJ27UYfydCWzH5LGPzpfSxYx9smNvd5L5LWN7UCsyKqncmPk/sKcG6plr6WVxdSxeY8kstj7TlHAt1XUyTljbLJE1JySlY9MQd+pZkVKEj1Y5F9XBezfTyQW+zzhdRKhfJCISI1pa5ncpmxfJBMj2uDiuRTliVSj/JYZCOZNpGKSH9nhHEWwWzpdnClPe5ChdTMIm7OGCFBmkiWe2m+t+xBJyYl5LrSTv76Z+w9iKFgmo4UcV2WpgySkiKs9iqqt3JmTdUTHlVPh/ku9I5Flc768j1WME/YpGuWk1ep4IFXVjppFIqa77enMdSpS0xcS0xrbycJxK5nRy1BxSWuvYz9hksRz56TNy7ILtuCDZ4du5chm1tHb+U4JYuRiddzgca9/rZZtpwN9BzpLaO2kJSQ6lboN047mSKE6mLxKn8aLq3CHfHQ4iznWSf2LSP/ACJRJLJPUy1yGcOPsG1YO7L8yXzM4JpujNzhoP06pXYVTdOJyWIkpr6MVVM30UJHQtrk450kZg4hJS5LU/ktk4l86WRf63e+eBubCfMgS0uYIpiDc6ad3WDmbWrjcoSWWTVBVTiRXuuZxOTGkE1YIXXAt278liDBz0xpby5+qU4WTsKmj0rSdJx0JemCJgUXG9aW7WwW16EmF7iqcP3IUFMXnoJaY8vbyvyL6ZLnzGh01ZXkg2fqbvYT0sX0nbIml8HFw09+ZKetsnKCUoq6nG2ZuzqRrctjTczBjR41S+o3PFOu15rdhqi/icmxp5Wu7xCNMPW5w56mbmSOhnS+nFVCXQ4LyXOEsyN0+xLYtPc7azptZP1CnnfSDft4oidLcNa5n6WaifEjajutXzg3EM3L5ESzvrYwKlfsXhCe3hT6E8vN2L4LXL0/JKMQS9LaNfS0rWOS8nh7s1O/4Gly8rqqZJfBBtL6qLaTHsOpjaiX2LMjmMxpG65kv6mTRUTBjTbpU/pkh1/GkaRp8irXUpqgv5Ep4WpK/DfJzqupI10Mm52G1yKWbadLHHn/AHEeJjqjdOt2cN/cnqzsQNk6WPf6amnotJL6sT7jXSo28yZ1/VpzR/Ybpi/UVdN3zXQltL3Y0ciSxCLK7ZiO5jTkK6P8DWBQrnFS0+pashssWxoyCOZE/TU92LSPIqep/wBxV4b9TutFpJ4iWYPDppztmomltM/V8aqqKsJ8yhfqRVCUM4ap9npB3E2sZE9LmCHJ8HIu0hVRYtQYjVKRLXmMvkn6OeiOy0b8tVsXTKYNy66MWj8V+I1PI3urfGE0f2OOhomltMv41f5H/Fqkpl1VRyE4SnSCxtLXMMuWeS8bS2tOwu9bE89IRD+iRXV8fyK+1MC3c1AqVZrz3KqJsx0ynHQmY06FPFJal/JOWTpKZ0JdWC6RZJI5FrjnIkyp9yJ8kG1ZH9Eil9dYI0tpWk76eFXzdN/LGu3wnfroqoRuq2lkcKa/qNniO/JijmdziksS35HUONHTVz1ySSW+lpX9Ilon5vGStdi/Ut0Kn5qvDql1RyL6WqYt978zhU+5G1J4wXq/Gm6YI2yXpLeGrkfp26kNG6u/+0u9LEiUYV41vLJ/YiPpaV/SS3eBaPWlyMq8Wv0+orqTr27bbiZvpfJI6t9kbfCdSJbl99cHpqaHFLLoeJELRu5LRtuTuUdCJt0L6WL4EoTJ5aWL6X8l/oFU8QYyNEM7CS/JfTI6MSeJR43FFNjdBLt7mxJ1MdFNNKTL+a1i+xJcpJOK0in0sutr6GTJFI0nc4vjzVVNNM4GcViX5LfSKORL5jtpfOmNOJFkVVPkNuptd3rZOfIrlqvktc3VVX6GJ7lvEb7ChYKPEmG1dEkkbEn1KvNBclUyQ0bi7j6aX0G5ENiaMipSvrkuOh+k2+F4dNL6wLfXK6QeJQphOD9PbS1/UvLHMjBmTjfD3KqpdKI/WW08OlPd3kRGj80zf2MxYSTsWd4uOSXVBVd1NcyzI+joXYp6TpY4tPTc3U2RJuSXuTrXW3alDqfPywyfwTSiXdm2qzN3iOrasKCySdPSxuqTJ5czouQ2PRuHYpaeS2lnc26OIkV50jlpcz9FPJIsrybeeksiFBw5ZsZciSIOen6C5XZHn4WxUp3Zj3OKtqOcn6iv4nUjfxdtOKOFmyn5FUkXRVXTWnOaRf8AT0ukmnwXTR7l6afCXdyUrwqt3uX9PUZ2KlTgf8Sn6VEch7jdN+Y6RkvpkxYxekW4xgs7sluR+Ix1TxN+SdeFqehsqW0VUVSil0VllPYqfiWpF4kfJmuin2GvDvV3RaKfc3RzGS//ANG3k4F8m6qWxuIKqauV9GKqkur+X1T7fRUvsMt6iUymltbexTtzzXQ3di7ljlj2RC0pX/lr9xx570X7oVW5Us2OtNdkKjwFM9WcdvEfSoiviNzrinpuP0K7UvEmbCqV4N0bqUTtj3FxprobVBh7V2Jq8NpG2n5G4fyRNi+kMla2+igjRyOTZHyVNdSykadmbuZW6qolWGnKqbO+skxbS0nrI42W3UnGyra9qXY4/EusVo2Lif8AuZxul1c7kRMdeRzLkUUv4Jc+zJnbJvq4nBZNUi21U09WZv1MWGuY1k4TcuZf+Tf+bPKrX5JQosUvno+g27i3eSDw/wBNJpoidvW4q09z6G51KhFt1X9RaxNUfNRw+KlT2Ob/AMjdfPseikminaus6WJbG6Yb9i/jfsRukSZ/DY+HmJRo3U3CE9u1YGi4uKdJn6NdtVGUOclxRZjcn9ZfJGl8CfJ4N0dimnhx+CFFftYajbHIl1FpZdfJ6hfpJtdya3RQn+SEpX+6CzppXdHF4k+xFFL+Rbqop5odH+nuWRlnTqzc1PRSRamT0kJrTZSrcxUq8aWJF2+kXmVyUVPqyF+UbpkwZhK7JpULktE1dj31RPJMe2vd3ZP6aSJ4tiJdULkhcF0WYt7kVMsxk4YXubq/Gt2Ipp3d3zIX5ObrKq24RteOxNVPsOFtXImqqWVVvJubjohttE8zs9Ov0sFNXkXUbqwskVW9zClErWJyVXwQyxS1yclE1Q3diS2wKfEijpA4qdXfGl1BZtiTpdyaf3MnUlIl1QkcL/Jsb4OxamahurJMuP7m2mk66RpvcJFnKI0v9HJt6+RNZE/9be4nJK4l0HXeCZvpJtqL67YlDqeeYndU5kU+Gb7KCaWtvQlOepncQXqg79ziIVQ3XU0u5RDn2KplfJZEI2qwlOOZZJ99G+SO31EG7WSn203pX7jfp24g/VoVufY4iy9vLK5Dc5OFjvdnqLt3M2FMpFW23/yHNvk3Tcmt/CON0vtBVRuXttwZJbITscOCxueDhJGuv1UTrItr7k2RfqVVzw1Yhk+HV6sp9DxLWSkpjK68xRkbdiBtKYyPfNKH/kiqq3Y27k7cieacOR/w/lG6mLdSh/p0ruuY1ya/BuUohupdRVU188D3THWTIjalbqJzCI3YE27dDhwOU1pH1UCq/PkiqzHTzRNW+IwRmmCqJlmytzOGOlO6HvyO9+RTw8W6/cedpztpxfkafOxFRG1GGXsYLkUux0k9N/cilWEuZf0k0203VNJZsOvdb6yS+NOITpZ0RCqhYkmapVs5KGnNNSyS5kbiLDqJN035zyOOpbXzLNWyRtuSqUf+GmRV4dS9jJNNSvk9ZfxH8k707F3BuTnsJOonchOTo9JZFo09UJcjdRgvgcY+r2/glaQ3DZUtNtSxgTgvzKm1NL5dTdTTtTWJG+oy6ksX3XLJmL6f8HOO5gnaXUDwzkSrcrChzBxSXQ0ZLkEm5fW/3JWC5KyiC6EMbSlWRt5aRafYkmlScyIOZDHaTJApXzp20zBZnEYJpflvgmn63toyHTxDnKIu1JNNV+htr2z3IdH40xcpi3/cem/VH+7SDJKuiz/BchI9JaC5dHQ4ay6TOhZ/Y10LCdOR1R7nSmrIq6fzArUuoadtIJUEQ56nFOkEmDmYZgwek6IscVOljBa5ct9hyJ0vHIh2Zx0wy2OhuU1UCqo4qejN1Sgnw4rp9zfte3+xbXJn+Rfzv7JfBNN0SXpVXubqFt7Hqfycmba6JTN3g8NXRnF+3kc58+LnEjmX+0ynboWN02LaTgmbn8Sn5Idz+Gl8GPJxadTMnKNIxrJMfaLM2vJjT/k/wcLIrOHiIrsTb3RZyY0lWfTycizGX+2Q+JdyaHD6MuelPTEaWhnC9tXYjJxKCV+xaqwzGkGLljsWX22Hf3L2Mr30sZZlyTuRZ2OhxJoyixfBb7peGXTRata5Jk5li99Zkv8Adcsz58/+4ENwes9R6z1nqPWeo9Q7nrPUXqFNQuI9UF6z1HrR6z1i4j1o9RG//wBA/wD/xAArEAEAAgICAgIBAwQDAQEAAAABABEhMUFRYXEQgZEwobFAUMHRIOHwcPH/2gAIAQEAAT8h/wDq9uoNx8xb4Ly8vLf3IbRGzLftThqlm+kIcQ+4ecJbwO2oe4fUNGoTf7Ygun4+L4lxyA4iiU/2sF18HWI67Za1cDsXncq2PzFMXX1OWbc1KQAgmVXqyMaQO3McWjFjOFyov6ZxK/mc+YHKES3lBSH/ALks6r1OnMayv7MC6i2pQUp+UDvy8AFq6RwGvUTXEDAaDN7hSHtO5TVxc4SlG14lQs9EZuj5heq+odvUM2ESWF8wZ2LoTFM5eIqXGoGoB3FdfCmMJX9jW1iDZcq/5I/1O4eWVlXYc4ge0e9svWWrupa2Cvco01gw7r7QyHLWJk0j1KJklMwWD8qhWfZgphcSajwmFHUuwGIWKepUfkiWHS+5RsgviKSvhp/sCKgjlZaymsHl1L157MQUe5ynzMpRQZDthwofM1C0sm5beJSh5UxgPg1Dks0EWwDiox4GDDiCNIGoO6+pedEwd+BHax09yq8amVXzKGN1M5bTKO/iVUYOMXmZI5+Fp/W0Il4L2IaKcrbM4TSoO4FUpICOp/icsbjR+o5YgiyDcCu/TmK1F8VD6C74CJs1+eWZ3PVLXMHP5KnE03zF3SpYy3xLlBnLKTCbywwoXQi3twWMWo3CGFMeAmDqOyNpr4p8KIp/q/CJQWfUUay+anVBFCjnQM0Cj4Rq3BWZkKYnV3zAXSAMglXqcLxDtG9wwfzRTsaqLchX5hIvBfM669IaMb6ji5pygxsH+YxZ3xHN4r54mkF8xLGpn0zOlB6zdy5zZ4JU0gxofCKqcy8uMjFfG9/1X4BK3FS3GuXn4KGZ+KVtR2yhGWAIR3eZijtj+yI64i3UpxBwHEqWegILoiBy4nM3NGtx0st1ozSWhm8XFJblubhiDTWtiyVEaYqm5tGoMsTXTN0PaWGk+o6xMyNzBa+4J8xo1YxUqz+o38MKlGuYaUrPcxFDTE4d3Aq7/CiDVrOEFdW3NIVKXe10RXPOHJ5h3i4AiKP5usSqOEWbpFkCsaOES8VPOYCCpVMHuWUNEVT+yHG+fEd9H1LruuOIFE7HcHWR3eoua0c4MEYKE1YC8R1OyG5CCoLiMOT+m2EIWJggbK14OYtC3t4RYzHSOGBliuHliU37I/VgzqVAavl4lkKXrzHsu/MQ5HJEFguGYVfgTe6hZxzCuxqbkcbjOXxaFxHG49JpwcRT7BdhMcq7Jw2eqmRY0wu8hMNa8wCg4d8Rak9TROZdVBvNlzXW4qpjGOJuCppKn+jYggGgGVmOqH7wmppHZsks3FkD63HLrgTIbrmov+vUrrFZtdywXPEO1BjcS6Ly7lAOcsW4zYmEeZxhfHaAujG5WHU33KVUQtGYa/bBdUbrwhFfolOg5uLn7FlbgudiNg5HieBmsSs4+phM+UzUck7TE7TTO4bhF4jCjGNjMHzKH+iQFMuoga23tiR15GKUSbYHkzfZ5TYf8Mprl+2WNjXMpR5WItIclxbIxAdjc31V0w1s6SYckyEI+4HHznODcuu68kTHjqOno15ZnxxyTJPqATxUqKbSwUqOYgiKFftcNVpFmmTpLcW+5whOMMxFxF5hxXL3Eu2MHr4OIaX+Ylf0CD1KkdMI4Sg1cQbd3UAH7I2di9QluYfhfjuAcYDCmjyshemKFKjppm7CRlhZxbuBKtKCJFQnDqVCtFWQQXooitXhMt4E2ln1Eplm48yHMrLH4FwJx7lMrLd/9INLV2twYtNKyJTKLcS/DPmL0S749BgcM06qYWOBqPsRy3cOJ68S2Hw2m0yINf0ELVMKc3+sS5FAmZrl7YxWG6l2hu4HAgo19RMNYjoRgR8nNRBH0vzNTZtmeaNEwL0zf9TbUtLROmNBEo5BmjmUENnmBdBfKJzYbgBmHDxDgMv0lGcEIy3CLIyzgY7FZfEdFSroZl8oPKXveYwUrZd5I3d85lIrqCEYy/M6pkgzDH4Cn9bL1MPZ59pmHaTb8ZjEuofDFb1FMoe2DTx9IgBjgWNAiV5nJBEBm4yyi2EfwCVM4RpLBgXG0JFDHJxBMNnfMsqrh4inIIAXbpcFXhi4IFeF1zLVZyV/uOAwCjxuM0CXmIfFHHEdSnj/AJj0iHVSqxo1FthEWGUuSjTb9SrdQRHcLMZIaIQShmxi2TiKOeYMFn6owR1TBf3GpMLFmbJeGEdgyIm1FM8ARZahFqKwTCAAIOdRCqFuh9w0q4lJvZqXFlmKYpgEkUredANaZZaQ1qkdAr0xfRXqbS2pvPqMw9V3YZxD8SjfLdxqAWOVijAOqToEGhzWO5cjiOo4ycRN3cXaSJvrzHaqiV6mS2h5jCu+4cQKzDcHeZwTummXT8Hwaf1KPogDtml5qZ4PuWFhNHQjzNzQOkD+ZtDtNTsvKG7hSgEC1hSAy3Y1VwXhe/jRXZ4DEjTPcPsa9w86jKJTq4OevUopd9Q7R4JZbK20h+IgRtQ6hqQMHtfxLVlZV1F7MK9TLhB564lbG8oVuGAspW8ONS6FW9GEsMXqDqfuihTUbMNVCB0hWr94aU0xbzP5zLfwfkgs/UvAwtvqFs/RDPCqG3U3mMN3iY0cIeUro+7DVjHMJKupUFqw1O8PLeKmkZDqEqtbfiFBOtQz/ZHYRK68REJf3E04IW6ArC9ytyeRMYhIDiczgQ2AT9iVtJjg3LKG1MRsDaVkb6gO02yzwI+7NGOJgxu7vUvwnEz32uAgq/cuOFTEy5cZJicd3FigvjH/AAL+axBT+npcp4QFV+oaG+fiLh2msTEvQ/mEIKavpjqAvDU3MPcpdE4JSWN1QRntpD7m7DZK14Hh5gGmDiuZhrZxBEjk6i1n7IccVjMfWJuXAZZjBcyxq1URGKmbmBKXxbUobhnQRCr6e2XV5o4h7vE/2hLIvGHFKchuXpWfMm1GVOMfAFMty7JANMXI8/8ADvKmPh1c5kH6WW6mAuz3FQg3rLFfwjpnzFoTYckN3rxP2md86YVvyMsczNsfAU/MEAGqUkUE/lELvPdUQdCm1gFtj3MXuuRi8vH8QqMAdty5CebBkQeaQWj7QHCdsl1ZK0y834VBh+Es1tqruZpzEZqPAB1A4w/G7g8WtZQn5J0ZizNSlhjm4OJ9pfIH9iCIxeoqnjUogjb4Ap+N5hhUdQf0qKnZ6hw7YOZueLhuUrMfKLSMunxMAremOYlxsl3XEZl3UotQRO0w+0fOk4C+dy9rAp1pGFFgZn5MZBNmHNdwR1nySzU0xCualzmCvggCbnNzA4Sg4I7lA+5GjGO00oqz1EAAVvzHbDRi9TAuwlWAfmHQXmdwfzGhFuV3vU7r7ig1tKKfbCVMOYae/BHE3MfKDcpip8R38OZd/oGWWGkA2wqFwEOoai6yy3rmXDT9unVAb9VLYB3Y+ioVbzMkefgGWMgvMCOfQJjv+lx2vZkAcEI1E0YUcy28xyuF0bWYWHaXcQMcTEVruXIB0ebiA1INWY2uKcTOZIKpRTFRxchXFTlMc2Vn8yhhLeDqPCuUxDBNMa8R6WILOsZgbb4lK4q5juxTDlBGCOffwTf9ChTDvhMacyrmJa0Qct3LuBf1KN3qVT/4V/mYEgwV5mOuRAgXkSklGDRFDKiF3cYnKb+BNgVV8oF4qJKanQXVzdl9nEo1fjvSo4rvcK3g8sayR7mfDf8AiJH2zLKoC9cxoxy6EwtrcEostMe4I0jcQlYyWUbgY80TVob3EbxqAvUCw229RBlniJd/DMJcGCKo7lkwZz+kkfMFmSunE4moSwEaI2uMkS1NW67qWuEhsn2jGRxmWYRQtMsYYYL0RDlLHpEXnczhX3mFgF9RZpu+CCXmF/iXCKhg3yl9d26gix0qJJtpvqGiAjuoMMcL1DQTEYipi1pyx8y4SwYQTMA643iHdDxGwtxJbrVTBpVxFWELzfx2jhncdvwqYs/Gv6Fkj0aMHZvMPBuPbhIlVfv1MAgk6uYtqM7hOg4rPMbBrad0xmozggN5Z4xMplj2YlhLGMrXDEWunUGpViemJIUpfhChQC7yLlhxnDW5cya44Szs+5m0rnEsMtQYIt+dS9gW4nPfMRlRZrxOx6gc+ZhcF4K+EoFsINzgg+zyBiAzsJYzcA8TUS13AA72R7jI5/4dqVL8h8A1nP8AQEgN6QO/wid4GLlsVYEwYhbERA6l9YOpRa4jE1bIN9kWsgHtbxOsDMOYLmUsoF04CDVN35l6nnI1cbPbaptqoJ0XKKsXMOu0uFKNdpLhTV56nURoJWuA+YTjiZDcFEp1KAv3KmyZXPDoLbNYFdDEvJymIl6bKzBgphJeE1uNdoHO5hyG5URSBsJWUmZFPwE5vwgljKp+N46foznB4xGKfDM03CFMxeWOUUS0sOrFh2K60dS4YzPEakwIvMzaxg+5WbE48TDGhyqOwHda/MOS1LuNhWB8KC8tRoqhKo0VNz9iMJGCXggMi2mIqPC99S/KmGHvFfwYCb3zLeB8Q0trQIErMvxKzA5A4yRQacMYEcfS2K7nYJRsRQJRMQHtrj4FsBFr8bf8AdfoLOAx9Vcco1rHRS1EwWC/uJYenxmC0XbndQs4rE05R41G1Z7qmLEbr9o6DAxWLl4F2GmcNyxpa6hdAe0wLHcGIWbAGW2YD6QwUdJiEHSYArbyhKmwybgGXSzwzKyju6xMz+UaOAKQ/wD5lH8z9nw5z3HcF9wWgOWZkWuGEuIeEwDIShXFjsLz+0bo1BZmO2FuL0ajaFqC34JsuJ+iXsKGp53A96lSduZcl+SEOcZgUcjdnEykm6lUNxokd7IiAFYy3A1Om4CmfFy1bFORnlmUpf3DTDwLGJVvSp6Yuk+pVStuobvUDPVtTPdJ5Z3i8RVWdFSwIfiK+c25ln3AOBHfpphXtVExZpLqDR0YuGpljmWGMTtvH4gXKGTfBFe+RmaI3bGlXYlybXQyhtXQkwoDbUeyv9pgB9ypRStziJiURzOYQ/RlUGE2j9hidllOFWuY0wW1NWpuVsG1OGo3LvY2+IAyuS+J5hdLL9St9o6hzC9pvCBnQOZs/Vr8Ck5HmGoXQJYa09GH2bMqQ2r0k5AuOa+pYCTkYl0K9KL76lkk3wQBNl6DzBZIuviXFM3DR8wGlGILgBbiFbW1nU2FkxmVutajdjwqp548ywMGJklaYzAVDTd4llu7lQuW6iGGWVmMKKLXEChmCZBlxhO/ghlmv6FQnM0Yp2nHwQkvhUAzRlbshB0OQmeTZm4wtSYlWWGXXG5YajMtefSJYu4EQrR76iO9kfhFIkLsgWnMPoB4iAjkmEvbs4lK0cqaQuqUVV29sui1gqAAKac36jqk0DxMo1TBbpzC+m+GWkvMcO4MHhKzEXTLVhwMfKY7PvSoYoDMW2xjkoxvKNN1KpPVhzSauoroguVxSG9RZbU7CNCbZwJzDAwjx+hYI3eb9RayxX1HXiDqZC8kpCZppq8waWJIsyXjEFuRDRCmZieOUcBTBqCWxiK6P3maX+Eq5Tq2W7EeFhMS9RbCuzFyvdHZBAS5vJKsOP2htGUyIMOO66gs+qxD9WMZdRLrM1/BMHK3jSwGsClEKevMtPQ3mqpLAFuiMxh7Rv8A5BBcR3HL4dKfMK68dwKDTiPfKWscsoGLmM4Wpc6jKgujlm6sNQYHxthzmcSoMJp+gqLLbeII0Gpdkeu1d3DuJeJc8MnlGwzDH0lczVKl1KTmI8RqYcGyKK6APohxv9/yitBReCJUsNfc2NeZexl1rmYK64jy4ztEnIxCm/2ZYQDNNJKURd3VM0IWm/PqWFwRpzcNKKGgYgYFbzPqpb5X1nUsRy3iklc8g8n1Czs94S9GMF5ZWqL6mdEtBHmcuSe4eMa/BsRJNPM3COKDuZOdq/qY2y3jqUYhQNVK0YOTMqyviFbmr4vGpWP0lf3xLbeGDmGDlpNkyGq1FZpVrQ58wu8Kqep7pcRjQGowvalKqw+5lAKeoL6188RlWzwKJbIRg4x0ypmO7iuoGNTNrU0GI14LhqIOE3db/Err0ocLX2XM9IFlSvyLCGiu26ztLGNeM6lIzOoez3XWFNLz5ZgCMDGpcB5Q1OEPFPLHtqduWFlVWbap8ouCU1iKodJR+Rl6jS9b2lhoUz0MUEvXmEzCO2CormduYEEZ2/RxtygTouVdGNFiqBxlUsxkalBabQgFtXMsCowQy2gr2uqhdgHBAEB8ze2GVqWlOMvmOlmG7A+4YKzgcozLQ4amNtgKLitCpr/8RQ2+6WEC28DP22EzZo5g2LzAyjGPcEIeDkIpuNRwa8ymoO7liuBcGqTwYkoZa8G4QomO5zBRkV3C1ZOFVFfAPcyV5nmRB/mdglPMyYZl9ig4LOYKj7zqVaJUZcsvcuWMO5eI8fpUk71f4ouFyB2Rmra4ysI7BctCz3KHgvWcwp8zpjthSRlhoOu0rWZnzlq984QncmokU9Y7ZTML23qdneWb1XxiW2C7+n+4s3erlzK9iVOyTv0mStnb+EMdlYlZVwGCAPkQYu7g3KAK0sZhb3OAGI5bwYmT2rZxD+BxBaBZsG4BrSWjGUGwe6l/lp1SYMex2bnkEQxW+YaDCM+YZNsobla1CPB83Hj9JVaU69lQWmPwSl4cMzKVtJj+3QXVw9W9Au5ZWfklkrHF1qBC3bUKlo7eiBsWN2avd8RUqnBmpgDOIN211JiAq+/qU2qNWEGVhWtYhdxNjLGgpkW9wVXqviPD9sa9SoG0ImagLvw9RGOhY1Hd43DVVOXP/SIk6s2P4l9pWVYhuow9y8rwqMiqHDmcFGlRhv1UxFG/GpeXG0alAP1GHDtUbDmCBE1EBdOpYPcue3ziV8cx5/TzGIF9MYRsudwKA/7wMibhM+x5TpHQShpdkxsrWWqjdU8ykW+MwhhMa78RuCjQH+CPYRrsIuKOJeILZj/4/EL+vywEjWwvmbiHKP4RLXoLh/kjKVUJlJVDK/MHCwGldRyKd0cTMK4cOoXzPMDI2zuWbQvGkPYDYP3hZ/xcoaqvDgId2w6ITxH+YBingHEyYOe4akPljBxxES+SwY8hL4GCHFmJ6eJRqVNwc5lwKI4I7/To4tbafvFIafc4xFSoNkNhXES6HyruZwd3Il8VpjF3AA9MVbR7gobVK4ayMsaU1zOJY1M7vttxLO0IUyaDk6gWf3xBg5seyodCnxBA1zB4Zk0l3xA6gMyYhfMdbtypGCIo5dYlGVXUYEPOBK/eeOUMDfxAjrOLmAIA3MXLI77JfT0S7hbQ2y6DHazCK9CDXuW7h3VLdxfg+Az8L9VxLZIUAhuJgwIFska1cKGBRfuUAuDBkq4aNzhorHlCx8c3PCPKW8L8jZCz2u84RlQ4D6iluVxcyt2yj6eGZ87u4LbVUXuJ2P8AylFO2rgkiFJo6blYbRYCb6IPjD4IbpLwIHuWsUDmPS4qlvvxMAvlUphAoyR8SjtSXDkZNxN8vYOds383GcfI+FRFt/VU2eZouXJhgXmOCMXqohVVh4jS2ii5VD7wddJZbEC9RpVGYO9uYIKtDTwxFfh4zL4CrF8wQTTSBdRjADOLjXcB4wWC5IjSd9/2jkA1DgSzqAQsIrasrlIAC3ncyp157VS6WBijuVVmoOcf3IWUnPRNC2DD6i0HwsYMlmnLG4dOYt2h+UfrFP5lgBaU5xHRRZ1OPOCWjAD/AIr5C4H9CMVvU5A4jFREop4lJy3rxAU1H7x85ySwyPoGEV7LB1cq934YoLB9EzUHczg9IHZQv2JwlBVwNWlxKl5U56iCx8y1nBvbmICGmVxnsxi3mK7NeBuIYYHfmWD3UVcLStu7jU55lbkesGXQyoleVA+D6XLnKgaH/aWWBWiJVaeG+ZgBdFqH5ha3lnLfwib/AOdB8VEW/wBdTEPAssMp4jRczmpiivTBcV1LFYg0QcKi1/wQMkUAmPV6mmGdJ+EwzRiuqlZYOPL1GqBlQwh3cKgOmVGgKBpg7Vp9Q549rDZH1YHeUzhLuomSHRyzUt1d6ZW7Kw8IajHBKmPtPCThgflHCG3HiIoRG6m9NrZ3LPEEWsMqFx3UGpeHMQijWo6M7WWpU3CnONSqbQTBVsEdf8AuUfDguXP9C2zEAU5Py8TtR/EJo0wDqKuMwUNx1PHMyobFOJWBTzDYixcSiHA8EAoc9DlScP8A25cgC81qcX+VLAvT3ET7GMnmA1BWd8xWmHhn+Y2LETV6ZVF397mcgDhpKyrY467l62HTqLbhW7ueSXNThQFVSazOUVWSmyQsQYBgbhAh7jWmOPEHHbzKxTMKWZDJMt9u5TYYiZitU/DC39OoYtdS1u+ECitbjfLphtXkgk0zKvBcJS4TcxVahySAJxzcqDae5mR73KNxWoOR7gqN0cXAhYNJ/wC1Epq3TLJw/iPHCpeJK4dJEqCsRRcCs1WoiQtREEQ1tMsIzgUdp3r+JbBf+ELbPV4iCZfUVt/UQqC4PlqDqjdcM1lYNQBzqAuDT4nd5+/gWZWJXzuf6MaYo5z/ADDCOezqDlV4mtWMp0nTezqUAdTUzQC4VqIYCfaXu4lqkFZAbvAtrUMm0MRnpvt4lLhU0u8ahYJbpxUt6q+ozNl6uA0IdVmXKHRWSVtlnjKUDIvzUsvI9TxItD6Sw/0ucISN4F4xKOryQYp/GJuXfqNrAFplvdMUmXMYwsKgBjUZgfDr4Vv+lRWS0Cy+m74mLZuKR3mXGtWVB4QNkqRY2Edq7NXXuACo1FFqmLA98zPZYMsALeJaZfUfZhdCEwJuVHtuYV3rqbhhEL9VwrssxmLlkkSXtMIFQGq6lmHMuaKjRxeyF5dPM1GmD3CuG5YfEu1DMqG4epZ/TorIGqj/ADMEXKFKgf3h2J2HMbb/ADIs8JqtTAaudxH6S7INMh9oGAvszGLVT/JOkeqynSMRbD0xyohPC/iFmypnmDcmO5nPn3OA19RcZ/mUMivM7UIj/MvonGZqYlXKN1e2UDu5YriYNcfFQSz4rP6kUcRmC0yi3gAT78kCU/zP9mpMplfHXqKtWm9iGoYuiiDxAPUwI59DMYH+E1A2GWYWX5PRiPiGE4dRQbL8RRrXmNEXfMowXXuKA/NOxA5Go4Z95atiVmlmBv6i3RuId7lm7/aa3Gcyu5xKSot/1jFOoweQUx9vYTfPDWoYYN5E6i/b3HG+yRMFP5QiFHhAKnpcPIMWl3CWtN+pXiDTKdC+qaqWXmUWxp08RgFXJEhwYo3BziEuuKODqPzx1UxYM+YgiLInCoxH/cUPMz+Gvmrf9chhh9oepiSLhgLNLwmpxI+moOV34hOhIaDA/iPkE4TZBWwHDuYZe1kRYWjfa783LLLG7iBKA9v+UyTNtnI41ctLa8bxG1ZiJ7O5Qzz6Z5S+JcemJ0h8DLPuURv/AGHU20DPSwrGSOlnwy1XsQxkE6gnEeoVxf0R6sOLhmU5IshOVMoRV5i5TMYzPwsR5S3T8BbdKMVBCdym2kFDARSgYj5fr4qtwfgu/wCyCmpu5UEp1FEV5UwjwPhjwIYGj1BZU12QFb2MwtsvK8TvvSflEg+EmSwZRSFlCakp3K8ysWvqYOYglku/7RdTlo/hT1P8+z/dTBYMGKOG4DiZDsSjxM8uEN0k3SkOdnqOyiHWTtEE5+Blf9uuBcwCa0PTBd29k+kr0SkQ/ALRiYU5Yplv7zf/AMEA6B5hc2EIRVjxrMSok98zYC8ZlhZqW4jeIMYvmaNarf3MuG6uDhiBiC2pC6t2v3loMm3Xj/caKMZzGKbRM0YXTKbR7It1r6gnFPA/8RvAHnXbE+hFmz/F5mKFrvVSwBv+2qu3/j5i3a/pmMnz/9oADAMBAAIAAwAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQz8ckoAAAAAAAAAAAAAAAAAAAAAAABC7inyhy2j4UgAAAAAAAAAAAAAAAAAShfWCsJgHPQ0eBoUgAAAAAAAAAAAAABw0s9sq9xuEu7R3WPJQIAAAAAAAAAAAAP8MGZfwHCXRc9lfS9W7q8AAAAAAAAABjUfqJ3JsX/wA9weOYyNpwyCiAAAAAAAAEjo0d5K10qWuKy0kfP2xICIYAAAAAAAAy/wAvrQ9w9KHWfcEnrfizrvmrQQAAAAABFU1KAFfMd/cv9QOHHwGSssg0IKgAAAANi7chsmYpPHEcaC8oIktvMI07uLQAAAANAy+8YGPZjjckbabbN445AXXcGqgAAAArFI2zQOZZnkSSHVwrPSNssV0q+BCgAANUUkpZra/c0t4ZikPafNc5ISPtfDiwAAKVNIn9vvQ2DXHtLFKfC6wbGF6uuPgwAAO0TessQh91r3yCx14Qa1iNUobImNjQAAKz9YTsDl1Nuy6CVbwnQXtuXY1HijowAAMlBq9eIPBrO9au2Us9JNuPw4ZzGEgwAAFHv4pFosijrWQMuf3ohFNn60b4OK4QAAAI56Rb81/n095pj3w2jqJL42bdouoAAAAKVK50gLfAf5pwXaoPCPMrY9wlFlwAAAALPArnztCdZI3NcW8DTo5Q8W/kB4gAAAAALEdAzSUy0MIU1W5bkB5TTVukYgAAAAAAEnTzkdqeihflMQdanAm0/YIKAgAAAAAAAKakqcucpN8QjT0Rz6x6e0UeAAAAAAAAAADq5gYivoR7pt48f/y3/wBNkAAAAAAAAAAACbzPDWfOE4Vv3rBGMGLEAAAAAAAAAAAAABSQBOoTlI73vOqnnOIAAAAAAAAAAAAAAAADtCnwTfjr14tQYAAAAAAAAAAAAAAAAAAAABBvC33oHKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYyjo83jMrDrHs4AAAAAAAAAAAAAAAAABz5yJ7576IKKKMD/xAAhEQEBAQACAgMBAQEBAAAAAAABABEQISAxMEFRQFBhcf/aAAgBAwEBPxD/ADdtLS23+lBb4bbwc7b/ACCSr7uvrh0wFjht8d/gXL8uDq98HbHjbZsi3wH5lyZdQCJ0hOHbuzh+EfjXOJsdd2BqzO1pAPp588EggJuWWfNt1HbBa6WP3KbFYR3U/wDAsZepDdZ4LOUJ5PhX0XePcWVgCCPtJ6fUbEQstssiZZLkY+pmOT4ArOkyT3ib2n0MA0tc4xZ+yFiXYjkpbku878K6yAF3sExu4gRLXZx4XLdky9pMstgWks+P3yeR3/5vrbV7ukMxJ72LNh71obayyT7k1sFiQrZfn9Wd5ZfZJC3pxVdJCYI6b/za9Mp4f4fTi6M6us4ZIs9sHuOxDhfiJ98JddLHcnD+ynotfc8h4njDhdsXtAOE30v3YPc/rPuQTA5QncdnGy86bnCeR4i+rcdITLvIr9Suz5Lha+GN23vzPE3gaN+kPdgvdj1C+/A49R6vfiW55Hh2ITMlsndsbDWBgx+kR5a9IMPkPF6xYOT2bHrJANLp3KWvB5Z5LIR8jxGTN7s+rGRYZyWFvjvhnOY/GdNif2/6lXgmGD+E8k2DHLL0WT/zwG3+cfZezSDhjg4LeN+MPiO2PqYJbtg046tttt+Ig+MEh+mFnII5Pj35AbU6bptSzZEhvqPkD5Qfcr2szstiYNiW287HkH8D+ZODhpZ+WcEeGfxoM/mZnOrpsssss/nwsWebLP8ABxYsWLSxwxYsWlj/AAv/xAAnEQEBAQACAgICAgEFAQAAAAABABEhMRBBIFEwYUBxsVCBkaHw8f/aAAgBAgEBPxD/AE0Tfo8lr+UwHbB9FmWCcXE4eEJMr+JzMcMa3sX9tglN6LpDbbb4/ufp/ARYQ8u0F+hZsErbFtvjbbfG+BnUmfld4XNu5Ule2V87bbb43ydfDgSZ+NFhDxcsc5ZbwXPw5tHEss7+G2GGWJtvncnGTPxMcu2yQJKI4IDvzPI9mOhD16y8XiI3bmB9+GPHULb4IafhBegsD0g453EoQsF1LYFcyupWQ/cHbktkwrfK8cMfUPN7vwLA/wC9mD/dq/S+hH+l4tdx4wxtuA7v1I24s+ot2Hjcs9xdyZ8hdvRzbNSeluHm/wB0toYU4erfVmmzxGocXqmhENhiZdW+F68n38uQ+4tlDzbH22Q5YYvaH+bDQ5jqB7kDqOGQTmT7kJas8r4PhGnxLi+guAy3aIp6nzYMrjwmA6+25J32MDZTnUAW39Rb8DnqMHwTH4DEkwEvMQ7nd/1XJmhe5G9X1YMoMZTASkjMhSVyF7bUjHhs8wmoE3vwXf4HTcluHx8GwNsxRE4INuL/AKZbDIFoziwS+nKA69+NiBRYbN2ETSb34Pj65ORDTwZKjxc193Zew+OeGcjlmtg3CNDu3x1sjXZ43zMx8rwXMp3dPIbC6XPp3AwGTJkjxHDc7biIBe/Djq6NvyQAYTMfKsDcpMOXq4T1LjiBw6/zM+FJc8WObDXmPV6lbGWMj4eeICaeFEW3f4DjYCGm2ZxbMbfudM6hHq8kE8uknuW8SBmZOQuErJ4SbyRgxuAjLJd8Fl2+P9chaSV5lygHGdeFxOmMmcyCTGw9SQ/ccW7dEuwZelYcNyLVnNk8Hy5F7jy3TCyP3B7ukPV605ZaJ9kjeJTL9y+rPaHbIwSGc2lvqxIfL9fJFpCZnknTO8Pczz4ZjxMavokOdv7u1ifpI9wJCOvCWHjq3Za/M/0MMcYvZLltJufSOtOpPq59x/cLtmDOZiZLmR4n9x4Z8LPB+AcdLlTsnqedlh7kYJGu4bCxYSfVks6tFkIYd5mWXbqXX8L6EVaRlbDndMSEzsSWz4NPGE3Mtl1slv40X6hBY8w21bllZHvSWhnZ+OTMy2Wn5XNLlTu5o2JUcJ5Ioh+CTzttuzx3afnRaRcLtepPuQ3tLZwJE5Ok+FtknUu/wukb0QXpkwkg9w+rHwMa1V/jhdMH4NS5Vr/QA1wuHb+v/khev8ni6C4d4/58wn/nYX/7D367P4r8H5bx4//EACwQAQACAgICAQMEAgMBAQEAAAEAESExQVFhcYGRobHB0eHwMPEQQFAgYHD/2gAIAQEAAT8Q/wD4xn/6qV/69LxB9Kcsg/EP+LoiMR4ifEQ4lf8AoVNyMoVKhoGO8CIhT4Wwcz4X7wYq3pW/oECqiacXU5blWofczOL1XhcsheriN0EVkh6TwHrEpNBLKkfZO/eo/SI+Ylx/xX/kq0FYpkQmfE8RG5VG0QIQUBuXv3bMLc4cPvF7M3VZEVy4RUD6ym4WmnR7jC0bcj51KlPwrT4xBbkpvA+IJaRhHIRdvq3QhQWfm0qYEvbUGUPtuCUptXczi6/EwYU9CyCQ2dxkyPsY66eoo2f+MrQVgC1niJIlzew8EPnDisPNR+YuAxCsDHLHqXBReAD9YdnICH5rMvrgNsLwcwqrT5kHZNmlv4gocYAiiEhVN9sOO1KpePVO5Y/iAqaseiIRi8MQTqOacMIoF55JjY0umZyGS6qPKIdYqUhD4WELUfj/AIHGPvKoqz/4QXAWkV8VfKX9DmUtQ8Vl4NRh3b2teYOGEsNP5lwfVRsPrFTJMBB6tyfSpYHYLrjr4me3cKh3zqJbXBeXLmphKpV0LfjiO9gGbfTuFwLFlGKhBefUXco0F37j52xoXPMv7PoIqXuhOH5giKp0kqqXwgZW8m96hhNHC48Wt94FzkdKiGkPWoNktHLwnZOjiCmouhETf/fPIWXQ6BBZQ81U/eWja3Xfi5VDbdKb6lrMbh5+Y2MNgXwf6l3Y2uePBAykXTzXUqCQ1abrkzccqAaTdvMHomGDTxKk2IsCeH7wCy8Cu17vqIcgGA17fmBaMghu4Wm+3Ma5kCAXjTq6juxFj2OeoiMZQcPUsIrzgoZ/iTGClqOuWDcQH4myGnLcaww9MAtOeSVQSnuGuh7jbnJALGfENyRn/wB0UOO4tDspPHx3Fkzb+qCWYF5ayHQce4lDHCtv8R3UFiGbJZLqcuKmctm0NjG9noGKRapYx3cdQcRYb5YGRrYEP0NxZVBmzqC7RQuJ8ktDO1N+xiAKDBjpXNQiS2LBIqytU32+olQQKzGLRu+vbFN5sDZXrxEBmiV0XN8JGSDjaZsMGZVayL0Nm4+QTjiaa45IFk3vLLrvwdyiXNdcR0FeFlG7PtKNPqC53EmgYi1/2yWHyiWWGf5QwTShofgOPiVi693V0e9samBKYf73E2OVhqMXEsl1HBIrOf7UPvYt72EHd1APgIYC4p3O2Mv0hW1Jgpjm73B4vm6uPVTJ1ldNL4JhTl0Y8in838QfLzpl+INGcwwunywuFbGgV5sJs8HKYH8ReAW7XZj5UChePmWogtbqjs95xBXkK0LQ6TjjiJW9KMTCBVA83FRdWq9RyAogpRMdzY1KSi7sclSgNNY2NO/pALIXeP4lB0rFRemxxMV1At+ImZg1t3FMkT/sC1GVs3pYVn3EVnNdMsUucFTFkRjA6FfFcEALXwYF9XBlFcnUSxTSu4wLh4uoKQv57cYz7gKCx4M+a2eI3VqDSeivzEM3vJAax+svWLhSpfcRUg5iQzHAVoitInzxNwPCLQVTlqWsmKifISr2Ck6vmAFEVu1Ll0Ghta5mPkUTfmVZEApkvliXEbsVidZ+l4ly5bLLXqGBeCrr7bhUAFLL3ENWVdLKIpf39zPJu7y+8YvHFXVkuYLGPFU8y107OYbH+pXozErH/WLY8mOE/Ia/mKGRbKyhuN5ZN78Sy4WrWsucRQC9fzFasCUXmtK5gFANbHoc/aoqu5o4gYdGcf2efEMwrZtT7NERADdgef6QxpVtWfdC2ljFubf0lsrStHDxLIIDB6joUDBVg+oG2myCpA81lisEqWmOokzk1UeG04DL2sVcIVlrtviGQAugfJ3GoFoGe13mKEW6Vf2RAbNJV06HfzHJ1oVAvfMfAqcZyRqo3X3hwALb9kwN1OuP4n1A31BCuWT9poY8nUteIJ8xC8JzKUcfiMZ/6oVKcw2wZsm4AybAbeZd9QIOB1+JpPAS4ZqkqVnRFBBQxgHvxxMVQwgo5go1hVQ6CEc2Fhj2jtl6wy/b+IUGBbTlXb3FTNXYHGIaAqrLqKsrGboB/wBRuhYClOPccFN6HiFd6CnJEsNXizJMvndVAqs33EWAzB2cPmXpWzLepiXvAHcpwV5H8ysWUAG/MEeEtU+ItnMtrfECBjLYahEEoKuhvEGozLSx3RriM87aGxOyLAapRCrTycxEgOQYneW3iobFUxfcBwMVrMkKF9zjX+0DDzxHTH/TEq1ZoArfBEDx0Z/YTKkYjlYv1qvrZiGxoF4A2wTyUbPwluFsBuvMaJa5Kx1DCC2tAA7XQe5okgtRe1qpUNdjkxDkSzbRFOlKCgN1HKBSqgdF8zNWKAzwQypCVpX6GX4ipukskKc717ghoTYMxpCBgGEosMdahMKao5ZmI2trCVA5ckmrdVLmJfumNNYBNNfvGomYJQeDqDdDReJQVHijZ+8YDHkV5v4hsYmoqXPX3mT0UKs5OuYfQQgJ+8OKuCqY4lgIh3lYbOC8QBmtfaKna3fUMC1BuNGEhxKoVFbNRwqrh+0bV/0Qtll1AEc+0umQo1xdR0frHdIkx1WfzKvKXwXojPvFwE5gSSOC7/KbwYbRwfHcbqIvQIeFXbi+3V+4xRcRaxRjN5jSbHOyFRQtfvogMiAw2kM0HSk+6hlrqMhmpU0KrVgSr/JCkRysVbKUNeGYrBbwGY4JHktnkYuOBdVlRlxQFdPiypYb8sacckJx4pWx6YFEDLCNCnJS+4FRLiv11CsBVqsH13HKkma/oqPYH5EwzJ+HB18zEKcc23GFHGsOIVf0EjNVm8kocjHEJcUNtPEUFmL1HaYvMFZIvLFZIm8wWE05GDX3Fyv+hgbBzGGRyeGuFlff4cngHluLUklHg5hPzwB0dEec/UiYzLgK3R3qOWwZKdJ47QrPxD3GSxhqjCND6mvtCN0Y20mWjvMJs9o6TMSJB0LePiVJE7CwShjLqaD6Qsyw3A8/mUGRoclQr8STDxQ33MfiFjavljBNQqtV7+sO1JsAl4uWwKfKDd9vRLMCCCnWrC/zMhIqJf1YbiV2l3GgGHbUPFo6Yb5jbKKbqt+iXLg8oUEZFlWsBGtp284IiKmeNRbQoOIqDjsm+5cD+srot7OSGpV0xMo26lBxRANcwC0lLOVhVJqozWIpS+pYTcJLP86iNrDdrm76+X4uUQKAdcRgcn+7gjggCkC8XzBDdqtruJOqt+n0xuK0dXR36lNFlrNsE2Z6KjGhRwUXH3xAoDVGwWtccvzLJXiNWH8QBa7aII4bJ3UezKGxw7hDdTdpbG4G3kMxbXFS7DNvE571Eqlyh1CNu0FXL8xOimLb88EvgZqF2q1xX+4BgiZYO8vxFyrYsAOYbMTlEYw4imBFjV4hgXAuUFFZjguaZQQa9wcmjC7zFddAue/mZMpHlgSILsMVMY1myLLco+GNcF3xFVKzN8MyxduCKAGcQgDZhGAmYmlg1l3GacRMeJrP8yG0g4xLXB/WeiFegkF7qAhVSkVypBJSNjLRADwRCA3moOYCsaVm08PiDSAFhYc5339YLcrKf14gbO35zAtNyLnLuFfNDXJqMSlPRGSCoVqDm+JSht6nwUaJRCODWHdwZQc+endm4XFhiumW4tu3CQiIDNTXmuZTkS2jQcfX6zKWJlUK7Xp/mXwpcqmtpGt+LjRm1oRruF4aiMDz6gqm54IzNSOHaRkYTWzf+4V7KnFi84uUoBu2AdfMdNIYHMsoLdu4vQVzzfqFcMuG2/kjyPjUZzOx16/iBDvKVpHBaVMZ5qzbKWq3kOpYLvVk0DvcDyEBzOC4BSwb8yjHDLHuJX+RQG1gPHD88P3+J9gl8EBWmsTFuiWSyj6H4lw3LQWj/uDTSAu6RphVKBlVghjDqX5Cz4x38zimRRLECtaYFVCAzhF+nfqGoVbMoJwXlUduJkUj1n3MAVslstOptdGosAXJS2KDQ4AFniNuShywpBHsiRXQ7e5a0G615vH96g0ve6NArx/EyD6plDlV23UrSgY20x1YbWsoFcxSs0/xqVVJugMd3mVTtO8e4Yd+RmlObfmASiirCqfcQC+vlVnnjVxYCjgui4yPHVTBUp4P6RxsbrEHu1cYmuNvmJBhYFNNwl4y+JUNcQ5YUweIuBjOcw56DNbxcyh1Hc2zDIsyn+MxFVVpAnoqfej6SjRYHULYYb6MbbLDfQfWcF6MzQFxr4w1ExtAj0L59R3Q5HV4xAxZFR74+IKiCHMqbw8sRkMAFHnXdzAGDBNZjRmmxOSLTpdFZ7llNNBX9IrYUBD+qCLnZRncYFDgP3ju22S6YnyyuEWqzYQ57l0meWXitfP95SoK7dw5Gzcw9lMhCnXM6vQHDLNrmqeu4QAUK6DR+KzGA3l4l7+YgqKpdlGeqgF2UFoKnf4gXqEbRO4RsVAy9Cf3uWW7iERzfqNk4G7i+uZfbdFhsyVjfM0QGrdX6hg/LAF4vHJA6lDiZgLO1XGJwPEe6dY8y1rWl61LXNoKaiEOGs/8DFhnuT/GFsyUfAWX9vmVhQ3R1FXI42+YiBTP8rMk4SgAcRJoGe5jvSdcQzxSECwKVwXyH93LWy2eUoD5IA5u5U0Wi/iKNGjUCeu9SlaYHlLoUKhlCEpd0mT7wrpG26m/7mFTBDHmJi6IA8v9qDCdZWyygQChRqIInI5VC0LFtY6u/qEC7YOSMQgrgD0QQjN0bOg4nb5oLQJ9eV2nNX+Jbq44N+fMspn2r5uUjHumIK47jZttmkb+ZeIsVWqFj4+8Jrxs4FuL5Guu47lK0Cq+kxlThnAiLa2/MVcOB/ELLdZ8zSjdDFTanHcuCgG64iZpsIQcHyNztcOn/htVhqG5qZWqWJ/iUTlmLiz9d/SGJtAfMpG9SuoeDblXcEUtWfExQQ4HCX1T+/EF+oHw2b9mO/EuHNLn27YyiRWoB5xxCBXOoBi1Oov3wQKbRNeOe4q1Auwwc/EKHZgx135/1KmhSrcP2m8M1l0iJJfQO15+sOEseV/rLSE42WMFSCjlbApCvFVmuYKi6pVYDMLBHTMbTOB3cbBxh4X1BqDwqQDCVxsNZ7eYPjSjJV/37x6UXFSrdx6Fgxe8eMZ6+stbwmGW0JQaUwtnFaxcakBA8kO2yv1lI0ADRUMRhz8zZjRdRt+xFvGuMwFHSnJl5a2kotysP93HKLypNVM6ddxrJWNtQcaoiGhxCjsJSo08MRGnZMwCXfRKW/8AFUMxBYUijyy/dZQwyuIGZgr3HLZlaBhlsuS2fUUhXdwUjYmDESzAIvtMP8gTwh/MUagOclHMYUhc0bPMGDyL9RJkF03DfU0uC+3wxMxR1iXcRAgV9GTP0hlP4lm+niNmjdS748eYUrNVWx4qFhScy/8AURGDy0lrncaAhu7i1h/WLbWLN4riK1xQLI8FwmLBVi19s2GD0anJWtcieIKprBfxxMaAOgruU40MPDzC7JGiOH+kAqRvAX57DfHMKGg2Lui/xnxCGLGOS3jxEyohF57WDcQbq5jRWjbjEDKGVOoqAAHJxKA7nYhYBU1Zj/RK1otLLDXHuPF4D2O5dgIdLHQ3rjmC21nmGafM2GHqLbKTy4lLZYzIPqW2mnMf8OdQD4Mv2iAspIlrhrB7lx6LjcatBf0gijgX5mOAWwRVP2HWm2AjFWGG3Pq/tChfgUz7Vb9YgdjgtnNBBTh0+JYJwqZgfC5us180nzMdDksKdHH+ozAhWEZUDK3u1tDxuvcYZpDgpheTuXOzUID6kKVYm7cRSQxWWNwYRuKbNxNCK7Uuf0ggEtqnuHZsho7lFVjwxwUCvCJvoLSbr6RQA0A8P2hZIDZRXxKuacoU6QFLQX95Q15Ja60aZVXPzt/3BExeacRFopgPgFBatD7G3acscF0m1HGcwozYHGmf4uXIh0YM65jQLXkc4mJXmnT/ALgAAVXkmS6zqMW7IALbYR2b7ipTJMY7bIEQlMNyuDj+/tDTP8BpO2OB+gV/a4IpWQ9xsRH7a9qytoRuxSPa/pOUYaKjDDbF7fbBO6Mpqy2fJZ7YgnD31YfqSphtYZSCl5M3wfpHM6vEoxGuc2+CObHMxd9xg5FcFcVLR0ogHhTN1HAUoy0DofZc3JNC1Pp0wrCbTQwfKF7XcAg41ZtwKnbeni8NXcMDgTYfpKjAdG8+JlMhKsaMn+5QgBsXSBDGsV9Za2s3go1z3KeUM/yjFScg5o8dSw6Bh1C9B3iMqLG8bmlk3Vy7zbnB4SnQMS3yJeXsrHHmJcEcVzGsgdrtT3CRUYayRCKc6E3/AG5Y5K2OfcASAlSNPdwgtYrBFMrHhTN8EupmJAEpuKtukC3ETkhr/wC3E8yMuGionov9Zg0rkO4oQFY0WwgoFYSZlPZGYHFL88wDbk5a/EpRhApa30/rEszVcARZ9ar5gyhyI8pmNaMAPzEC3sYI2r4uLH3lo8RzUp5mfjjLEayG6TT8MG/z3rKckXDHDuocDXSbYQ2ptQPKcxmGifA8HccE1iqgV/qGd0coceo25vLUvpLQVObKa7iOlsWceC9xG68lA9LZWrM1wPSR7eUqHH1GCnZr9ZeVjxY7ZSh02JQvcdF0SDKgaPrAxBgypHhuEKRrFVTCJs3WLgpWzbzcFTRbhzKqua+JUOpQeTG3qIhR2Zt4+J8gSoqqVvmG76hFBcYzMxrxCGYrhniDGzUxUvDiHX+CpeZgYtX61+hDN0gDt1LpdnES4uNkrFz4mLk1mU1a7qvMVRQ9wl1M0tsGjy1EfIgVL9vYKfnEVBKWvHMYUYIRV/SBCx1G0Ay5ZdS8dkNqpZuGlr5PhR8ZvyRTQqmFqLtYSmadWCZbyjYt/wBr6xxGV21rYOYVCg0050MuL3UpjnKsMSA1OBnwzb72GPiO53bi8o+o9OqrRGAqANCNynQ0/eWlRaE38xxJNHXqVYbG++vpAm8K0YPccVRzvnp8QMtUC8fzLoDbJymSA4HBBz0C+JnQWtbjligKM7TfzOxioYKbze42lmmAEXwS2vBLwzDcGhcS6xqUr8Q3/g1T1GMHDfK3M5hCvjn9JzIkqXc5DYPMrhNi/oQFHWZYthbChMqVVxi6s84zCHn0ZAcj5iwLblPW4z8zMLCJ1W4IuT0TnY+81rpZZ7glLcTcghMnDK+ovSJxwJaEL7uXDHoCZzONrQ2BrMCuAFoesfL+zFttNCF0zjzjcYqjklWNBeqx3BVNBVjWIsaaPO4rOuOFf68/WAeRbSy7riVV4m6rjxBVYSuFfWOD9JiNIsULun+4i0BFpSp5cdy3UmwUCeoBYvAQ2oGVrLxZNg0UgfeoVVo5zcRlCOVKiwCaAu8yv4AgtkPMGFeASvvDlS2xv5l8Ticy6dIZiFFCLiK7OJVmxUOB5/wWJgntKeMEwnlBYaMo5cDHoICUVT7iXpYVUtWQU0zUYbW/iCKWUDapj8SuyDhTt4L93EHkzZFv4aX5goI2MX9AJQ7fqMTYrUeqCVbolSDcc68sYCUL/QczmwVexrdN4L+sU1dqKvlmeXkuPKQHuGhScAXB2qlfwdSqzuNC/EUhMgNH884CPFlYDLHNqb+YKxl5ClwASlTQZ2JFWAicLUWiMrw8zPD6U1K/ZALgvqFY8roo6rj3H7LgBlMNazk5i1zKtjS1uX0rzMkPErzDpdx8pVFgGheLxMoBtW6IPSiY9xJvmSP98TGXfON8xTdAmRqoeUUNQB7mcafc7/4R1BzwFkLS3RcFLNxeiDFkeIvZGIpyXHf/AN3QyQy64xMirQ/D9P2jEmLj3cLmWoHnv4xEGwArOFhFzqQ0Ryiykox6h7zvVVqphzCzys6hLoNGqIka4xtKACgfmUAVdSyFqAFgfR3HRG4Cj0239YoBDrdJTXUzA7T/AFAFbaAu4eKx5INiw33LIUNXLm78zwWMNWRu6QsrDvN4xnzDSGwmisVzWqlvAULuM1rcXigbLT1+UAMftVhbVytCu1ZpqZe7ALF37j2Alrxnx3NaBkvcdkHHAZ3b3BQLv3KiuJHR8MdN4I2dLgUJ48/zK4pn6esR2s4xRCbMoC/ayMBaboN9SsFoLe7lqoJ73Fys8g7jdZthrxHCzdtE0rFauXPBcxYygjm/+HQn2Yxl3/8AdEHPVcHBMRldHhw7+8ZGm007rmOoECqyLwkPMjSBy5X9ICAeLDhfnzGC0OuI9aRz4b6lrbKWIGfcRqbEt4vKd1cK4VVOeB9oUAUh2XBasszEoS3BdUGtSiwHyOCCoIWAXc1EgbsfggJXbmhup9uUJ74mISbZhxQGDDSxoFsgoTqxI+XqoKAVeRl5p0xamKZkrinFROtYdSxxdOFPfxBDU6CssrAtYABurtUYlAGrLv4lGQgFF8YVvMdIRzz5Liri4oODDmW3lxhOhyZCAHQ8kQoUpPtULXGd2j4gezGt0Qi+rzZdeZYbMK7gkWQAWoqKBwWrpIHShvMcTk/W4bqzUQKa4WMTQKnqIAO3jqFaaiTlAU6NSr6o7/8At0yW6i0cqpf0hERWpzlZm8lgGmrgKHYofTHcTAliuLzBk2G3RQNXB2KBZis/tHST5Ja7hAGC6cAbE8sFcDQsv65hJaznXLeeL7iaoFj4Fy67iBvMF09ZYl4NgKU1uZ52MibULHBzHvKL1GKuxumV+DDQR0lNMS14QEv0Qwm4GzEIDiWVBK69fZIJDLewGKDruDAbqqFd4Oy46uDy1ylVh1iC68gQytYg30M7rXXcLOZBcPcakNHmoioDqMWVAUt3jX97gMgHUM3lSgQ6wUbzCaeTED5efUdkIKi9+PcBojKoXffOvpNg4yAfWMK5Jz6/vUSRHdEb7f0IUiyo4IaO/wCZg0ZF6URgFYRC/HuUn3KsTPK31OUUsG91GWCtcR3ruXvHEaFPLf2lgnuO/wD7wksPtp+Z+GWmpgOyApCWpTEwAtTD819oFRorrjJmNeKp2C9+oMz0O42M4hOIS7VukzL2lAqKvIYjpcgi1nv31B1QF1gmUvtbB01W2SvkB8q0e38xEluDa/qxBVGPcR9k2I2r+kdhM+4bk/ZuVzoNJrN58xoqqKv+paa5kNwYgpTeThpmN2x2KNZvHHGoUWYJ0snJ2zJ4Q1N52wKhHaB1g5uKR9u36tb/AGhTlNyNxUc0zL5i+CcQfZvXoIO1aYizGYuYOCWj48S0BMrKoZaUTTBjuW/GtD4/hiKRVQrUNj01oS+1doHbQcS40Nxcs0lS4qUbqtG6l7qVc+4pgporrxKMFBtdssrtx3HKM1bECqjZVk4hZc1frE2u7mA5x/g3XcNnWSJvZ+8ONAYG7n1crApyrZNLzLFOIq7a163C3QcxQDFeeI44pBW/MRVoIaq68Rx0tV3iZCXwtgW+Nf6lQbAVy/EBmYKdZTkeA8RQCtV50vQ38+JhUWkTI/8ACrhVXj9o8tA6rqNIpGtTtVFxqmtotxWSUhzLoMKiyrni41+1NgeMpesjMl4qp4AwudxvTAGB8dRKUwkKVs+dV85lAA8V7CuLq9RaaqaGMcXE+5bYnYvuW1Jspl/kgoIzOwYQr3fP5q5Cra28Ln7xE5bOkXlPHmKdKrR/wfYIrcq2NfQ0w8AQ2VGf1+sHigVZf2gAoWwyHoiCKlJi8QoyVN5awDzErSu6xDciOe6MCVXo4iOQ9EAycLoICxY3hGWAg+o5QbKxKXyG2AHYmarZU33LPh/9s9xS1sqZeD+qS6i9Ku7KP5IRLXs4y/OpvkVZ+kBQuj4KNSj6hd7OMfaGjY7wFlf33GwGQWYSiq8ZqDrREdPUOYrDNwpBIHCG68eowvSjjb+1QCF4h2rR7YmfCt5W8q/WBttzeYO1F1KFL0dy8Krac8/x9Ym1nVuo2RO3MQA5hlel4+8U4jOivvHAOqLX4pPvCPcmSmnHN3DJ+0cjx7qv4hemsZRbLggIJivoy483F3TYsMXVP5jX8Qpc6e24tGwSjV1ClhnkMi7MRmACKrIHx4h5LBajxPQp9YBfDGWvm8Qa2sQ+6HW5U9BqlVdXHAKtYOVqvEVoFtCmh8FLAgsdjNxSQVHDrcvwYu1+j4l3rzA3uIawSJnJcqK0c0ajtqq/WLW7qXRFqomG1w2qqjDW2AAp85mYGPUu1Yx1H7IJpesyy0WH+Dw8yqK6XMFq5e+fvcpAaK96YSqZhkZ6fpHHEATviIZZali3Z3VfQhrBrTRgtP3hZivR28feIaAA0q/MfTo1XUU3dBsz/dR7dCRUEy3eitzMLLHk0oeOjqHeAsl0XgibWXGRoHllmJap26hWMG7ZYH5SlBugh39IwYYyTnIhXEWTwYFXmnHi5c0QrOkhcLQVPsC0FXzLo/VcMO2W61uuIwDaARfI9eZbhwK6rm7PpBUCURwvYXb3dQCmCCI1NPD9bi8wLSIHd3l7lEQm+6M4oF+yNd5WFsYwpLfSp2opbfvCJIW2Wdf3uKbGBLhylh4hBVG2IbrH8Zi1ChmWLXZuEhGqu6nh19ZRplUDDufPqhuYcBTCVZ+0BsLVLMJeZfwwE3t945UWO8QrbDVzmFVpKuKq6GYLA1nJFTkeoqUZWEqC2VVHbzNlUhS7FaH+AablouT9XH3qNyzOfP8AqI0M1iBW1hvjj9ftARLODYuEmeWKZGObPxUtyaW7y/twoPegr8vuz4lG1bTDXTzDzbaXRWiD6g5Vkb0GmhHC76YrC17dga+0KbP4giJYAFw3NkhhqEi8B0zZoUgDj9ZcUcULthnn3BXPDcHy39oEsXAF+XEVqByspB67KDa+r2wwBpIC43VY2dwrZXHLrt3Uyp/J4dHhuo5V4CKjzCywVeJZ1XU3QjlYy6m5MNWtcfpFKWlUiOhNyobEnDnL4qAhaoQV1bj5hlo1DX1J9IEGl015rNv4mc8ltMt7riNjCMHTBGLOnUrhlkFQ4dwNQclfl8xo6ozgrmHxKJ4KDLGorBX3YxZhpsigxBpzqNsatwEInczFHxDQfQh3f0EyWjF7jBdx2/8AC6GiNk1FDU4eT6kQ2BrEpXYPJySlTBQ1fRLlftnIxArnyHuFU6g7q8X8BDKFBqphU22cnETcq4ih0fSKEia2FaM8ZmZ/hI3947WUZjFEq0N/pDMjCysrrzNTm9Dd6JvXgiOQNxXhZqOmqpsqMpABwUDcLq3N36jVPFgJXJhiOSXTh99qXm02weeYiqyUp1fTz947tRnS3imNWHgAorV1A+tUbv57hka1meg4g21+5gRMGHwvp4ZgrgzoPu4eCr45xvMzUiw3Og4hQkIRJmvvLutpcgDwfvuEPDE2ezxC1pdjJBCorQEQpNgKD+vMYqmwwCnPt+dEWgVa+JSwDrGpQhYUHEGlPENCHEP1xUyWXz5jKl1zLrOUNjmfEajoUZICp3NaLa/4UbdC1LDhaPD/ADcdCVXEoQm8/MYUJYvt+ssjZF7yd/EakU4UcsTqig1m757xUpxvUBqJUkqFpbX1G4IO5ehfN/NS7TuPcRL9yDUsNg1EonBvTPrX3lURu3Q4zmJ8LW0ij6zSR18K3f08y60woh+TiU0pajJ7aIlxjmwiI2qULvWaP0S6V8CvguvvBGgdjkFzqJubq4MUj1241aORGr98RgKuTtfr+YVzCq2/H9YroTKK+24e2rgI7V0fxAhVFIV8v5lksylV9kdtvtanrmp3uytAdsBkq0hjY3DFsG0HyxAxcpWsyuGOQp+GLjyeyoQIi2pz58Z8TXNiAWvdb7qML9d/tALUGFLqK2IVhi5V2uD25ZZcUYKJTaVu4QHfcVudXEU/8LwSyfiVU/xKQ4YDmF39PvUBDXJ6juk3ENVm4ljkBfswoUWPiY1uzeG9VLNj4GQoufQ+4aJkAFg2Xr+1EWG2rtOaslvFC1HgvX4mMKt015ir1xzt9xxhFs4pk0cvm9cxfZHDrjUChRxKrqW3OFlNByPDnvMfbOKLQzZ01ZmUY4EyL8NPvMT4WYxGsJfP1mBnW1wZu4bc9lBpbU1F0mBy46h4JewWikdhaCWcnjhj4oqsFHgomOCHQFI3MUV8RYQ4BfML2K0j2L1QgF0SWSMOH0JXb4gX+ez2jhVtAt1gikLWqt/SKZw2tPleZbGSGwB4jIbYahD7wtZByYHLzDS74Bz6Kv8AmKA2IXtRzQy915ESIXb1GxY09EUAyrQJYxWJY0iNXu/UbSkhSyr8wAeepWDl5gO3Eup/jsErqZjGk+mDxKXlxeiIVwwPES5UwIQ4Ki396A8sVeRgGq1Sn6eZg8kByHHn9or+BXJOaznPV5uIu4oY8f38RL2AYYIROEHz8Zfv1Eeg2FlCGjd9eY1sJ3L/AGHMPnGlidzNDixQ5w34B8TuLrAqVik5vlhI9E8wMrfEIQENHAKA4RcS25hZiNR1UMDkWjb9VMkDuS9au9biAChgBv8ASCdLMALeIs7Wkht2iWFKT6VF3CJYBz+NRmrVQEHFvucZix29nUFk4Zpoe+fiDbpqOxChlQYEGDXEAqTVoZHD6lbW5FQvHmX9sqr8CX41dUQGHavC9wwrq2q+6iODAK5O8xplOarimjPVblhVljKG7rXaxyykoyDW8yzRXqKb7YFj1Fa8sVp/xqM8wzAmI+z9vmM3WplDQsjhIzXPcq/khwwSRjcS9J47iQ6XLAVArO4urzV6i4GoNRbhJZmbl8ZxUVSNhB5LK6depkyq8vu78fpNEDC3197iCMUhnzDZBfNam0vhkrVHxdPxLMILBumtePUfTBgKDSh0vZ3ByVC72dB9EbFgVXFftAqTBUDk1u9wc1S3DcmTiZawF8WPvojRoeDjiIhu45NGbxLwUAyeTG40jrTArxriFMxYAbv1NRqks+fXUoRRo2u6SJaK2w0QxNpTza7i6lLqx34ixBAgZrt8xeUGTlbAssOXcvnUWY4zEdMOgjx9eIR0W3ATMeGvEp2zuyaS7cygAaeYncW4LaqWfMdFkQRucJ/j3/xcgLYxb5S0/MAwyaiqQu9wM3TIn0hXQLVdu+PTEKk0LITWya1btL+cTC5iTLZvWsx0E0Cy07N158TPU4BVn7xldaUDS/d+IqWxwAH6VdXMrDabBvwn3ihpqiInI9HcHYxDuk8S+g1OCBEWsJgDOuYu6oUVVBXxDiI3ayL5zrjMf4EG7bdB3uMmmCnOtlt1CQ9i7F6p3sgs1oXwMVfEPrFyUDHNQ8VA9zwzQaHJw2r8fxHlOlrH3yUc9sKaNcQU883Lve9zhqdmqV08/tBwQEQKPT+sqXBUui19te2D8AmU/vqMWcvKtej3FNkuGqOpdKjWEc2wGRByFIfrcbHdRcc1LeJZMsSRq13fE9wa1L20ldQqpcP+U3tF5h6AFjf1/vuFtKSBEji7IEZ8QPxDaFD02h656+YMK2hwarHEQmqpSkTm/WEii3JQB8XdcJsxFhHRcAc3hHP0ldV5G1I1XnmGEblGXN4NvzeamZYadRRq7zRy1rUHXsZM/HccVrtox56JhrMmU6jAgGN2dF1R8wZMWrFade2WCVXaA/3EAFBVKK5oS42TE4kzkq/uQAQK76Ld549cxCeFA5Kd+89VGI7qXgKHVO/rBdwAXB257MfeHleLBl08/wAxBYeBqzz58yuhqkVTWtZJeEG7au6OiU0zBAHJ2feGRmwmFN5q+oTxG2+28nzHhyR6r3HpHZeXqUAxhoVb5OeoSomxdFcB+kABMXc7a0+I+cmTxzxFAAKwbmio3/wGc3XcBrNy5Vx14gBRMG9EtU5f87NqjalZuWL8f3xBsF5xMMUrJ4mY/LRYtIlOOGPpD2slDgxeIbPasKuWnky43Cn1pFWQ8mPpLRBlilNZqnO48g9G75uvakVmtxuk49/7i2pm8bObfcxUcp1Q2e9RgC8IoHCelIYhDVbxd75B7gojKh9z1iUhLwL5GbMPLBf38x4Rg7qefdcxJKqy/RfEdkKsTm9158xxTcILPCkhx8wtmTuql/UC9rUKGc5EF1oi2ywdAuvPx7jIFTRQSBac0rg3wS5EuV0X95zSpaQm6HAtfODnvcFsef3hkCF7yOomZRqBV29viWmOU2eq8RpbDb8zUxIRS8yqggK74isWMC2pgv8AjFfWIrf86IZGeDu9eZUc60nPmVmUctmeJMnT0w0oZfD/ALjqm08lGWORBWwHflhlCuMA8j5OoVRuHpPe5WcCLdi/HiFeiF/ifRKjrQItmz0ajTTI2Srzephyi21OTw34h2zyVojkfk8Mf57stn30W1xrUTtGRt26rxx9IMjGhsHSWfFeSLptmO2Sr1emHqPwW16fEdqhtswli6xFgRG6LYGn13LRQjYRWqcU++oZVqypb47xBgWSlbKwmMbv4hFULnlYrP8AdwLNuAyBVHWs1CZipGuP0/ExDVDRtjP2/EVVAYF5huymNwBQwEWr46lMcOzODM0LXjyR1taRvKtECwMAMa7XxAXVbKS6pegcTEbybuP/AA7iKiBlt7/4Rc+I1F/9E/yOSAXSu/DmMdLcpzDFsNjWmIHCTPR+gzaoNtbzuKoKEp2TMAqYFD9fMsG7pZH+/iAGiKAxnUAwNGhgH7k5P1JQprvXcBuCArdmlrAq+t6iWMHRlzBpAni8U3k8QFd2JR338MREs7gbPRu8wQCODTDuixd+Il9xUc29PDWzcAadaC+6tMFIpdjg4HjDm5RVBpi6auxx/MHZ6RsdhcfvLplULQVneKh+QTVAp9Z+OyMly4YGtglF3Rp5g7RCI9LCc8n0mdTWlFj11u8xRbFllB8iNfvGRgb3uJgvQqk0sdAbe0YUQF+cI1rcNywRdk49MvXVpxqqqHgZtSjHR+ZRQH6RFjAxijZcQowFf8cZ1OIx1/02uoRQ6YWQwrzdnuVZOwNkMYBDgYyo003fhYEr/hM2ALFNxD15p31CtujTVI43MuGOxngeHfUsKwoLP8MJTBRk1UbB7AGxpQeTmbtq+Y4pv3+e5kCvFUaflZeP3RMX0Rut76iALgVbf2Y5xEFdC3NFX3X+oE7BTf8ANAzB/g5awhtOLzzxCy6AB09098l7xiUA9s4B6w8cfeFYS0rDPf2uXrpMnIeMSsKRRhk8fRjSXLzu5zDyhy4+o+JfpOAQOEgs46sRcoYaQfiZCYUcfaYDAKrfzOeAvgijamw8wAFtiuDzLZZZAhuIA0/jxEpoiOUADnmbjRGonaJW5UUaiVb/ANK4gI5IWuDCLgdR87jTftLiIS2cxK1DSOv9wiDpVHII5/MsPBq2cfT1EmYIo2vHpg19kBpHniNTuAhy1z9/HzKGMDRXlON5mRb4rh+koJi2NpXkR/iZU0Bgq9iqNsr3DjBI2Z3rEoiUYB2ap/aOGzntC/zzC0lcLfnjf2g601bnDGBc/b9YOhAJuQ5aKMXAo/gbo1d1+32g0IZkFnWcP5uD447UF38+CA5uNWv9IxXQ4XJ61cVR3xgYfS5l8ELN/tK5wDlW+0eaZIEhKUYZRZ+bmlAY5wyOmkumKgybXcAyoHuHlUPLELILrqUgmrzBdRWWiUXGoINqDzAFlAJudHUdf9UGlJFylpF3MGV8l6evD+YBR2jZuvP1gvmmBpT8RGm5pa7U/WLBAUFp39Z4u8EFbv8ASIwCCVj0OmvxNSj62HjUNLB5loYJdGwfTevvEoHQJHXuPHdi0Oc438xGlfH4Vz1G9CrLaN7iYgZyFenuo4wAaVlPn67uEgw4APeKCaASscsZDqosiyiz9BrfUJRYYpv8Yhsbtrf6QpDvJnf0hucFMBXxcsRb4wYgygC6AGa4TpNx4sWeUuBaAVhqLyHKVEjYqFEqnxiOszHU1DYNMVgsdTIVRMAIO+tspUcG4j8f9cGlJMJPhvXtCRDtOKv9I+yCLaJSHsLCY6dRwq0V0DE4q2SU9dS7KyqfS68kxA7OIfctxtkwp0TsqDidMIxsVWzkv6Qtnzygg9wBjRYteKgiihcFvlb3LVa8bXEXURgy3EcCVxnEqBZYWYFgWelEVYD4EDJD06VMj9WG+pSZCucFe4xEPIb/ABK6oF9Sss7RsiKGHg2d6hU4zWbzmWAHrZRBFR6XLhADuIazleOfmKriP1TJcwdzGg48RH4/7JpVMfmGLmoLLRyRIqGKp0eyXToUyA+uP0iDSUgpB5IrugYLN2HH0IRpbIDe4yEg1mL2eGcQwEH0ZZnjOgeMxx4bbY7IWkbIOto1UoWFNKzqAix8mI24AZaPvBAXTaevcQXS27RbbTC0xyfQGr9TTRk03fm4slcK3LiMsdFIPfmAbMCgBlhAULq3P0nYBbHP3IUhSccvtLkk6cygb8lXnqZFAJVYk5ofpuNaxUNg34gROUeyExhxHX/bLMkBLcXwl2BPUx1E2jnshrkrVhy5p3z9YgWD+AJDoRCmeGNfeDNWGRY/3EYOdtuvbuL0Y4Sh/mXd3IZ/mZqF3w+0zNtZOQ5gKPEMsxdo6SienUdAnOg8Kh1Vs88fvFBiW8vTPzKZkMGabl82BVgh9xAoRCuLMQAFlNXbzAlhRzhvtxkiVXyy7V5YAAfPM2JM2GDxTEAAFYoEatjqgKSUNqHILuOitdHEAOJQ2o7XH0MRWv8A3r+0ePzLT8TCNacg+u5Qxdn2M3VMB6oLB8MUQRWulPDpjYtVm13+vzHUB7obfXmUx21lnxBqCKuoEMWNVkB/E8CcZPrFsJkKidRIN+gedjyTQm709TBbYZX7tesy0c5mArcbgJGUORDw+PiDuUHQ0+IsyBEOLOYHbDiAM8OYgDRuObHmbl1gs1AAxreYkXAWaIC/dRTuvXEXlSZDK+WDbPzG0/8ABFVjTFASkWs0LZPT+8K2fOAfh5hSWCfscS6LQKGfet+SEBw3d/v0ioog6ihBt1fJ5qC7pAMp4fECSzRWP7/WIqEZNKQBVYxsX3DJc21i4usQmSqPrE4ABVOv4l2OLdFxosweIiGM2PNxVJbVBivMdibs4PUAxCmMYgNTkdxVUHU1+ymU6/MCLw9wGsyzTFbf+IraRlAKyOJngyV8y+9NW4+v+pcLQ8j6YiRtDVOIyG2PWYkVw/nzSeYCvvsT8QywQkOayca+SYAAN5UheP8AUNG7Och9wKvEDD5g5NdZgDR4tPxDeGzd88eZaErv4g0Sucy0CV5xFSMF4DmC+2/AxxjHQjygYBj6sVbuK2f/ACBKxqalJCSr5R4Ffxp+pMWg5UaH99QHJoFlkcB9lM/aBU0zlMh8QQGxgyfTjnqOdKuQVflqDuKhwuCZJXsUlaAe13KZT2UyCAcGLhqgrVxwy3sltVmAttPuO8/SI1FXf/miNM1am6zPvihMpa7C4WMq9kL7yeGpjaxfTDqb+sS0E4Qm7+ib1vn/AIRbmKu//Wt7lvct3Le5f/4iv/aOhyGiXJQ4QvXny/SVwDVK4LapvxzW4NJORph4z+Y6l58C1x8/aC+HTIsKHvzXsjhbZBPkZ/mAN77Mw4d9ZgysGrTyhvxXOWD0AKsy45UOftGuIVesXzvX3xqKDGoV7HO6T6xWYJQowlDe/wBEtFEVoUq/ofeHF2CjWBBvfn7R5VAy4bo+gfWFolYoDlzdvX3hRc0woeMb3l+kSL8Rroxh9/SaaZ1WC3LGfj3K8FWJdqO+g73Gu/NAgDXO1E+kK+A0N0fq8H1l58i1rNGKzz5qLQqRaHF3z4+5Grxr/wAhV3FXf/ApKCxoxb/8W1LeTcRIV7f+LWP/ANKvP/CaIj4i25/4/9k=\" name=\"Imagen 12\" align=\"bottom\" width=\"208\" height=\"183\" border=\"0\"/></p>';\n        Html::addHtml($section, $html);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $baseXpath = '/w:document/w:body/w:p/w:r';\n        self::assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape'));\n    }\n\n    /**\n     * Test parsing of remote img that can be found locally.\n     */\n    public function testParseRemoteLocalImage(): void\n    {\n        $src = 'https://fakedomain.io/images/firefox.png';\n        $localPath = __DIR__ . '/../_files/images/';\n        $options = [\n            'IMG_SRC_SEARCH' => 'https://fakedomain.io/images/',\n            'IMG_SRC_REPLACE' => $localPath,\n        ];\n\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $html = '<p><img src=\"' . $src . '\" width=\"150\" height=\"200\" style=\"float: right;\"/></p>';\n        Html::addHtml($section, $html, false, true, $options);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $baseXpath = '/w:document/w:body/w:p/w:r';\n        self::assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape'));\n    }\n\n    /**\n     * Test parsing of remote img that can be found locally.\n     */\n    public function testCouldNotLoadImage(): void\n    {\n        $this->expectException(Exception::class);\n        $src = 'https://fakedomain.io/images/firefox.png';\n\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $html = '<p><img src=\"' . $src . '\" width=\"150\" height=\"200\" style=\"float: right;\"/></p>';\n        Html::addHtml($section, $html, false, true);\n    }\n\n    public function testParseLink(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $html = '<p><a href=\"https://phpoffice.github.io/PHPWord/\" style=\"text-decoration: underline\">link text</a></p>';\n        Html::addHtml($section, $html);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:hyperlink'));\n        self::assertEquals('link text', $doc->getElement('/w:document/w:body/w:p/w:hyperlink/w:r/w:t')->nodeValue);\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:hyperlink/w:r/w:rPr/w:u'));\n        self::assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p/w:hyperlink/w:r/w:rPr/w:u', 'w:val'));\n    }\n\n    public function testParseLink2(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $section->addBookmark('bookmark');\n        $html = '<p><a href=\"#bookmark\">internal link text</a></p>';\n        Html::addHtml($section, $html);\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:hyperlink'));\n        self::assertTrue($doc->getElement('/w:document/w:body/w:p/w:hyperlink')->hasAttribute('w:anchor'));\n        self::assertEquals('bookmark', $doc->getElement('/w:document/w:body/w:p/w:hyperlink')->getAttribute('w:anchor'));\n    }\n\n    public function testParseLinkAllowsAbsenceOfHref(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $html = '<p><a>text of href-less link</a></p>';\n        Html::addHtml($section, $html);\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:hyperlink'));\n        self::assertEquals('text of href-less link', $doc->getElement('/w:document/w:body/w:p/w:hyperlink/w:r/w:t')->nodeValue);\n\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $html = '<p><a href=\"\">text of empty-href link</a></p>';\n        Html::addHtml($section, $html);\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:hyperlink'));\n        self::assertEquals('text of empty-href link', $doc->getElement('/w:document/w:body/w:p/w:hyperlink/w:r/w:t')->nodeValue);\n    }\n\n    public function testParseMalformedStyleIsIgnored(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $html = '<p style=\"\">text</p>';\n        Html::addHtml($section, $html);\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n        self::assertFalse($doc->elementExists('/w:document/w:body/w:p[1]/w:pPr/w:jc'));\n    }\n\n    /**\n     * Tests parsing hidden text.\n     */\n    public function testParseHiddenText(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $html = '<p style=\"display: hidden\">This is some hidden text.</p>';\n        Html::addHtml($section, $html);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:vanish'));\n    }\n\n    /**\n     * Tests parsing letter spacing.\n     */\n    public function testParseLetterSpacing(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $html = '<p style=\"letter-spacing: 150px\">This is some text with letter spacing.</p>';\n        Html::addHtml($section, $html);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:spacing'));\n        self::assertEquals(150 * 15, $doc->getElement('/w:document/w:body/w:p/w:r/w:rPr/w:spacing')->getAttribute('w:val'));\n    }\n\n    /**\n     * Tests checkbox input field.\n     */\n    public function testInputCheckbox(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $html = '<input type=\"checkbox\" checked=\"true\" /><input type=\"checkbox\" />';\n        Html::addHtml($section, $html);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:r/w:fldChar/w:ffData/w:checkBox'));\n        self::assertEquals(1, $doc->getElement('/w:document/w:body/w:p[1]/w:r/w:fldChar/w:ffData/w:checkBox/w:checked')->getAttribute('w:val'));\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p[2]/w:r/w:fldChar/w:ffData/w:checkBox'));\n        self::assertEquals(0, $doc->getElement('/w:document/w:body/w:p[2]/w:r/w:fldChar/w:ffData/w:checkBox/w:checked')->getAttribute('w:val'));\n    }\n\n    /**\n     * Parse horizontal rule.\n     */\n    public function testParseHorizontalRule(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        // borders & backgrounds are here just for better visual comparison\n        $html = <<<HTML\n<p>Simple default rule:</p>\n<hr/>\n<p>Custom style rule:</p>\n<hr style=\"margin-top: 30px; margin-bottom: 0; border-bottom: 5px lightblue solid;\" />\n<p>END</p>\nHTML;\n\n        Html::addHtml($section, $html);\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        // default rule\n        $xpath = '/w:document/w:body/w:p[2]/w:pPr/w:pBdr/w:bottom';\n        self::assertTrue($doc->elementExists($xpath));\n        self::assertEquals('single', $doc->getElement($xpath)->getAttribute('w:val')); // solid\n        self::assertEquals('1', $doc->getElement($xpath)->getAttribute('w:sz')); // 1 twip\n        self::assertEquals('000000', $doc->getElement($xpath)->getAttribute('w:color')); // black\n\n        // custom style rule\n        $xpath = '/w:document/w:body/w:p[4]/w:pPr/w:pBdr/w:bottom';\n        self::assertTrue($doc->elementExists($xpath));\n        self::assertEquals('single', $doc->getElement($xpath)->getAttribute('w:val'));\n        self::assertEquals((int) (5 * 15 / 2), $doc->getElement($xpath)->getAttribute('w:sz'));\n        self::assertEquals('lightblue', $doc->getElement($xpath)->getAttribute('w:color'));\n\n        $xpath = '/w:document/w:body/w:p[4]/w:pPr/w:spacing';\n        self::assertTrue($doc->elementExists($xpath));\n        self::assertEquals(450, $doc->getElement($xpath)->getAttribute('w:before'));\n        self::assertEquals(0, $doc->getElement($xpath)->getAttribute('w:after'));\n        self::assertEquals(240, $doc->getElement($xpath)->getAttribute('w:line'));\n    }\n\n    /**\n     * Parse ordered list start & numbering style.\n     */\n    public function testParseOrderedList(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        // borders & backgrounds are here just for better visual comparison\n        $html = <<<HTML\n<ol>\n    <li>standard ordered list line 1</li>\n    <li>standard ordered list line 2</li>\n</ol>\n\n<ol start=\"5\" type=\"A\">\n    <li>ordered list alphabetical, <span style=\"background-color: #EEEEEE; color: #FF0000;\">line 5 => E</span></li>\n    <li>ordered list alphabetical, <span style=\"background-color: #EEEEEE; color: #FF0000;\">line 6 => F</span></li>\n</ol>\n\n<ol start=\"3\" type=\"i\">\n    <li>ordered list roman lower, line <b>3 => iii</b></li>\n    <li>ordered list roman lower, line <b>4 => iv</b></li>\n</ol>\n\nHTML;\n\n        Html::addHtml($section, $html);\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        // compare numbering file\n        $xmlFile = 'word/numbering.xml';\n\n        // default - decimal start = 1\n        $xpath = '/w:numbering/w:abstractNum[1]/w:lvl[1]/w:start';\n        self::assertTrue($doc->elementExists($xpath, $xmlFile));\n        self::assertEquals('1', $doc->getElement($xpath, $xmlFile)->getAttribute('w:val'));\n\n        $xpath = '/w:numbering/w:abstractNum[1]/w:lvl[1]/w:numFmt';\n        self::assertTrue($doc->elementExists($xpath, $xmlFile));\n        self::assertEquals('decimal', $doc->getElement($xpath, $xmlFile)->getAttribute('w:val'));\n\n        // second list - start = 5, type A = upperLetter\n        $xpath = '/w:numbering/w:abstractNum[2]/w:lvl[1]/w:start';\n        self::assertTrue($doc->elementExists($xpath, $xmlFile));\n        self::assertEquals('5', $doc->getElement($xpath, $xmlFile)->getAttribute('w:val'));\n\n        $xpath = '/w:numbering/w:abstractNum[2]/w:lvl[1]/w:numFmt';\n        self::assertTrue($doc->elementExists($xpath, $xmlFile));\n        self::assertEquals('upperLetter', $doc->getElement($xpath, $xmlFile)->getAttribute('w:val'));\n\n        // third list - start = 3, type i = lowerRoman\n        $xpath = '/w:numbering/w:abstractNum[3]/w:lvl[1]/w:start';\n        self::assertTrue($doc->elementExists($xpath, $xmlFile));\n        self::assertEquals('3', $doc->getElement($xpath, $xmlFile)->getAttribute('w:val'));\n\n        $xpath = '/w:numbering/w:abstractNum[3]/w:lvl[1]/w:numFmt';\n        self::assertTrue($doc->elementExists($xpath, $xmlFile));\n        self::assertEquals('lowerRoman', $doc->getElement($xpath, $xmlFile)->getAttribute('w:val'));\n    }\n\n    /**\n     * Parse ordered list start & numbering style.\n     */\n    public function testParseVerticalAlign(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        // borders & backgrounds are here just for better visual comparison\n        $html = <<<HTML\n<table width=\"100%\">\n    <tr>\n        <td width=\"20%\" style=\"border: 1px #666666 solid;\">default</td>\n        <td width=\"20%\" style=\"vertical-align: top; border: 1px #666666 solid;\">top</td>\n        <td width=\"20%\" style=\"vertical-align: middle; border: 1px #666666 solid;\">middle</td>\n        <td width=\"20%\" valign=\"bottom\" style=\"border: 1px #666666 solid;\">bottom</td>\n        <td bgcolor=\"#DDDDDD\"><br/><br/><br/><br/><br/><br/><br/></td>\n    </tr>\n</table>\nHTML;\n\n        Html::addHtml($section, $html);\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $xpath = '/w:document/w:body/w:tbl/w:tr/w:tc[1]/w:tcPr/w:vAlign';\n        self::assertFalse($doc->elementExists($xpath));\n\n        $xpath = '/w:document/w:body/w:tbl/w:tr/w:tc[2]/w:tcPr/w:vAlign';\n        self::assertTrue($doc->elementExists($xpath));\n        self::assertEquals('top', $doc->getElement($xpath)->getAttribute('w:val'));\n\n        $xpath = '/w:document/w:body/w:tbl/w:tr/w:tc[3]/w:tcPr/w:vAlign';\n        self::assertTrue($doc->elementExists($xpath));\n        self::assertEquals('center', $doc->getElement($xpath)->getAttribute('w:val'));\n\n        $xpath = '/w:document/w:body/w:tbl/w:tr/w:tc[4]/w:tcPr/w:vAlign';\n        self::assertTrue($doc->elementExists($xpath));\n        self::assertEquals('bottom', $doc->getElement($xpath)->getAttribute('w:val'));\n    }\n\n    /**\n     * Fix bug - don't decode double quotes inside double quoted string.\n     */\n    public function testDontDecodeAlreadyEncodedDoubleQuotes(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        // borders & backgrounds are here just for better visual comparison\n        $html = <<<HTML\n<div style=\"font-family: Arial, &quot;Helvetice Neue&quot;\">This would crash if inline quotes also decoded at loading XML into DOMDocument!</div>\nHTML;\n\n        Html::addHtml($section, $html);\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n        self::assertIsObject($doc);\n    }\n\n    public static function providerParseWidth(): array\n    {\n        return [\n            ['auto', 5000, TblWidth::PERCENT],\n            ['100%', 5000, TblWidth::PERCENT],\n            ['200pt', 3999.999999999999, TblWidth::TWIP],\n            ['300px', 4500, TblWidth::TWIP],\n            ['400', 6000, TblWidth::TWIP],\n        ];\n    }\n\n    /**\n     * Test ruby.\n     */\n    public function testParseRubyHtml(): void\n    {\n        $html = <<<HTML\n<ruby lang=\"en-US\" style=\"line-height: 8pt;font-size:20pt;ruby-align:center;\">\n    base text\n    <rp>(</rp>\n    <rt style=\"line-height: 4pt;font-size:10pt\">ruby text</rt>\n    <rp>)</rp>\n</ruby>\nHTML;\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        Html::addHtml($section, $html);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby'));\n        self::assertEquals('ruby text', $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rt/w:r/w:t')->textContent);\n        self::assertEquals(\n            'base text',\n            $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rubyBase/w:r/w:t')->textContent\n        );\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:rubyAlign'));\n        self::assertEquals(\n            RubyProperties::ALIGNMENT_CENTER,\n            $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:rubyAlign', 'w:val')\n        );\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:hps'));\n        self::assertEquals(\n            10,\n            $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:hps', 'w:val')\n        );\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:hpsBaseText'));\n        self::assertEquals(\n            20,\n            $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:hpsBaseText', 'w:val')\n        );\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:lid'));\n        self::assertEquals(\n            'en-US',\n            $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:lid', 'w:val')\n        );\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Shared/Microsoft/PasswordEncoderTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Shared\\Microsoft;\n\nuse PhpOffice\\PhpWord\\Shared\\Microsoft\\PasswordEncoder;\n\n/**\n * Test class for \\PhpOffice\\PhpWord\\Shared\\Microsoft.\n */\nclass PasswordEncoderTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test that a password can be hashed without specifying any additional parameters.\n     */\n    public function testEncodePassword(): void\n    {\n        //given\n        $password = 'test';\n\n        //when\n        $hashPassword = PasswordEncoder::hashPassword($password);\n\n        //then\n        self::assertEquals('M795/MAlmGU8RIsY9Q9uDLHC7bk=', $hashPassword);\n    }\n\n    /**\n     * Test that a password can be hashed with a custom salt.\n     */\n    public function testEncodePasswordWithSalt(): void\n    {\n        //given\n        $password = 'test';\n        $salt = base64_decode('uq81pJRRGFIY5U+E9gt8tA==');\n\n        //when\n        $hashPassword = PasswordEncoder::hashPassword($password, PasswordEncoder::ALGORITHM_SHA_1, $salt);\n\n        //then\n        self::assertEquals('QiDOcpia1YzSVJPiKPwWebl9p/0=', $hashPassword);\n    }\n\n    /**\n     * Test that the encoder falls back on SHA-1 if a non supported algorithm is given.\n     */\n    public function testDefaultsToSha1IfUnsupportedAlgorithm(): void\n    {\n        //given\n        $password = 'test';\n        $salt = base64_decode('uq81pJRRGFIY5U+E9gt8tA==');\n\n        //when\n        $hashPassword = PasswordEncoder::hashPassword($password, PasswordEncoder::ALGORITHM_MAC, $salt);\n\n        //then\n        self::assertEquals('QiDOcpia1YzSVJPiKPwWebl9p/0=', $hashPassword);\n    }\n\n    /**\n     * Test that the encoder falls back on SHA-1 if a non supported algorithm is given.\n     */\n    public function testEncodePasswordWithNullAsciiCodeInPassword(): void\n    {\n        //given\n        $password = 'test' . chr(0);\n        $salt = base64_decode('uq81pJRRGFIY5U+E9gt8tA==');\n\n        //when\n        $hashPassword = PasswordEncoder::hashPassword($password, PasswordEncoder::ALGORITHM_MAC, $salt, 1);\n\n        //then\n        self::assertEquals('rDV9sgdDsztoCQlvRCb1lF2wxNg=', $hashPassword);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Shared/TextTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Shared;\n\nuse PhpOffice\\PhpWord\\Shared\\Text;\n\n/**\n * Test class for Text.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Shared\\Text\n */\nclass TextTest extends \\PHPUnit\\Framework\\TestCase\n{\n    public function testControlCharacters(): void\n    {\n        self::assertEquals('', Text::controlCharacterPHP2OOXML());\n        self::assertEquals('aeiou', Text::controlCharacterPHP2OOXML('aeiou'));\n        self::assertEquals('àéîöù', Text::controlCharacterPHP2OOXML('àéîöù'));\n\n        $value = mt_rand(0, 8);\n        self::assertEquals('_x' . sprintf('%04s', strtoupper(dechex($value))) . '_', Text::controlCharacterPHP2OOXML(chr($value)));\n\n        self::assertEquals('', Text::controlCharacterOOXML2PHP(''));\n        self::assertEquals(chr(0x08), Text::controlCharacterOOXML2PHP('_x0008_'));\n    }\n\n    public function testNumberFormat(): void\n    {\n        self::assertEquals('2.1', Text::numberFormat('2.06', 1));\n        self::assertEquals('2.1', Text::numberFormat('2.12', 1));\n        self::assertEquals('1234.0', Text::numberFormat(1234, 1));\n    }\n\n    public function testChr(): void\n    {\n        self::assertEquals('A', Text::chr(65));\n        self::assertEquals('A', Text::chr(0x41));\n        self::assertEquals('é', Text::chr(233));\n        self::assertEquals('é', Text::chr(0xE9));\n        self::assertEquals('⼳', Text::chr(12083));\n        self::assertEquals('⼳', Text::chr(0x2F33));\n        self::assertEquals('🌃', Text::chr(127747));\n        self::assertEquals('🌃', Text::chr(0x1F303));\n        self::assertEquals('', Text::chr(2097152));\n    }\n\n    /**\n     * Is UTF8.\n     */\n    public function testIsUTF8(): void\n    {\n        self::assertTrue(Text::isUTF8(''));\n        self::assertTrue(Text::isUTF8('éééé'));\n        self::assertFalse(Text::isUTF8(utf8decode('éééé')));\n    }\n\n    /**\n     * Test unicode conversion.\n     */\n    public function testToUnicode(): void\n    {\n        self::assertEquals('a', Text::toUnicode('a'));\n        self::assertEquals('\\uc0{\\u8364}', Text::toUnicode('€'));\n        self::assertEquals('\\uc0{\\u233}', Text::toUnicode('é'));\n    }\n\n    /**\n     * Test remove underscore prefix.\n     */\n    public function testRemoveUnderscorePrefix(): void\n    {\n        self::assertEquals('item', Text::removeUnderscorePrefix('_item'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Shared/ValidateTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Shared;\n\nuse PhpOffice\\PhpWord\\Shared\\Validate;\n\nclass ValidateTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * @dataProvider providerCSSGenericFont\n     */\n    public function testValidateCSSGenericFont(?string $value, string $expected): void\n    {\n        self::assertEquals($expected, Validate::validateCSSGenericFont($value));\n    }\n\n    public static function providerCSSGenericFont(): iterable\n    {\n        $data = [];\n        // Valid data\n        foreach (Validate::CSS_GENERICFONT as $value) {\n            $data[] = [\n                $value,\n                $value,\n            ];\n        }\n        // Invalid data\n        $data[] = ['invalidData', ''];\n        $data[] = ['', ''];\n        $data[] = [null, ''];\n\n        return $data;\n    }\n\n    /**\n     * @dataProvider providerCSSWhiteSpace\n     */\n    public function testValidateCSSWhiteSpace(?string $value, string $expected): void\n    {\n        self::assertEquals($expected, Validate::validateCSSWhiteSpace($value));\n    }\n\n    public static function providerCSSWhiteSpace(): iterable\n    {\n        $data = [];\n        // Valid data\n        foreach (Validate::CSS_WHITESPACE as $value) {\n            $data[] = [\n                $value,\n                $value,\n            ];\n        }\n        // Invalid data\n        $data[] = ['invalidData', ''];\n        $data[] = ['', ''];\n        $data[] = [null, ''];\n\n        return $data;\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Shared/XMLReaderTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Shared;\n\nuse Exception;\nuse InvalidArgumentException;\nuse PhpOffice\\PhpWord\\Shared\\XMLReader;\n\n/**\n * Test class for XMLReader.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Shared\\XMLReader\n */\nclass XMLReaderTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test reading XML from string.\n     */\n    public function testDomFromString(): void\n    {\n        $reader = new XMLReader();\n        $reader->getDomFromString('<element attr=\"test\"><child attr=\"subtest\">AAA</child></element>');\n\n        self::assertTrue($reader->elementExists('/element/child'));\n        self::assertEquals('AAA', $reader->getElement('/element/child')->textContent);\n        self::assertEquals('AAA', $reader->getValue('/element/child'));\n        self::assertEquals('test', $reader->getAttribute('attr', $reader->getElement('/element')));\n        self::assertEquals('subtest', $reader->getAttribute('attr', $reader->getElement('/element'), 'child'));\n    }\n\n    /**\n     * Test reading XML from zip.\n     */\n    public function testDomFromZip(): void\n    {\n        $archiveFile = __DIR__ . '/../_files/xml/reader.zip';\n\n        $reader = new XMLReader();\n        $reader->getDomFromZip($archiveFile, 'test.xml');\n\n        self::assertTrue($reader->elementExists('/element/child'));\n\n        self::assertFalse($reader->getDomFromZip($archiveFile, 'non_existing_xml_file.xml'));\n    }\n\n    /**\n     * Office 365 add some slash before the path of XML file.\n     */\n    public function testDomFromZipOffice365(): void\n    {\n        $archiveFile = __DIR__ . '/../_files/xml/reader.zip';\n\n        $reader = new XMLReader();\n        $reader->getDomFromZip($archiveFile, '/test.xml');\n\n        self::assertTrue($reader->elementExists('/element/child'));\n\n        self::assertFalse($reader->getDomFromZip($archiveFile, 'non_existing_xml_file.xml'));\n    }\n\n    /**\n     * Test that read from non existing archive throws exception.\n     */\n    public function testThrowsExceptionOnNonExistingArchive(): void\n    {\n        $this->expectException(Exception::class);\n        $archiveFile = __DIR__ . '/../_files/xml/readers.zip';\n\n        $reader = new XMLReader();\n        $reader->getDomFromZip($archiveFile, 'test.xml');\n    }\n\n    /**\n     * Test that read from invalid archive throws exception.\n     */\n    public function testThrowsExceptionOnZipArchiveOpenErrors(): void\n    {\n        $tempPath = tempnam(sys_get_temp_dir(), 'PhpWord') ?: 'tempNameFile';\n\n        // Simulate a corrupt archive\n        file_put_contents($tempPath, mt_rand());\n\n        $exceptionMessage = null;\n\n        try {\n            $reader = new XMLReader();\n            $reader->getDomFromZip($tempPath, 'test.xml');\n        } catch (Exception $e) {\n            $exceptionMessage = $e->getMessage();\n        }\n\n        self::assertNotNull($exceptionMessage);\n\n        unlink($tempPath);\n    }\n\n    /**\n     * Test elements count.\n     */\n    public function testCountElements(): void\n    {\n        $reader = new XMLReader();\n        $reader->getDomFromString('<element attr=\"test\"><child>AAA</child><child>BBB</child></element>');\n\n        self::assertEquals(2, $reader->countElements('/element/child'));\n    }\n\n    /**\n     * Test read non existing elements.\n     */\n    public function testReturnNullOnNonExistingNode(): void\n    {\n        $reader = new XMLReader();\n        self::assertSame(0, $reader->getElements('/element/children')->length);\n        $reader->getDomFromString('<element><child>AAA</child></element>');\n\n        self::assertNull($reader->getElement('/element/children'));\n        self::assertNull($reader->getValue('/element/children'));\n    }\n\n    /**\n     * Test that xpath fails if custom namespace is not registered.\n     */\n    public function testShouldThrowExceptionIfNamespaceIsNotKnown(): void\n    {\n        try {\n            $reader = new XMLReader();\n            $reader->getDomFromString('<element><test:child xmlns:test=\"http://phpword.com/my/custom/namespace\">AAA</test:child></element>');\n\n            self::assertTrue($reader->elementExists('/element/test:child'));\n            self::assertEquals('AAA', $reader->getElement('/element/test:child')->textContent);\n            self::fail();\n        } catch (Exception $e) {\n            // @phpstan-ignore-next-line\n            self::assertTrue(true);\n        }\n    }\n\n    /**\n     * Test reading XML with manually registered namespace.\n     */\n    public function testShouldParseXmlWithCustomNamespace(): void\n    {\n        $reader = new XMLReader();\n        $reader->getDomFromString('<element><test:child xmlns:test=\"http://phpword.com/my/custom/namespace\">AAA</test:child></element>');\n        $reader->registerNamespace('test', 'http://phpword.com/my/custom/namespace');\n\n        self::assertTrue($reader->elementExists('/element/test:child'));\n        self::assertEquals('AAA', $reader->getElement('/element/test:child')->textContent);\n    }\n\n    /**\n     * Test that xpath fails if custom namespace is not registered.\n     */\n    public function testShouldThowExceptionIfTryingToRegisterNamespaceBeforeReadingDoc(): void\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $reader = new XMLReader();\n        $reader->registerNamespace('test', 'http://phpword.com/my/custom/namespace');\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Shared/XMLWriterTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Shared;\n\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\n\n/**\n * Test class for XMLWriter.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Shared\\XMLWriter\n */\nclass XMLWriterTest extends \\PHPUnit\\Framework\\TestCase\n{\n    public function testConstruct(): void\n    {\n        // Memory\n        $object = new XMLWriter();\n        $object->startElement('element');\n        $object->text('AAA');\n        $object->endElement();\n        self::assertEquals('<element>AAA</element>' . chr(10), $object->getData());\n\n        // Disk\n        $object = new XMLWriter(XMLWriter::STORAGE_DISK);\n        $object->startElement('element');\n        $object->text('BBB');\n        $object->endElement();\n        self::assertEquals('<element>BBB</element>' . chr(10), $object->getData());\n    }\n\n    public function testWriteAttribute(): void\n    {\n        $xmlWriter = new XMLWriter();\n        $xmlWriter->startElement('element');\n        $xmlWriter->writeAttribute('name', 'value');\n        $xmlWriter->endElement();\n\n        self::assertSame('<element name=\"value\"/>' . chr(10), $xmlWriter->getData());\n    }\n\n    public function testWriteAttributeShouldWriteFloatValueLocaleIndependent(): void\n    {\n        $value = 1.2;\n\n        $xmlWriter = new XMLWriter();\n        $xmlWriter->startElement('element');\n        $xmlWriter->writeAttribute('name', $value);\n        $xmlWriter->endElement();\n\n        $currentLocale = setlocale(LC_NUMERIC, 0);\n\n        setlocale(LC_NUMERIC, 'de_DE.UTF-8', 'de');\n\n        self::assertSame('<element name=\"1.2\"/>' . chr(10), $xmlWriter->getData());\n\n        setlocale(LC_NUMERIC, $currentLocale);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Shared/ZipArchiveTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Shared;\n\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Shared\\ZipArchive;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Shared\\ZipArchive.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Shared\\ZipArchive\n *\n * @runTestsInSeparateProcesses\n */\nclass ZipArchiveTest extends \\PHPUnit\\Framework\\TestCase\n{\n//     /**\n//      * Test close method exception: Working in local, not working in Travis\n//      *\n//      * expectedException \\PhpOffice\\PhpWord\\Exception\\Exception\n//      * expectedExceptionMessage Could not close zip file\n//      * covers ::close\n//      */\n//     public function testCloseException()\n//     {\n//         $zipFile = __DIR__ . \"/../_files/documents/ziptest.zip\";\n\n//         $object = new ZipArchive();\n//         $object->open($zipFile, ZipArchive::CREATE);\n//         $object->addFromString('content/string.txt', 'Test');\n\n//         // Lock the file\n//         $resource = fopen($zipFile, \"w\");\n//         flock($resource, LOCK_EX);\n\n//         // Closing the file should throws an exception\n//         $object->close();\n\n//         // Unlock the file\n//         flock($resource, LOCK_UN);\n//         fclose($resource);\n\n//         @unlink($zipFile);\n//     }\n\n    /**\n     * Test all methods.\n     *\n     * @param string $zipClass\n     */\n    public function testZipArchive($zipClass = 'ZipArchive'): void\n    {\n        // Preparation\n        $existingFile = __DIR__ . '/../_files/documents/sheet.xls';\n        $zipFile = __DIR__ . '/../_files/documents/ziptest.zip';\n        $destination1 = __DIR__ . '/../_files/documents/extract1';\n        $destination2 = __DIR__ . '/../_files/documents/extract2';\n        @mkdir($destination1);\n        @mkdir($destination2);\n\n        Settings::setZipClass($zipClass);\n\n        $object = new ZipArchive();\n        $object->open($zipFile, ZipArchive::CREATE);\n        $object->addFile($existingFile, 'xls/new.xls');\n        $object->addFromString('content/string.txt', 'Test');\n        $object->close();\n        $object->open($zipFile);\n\n        // Run tests\n        self::assertEquals(0, $object->locateName('xls/new.xls'));\n        self::assertFalse($object->locateName('blablabla'));\n\n        self::assertEquals('Test', $object->getFromName('content/string.txt'));\n        self::assertEquals('Test', $object->getFromName('/content/string.txt'));\n\n        self::assertFalse($object->getNameIndex(-1));\n        self::assertEquals('content/string.txt', $object->getNameIndex(1));\n\n        self::assertFalse($object->extractTo('blablabla'));\n        self::assertTrue($object->extractTo($destination1));\n        self::assertTrue($object->extractTo($destination2, 'xls/new.xls'));\n        self::assertFalse($object->extractTo($destination2, 'blablabla'));\n\n        // Cleanup\n        $this->deleteDir($destination1);\n        $this->deleteDir($destination2);\n        @unlink($zipFile);\n    }\n\n    /**\n     * Test PclZip.\n     */\n    public function testPCLZip(): void\n    {\n        $this->testZipArchive('PhpOffice\\PhpWord\\Shared\\ZipArchive');\n    }\n\n    /**\n     * Delete directory.\n     *\n     * @param string $dir\n     */\n    private function deleteDir($dir): void\n    {\n        foreach (scandir($dir) as $file) {\n            if ('.' === $file || '..' === $file) {\n                continue;\n            } elseif (is_file($dir . '/' . $file)) {\n                unlink($dir . '/' . $file);\n            } elseif (is_dir($dir . '/' . $file)) {\n                $this->deleteDir($dir . '/' . $file);\n            }\n        }\n\n        rmdir($dir);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Style/AbstractStyleTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Style;\n\nuse InvalidArgumentException;\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\nuse PhpOffice\\PhpWord\\Style\\AbstractStyle;\nuse PhpOffice\\PhpWord\\Style\\Paragraph;\nuse ReflectionClass;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Style\\AbstractStyle.\n *\n * @runTestsInSeparateProcesses\n */\nclass AbstractStyleTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test set style by array.\n     */\n    public function testSetStyleByArray(): void\n    {\n        // @phpstan-ignore-next-line\n        if (method_exists($this, 'getMockForAbstractClass')) {\n            $stub = $this->getMockForAbstractClass(AbstractStyle::class);\n        } else {\n            /** @var AbstractStyle $stub */\n            $stub = new class() extends AbstractStyle {\n            };\n        }\n        $stub->setStyleByArray(['index' => 1]);\n\n        self::assertEquals(1, $stub->getIndex());\n    }\n\n    public function testSetStyleByArrayWithAlign(): void\n    {\n        $stub = new Paragraph();\n        $stub->setStyleByArray(['align' => Jc::CENTER]);\n\n        self::assertEquals(Jc::CENTER, $stub->getAlignment());\n    }\n\n    public function testSetStyleByArrayWithAlignment(): void\n    {\n        $stub = new Paragraph();\n        $stub->setStyleByArray(['alignment' => Jc::CENTER]);\n\n        self::assertEquals(Jc::CENTER, $stub->getAlignment());\n    }\n\n    /**\n     * Test setBoolVal, setIntVal, setFloatVal, setEnumVal with normal value.\n     */\n    public function testSetValNormal(): void\n    {\n        // @phpstan-ignore-next-line\n        if (method_exists($this, 'getMockForAbstractClass')) {\n            $stub = $this->getMockForAbstractClass(AbstractStyle::class);\n        } else {\n            /** @var AbstractStyle $stub */\n            $stub = new class() extends AbstractStyle {\n            };\n        }\n\n        self::assertTrue(self::callProtectedMethod($stub, 'setBoolVal', [true, false]));\n        self::assertEquals(12, self::callProtectedMethod($stub, 'setIntVal', [12, 200]));\n        self::assertEquals(871.1, self::callProtectedMethod($stub, 'setFloatVal', [871.1, 2.1]));\n        self::assertEquals(871.1, self::callProtectedMethod($stub, 'setFloatVal', ['871.1', 2.1]));\n        self::assertEquals('a', self::callProtectedMethod($stub, 'setEnumVal', ['a', ['a', 'b'], 'b']));\n    }\n\n    /**\n     * Test setBoolVal, setIntVal, setFloatVal, setEnumVal with default value.\n     */\n    public function testSetValDefault(): void\n    {\n        // @phpstan-ignore-next-line\n        if (method_exists($this, 'getMockForAbstractClass')) {\n            $stub = $this->getMockForAbstractClass(AbstractStyle::class);\n        } else {\n            /** @var AbstractStyle $stub */\n            $stub = new class() extends AbstractStyle {\n            };\n        }\n\n        self::assertNotTrue(self::callProtectedMethod($stub, 'setBoolVal', ['a', false]));\n        self::assertEquals(200, self::callProtectedMethod($stub, 'setIntVal', ['foo', 200]));\n        self::assertEquals(2.1, self::callProtectedMethod($stub, 'setFloatVal', ['foo', 2.1]));\n        self::assertEquals('b', self::callProtectedMethod($stub, 'setEnumVal', [null, ['a', 'b'], 'b']));\n    }\n\n    /**\n     * Test setEnumVal exception.\n     */\n    public function testSetValEnumException(): void\n    {\n        $this->expectException(InvalidArgumentException::class);\n        // @phpstan-ignore-next-line\n        if (method_exists($this, 'getMockForAbstractClass')) {\n            $stub = $this->getMockForAbstractClass(AbstractStyle::class);\n        } else {\n            /** @var AbstractStyle $stub */\n            $stub = new class() extends AbstractStyle {\n            };\n        }\n\n        self::assertEquals('b', self::callProtectedMethod($stub, 'setEnumVal', ['z', ['a', 'b'], 'b']));\n    }\n\n    /**\n     * Helper function to call protected method.\n     *\n     * @param mixed $object\n     * @param string $method\n     */\n    public static function callProtectedMethod($object, $method, array $args = [])\n    {\n        $class = new ReflectionClass(get_class($object));\n        $method = $class->getMethod($method);\n        $method->setAccessible(true);\n\n        return $method->invokeArgs($object, $args);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Style/CellTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Style;\n\nuse PhpOffice\\PhpWord\\SimpleType\\VerticalJc;\nuse PhpOffice\\PhpWord\\Style\\Cell;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Style\\Cell.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Style\\Cell\n *\n * @runTestsInSeparateProcesses\n */\nclass CellTest extends \\PHPUnit\\Framework\\TestCase\n{\n    public function testSetGetNormalInt(): void\n    {\n        $object = new Cell();\n\n        foreach ([\n            'borderTopSize' => 120,\n            'borderLeftSize' => 120,\n            'borderRightSize' => 120,\n            'borderBottomSize' => 120,\n            'gridSpan' => 2,\n        ] as $key => $value) {\n            $set = \"set{$key}\";\n            $get = \"get{$key}\";\n\n            self::assertNull($object->$get()); // Init with null value\n\n            $object->$set($value);\n\n            self::assertEquals($value, $object->$get());\n        }\n    }\n\n    public function testSetGetNormalString(): void\n    {\n        $object = new Cell();\n\n        foreach ([\n            'valign' => VerticalJc::TOP,\n            'textDirection' => Cell::TEXT_DIR_BTLR,\n            'bgColor' => 'FFFF00',\n            'borderTopColor' => 'FFFF00',\n            'borderLeftColor' => 'FFFF00',\n            'borderRightColor' => 'FFFF00',\n            'borderBottomColor' => 'FFFF00',\n            'vMerge' => Cell::VMERGE_RESTART,\n        ] as $key => $value) {\n            $set = \"set{$key}\";\n            $get = \"get{$key}\";\n\n            self::assertNull($object->$get()); // Init with null value\n\n            $object->$set($value);\n\n            self::assertEquals($value, $object->$get());\n        }\n    }\n\n    /**\n     * Test border color.\n     */\n    public function testBorderColor(): void\n    {\n        $object = new Cell();\n\n        $value = 'FF0000';\n\n        $object->setStyleValue('borderColor', $value);\n        $expected = [$value, $value, $value, $value];\n        self::assertEquals($expected, $object->getBorderColor());\n    }\n\n    /**\n     * Test border size.\n     */\n    public function testBorderSize(): void\n    {\n        $object = new Cell();\n\n        $value = 120;\n        $expected = [$value, $value, $value, $value];\n        $object->setStyleValue('borderSize', $value);\n        self::assertEquals($expected, $object->getBorderSize());\n    }\n\n    /**\n     * Test cell padding.\n     */\n    public function testPadding(): void\n    {\n        $object = new Cell();\n        $methods = [\n            'paddingTop' => 10,\n            'paddingBottom' => 20,\n            'paddingLeft' => 30,\n            'paddingRight' => 40,\n        ];\n\n        foreach ($methods as $methodName => $methodValue) {\n            $object->setStyleValue($methodName, $methodValue);\n            $getterName = 'get' . ucfirst($methodName);\n\n            self::assertEquals($methodValue, $object->$getterName());\n        }\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Style/ChartTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see       https://github.com/PHPOffice/PHPWord\n *\n * @license   http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Style;\n\nuse PhpOffice\\PhpWord\\Style\\Chart;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Style\\Chart.\n *\n * @coversDefaultClass          \\PhpOffice\\PhpWord\\Style\\Chart\n *\n * @runTestsInSeparateProcesses\n */\nclass ChartTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Testing getter and setter for chart width.\n     */\n    public function testSetGetWidth(): void\n    {\n        $chart = new Chart();\n\n        self::assertEquals($chart->getWidth(), 1000000);\n\n        $chart->setWidth(200);\n\n        self::assertEquals($chart->getWidth(), 200);\n    }\n\n    /**\n     * Testing getter and setter for chart height.\n     */\n    public function testSetGetHeight(): void\n    {\n        $chart = new Chart();\n\n        self::assertEquals($chart->getHeight(), 1000000);\n\n        $chart->setHeight(200);\n\n        self::assertEquals($chart->getHeight(), 200);\n    }\n\n    /**\n     * Testing getter and setter for is3d.\n     */\n    public function testSetIs3d(): void\n    {\n        $chart = new Chart();\n\n        self::assertEquals($chart->is3d(), false);\n\n        $chart->set3d(true);\n\n        self::assertEquals($chart->is3d(), true);\n    }\n\n    /**\n     * Testing getter and setter for chart colors.\n     */\n    public function testSetGetColors(): void\n    {\n        $chart = new Chart();\n\n        self::assertIsArray($chart->getColors());\n\n        self::assertEquals(count($chart->getColors()), 0);\n\n        $chart->setColors(['FFFFFFFF', 'FF000000', 'FFFF0000']);\n\n        self::assertEquals($chart->getColors(), ['FFFFFFFF', 'FF000000', 'FFFF0000']);\n    }\n\n    /**\n     * Testing getter and setter for dataLabelOptions.\n     */\n    public function testSetGetDataLabelOptions(): void\n    {\n        $chart = new Chart();\n\n        $originalDataLabelOptions = [\n            'showVal' => true,\n            'showCatName' => true,\n            'showLegendKey' => false,\n            'showSerName' => false,\n            'showPercent' => false,\n            'showLeaderLines' => false,\n            'showBubbleSize' => false,\n        ];\n\n        self::assertEquals($chart->getDataLabelOptions(), $originalDataLabelOptions);\n\n        $changedDataLabelOptions = [\n            'showVal' => false,\n            'showCatName' => false,\n            'showLegendKey' => true,\n            'showSerName' => true,\n            'showPercent' => true,\n            'showLeaderLines' => true,\n            'showBubbleSize' => true,\n        ];\n\n        $chart->setDataLabelOptions(\n            [\n                'showVal' => false,\n                'showCatName' => false,\n                'showLegendKey' => true,\n                'showSerName' => true,\n                'showPercent' => true,\n                'showLeaderLines' => true,\n                'showBubbleSize' => true,\n            ]\n        );\n        self::assertEquals($chart->getDataLabelOptions(), $changedDataLabelOptions);\n    }\n\n    /**\n     * Testing categoryLabelPosition getter and setter.\n     */\n    public function testSetGetCategoryLabelPosition(): void\n    {\n        $chart = new Chart();\n\n        self::assertEquals($chart->getCategoryLabelPosition(), 'nextTo');\n\n        $chart->setCategoryLabelPosition('high');\n\n        self::assertEquals($chart->getCategoryLabelPosition(), 'high');\n    }\n\n    /**\n     * Testing valueLabelPosition getter and setter.\n     */\n    public function testSetGetValueLabelPosition(): void\n    {\n        $chart = new Chart();\n\n        self::assertEquals($chart->getValueLabelPosition(), 'nextTo');\n\n        $chart->setValueLabelPosition('low');\n\n        self::assertEquals($chart->getValueLabelPosition(), 'low');\n    }\n\n    /**\n     * Testing categoryAxisTitle getter and setter.\n     */\n    public function testSetGetCategoryAxisTitle(): void\n    {\n        $chart = new Chart();\n\n        self::assertEquals($chart->getCategoryAxisTitle(), null);\n\n        $chart->setCategoryAxisTitle('Test Category Axis Title');\n\n        self::assertEquals($chart->getCategoryAxisTitle(), 'Test Category Axis Title');\n    }\n\n    /**\n     * Testing valueAxisTitle getter and setter.\n     */\n    public function testSetGetValueAxisTitle(): void\n    {\n        $chart = new Chart();\n\n        self::assertEquals($chart->getValueAxisTitle(), null);\n\n        $chart->setValueAxisTitle('Test Value Axis Title');\n\n        self::assertEquals($chart->getValueAxisTitle(), 'Test Value Axis Title');\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Style/FontTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Style;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\nuse PhpOffice\\PhpWord\\Style\\Font;\nuse PhpOffice\\PhpWord\\Style\\Language;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Style\\Font.\n *\n * @runTestsInSeparateProcesses\n */\nclass FontTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Tear down after each test.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    /**\n     * Test initiation for style type and paragraph style.\n     */\n    public function testInitiation(): void\n    {\n        $object = new Font('text', ['alignment' => Jc::BOTH]);\n\n        self::assertEquals('text', $object->getStyleType());\n        self::assertInstanceOf(\\PhpOffice\\PhpWord\\Style\\Paragraph::class, $object->getParagraph());\n        self::assertIsArray($object->getStyleValues());\n    }\n\n    /**\n     * Test setting style values with null or empty value.\n     */\n    public function testSetStyleValueWithNullOrEmpty(): void\n    {\n        $object = new Font();\n\n        $attributes = [\n            'name' => null,\n            'size' => null,\n            'hint' => null,\n            'color' => null,\n            'bold' => false,\n            'italic' => false,\n            'underline' => Font::UNDERLINE_NONE,\n            'superScript' => false,\n            'subScript' => false,\n            'strikethrough' => false,\n            'doubleStrikethrough' => false,\n            'smallCaps' => false,\n            'allCaps' => false,\n            'rtl' => false,\n            'fgColor' => null,\n            'bgColor' => null,\n            'scale' => null,\n            'spacing' => null,\n            'kerning' => null,\n            'lang' => null,\n            'hidden' => false,\n            'whiteSpace' => '',\n            'fallbackFont' => '',\n        ];\n        foreach ($attributes as $key => $default) {\n            $get = is_bool($default) ? \"is{$key}\" : \"get{$key}\";\n            self::assertEquals($default, $object->$get());\n            $object->setStyleValue($key, null);\n            self::assertEquals($default, $object->$get());\n            $object->setStyleValue($key, '');\n            self::assertEquals($default, $object->$get());\n        }\n    }\n\n    /**\n     * Test setting style values with normal value.\n     */\n    public function testSetStyleValueNormal(): void\n    {\n        $object = new Font();\n\n        $attributes = [\n            'name' => 'Times New Roman',\n            'size' => 9,\n            'color' => '999999',\n            'hint' => 'eastAsia',\n            'bold' => true,\n            'italic' => true,\n            'underline' => Font::UNDERLINE_HEAVY,\n            'superScript' => true,\n            'subScript' => false,\n            'strikethrough' => true,\n            'doubleStrikethrough' => false,\n            'smallCaps' => true,\n            'allCaps' => false,\n            'fgColor' => Font::FGCOLOR_YELLOW,\n            'bgColor' => 'FFFF00',\n            'lineHeight' => 2,\n            'scale' => 150,\n            'spacing' => 240,\n            'kerning' => 10,\n            'rtl' => true,\n            'noProof' => true,\n            'lang' => new Language(Language::EN_US),\n            'hidden' => true,\n            'whiteSpace' => 'pre-wrap',\n            'fallbackFont' => 'serif',\n        ];\n        $object->setStyleByArray($attributes);\n        foreach ($attributes as $key => $value) {\n            $get = is_bool($value) ? \"is{$key}\" : \"get{$key}\";\n            self::assertEquals($value, $object->$get());\n        }\n    }\n\n    /**\n     * Test set line height.\n     */\n    public function testLineHeight(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        // Test style array\n        $text = $section->addText('This is a test', ['line-height' => 2.0]);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n        $element = $doc->getElement('/w:document/w:body/w:p/w:pPr/w:spacing');\n\n        $lineHeight = $element->getAttribute('w:line');\n        $lineRule = $element->getAttribute('w:lineRule');\n\n        self::assertEquals(480, $lineHeight);\n        self::assertEquals('auto', $lineRule);\n\n        // Test setter\n        TestHelperDOCX::clear();\n        $text->getFontStyle()->setLineHeight(3.0);\n        $doc = TestHelperDOCX::getDocument($phpWord);\n        $element = $doc->getElement('/w:document/w:body/w:p/w:pPr/w:spacing');\n\n        $lineHeight = $element->getAttribute('w:line');\n        $lineRule = $element->getAttribute('w:lineRule');\n\n        self::assertEquals(720, $lineHeight);\n        self::assertEquals('auto', $lineRule);\n    }\n\n    /**\n     * Test line height floatval.\n     */\n    public function testLineHeightFloatval(): void\n    {\n        $object = new Font(null, ['alignment' => Jc::CENTER]);\n        $object->setLineHeight('1.5pt');\n        self::assertEquals(1.5, $object->getLineHeight());\n    }\n\n    /**\n     * Test line height exception by using nonnumeric value.\n     */\n    public function testLineHeightException(): void\n    {\n        $this->expectException(\\PhpOffice\\PhpWord\\Exception\\InvalidStyleException::class);\n        $object = new Font();\n        $object->setLineHeight('a');\n    }\n\n    /**\n     * Test setting the language as a string.\n     */\n    public function testSetLangAsString(): void\n    {\n        $object = new Font();\n        $object->setLang(Language::FR_BE);\n        self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Language', $object->getLang());\n        self::assertEquals(Language::FR_BE, $object->getLang()->getLatin());\n    }\n\n    public function testRTL(): void\n    {\n        $object = new Font();\n        self::assertNull($object->isRTL());\n        self::assertInstanceOf(Font::class, $object->setRTL(true));\n        self::assertTrue($object->isRTL());\n        self::assertInstanceOf(Font::class, $object->setRTL(false));\n        self::assertFalse($object->isRTL());\n    }\n\n    public function testRTLSettings(): void\n    {\n        Settings::setDefaultRtl(null);\n        $object = new Font();\n        self::assertNull($object->isRTL());\n\n        Settings::setDefaultRtl(true);\n        $object = new Font();\n        self::assertTrue($object->isRTL());\n\n        Settings::setDefaultRtl(false);\n        $object = new Font();\n        self::assertFalse($object->isRTL());\n\n        Settings::setDefaultRtl(null);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Style/ImageTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Style;\n\nuse InvalidArgumentException;\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\nuse PhpOffice\\PhpWord\\Style\\Image;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Style\\Image.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Style\\Image\n *\n * @runTestsInSeparateProcesses\n */\nclass ImageTest extends \\PHPUnit\\Framework\\TestCase\n{\n    public function testSetGetNormalInt(): void\n    {\n        $object = new Image();\n        foreach ([\n            'width' => 200,\n            'height' => 200,\n            'marginTop' => 240,\n            'marginLeft' => 240,\n            'wrapDistanceLeft' => 10,\n            'wrapDistanceRight' => 20,\n            'wrapDistanceTop' => 30,\n            'wrapDistanceBottom' => 40,\n        ] as $key => $value) {\n            $set = \"set{$key}\";\n            $get = \"get{$key}\";\n            $object->$set($value);\n            self::assertEquals($value, $object->$get());\n        }\n    }\n\n    public function testSetGetNormalString(): void\n    {\n        $object = new Image();\n        foreach ([\n            'alignment' => Jc::START,\n            'wrappingStyle' => 'inline',\n        ] as $key => $value) {\n            $set = \"set{$key}\";\n            $get = \"get{$key}\";\n            $object->$set($value);\n            self::assertEquals($value, $object->$get());\n        }\n    }\n\n    /**\n     * Test setStyleValue method.\n     */\n    public function testSetStyleValue(): void\n    {\n        $object = new Image();\n\n        $properties = [\n            'width' => 200,\n            'height' => 200,\n            'alignment' => Jc::START,\n            'marginTop' => 240,\n            'marginLeft' => 240,\n            'position' => 10,\n            'positioning' => Image::POSITION_ABSOLUTE,\n            'posHorizontal' => Image::POSITION_HORIZONTAL_CENTER,\n            'posVertical' => Image::POSITION_VERTICAL_TOP,\n            'posHorizontalRel' => Image::POSITION_RELATIVE_TO_COLUMN,\n            'posVerticalRel' => Image::POSITION_RELATIVE_TO_IMARGIN,\n            'wrapDistanceLeft' => 10,\n            'wrapDistanceRight' => 20,\n            'wrapDistanceTop' => 30,\n            'wrapDistanceBottom' => 40,\n        ];\n        foreach ($properties as $key => $value) {\n            $get = \"get{$key}\";\n            $object->setStyleValue(\"{$key}\", $value);\n            self::assertEquals($value, $object->$get());\n        }\n    }\n\n    /**\n     * Test setWrappingStyle exception.\n     */\n    public function testSetWrappingStyleException(): void\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $object = new Image();\n        $object->setWrappingStyle('foo');\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Style/IndentationTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Style;\n\nuse PhpOffice\\PhpWord\\Style\\Indentation;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Style\\Indentation.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Style\\Indentation\n */\nclass IndentationTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test get/set.\n     */\n    public function testGetSetProperties(): void\n    {\n        $object = new Indentation();\n        $properties = [\n            'left' => [0, 10],\n            'right' => [0, 10],\n            'firstLine' => [null, 20],\n            'firstLineChars' => [0, 20],\n            'hanging' => [null, 20],\n        ];\n        foreach ($properties as $property => $value) {\n            [$default, $expected] = $value;\n            $get = \"get{$property}\";\n            $set = \"set{$property}\";\n\n            self::assertEquals($default, $object->$get()); // Default value\n\n            $object->$set($expected);\n\n            self::assertEquals($expected, $object->$get()); // New value\n        }\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Style/LanguageTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Style;\n\nuse InvalidArgumentException;\nuse PhpOffice\\PhpWord\\Style\\Language;\nuse PHPUnit\\Framework\\Assert;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Style\\Language.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Style\\Language\n */\nclass LanguageTest extends \\PHPUnit\\Framework\\TestCase\n{\n    public function testGetSetPropertiesInt(): void\n    {\n        $object = new Language();\n        foreach ([\n            'langId' => [null, 1036],\n        ] as $property => $value) {\n            [$default, $expected] = $value;\n            $get = \"get{$property}\";\n            $set = \"set{$property}\";\n\n            self::assertEquals($default, $object->$get()); // Default value\n\n            $object->$set($expected);\n\n            self::assertEquals($expected, $object->$get()); // New value\n        }\n    }\n\n    public function testGetSetPropertiesString(): void\n    {\n        $object = new Language();\n        foreach ([\n            'latin' => [null, 'fr-BE'],\n            'eastAsia' => [null, 'ja-JP'],\n            'bidirectional' => [null, 'ar-SA'],\n        ] as $property => $value) {\n            [$default, $expected] = $value;\n            $get = \"get{$property}\";\n            $set = \"set{$property}\";\n\n            self::assertEquals($default, $object->$get()); // Default value\n\n            $object->$set($expected);\n\n            self::assertEquals($expected, $object->$get()); // New value\n        }\n    }\n\n    /**\n     * Test throws exception if wrong locale is given.\n     */\n    public function testWrongLanguage(): void\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $language = new Language();\n        $language->setLatin('fra');\n    }\n\n    /**\n     * Tests that a language can be set with just a 2 char code.\n     */\n    public function testShortLanguage(): void\n    {\n        //when\n        $language = new Language();\n        $language->setLatin('fr');\n\n        //then\n        Assert::assertEquals('fr-FR', $language->getLatin());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Style/LineNumberingTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Style;\n\nuse PhpOffice\\PhpWord\\Style\\LineNumbering;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Style\\LineNumbering.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Style\\LineNumbering\n */\nclass LineNumberingTest extends \\PHPUnit\\Framework\\TestCase\n{\n    public function testGetSetPropertiesInt(): void\n    {\n        $object = new LineNumbering();\n        foreach ([\n            'start' => [1, 2],\n            'increment' => [1, 10],\n            'distance' => [null, 10],\n        ] as $property => $value) {\n            [$default, $expected] = $value;\n            $get = \"get{$property}\";\n            $set = \"set{$property}\";\n\n            self::assertEquals($default, $object->$get()); // Default value\n\n            $object->$set($expected);\n\n            self::assertEquals($expected, $object->$get()); // New value\n        }\n    }\n\n    public function testGetSetPropertiesString(): void\n    {\n        $object = new LineNumbering();\n        foreach ([\n            'restart' => [null, 'continuous'],\n        ] as $property => $value) {\n            [$default, $expected] = $value;\n            $get = \"get{$property}\";\n            $set = \"set{$property}\";\n\n            self::assertEquals($default, $object->$get()); // Default value\n\n            $object->$set($expected);\n\n            self::assertEquals($expected, $object->$get()); // New value\n        }\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Style/LineTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Style;\n\nuse PhpOffice\\PhpWord\\Style\\Line;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Style\\Image.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Style\\Image\n *\n * @runTestsInSeparateProcesses\n */\nclass LineTest extends \\PHPUnit\\Framework\\TestCase\n{\n    public function testSetGetNormalInt(): void\n    {\n        $object = new Line();\n\n        foreach ([\n            'weight' => 10,\n        ] as $key => $value) {\n            $set = \"set{$key}\";\n            $get = \"get{$key}\";\n            $object->$set($value);\n            self::assertEquals($value, $object->$get());\n        }\n    }\n\n    public function testSetGetNormalString(): void\n    {\n        $object = new Line();\n\n        foreach ([\n            'connectorType' => Line::CONNECTOR_TYPE_STRAIGHT,\n            'beginArrow' => Line::ARROW_STYLE_BLOCK,\n            'endArrow' => Line::ARROW_STYLE_OVAL,\n            'dash' => Line::DASH_STYLE_LONG_DASH_DOT_DOT,\n            'color' => 'red',\n        ] as $key => $value) {\n            $set = \"set{$key}\";\n            $get = \"get{$key}\";\n            $object->$set($value);\n            self::assertEquals($value, $object->$get());\n        }\n    }\n\n    /**\n     * Test setStyleValue method.\n     */\n    public function testSetStyleValue(): void\n    {\n        $object = new Line();\n\n        $properties = [\n            'connectorType' => Line::CONNECTOR_TYPE_STRAIGHT,\n            'beginArrow' => Line::ARROW_STYLE_BLOCK,\n            'endArrow' => Line::ARROW_STYLE_OVAL,\n            'dash' => Line::DASH_STYLE_LONG_DASH_DOT_DOT,\n            'weight' => 10,\n            'color' => 'red',\n        ];\n        foreach ($properties as $key => $value) {\n            $get = \"get{$key}\";\n            $object->setStyleValue(\"{$key}\", $value);\n            self::assertEquals($value, $object->$get());\n        }\n    }\n\n    /**\n     * Test set/get flip.\n     */\n    public function testSetGetFlip(): void\n    {\n        $expected = true;\n        $object = new Line();\n        $object->setFlip($expected);\n        self::assertEquals($expected, $object->isFlip());\n    }\n\n    /**\n     * Test set/get connectorType.\n     */\n    public function testSetGetConnectorType(): void\n    {\n        $expected = Line::CONNECTOR_TYPE_STRAIGHT;\n        $object = new Line();\n        $object->setConnectorType($expected);\n        self::assertEquals($expected, $object->getConnectorType());\n    }\n\n    /**\n     * Test set/get weight.\n     */\n    public function testSetGetWeight(): void\n    {\n        $expected = 10;\n        $object = new Line();\n        $object->setWeight($expected);\n        self::assertEquals($expected, $object->getWeight());\n    }\n\n    /**\n     * Test set/get color.\n     */\n    public function testSetGetColor(): void\n    {\n        $expected = 'red';\n        $object = new Line();\n        $object->setColor($expected);\n        self::assertEquals($expected, $object->getColor());\n    }\n\n    /**\n     * Test set/get dash.\n     */\n    public function testSetGetDash(): void\n    {\n        $expected = Line::DASH_STYLE_LONG_DASH_DOT_DOT;\n        $object = new Line();\n        $object->setDash($expected);\n        self::assertEquals($expected, $object->getDash());\n    }\n\n    /**\n     * Test set/get beginArrow.\n     */\n    public function testSetGetBeginArrow(): void\n    {\n        $expected = Line::ARROW_STYLE_BLOCK;\n        $object = new Line();\n        $object->setBeginArrow($expected);\n        self::assertEquals($expected, $object->getBeginArrow());\n    }\n\n    /**\n     * Test set/get endArrow.\n     */\n    public function testSetGetEndArrow(): void\n    {\n        $expected = Line::ARROW_STYLE_CLASSIC;\n        $object = new Line();\n        $object->setEndArrow($expected);\n        self::assertEquals($expected, $object->getEndArrow());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Style/ListItemTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Style;\n\nuse PhpOffice\\PhpWord\\Style\\ListItem;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Style\\ListItem.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Style\\ListItem\n *\n * @runTestsInSeparateProcesses\n */\nclass ListItemTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test construct.\n     */\n    public function testConstruct(): void\n    {\n        $object = new ListItem();\n\n        $value = ListItem::TYPE_BULLET_FILLED;\n        self::assertEquals($value, $object->getListType());\n    }\n\n    /**\n     * Test set style value.\n     */\n    public function testSetStyleValue(): void\n    {\n        $object = new ListItem();\n\n        $value = ListItem::TYPE_ALPHANUM;\n        $object->setStyleValue('listType', $value);\n        self::assertEquals($value, $object->getListType());\n    }\n\n    /**\n     * Test list type.\n     */\n    public function testListType(): void\n    {\n        $object = new ListItem();\n\n        $value = ListItem::TYPE_ALPHANUM;\n        $object->setListType($value);\n        self::assertEquals($value, $object->getListType());\n    }\n\n    /**\n     * Test set/get numbering style name.\n     */\n    public function testSetGetNumStyle(): void\n    {\n        $expected = 'List Name';\n\n        $object = new ListItem();\n        $object->setNumStyle($expected);\n        self::assertEquals($expected, $object->getNumStyle());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Style/NumberingLevelTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Style;\n\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\nuse PhpOffice\\PhpWord\\Style\\NumberingLevel;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Style\\NumberingLevel.\n *\n * @runTestsInSeparateProcesses\n */\nclass NumberingLevelTest extends \\PHPUnit\\Framework\\TestCase\n{\n    public function testSetGetNormalInt(): void\n    {\n        $object = new NumberingLevel();\n\n        $attributes = [\n            'level' => 1,\n            'start' => 1,\n            'restart' => 1,\n            'left' => 360,\n            'hanging' => 360,\n            'tabPos' => 360,\n        ];\n        foreach ($attributes as $key => $value) {\n            $set = \"set{$key}\";\n            $get = \"get{$key}\";\n            $object->$set($value);\n            self::assertEquals($value, $object->$get());\n        }\n    }\n\n    public function testSetGetNormalString(): void\n    {\n        $object = new NumberingLevel();\n\n        $attributes = [\n            'format' => 'decimal',\n            'pStyle' => 'pStyle',\n            'suffix' => 'space',\n            'text' => '%1.',\n            'alignment' => Jc::START,\n            'font' => 'Arial',\n            'hint' => 'default',\n        ];\n        foreach ($attributes as $key => $value) {\n            $set = \"set{$key}\";\n            $get = \"get{$key}\";\n            $object->$set($value);\n            self::assertEquals($value, $object->$get());\n        }\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Style/NumberingTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Style;\n\nuse PhpOffice\\PhpWord\\Style\\Numbering;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Style\\Numbering.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Style\\Numbering\n */\nclass NumberingTest extends \\PHPUnit\\Framework\\TestCase\n{\n    public function testGetSetPropertiesInt(): void\n    {\n        $object = new Numbering();\n        foreach ([\n            'numId' => [null, 1],\n        ] as $property => $value) {\n            [$default, $expected] = $value;\n            $get = \"get{$property}\";\n            $set = \"set{$property}\";\n\n            self::assertEquals($default, $object->$get()); // Default value\n\n            $object->$set($expected);\n\n            self::assertEquals($expected, $object->$get()); // New value\n        }\n    }\n\n    public function testGetSetPropertiesString(): void\n    {\n        $object = new Numbering();\n        foreach ([\n            'type' => [null, 'singleLevel'],\n        ] as $property => $value) {\n            [$default, $expected] = $value;\n            $get = \"get{$property}\";\n            $set = \"set{$property}\";\n\n            self::assertEquals($default, $object->$get()); // Default value\n\n            $object->$set($expected);\n\n            self::assertEquals($expected, $object->$get()); // New value\n        }\n    }\n\n    public function testGetLevels(): void\n    {\n        $object = new Numbering();\n\n        self::assertEmpty($object->getLevels());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Style/PaperTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Style;\n\nuse PhpOffice\\PhpWord\\Style\\Paper;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Style\\Paper.\n *\n * @runTestsInSeparateProcesses\n */\nclass PaperTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Tear down after each test.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    /**\n     * Test initiation for paper.\n     */\n    public function testInitiation(): void\n    {\n        $object = new Paper();\n\n        self::assertEquals('A4', $object->getSize());\n    }\n\n    /**\n     * Test paper size for B5 format.\n     */\n    public function testB5Size(): void\n    {\n        $object = new Paper('B5');\n\n        self::assertEquals('B5', $object->getSize());\n        self::assertEqualsWithDelta(9977.9527559055, $object->getWidth(), 0.000000001);\n        self::assertEqualsWithDelta(14173.228346457, $object->getHeight(), 0.000000001);\n    }\n\n    /**\n     * Test paper size for Folio format.\n     */\n    public function testFolioSize(): void\n    {\n        $object = new Paper();\n        $object->setSize('Folio');\n\n        self::assertEquals('Folio', $object->getSize());\n        self::assertEqualsWithDelta(12240, $object->getWidth(), 0.1);\n        self::assertEqualsWithDelta(18720, $object->getHeight(), 0.1);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Style/ParagraphTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Style;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\SimpleType\\LineSpacingRule;\nuse PhpOffice\\PhpWord\\Style\\Paragraph;\nuse PhpOffice\\PhpWord\\Style\\Tab;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Style\\Paragraph.\n *\n * @runTestsInSeparateProcesses\n */\nclass ParagraphTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Tear down after each test.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    /**\n     * Test setting style values with null or empty value.\n     */\n    public function testSetStyleValueWithNullOrEmpty(): void\n    {\n        $object = new Paragraph();\n\n        $attributes = [\n            'widowControl' => true,\n            'keepNext' => false,\n            'keepLines' => false,\n            'pageBreakBefore' => false,\n            'contextualSpacing' => false,\n        ];\n        foreach ($attributes as $key => $default) {\n            $get = $this->findGetter($key, $default, $object);\n            $object->setStyleValue($key, null);\n            self::assertEquals($default, $object->$get());\n            $object->setStyleValue($key, '');\n            self::assertEquals($default, $object->$get());\n        }\n    }\n\n    /**\n     * Test setting style values with normal value.\n     */\n    public function testSetStyleValueNormal(): void\n    {\n        $object = new Paragraph();\n\n        $attributes = [\n            'spaceAfter' => 240,\n            'spaceBefore' => 240,\n            'indent' => 1,\n            'hanging' => 1,\n            'spacing' => 120,\n            'spacingLineRule' => LineSpacingRule::AT_LEAST,\n            'basedOn' => 'Normal',\n            'next' => 'Normal',\n            'numStyle' => 'numStyle',\n            'numLevel' => 1,\n            'widowControl' => false,\n            'keepNext' => true,\n            'keepLines' => true,\n            'pageBreakBefore' => true,\n            'contextualSpacing' => true,\n            'textAlignment' => 'auto',\n            'bidi' => true,\n            'suppressAutoHyphens' => true,\n        ];\n        foreach ($attributes as $key => $value) {\n            $get = $this->findGetter($key, $value, $object);\n            $object->setStyleValue(\"$key\", $value);\n            if (('indent' == $key || 'hanging' == $key) && is_numeric($value)) {\n                $value = $value * 720;\n            }\n            self::assertEquals($value, $object->$get());\n        }\n    }\n\n    /**\n     * @param string $key\n     * @param mixed $value\n     * @param object $object\n     *\n     * @return string\n     */\n    private function findGetter($key, $value, $object)\n    {\n        if (is_bool($value)) {\n            if (method_exists($object, \"is{$key}\")) {\n                return \"is{$key}\";\n            } elseif (method_exists($object, \"has{$key}\")) {\n                return \"has{$key}\";\n            }\n        }\n\n        return \"get{$key}\";\n    }\n\n    /**\n     * Test get null style value.\n     */\n    public function testGetNullStyleValue(): void\n    {\n        $object = new Paragraph();\n\n        $attributes = ['spacing', 'indent', 'hanging', 'spaceBefore', 'spaceAfter', 'textAlignment'];\n        foreach ($attributes as $key) {\n            $get = $this->findGetter($key, null, $object);\n            self::assertNull($object->$get());\n        }\n    }\n\n    /**\n     * Test tabs.\n     */\n    public function testTabs(): void\n    {\n        $object = new Paragraph();\n        $object->setTabs([new Tab('left', 1550), new Tab('right', 5300)]);\n        self::assertCount(2, $object->getTabs());\n    }\n\n    public function testHanging(): void\n    {\n        $rand = mt_rand(0, 255);\n\n        $object = new Paragraph();\n        self::assertNull($object->getHanging());\n\n        $object->setHanging($rand);\n        self::assertEquals($rand, $object->getHanging());\n\n        $object->setHanging(null);\n        self::assertNull($object->getHanging());\n\n        $object->setHanging($rand);\n        self::assertEquals($rand, $object->getHanging());\n\n        $object->setHanging();\n        self::assertNull($object->getHanging());\n    }\n\n    public function testIndent(): void\n    {\n        $rand = mt_rand(0, 255);\n\n        $object = new Paragraph();\n        self::assertNull($object->getIndent());\n\n        $object->setIndent($rand);\n        self::assertEquals($rand, $object->getIndent());\n\n        $object->setIndent(null);\n        self::assertNull($object->getIndent());\n\n        $object->setIndent($rand);\n        self::assertEquals($rand, $object->getIndent());\n\n        $object->setIndent();\n        self::assertNull($object->getIndent());\n    }\n\n    public function testIndentation(): void\n    {\n        $rand = mt_rand(0, 255);\n        $rand2 = mt_rand(0, 255);\n\n        $object = new Paragraph();\n        self::assertNull($object->getIndentation());\n        // Set Basic indentation\n        $object->setIndentation([]);\n        self::assertNotNull($object->getIndentation());\n        self::assertEquals(0, $object->getIndentation()->getLeft());\n        self::assertEquals(0, $object->getIndentation()->getRight());\n        self::assertEquals(0, $object->getIndentation()->getHanging());\n        self::assertEquals(0, $object->getIndentation()->getFirstLine());\n        // Set indentation : left\n        $object->setIndentation([\n            'left' => $rand,\n        ]);\n        self::assertNotNull($object->getIndentation());\n        self::assertEquals($rand, $object->getIndentation()->getLeft());\n        self::assertEquals(0, $object->getIndentation()->getRight());\n        self::assertEquals(0, $object->getIndentation()->getHanging());\n        self::assertEquals(0, $object->getIndentation()->getFirstLine());\n        // Set indentation : right\n        $object->setIndentation([\n            'right' => $rand,\n        ]);\n        self::assertNotNull($object->getIndentation());\n        self::assertEquals($rand, $object->getIndentation()->getLeft());\n        self::assertEquals($rand, $object->getIndentation()->getRight());\n        self::assertEquals(0, $object->getIndentation()->getHanging());\n        self::assertEquals(0, $object->getIndentation()->getFirstLine());\n        // Set indentation : hanging\n        $object->setIndentation([\n            'hanging' => $rand,\n        ]);\n        self::assertNotNull($object->getIndentation());\n        self::assertEquals($rand, $object->getIndentation()->getLeft());\n        self::assertEquals($rand, $object->getIndentation()->getRight());\n        self::assertEquals($rand, $object->getIndentation()->getHanging());\n        self::assertEquals(0, $object->getIndentation()->getFirstLine());\n        // Set indentation : firstline\n        $object->setIndentation([\n            'firstline' => $rand,\n        ]);\n        self::assertNotNull($object->getIndentation());\n        self::assertEquals($rand, $object->getIndentation()->getLeft());\n        self::assertEquals($rand, $object->getIndentation()->getRight());\n        self::assertEquals($rand, $object->getIndentation()->getHanging());\n        self::assertEquals($rand, $object->getIndentation()->getFirstLine());\n        // Replace indentation : left & firstline\n        $object->setIndentation([\n            'left' => $rand2,\n            'firstline' => $rand2,\n        ]);\n        self::assertNotNull($object->getIndentation());\n        self::assertEquals($rand2, $object->getIndentation()->getLeft());\n        self::assertEquals($rand, $object->getIndentation()->getRight());\n        self::assertEquals($rand, $object->getIndentation()->getHanging());\n        self::assertEquals($rand2, $object->getIndentation()->getFirstLine());\n        // Replace indentation : N/A\n        $object->setIndentation();\n        self::assertNotNull($object->getIndentation());\n        self::assertEquals($rand2, $object->getIndentation()->getLeft());\n        self::assertEquals($rand, $object->getIndentation()->getRight());\n        self::assertEquals($rand, $object->getIndentation()->getHanging());\n        self::assertEquals($rand2, $object->getIndentation()->getFirstLine());\n    }\n\n    public function testIndentFirstLine(): void\n    {\n        $rand = mt_rand(0, 255);\n\n        $object = new Paragraph();\n        self::assertNull($object->getIndentFirstLine());\n        $object->setIndentFirstLine($rand);\n        self::assertEquals($rand, $object->getIndentFirstLine());\n        $object->setIndentFirstLine(null);\n        self::assertNull($object->getIndentFirstLine());\n        $object->setIndentFirstLine($rand);\n        self::assertEquals($rand, $object->getIndentFirstLine());\n        $object->setIndentFirstLine();\n        self::assertNull($object->getIndentFirstLine());\n    }\n\n    public function testIndentLeft(): void\n    {\n        $rand = mt_rand(0, 255);\n\n        $object = new Paragraph();\n        self::assertNull($object->getIndentLeft());\n        $object->setIndentLeft($rand);\n        self::assertEquals($rand, $object->getIndentLeft());\n        $object->setIndentLeft(null);\n        self::assertNull($object->getIndentLeft());\n        $object->setIndentLeft($rand);\n        self::assertEquals($rand, $object->getIndentLeft());\n        $object->setIndentLeft();\n        self::assertNull($object->getIndentLeft());\n    }\n\n    public function testIndentRight(): void\n    {\n        $rand = mt_rand(0, 255);\n\n        $object = new Paragraph();\n        self::assertNull($object->getIndentRight());\n        $object->setIndentRight($rand);\n        self::assertEquals($rand, $object->getIndentRight());\n        $object->setIndentRight(null);\n        self::assertNull($object->getIndentRight());\n        $object->setIndentRight($rand);\n        self::assertEquals($rand, $object->getIndentRight());\n        $object->setIndentRight();\n        self::assertNull($object->getIndentRight());\n    }\n\n    /**\n     * Line height.\n     */\n    public function testLineHeight(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        // Test style array\n        $text = $section->addText('This is a test', [], ['line-height' => 2.0]);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n        $element = $doc->getElement('/w:document/w:body/w:p/w:pPr/w:spacing');\n\n        $lineHeight = $element->getAttribute('w:line');\n        $lineRule = $element->getAttribute('w:lineRule');\n\n        self::assertEquals(480, $lineHeight);\n        self::assertEquals('auto', $lineRule);\n\n        // Test setter\n        $text->getParagraphStyle()->setLineHeight(3.0);\n        TestHelperDOCX::clear();\n        $doc = TestHelperDOCX::getDocument($phpWord);\n        $element = $doc->getElement('/w:document/w:body/w:p/w:pPr/w:spacing');\n\n        $lineHeight = $element->getAttribute('w:line');\n        $lineRule = $element->getAttribute('w:lineRule');\n\n        self::assertEquals(720, $lineHeight);\n        self::assertEquals('auto', $lineRule);\n    }\n\n    /**\n     * Test setLineHeight validation.\n     */\n    public function testLineHeightValidation(): void\n    {\n        $object = new Paragraph();\n        $object->setLineHeight('12.5pt');\n        self::assertEquals(12.5, $object->getLineHeight());\n    }\n\n    /**\n     * Test line height exception by using nonnumeric value.\n     */\n    public function testLineHeightException(): void\n    {\n        $this->expectException(\\PhpOffice\\PhpWord\\Exception\\InvalidStyleException::class);\n        $object = new Paragraph();\n        $object->setLineHeight('a');\n    }\n\n    public function testBidiVisual(): void\n    {\n        $object = new Paragraph();\n        self::assertNull($object->isBidi());\n        $object->setBidi(true);\n        self::assertTrue($object->isBidi());\n        $object->setBidi(false);\n        self::assertFalse($object->isBidi());\n        $object->setBidi(null);\n        self::assertNull($object->isBidi());\n    }\n\n    public function testBidiVisualSettings(): void\n    {\n        Settings::setDefaultRtl(null);\n        $object = new Paragraph();\n        self::assertNull($object->isBidi());\n\n        Settings::setDefaultRtl(true);\n        $object = new Paragraph();\n        self::assertTrue($object->isBidi());\n\n        Settings::setDefaultRtl(false);\n        $object = new Paragraph();\n        self::assertFalse($object->isBidi());\n\n        Settings::setDefaultRtl(null);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Style/RowTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Style;\n\nuse PhpOffice\\PhpWord\\Style\\Row;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Style\\Row.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Style\\Row\n *\n * @runTestsInSeparateProcesses\n */\nclass RowTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test properties with boolean value.\n     */\n    public function testBooleanValue(): void\n    {\n        $object = new Row();\n\n        $properties = [\n            'tblHeader' => true,\n            'cantSplit' => false,\n            'exactHeight' => true,\n        ];\n        foreach ($properties as $key => $value) {\n            // set/get\n            $set = \"set{$key}\";\n            $get = \"is{$key}\";\n            $expected = $value ? 1 : 0;\n            $object->$set($value);\n            self::assertEquals($expected, $object->$get());\n\n            // setStyleValue\n            $value = !$value;\n            $expected = $value ? 1 : 0;\n            $object->setStyleValue(\"{$key}\", $value);\n            self::assertEquals($expected, $object->$get());\n        }\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Style/SectionTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Style;\n\nuse PhpOffice\\PhpWord\\SimpleType\\VerticalJc;\nuse PhpOffice\\PhpWord\\Style\\Section;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Style\\Section.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Element\\Section\n *\n * @runTestsInSeparateProcesses\n */\nclass SectionTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Executed before each method of the class.\n     */\n    public function testSettingValue(): void\n    {\n        $oSettings = new Section();\n\n        self::assertEquals('portrait', $oSettings->getOrientation());\n        self::assertEqualsWithDelta(Section::DEFAULT_WIDTH, $oSettings->getPageSizeW(), 0.000000001);\n        self::assertEqualsWithDelta(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeH(), 0.000000001);\n        self::assertEquals('A4', $oSettings->getPaperSize());\n\n        $oSettings->setSettingValue('orientation', 'landscape');\n        self::assertEquals('landscape', $oSettings->getOrientation());\n        self::assertEqualsWithDelta(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeW(), 0.000000001);\n        self::assertEqualsWithDelta(Section::DEFAULT_WIDTH, $oSettings->getPageSizeH(), 0.000000001);\n\n        $iVal = mt_rand(1, 1000);\n        $oSettings->setSettingValue('borderSize', $iVal);\n        self::assertEquals([$iVal, $iVal, $iVal, $iVal], $oSettings->getBorderSize());\n        self::assertEquals($iVal, $oSettings->getBorderBottomSize());\n        self::assertEquals($iVal, $oSettings->getBorderLeftSize());\n        self::assertEquals($iVal, $oSettings->getBorderRightSize());\n        self::assertEquals($iVal, $oSettings->getBorderTopSize());\n\n        $oSettings->setSettingValue('borderColor', 'FF00AA');\n        self::assertEquals(['FF00AA', 'FF00AA', 'FF00AA', 'FF00AA'], $oSettings->getBorderColor());\n        self::assertEquals('FF00AA', $oSettings->getBorderBottomColor());\n        self::assertEquals('FF00AA', $oSettings->getBorderLeftColor());\n        self::assertEquals('FF00AA', $oSettings->getBorderRightColor());\n        self::assertEquals('FF00AA', $oSettings->getBorderTopColor());\n\n        $iVal = mt_rand(1, 1000);\n        $oSettings->setSettingValue('headerHeight', $iVal);\n        self::assertEquals($iVal, $oSettings->getHeaderHeight());\n\n        $oSettings->setSettingValue('lineNumbering', []);\n        $oSettings->setSettingValue(\n            'lineNumbering',\n            [\n                'start' => 1,\n                'increment' => 1,\n                'distance' => 240,\n                'restart' => 'newPage',\n            ]\n        );\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\LineNumbering', $oSettings->getLineNumbering());\n\n        $oSettings->setSettingValue('lineNumbering', null);\n        self::assertNull($oSettings->getLineNumbering());\n    }\n\n    /**\n     * Set/get margin.\n     */\n    public function testMargin(): void\n    {\n        // Section Settings\n        $oSettings = new Section();\n\n        $iVal = mt_rand(1, 1000);\n        $oSettings->setMarginTop($iVal);\n        self::assertEquals($iVal, $oSettings->getMarginTop());\n\n        $iVal = mt_rand(1, 1000);\n        $oSettings->setMarginBottom($iVal);\n        self::assertEquals($iVal, $oSettings->getMarginBottom());\n\n        $iVal = mt_rand(1, 1000);\n        $oSettings->setMarginLeft($iVal);\n        self::assertEquals($iVal, $oSettings->getMarginLeft());\n\n        $iVal = mt_rand(1, 1000);\n        $oSettings->setMarginRight($iVal);\n        self::assertEquals($iVal, $oSettings->getMarginRight());\n    }\n\n    /**\n     * Set/get page width.\n     */\n    public function testPageWidth(): void\n    {\n        // Section Settings\n        $oSettings = new Section();\n\n        self::assertEqualsWithDelta(Section::DEFAULT_WIDTH, $oSettings->getPageSizeW(), 0.000000001);\n        $iVal = mt_rand(1, 1000);\n        $oSettings->setSettingValue('pageSizeW', $iVal);\n        self::assertEquals($iVal, $oSettings->getPageSizeW());\n    }\n\n    /**\n     * Set/get page height.\n     */\n    public function testPageHeight(): void\n    {\n        // Section Settings\n        $oSettings = new Section();\n\n        self::assertEqualsWithDelta(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeH(), 0.000000001);\n        $iVal = mt_rand(1, 1000);\n        $oSettings->setSettingValue('pageSizeH', $iVal);\n        self::assertEquals($iVal, $oSettings->getPageSizeH());\n    }\n\n    /**\n     * Set/get landscape orientation.\n     */\n    public function testOrientationLandscape(): void\n    {\n        // Section Settings\n        $oSettings = new Section();\n\n        $oSettings->setLandscape();\n        self::assertEquals('landscape', $oSettings->getOrientation());\n        self::assertEqualsWithDelta(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeW(), 0.000000001);\n        self::assertEqualsWithDelta(Section::DEFAULT_WIDTH, $oSettings->getPageSizeH(), 0.000000001);\n    }\n\n    /**\n     * Set/get portrait orientation.\n     */\n    public function testOrientationPortrait(): void\n    {\n        // Section Settings\n        $oSettings = new Section();\n\n        $oSettings->setPortrait();\n        self::assertEquals('portrait', $oSettings->getOrientation());\n        self::assertEqualsWithDelta(Section::DEFAULT_WIDTH, $oSettings->getPageSizeW(), 0.000000001);\n        self::assertEqualsWithDelta(Section::DEFAULT_HEIGHT, $oSettings->getPageSizeH(), 0.000000001);\n    }\n\n    /**\n     * Set/get border size.\n     */\n    public function testBorderSize(): void\n    {\n        // Section Settings\n        $oSettings = new Section();\n\n        $iVal = mt_rand(1, 1000);\n        $oSettings->setBorderSize($iVal);\n        self::assertEquals([$iVal, $iVal, $iVal, $iVal], $oSettings->getBorderSize());\n        self::assertEquals($iVal, $oSettings->getBorderBottomSize());\n        self::assertEquals($iVal, $oSettings->getBorderLeftSize());\n        self::assertEquals($iVal, $oSettings->getBorderRightSize());\n        self::assertEquals($iVal, $oSettings->getBorderTopSize());\n\n        $iVal = mt_rand(1, 1000);\n        $oSettings->setBorderBottomSize($iVal);\n        self::assertEquals($iVal, $oSettings->getBorderBottomSize());\n\n        $iVal = mt_rand(1, 1000);\n        $oSettings->setBorderLeftSize($iVal);\n        self::assertEquals($iVal, $oSettings->getBorderLeftSize());\n\n        $iVal = mt_rand(1, 1000);\n        $oSettings->setBorderRightSize($iVal);\n        self::assertEquals($iVal, $oSettings->getBorderRightSize());\n\n        $iVal = mt_rand(1, 1000);\n        $oSettings->setBorderTopSize($iVal);\n        self::assertEquals($iVal, $oSettings->getBorderTopSize());\n    }\n\n    /**\n     * Set/get border color.\n     */\n    public function testBorderColor(): void\n    {\n        // Section Settings\n        $oSettings = new Section();\n\n        $oSettings->setBorderColor('FF00AA');\n        self::assertEquals(['FF00AA', 'FF00AA', 'FF00AA', 'FF00AA'], $oSettings->getBorderColor());\n        self::assertEquals('FF00AA', $oSettings->getBorderBottomColor());\n        self::assertEquals('FF00AA', $oSettings->getBorderLeftColor());\n        self::assertEquals('FF00AA', $oSettings->getBorderRightColor());\n        self::assertEquals('FF00AA', $oSettings->getBorderTopColor());\n\n        $oSettings->setBorderBottomColor('BBCCDD');\n        self::assertEquals('BBCCDD', $oSettings->getBorderBottomColor());\n\n        $oSettings->setBorderLeftColor('CCDDEE');\n        self::assertEquals('CCDDEE', $oSettings->getBorderLeftColor());\n\n        $oSettings->setBorderRightColor('11EE22');\n        self::assertEquals('11EE22', $oSettings->getBorderRightColor());\n\n        $oSettings->setBorderTopColor('22FF33');\n        self::assertEquals('22FF33', $oSettings->getBorderTopColor());\n    }\n\n    /**\n     * Set/get page numbering start.\n     */\n    public function testNumberingStart(): void\n    {\n        // Section Settings\n        $oSettings = new Section();\n\n        self::assertNull($oSettings->getPageNumberingStart());\n\n        $iVal = mt_rand(1, 1000);\n        $oSettings->setPageNumberingStart($iVal);\n        self::assertEquals($iVal, $oSettings->getPageNumberingStart());\n\n        $oSettings->setPageNumberingStart();\n        self::assertNull($oSettings->getPageNumberingStart());\n    }\n\n    /**\n     * Set/get header height.\n     */\n    public function testHeader(): void\n    {\n        $oSettings = new Section();\n\n        self::assertEquals(720, $oSettings->getHeaderHeight());\n\n        $iVal = mt_rand(1, 1000);\n        $oSettings->setHeaderHeight($iVal);\n        self::assertEquals($iVal, $oSettings->getHeaderHeight());\n\n        $oSettings->setHeaderHeight();\n        self::assertEquals(720, $oSettings->getHeaderHeight());\n    }\n\n    /**\n     * Set/get footer height.\n     */\n    public function testFooter(): void\n    {\n        // Section Settings\n        $oSettings = new Section();\n\n        self::assertEquals(720, $oSettings->getFooterHeight());\n\n        $iVal = mt_rand(1, 1000);\n        $oSettings->setFooterHeight($iVal);\n        self::assertEquals($iVal, $oSettings->getFooterHeight());\n\n        $oSettings->setFooterHeight();\n        self::assertEquals(720, $oSettings->getFooterHeight());\n    }\n\n    /**\n     * Set/get column number.\n     */\n    public function testColumnsNum(): void\n    {\n        // Section Settings\n        $oSettings = new Section();\n\n        // Default\n        self::assertEquals(1, $oSettings->getColsNum());\n\n        // Null value\n        $oSettings->setColsNum();\n        self::assertEquals(1, $oSettings->getColsNum());\n\n        // Random value\n        $iVal = mt_rand(1, 1000);\n        $oSettings->setColsNum($iVal);\n        self::assertEquals($iVal, $oSettings->getColsNum());\n    }\n\n    /**\n     * Set/get column spacing.\n     */\n    public function testColumnsSpace(): void\n    {\n        // Section Settings\n        $oSettings = new Section();\n\n        // Default\n        self::assertEquals(720, $oSettings->getColsSpace());\n\n        $iVal = mt_rand(1, 1000);\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Section', $oSettings->setColsSpace($iVal));\n        self::assertEquals($iVal, $oSettings->getColsSpace());\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Section', $oSettings->setColsSpace());\n        self::assertEquals(720, $oSettings->getColsSpace());\n    }\n\n    /**\n     * Set/get break type.\n     */\n    public function testBreakType(): void\n    {\n        // Section Settings\n        $oSettings = new Section();\n\n        self::assertNull($oSettings->getBreakType());\n\n        $oSettings->setBreakType('continuous');\n        self::assertEquals('continuous', $oSettings->getBreakType());\n\n        $oSettings->setBreakType();\n        self::assertNull($oSettings->getBreakType());\n    }\n\n    /**\n     * Vertical page alignment.\n     */\n    public function testVerticalAlign(): void\n    {\n        // Section Settings\n        $oSettings = new Section();\n\n        self::assertNull($oSettings->getVAlign());\n\n        $oSettings->setVAlign(VerticalJc::BOTH);\n        self::assertEquals('both', $oSettings->getVAlign());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Style/ShadingTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Style;\n\nuse PhpOffice\\PhpWord\\Style\\Shading;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Style\\Shading.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Style\\Shading\n */\nclass ShadingTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test get/set.\n     */\n    public function testGetSetProperties(): void\n    {\n        $object = new Shading();\n        $properties = [\n            'pattern' => ['clear', 'solid'],\n            'color' => [null, 'FF0000'],\n            'fill' => [null, 'FF0000'],\n        ];\n        foreach ($properties as $property => $value) {\n            [$default, $expected] = $value;\n            $get = \"get{$property}\";\n            $set = \"set{$property}\";\n\n            self::assertEquals($default, $object->$get()); // Default value\n\n            $object->$set($expected);\n\n            self::assertEquals($expected, $object->$get()); // New value\n        }\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Style/SpacingTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Style;\n\nuse PhpOffice\\PhpWord\\Style\\Spacing;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Style\\Spacing.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Style\\Spacing\n */\nclass SpacingTest extends \\PHPUnit\\Framework\\TestCase\n{\n    public function testGetSetPropertiesInt(): void\n    {\n        $object = new Spacing();\n        $properties = [\n            'before' => [null, 10],\n            'after' => [null, 10],\n            'line' => [null, 10],\n        ];\n        foreach ($properties as $property => $value) {\n            [$default, $expected] = $value;\n            $get = \"get{$property}\";\n            $set = \"set{$property}\";\n\n            self::assertEquals($default, $object->$get()); // Default value\n\n            $object->$set($expected);\n\n            self::assertEquals($expected, $object->$get()); // New value\n        }\n    }\n\n    public function testGetSetPropertiesString(): void\n    {\n        $object = new Spacing();\n        $properties = [\n            'lineRule' => ['auto', 'exact'],\n        ];\n        foreach ($properties as $property => $value) {\n            [$default, $expected] = $value;\n            $get = \"get{$property}\";\n            $set = \"set{$property}\";\n\n            self::assertEquals($default, $object->$get()); // Default value\n\n            $object->$set($expected);\n\n            self::assertEquals($expected, $object->$get()); // New value\n        }\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Style/TOCTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Style;\n\nuse PhpOffice\\PhpWord\\Style\\TOC;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Style\\TOC.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Style\\TOC\n */\nclass TOCTest extends \\PHPUnit\\Framework\\TestCase\n{\n    public function testGetSetInt(): void\n    {\n        $object = new TOC();\n        foreach ([\n            'tabPos' => [9062, 10],\n            'indent' => [200, 10],\n        ] as $property => $value) {\n            [$default, $expected] = $value;\n            $get = \"get{$property}\";\n            $set = \"set{$property}\";\n\n            self::assertEquals($default, $object->$get()); // Default value\n\n            $object->$set($expected);\n\n            self::assertEquals($expected, $object->$get()); // New value\n        }\n    }\n\n    public function testGetSetString(): void\n    {\n        $object = new TOC();\n        foreach ([\n            'tabLeader' => [TOC::TAB_LEADER_DOT, TOC::TAB_LEADER_UNDERSCORE],\n        ] as $property => $value) {\n            [$default, $expected] = $value;\n            $get = \"get{$property}\";\n            $set = \"set{$property}\";\n\n            self::assertEquals($default, $object->$get()); // Default value\n\n            $object->$set($expected);\n\n            self::assertEquals($expected, $object->$get()); // New value\n        }\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Style/TabTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Style;\n\nuse PhpOffice\\PhpWord\\Style\\Tab;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Style\\Tab.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Style\\Tab\n */\nclass TabTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test get/set.\n     */\n    public function testGetSetPropertiesInt(): void\n    {\n        $object = new Tab();\n        foreach ([\n            'position' => [0, 10],\n        ] as $property => $value) {\n            [$default, $expected] = $value;\n            $get = \"get{$property}\";\n            $set = \"set{$property}\";\n\n            self::assertEquals($default, $object->$get()); // Default value\n\n            $object->$set($expected);\n\n            self::assertEquals($expected, $object->$get()); // New value\n        }\n    }\n\n    /**\n     * Test get/set.\n     */\n    public function testGetSetPropertiesString(): void\n    {\n        $object = new Tab();\n        foreach ([\n            'type' => [Tab::TAB_STOP_CLEAR, Tab::TAB_STOP_RIGHT],\n            'leader' => [Tab::TAB_LEADER_NONE, Tab::TAB_LEADER_DOT],\n        ] as $property => $value) {\n            [$default, $expected] = $value;\n            $get = \"get{$property}\";\n            $set = \"set{$property}\";\n\n            self::assertEquals($default, $object->$get()); // Default value\n\n            $object->$set($expected);\n\n            self::assertEquals($expected, $object->$get()); // New value\n        }\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Style/TablePositionTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Style;\n\nuse PhpOffice\\PhpWord\\Style\\TablePosition;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Style\\Table.\n *\n * @runTestsInSeparateProcesses\n */\nclass TablePositionTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test class construction.\n     */\n    public function testConstruct(): void\n    {\n        $styleTable = ['vertAnchor' => TablePosition::VANCHOR_PAGE, 'bottomFromText' => 20];\n\n        $object = new TablePosition($styleTable);\n        self::assertEquals(TablePosition::VANCHOR_PAGE, $object->getVertAnchor());\n        self::assertEquals(20, $object->getBottomFromText());\n    }\n\n    /**\n     * Test setting style with normal value.\n     */\n    public function testSetGetNormalInt(): void\n    {\n        $object = new TablePosition();\n\n        foreach ([\n            'leftFromText' => 4,\n            'rightFromText' => 4,\n            'topFromText' => 4,\n            'bottomFromText' => 4,\n            'tblpX' => 5,\n            'tblpY' => 6,\n        ] as $key => $value) {\n            $set = \"set{$key}\";\n            $get = \"get{$key}\";\n            $object->$set($value);\n            self::assertEquals($value, $object->$get());\n        }\n    }\n\n    /**\n     * Test setting style with normal value.\n     */\n    public function testSetGetNormalString(): void\n    {\n        $object = new TablePosition();\n\n        foreach ([\n            'vertAnchor' => TablePosition::VANCHOR_PAGE,\n            'horzAnchor' => TablePosition::HANCHOR_TEXT,\n            'tblpXSpec' => TablePosition::XALIGN_CENTER,\n            'tblpYSpec' => TablePosition::YALIGN_OUTSIDE,\n        ] as $key => $value) {\n            $set = \"set{$key}\";\n            $get = \"get{$key}\";\n            $object->$set($value);\n            self::assertEquals($value, $object->$get());\n        }\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Style/TableTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Style;\n\nuse PhpOffice\\PhpWord\\ComplexType\\TblWidth as TblWidthComplexType;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\SimpleType\\JcTable;\nuse PhpOffice\\PhpWord\\SimpleType\\TblWidth;\nuse PhpOffice\\PhpWord\\Style\\Table;\nuse PhpOffice\\PhpWord\\Style\\TablePosition;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Style\\Table.\n *\n * @runTestsInSeparateProcesses\n */\nclass TableTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test class construction.\n     *\n     * There are 3 variables for class constructor:\n     * - $styleTable: Define table styles\n     * - $styleFirstRow: Define style for the first row\n     */\n    public function testConstruct(): void\n    {\n        $styleTable = ['bgColor' => 'FF0000'];\n        $styleFirstRow = ['borderBottomSize' => 3];\n\n        $object = new Table($styleTable, $styleFirstRow);\n        self::assertEquals('FF0000', $object->getBgColor());\n\n        $firstRow = $object->getFirstRow();\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Table', $firstRow);\n        self::assertEquals(3, $firstRow->getBorderBottomSize());\n    }\n\n    /**\n     * Test default values when passing no style.\n     */\n    public function testDefaultValues(): void\n    {\n        $object = new Table();\n\n        self::assertNull($object->getBgColor());\n        self::assertEquals(Table::LAYOUT_AUTO, $object->getLayout());\n        self::assertEquals(TblWidth::AUTO, $object->getUnit());\n        self::assertNull($object->getIndent());\n    }\n\n    /**\n     * Test setting style with normal value.\n     */\n    public function testSetGetNormal(): void\n    {\n        $object = new Table();\n\n        $attributes = [\n            'bgColor' => 'FF0000',\n            'borderTopSize' => 4,\n            'borderTopColor' => 'FF0000',\n            'borderLeftSize' => 4,\n            'borderLeftColor' => 'FF0000',\n            'borderRightSize' => 4,\n            'borderRightColor' => 'FF0000',\n            'borderBottomSize' => 4,\n            'borderBottomColor' => 'FF0000',\n            'borderInsideHSize' => 4,\n            'borderInsideHColor' => 'FF0000',\n            'borderInsideVSize' => 4,\n            'borderInsideVColor' => 'FF0000',\n            'cellMarginTop' => 240,\n            'cellMarginLeft' => 240,\n            'cellMarginRight' => 240,\n            'cellMarginBottom' => 240,\n            'alignment' => JcTable::CENTER,\n            'width' => 100,\n            'unit' => 'pct',\n            'layout' => Table::LAYOUT_FIXED,\n        ];\n        foreach ($attributes as $key => $value) {\n            $set = \"set{$key}\";\n            $get = \"get{$key}\";\n            $object->$set($value);\n            self::assertEquals($value, $object->$get());\n        }\n    }\n\n    public function testBidiVisual(): void\n    {\n        $object = new Table();\n        self::assertNull($object->isBidiVisual());\n        self::assertInstanceOf(Table::class, $object->setBidiVisual(true));\n        self::assertTrue($object->isBidiVisual());\n        self::assertInstanceOf(Table::class, $object->setBidiVisual(false));\n        self::assertFalse($object->isBidiVisual());\n        self::assertInstanceOf(Table::class, $object->setBidiVisual(null));\n        self::assertNull($object->isBidiVisual());\n    }\n\n    public function testBidiVisualSettings(): void\n    {\n        Settings::setDefaultRtl(null);\n        $object = new Table();\n        self::assertNull($object->isBidiVisual());\n\n        Settings::setDefaultRtl(true);\n        $object = new Table();\n        self::assertTrue($object->isBidiVisual());\n\n        Settings::setDefaultRtl(false);\n        $object = new Table();\n        self::assertFalse($object->isBidiVisual());\n\n        Settings::setDefaultRtl(null);\n    }\n\n    /**\n     * Test border color.\n     *\n     * Set border color and test if each part has the same color\n     * While looping, push values array to be asserted with getBorderColor\n     */\n    public function testBorderColor(): void\n    {\n        $object = new Table();\n        $parts = ['Top', 'Left', 'Right', 'Bottom', 'InsideH', 'InsideV'];\n\n        $value = 'FF0000';\n        $object->setBorderColor($value);\n        $values = [];\n        foreach ($parts as $part) {\n            $get = \"getBorder{$part}Color\";\n            $values[] = $value;\n            self::assertEquals($value, $object->$get());\n        }\n        self::assertEquals($values, $object->getBorderColor());\n    }\n\n    /**\n     * Test border size.\n     *\n     * Set border size and test if each part has the same size\n     * While looping, push values array to be asserted with getBorderSize\n     * Value is in eights of a point, i.e. 4 / 8 = .5pt\n     */\n    public function testBorderSize(): void\n    {\n        $object = new Table();\n        $parts = ['Top', 'Left', 'Right', 'Bottom', 'InsideH', 'InsideV'];\n\n        $value = 4;\n        $object->setBorderSize($value);\n        $values = [];\n        foreach ($parts as $part) {\n            $get = \"getBorder{$part}Size\";\n            $values[] = $value;\n            self::assertEquals($value, $object->$get());\n        }\n        self::assertEquals($values, $object->getBorderSize());\n    }\n\n    /**\n     * Test cell margin.\n     *\n     * Set cell margin and test if each part has the same margin\n     * While looping, push values array to be asserted with getCellMargin\n     * Value is in twips\n     */\n    public function testCellMargin(): void\n    {\n        $object = new Table();\n        $parts = ['Top', 'Left', 'Right', 'Bottom'];\n\n        $value = 240;\n        $object->setCellMargin($value);\n        $values = [];\n        foreach ($parts as $part) {\n            $get = \"getCellMargin{$part}\";\n            $values[] = $value;\n            self::assertEquals($value, $object->$get());\n        }\n        self::assertEquals($values, $object->getCellMargin());\n        self::assertTrue($object->hasMargin());\n    }\n\n    /**\n     * Set style value for various special value types.\n     */\n    public function testSetStyleValue(): void\n    {\n        $object = new Table();\n        $object->setStyleValue('borderSize', 120);\n        $object->setStyleValue('cellMargin', 240);\n        $object->setStyleValue('borderColor', '999999');\n\n        self::assertEquals([120, 120, 120, 120, 120, 120], $object->getBorderSize());\n        self::assertEquals([240, 240, 240, 240], $object->getCellMargin());\n        self::assertEquals(\n            ['999999', '999999', '999999', '999999', '999999', '999999'],\n            $object->getBorderColor()\n        );\n    }\n\n    /**\n     * Tests table cell spacing.\n     */\n    public function testTableCellSpacing(): void\n    {\n        $object = new Table();\n        self::assertNull($object->getCellSpacing());\n\n        $object = new Table(['cellSpacing' => 20]);\n        self::assertEquals(20, $object->getCellSpacing());\n    }\n\n    /**\n     * Tests table floating position.\n     */\n    public function testTablePosition(): void\n    {\n        $object = new Table();\n        self::assertNull($object->getPosition());\n\n        $object->setPosition(['vertAnchor' => TablePosition::VANCHOR_PAGE]);\n        self::assertNotNull($object->getPosition());\n        self::assertEquals(TablePosition::VANCHOR_PAGE, $object->getPosition()->getVertAnchor());\n    }\n\n    public function testIndent(): void\n    {\n        $indent = new TblWidthComplexType(100, TblWidth::TWIP);\n\n        $table = new Table(['indent' => $indent]);\n\n        self::assertSame($indent, $table->getIndent());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Style/TextBoxTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Style;\n\nuse InvalidArgumentException;\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\nuse PhpOffice\\PhpWord\\Style\\TextBox;\nuse PHPUnit\\Framework\\TestCase;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Style\\Image.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Style\\Image\n *\n * @runTestsInSeparateProcesses\n */\nclass TextBoxTest extends TestCase\n{\n    /**\n     * Test setting style with normal value.\n     */\n    public function testSetGetNormal(): void\n    {\n        $object = new TextBox();\n\n        $properties = [\n            'width' => 200,\n            'height' => 200,\n            'alignment' => Jc::START,\n            'marginTop' => 240,\n            'marginLeft' => 240,\n            'wrappingStyle' => 'inline',\n            'positioning' => 'absolute',\n            'posHorizontal' => 'center',\n            'posVertical' => 'top',\n            'posHorizontalRel' => 'margin',\n            'posVerticalRel' => 'page',\n            'innerMarginTop' => '5',\n            'innerMarginRight' => '5',\n            'innerMarginBottom' => '5',\n            'innerMarginLeft' => '5',\n            'borderSize' => '2',\n            'borderColor' => 'red',\n            'bgColor' => 'blue',\n        ];\n        foreach ($properties as $key => $value) {\n            $set = \"set{$key}\";\n            $get = \"get{$key}\";\n            $object->$set($value);\n            self::assertEquals($value, $object->$get());\n        }\n    }\n\n    /**\n     * Test setStyleValue method.\n     */\n    public function testSetStyleValue(): void\n    {\n        $object = new TextBox();\n\n        $properties = [\n            'width' => 200,\n            'height' => 200,\n            'alignment' => Jc::START,\n            'marginTop' => 240,\n            'marginLeft' => 240,\n            'wrappingStyle' => 'inline',\n            'positioning' => 'absolute',\n            'posHorizontal' => 'center',\n            'posVertical' => 'top',\n            'posHorizontalRel' => 'margin',\n            'posVerticalRel' => 'page',\n            'innerMarginTop' => '5',\n            'innerMarginRight' => '5',\n            'innerMarginBottom' => '5',\n            'innerMarginLeft' => '5',\n            'borderSize' => '2',\n            'borderColor' => 'red',\n            'bgColor' => 'blue',\n        ];\n        foreach ($properties as $key => $value) {\n            $get = \"get{$key}\";\n            $object->setStyleValue(\"{$key}\", $value);\n            self::assertEquals($value, $object->$get());\n        }\n    }\n\n    /**\n     * Test setWrappingStyle exception.\n     */\n    public function testSetWrappingStyleException(): void\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $object = new TextBox();\n        $object->setWrappingStyle('foo');\n    }\n\n    /**\n     * Test set/get width.\n     */\n    public function testSetGetWidth(): void\n    {\n        $expected = 200;\n        $object = new TextBox();\n        $object->setWidth($expected);\n        self::assertEquals($expected, $object->getWidth());\n    }\n\n    /**\n     * Test set/get height.\n     */\n    public function testSetGetHeight(): void\n    {\n        $expected = 200;\n        $object = new TextBox();\n        $object->setHeight($expected);\n        self::assertEquals($expected, $object->getHeight());\n    }\n\n    /**\n     * Test set/get height.\n     */\n    public function testSetGetAlign(): void\n    {\n        $textBox = new TextBox();\n\n        $expectedAlignment = Jc::START;\n        $textBox->setAlignment($expectedAlignment);\n        self::assertEquals($expectedAlignment, $textBox->getAlignment());\n    }\n\n    /**\n     * Test set/get marginTop.\n     */\n    public function testSetGetMarginTop(): void\n    {\n        $expected = 5;\n        $object = new TextBox();\n        $object->setMarginTop($expected);\n        self::assertEquals($expected, $object->getMarginTop());\n    }\n\n    /**\n     * Test set/get marginLeft.\n     */\n    public function testSetGetMarginLeft(): void\n    {\n        $expected = 5;\n        $object = new TextBox();\n        $object->setMarginLeft($expected);\n        self::assertEquals($expected, $object->getMarginLeft());\n    }\n\n    /**\n     * Test set/get innerMarginTop.\n     */\n    public function testSetGetInnerMarginTop(): void\n    {\n        $expected = 5;\n        $object = new TextBox();\n        $object->setInnerMarginTop($expected);\n        self::assertEquals($expected, $object->getInnerMarginTop());\n    }\n\n    /**\n     * Test set/get wrappingStyle.\n     */\n    public function testSetGetWrappingStyle(): void\n    {\n        $expected = 'inline';\n        $object = new TextBox();\n        $object->setWrappingStyle($expected);\n        self::assertEquals($expected, $object->getWrappingStyle());\n    }\n\n    /**\n     * Test set/get positioning.\n     */\n    public function testSetGetPositioning(): void\n    {\n        $expected = 'absolute';\n        $object = new TextBox();\n        $object->setPositioning($expected);\n        self::assertEquals($expected, $object->getPositioning());\n    }\n\n    /**\n     * Test set/get posHorizontal.\n     */\n    public function testSetGetPosHorizontal(): void\n    {\n        $expected = 'center';\n        $object = new TextBox();\n        $object->setPosHorizontal($expected);\n        self::assertEquals($expected, $object->getPosHorizontal());\n    }\n\n    /**\n     * Test set/get posVertical.\n     */\n    public function testSetGetPosVertical(): void\n    {\n        $expected = 'top';\n        $object = new TextBox();\n        $object->setPosVertical($expected);\n        self::assertEquals($expected, $object->getPosVertical());\n    }\n\n    /**\n     * Test set/get posHorizontalRel.\n     */\n    public function testSetGetPosHorizontalRel(): void\n    {\n        $expected = 'margin';\n        $object = new TextBox();\n        $object->setPosHorizontalRel($expected);\n        self::assertEquals($expected, $object->getPosHorizontalRel());\n    }\n\n    /**\n     * Test set/get posVerticalRel.\n     */\n    public function testSetGetPosVerticalRel(): void\n    {\n        $expected = 'page';\n        $object = new TextBox();\n        $object->setPosVerticalRel($expected);\n        self::assertEquals($expected, $object->getPosVerticalRel());\n    }\n\n    /**\n     * Test set/get innerMarginRight.\n     */\n    public function testSetGetInnerMarginRight(): void\n    {\n        $expected = 5;\n        $object = new TextBox();\n        $object->setInnerMarginRight($expected);\n        self::assertEquals($expected, $object->getInnerMarginRight());\n    }\n\n    /**\n     * Test set/get innerMarginBottom.\n     */\n    public function testSetGetInnerMarginBottom(): void\n    {\n        $expected = 5;\n        $object = new TextBox();\n        $object->setInnerMarginBottom($expected);\n        self::assertEquals($expected, $object->getInnerMarginBottom());\n    }\n\n    /**\n     * Test set/get innerMarginLeft.\n     */\n    public function testSetGetInnerMarginLeft(): void\n    {\n        $expected = 5;\n        $object = new TextBox();\n        $object->setInnerMarginLeft($expected);\n        self::assertEquals($expected, $object->getInnerMarginLeft());\n    }\n\n    /**\n     * Test set/get innerMarginLeft.\n     */\n    public function testSetGetInnerMargin(): void\n    {\n        $expected = 5;\n        $object = new TextBox();\n        $object->setInnerMargin($expected);\n        self::assertEquals([$expected, $expected, $expected, $expected], $object->getInnerMargin());\n    }\n\n    /**\n     * Test set/get borderSize.\n     */\n    public function testSetGetBorderSize(): void\n    {\n        $expected = 2;\n        $object = new TextBox();\n        $object->setBorderSize($expected);\n        self::assertEquals($expected, $object->getBorderSize());\n    }\n\n    /**\n     * Test set/get borderColor.\n     */\n    public function testSetGetBorderColor(): void\n    {\n        $expected = 'red';\n        $object = new TextBox();\n        $object->setBorderColor($expected);\n        self::assertEquals($expected, $object->getBorderColor());\n    }\n\n    /**\n     * Test set/get bgColor.\n     */\n    public function testSetGetBgColor(): void\n    {\n        $expected = 'blue';\n        $object = new TextBox();\n        $object->setBgColor($expected);\n        self::assertEquals($expected, $object->getBgColor());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/StyleTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests;\n\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\nuse PhpOffice\\PhpWord\\Style;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Style.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Style\n *\n * @runTestsInSeparateProcesses\n */\nclass StyleTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Add and get paragraph, font, link, title, and table styles.\n     *\n     * @covers ::addFontStyle\n     * @covers ::addLinkStyle\n     * @covers ::addNumberingStyle\n     * @covers ::addParagraphStyle\n     * @covers ::addTableStyle\n     * @covers ::addTitleStyle\n     * @covers ::countStyles\n     * @covers ::getStyle\n     * @covers ::getStyles\n     * @covers ::resetStyles\n     * @covers ::setDefaultParagraphStyle\n     */\n    public function testStyles(): void\n    {\n        $paragraph = ['alignment' => Jc::CENTER];\n        $font = ['italic' => true, '_bold' => true];\n        $table = ['bgColor' => 'CCCCCC'];\n        $numbering = [\n            'type' => 'multilevel',\n            'levels' => [\n                [\n                    'start' => 1,\n                    'format' => 'decimal',\n                    'restart' => 1,\n                    'suffix' => 'space',\n                    'text' => '%1.',\n                    'alignment' => Jc::START,\n                ],\n            ],\n        ];\n\n        $styles = [\n            'Paragraph' => 'Paragraph',\n            'Font' => 'Font',\n            'Link' => 'Font',\n            'Table' => 'Table',\n            'Heading_1' => 'Font',\n            'Normal' => 'Paragraph',\n            'Numbering' => 'Numbering',\n        ];\n\n        Style::addParagraphStyle('Paragraph', $paragraph);\n        Style::addFontStyle('Font', $font);\n        Style::addLinkStyle('Link', $font);\n        Style::addNumberingStyle('Numbering', $numbering);\n        Style::addTitleStyle(1, $font);\n        Style::addTableStyle('Table', $table);\n        Style::setDefaultParagraphStyle($paragraph);\n\n        self::assertCount(count($styles), Style::getStyles());\n        foreach ($styles as $name => $style) {\n            self::assertInstanceOf(\"PhpOffice\\\\PhpWord\\\\Style\\\\{$style}\", Style::getStyle($name));\n        }\n        self::assertNull(Style::getStyle('Unknown'));\n\n        Style::resetStyles();\n        self::assertCount(0, Style::getStyles());\n    }\n\n    /**\n     * Test default paragraph style.\n     *\n     * @covers ::setDefaultParagraphStyle\n     */\n    public function testDefaultParagraphStyle(): void\n    {\n        $paragraph = ['alignment' => Jc::CENTER];\n\n        Style::setDefaultParagraphStyle($paragraph);\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph', Style::getStyle('Normal'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/TemplateProcessorTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests;\n\nuse DOMDocument;\nuse Exception;\nuse PhpOffice\\PhpWord\\Element\\Text;\nuse PhpOffice\\PhpWord\\Element\\TextRun;\nuse PhpOffice\\PhpWord\\IOFactory;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\TemplateProcessor;\nuse Throwable;\nuse TypeError;\nuse ZipArchive;\n\n/**\n * @covers \\PhpOffice\\PhpWord\\TemplateProcessor\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\TemplateProcessor\n *\n * @runTestsInSeparateProcesses\n */\nfinal class TemplateProcessorTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /** @var ?TemplateProcessor */\n    private $templateProcessor;\n\n    private function getTemplateProcessor(string $filename): TemplateProcessor\n    {\n        $this->templateProcessor = new TemplateProcessor($filename);\n\n        return $this->templateProcessor;\n    }\n\n    protected function tearDown(): void\n    {\n        if ($this->templateProcessor !== null) {\n            $filename = $this->templateProcessor->getTempDocumentFilename();\n            $this->templateProcessor = null;\n            if (file_exists($filename)) {\n                @unlink($filename);\n            }\n        }\n    }\n\n    /**\n     * Construct test.\n     *\n     * @covers ::__construct\n     * @covers ::__destruct\n     * @covers \\PhpOffice\\PhpWord\\Shared\\ZipArchive::close\n     */\n    public function testTheConstruct(): void\n    {\n        $object = $this->getTemplateProcessor(__DIR__ . '/_files/templates/blank.docx');\n        self::assertEquals([], $object->getVariables());\n        $object->save();\n\n        try {\n            $object->zip()->close();\n            self::fail('Expected exception for double close');\n        } catch (Throwable $e) {\n            // nothing to do here\n        }\n    }\n\n    /**\n     * Template can be saved in temporary location.\n     *\n     * @covers ::save\n     * @covers ::zip\n     */\n    public function xtestTemplateCanBeSavedInTemporaryLocation(string $templateFqfn, TemplateProcessor $templateProcessor): string\n    {\n        $xslDomDocument = new DOMDocument();\n        $xslDomDocument->load(__DIR__ . '/_files/xsl/remove_tables_by_needle.xsl');\n        foreach (['${employee.', '${scoreboard.', '${reference.'] as $needle) {\n            $templateProcessor->applyXslStyleSheet($xslDomDocument, ['needle' => $needle]);\n        }\n\n        $embeddingText = 'The quick Brown Fox jumped over the lazy^H^H^H^Htired unitTester';\n        $templateProcessor->zip()->AddFromString('word/embeddings/fox.bin', $embeddingText);\n        $documentFqfn = $templateProcessor->save();\n\n        self::assertNotEmpty($documentFqfn, 'FQFN of the saved document is empty.');\n        self::assertFileExists($documentFqfn, \"The saved document \\\"{$documentFqfn}\\\" doesn't exist.\");\n\n        $templateZip = new ZipArchive();\n        $templateZip->open($templateFqfn);\n        $templateHeaderXml = $templateZip->getFromName('word/header1.xml');\n        $templateMainPartXml = $templateZip->getFromName('word/document.xml');\n        $templateFooterXml = $templateZip->getFromName('word/footer1.xml');\n        if (false === $templateZip->close()) {\n            throw new Exception(\"Could not close zip file \\\"{$templateZip}\\\".\");\n        }\n\n        $documentZip = new ZipArchive();\n        $documentZip->open($documentFqfn);\n        $documentHeaderXml = $documentZip->getFromName('word/header1.xml');\n        $documentMainPartXml = $documentZip->getFromName('word/document.xml');\n        $documentFooterXml = $documentZip->getFromName('word/footer1.xml');\n        $documentEmbedding = $documentZip->getFromName('word/embeddings/fox.bin');\n        if (false === $documentZip->close()) {\n            throw new Exception(\"Could not close zip file \\\"{$documentZip}\\\".\");\n        }\n\n        self::assertNotEquals($templateHeaderXml, $documentHeaderXml);\n        self::assertNotEquals($templateMainPartXml, $documentMainPartXml);\n        self::assertNotEquals($templateFooterXml, $documentFooterXml);\n        self::assertEquals($embeddingText, $documentEmbedding);\n\n        return $documentFqfn;\n    }\n\n    /**\n     * XSL stylesheet can be applied.\n     *\n     * @covers ::applyXslStyleSheet\n     */\n    public function testXslStyleSheetCanBeApplied(): void\n    {\n        $templateFqfn = __DIR__ . '/_files/templates/with_table_macros.docx';\n        $templateProcessor = $this->getTemplateProcessor($templateFqfn);\n\n        $actualDocumentFqfn = $this->xtestTemplateCanBeSavedInTemporaryLocation($templateFqfn, $templateProcessor);\n        $expectedDocumentFqfn = __DIR__ . '/_files/documents/without_table_macros.docx';\n\n        $actualDocumentZip = new ZipArchive();\n        $actualDocumentZip->open($actualDocumentFqfn);\n        $actualHeaderXml = $actualDocumentZip->getFromName('word/header1.xml');\n        $actualMainPartXml = $actualDocumentZip->getFromName('word/document.xml');\n        $actualFooterXml = $actualDocumentZip->getFromName('word/footer1.xml');\n        if (false === $actualDocumentZip->close()) {\n            throw new Exception(\"Could not close zip file \\\"{$actualDocumentFqfn}\\\".\");\n        }\n\n        $expectedDocumentZip = new ZipArchive();\n        $expectedDocumentZip->open($expectedDocumentFqfn);\n        $expectedHeaderXml = $expectedDocumentZip->getFromName('word/header1.xml');\n        $expectedMainPartXml = $expectedDocumentZip->getFromName('word/document.xml');\n        $expectedFooterXml = $expectedDocumentZip->getFromName('word/footer1.xml');\n        if (false === $expectedDocumentZip->close()) {\n            throw new Exception(\"Could not close zip file \\\"{$expectedDocumentFqfn}\\\".\");\n        }\n\n        self::assertSame($expectedHeaderXml, $actualHeaderXml);\n        self::assertSame($expectedMainPartXml, $actualMainPartXml);\n        self::assertSame($expectedFooterXml, $actualFooterXml);\n    }\n\n    /**\n     * XSL stylesheet cannot be applied on failure in setting parameter value.\n     *\n     * @covers                   ::applyXslStyleSheet\n     */\n    public function testXslStyleSheetCanNotBeAppliedOnFailureOfSettingParameterValue(): void\n    {\n        if (\\PHP_VERSION_ID >= 80000) {\n            // PHP 8+ internal validation throws TypeError.\n            $this->expectException(TypeError::class);\n            $this->expectExceptionMessage('must contain only string keys');\n        } else {\n            $this->expectException(\\PhpOffice\\PhpWord\\Exception\\Exception::class);\n            $this->expectExceptionMessage('Could not set values for the given XSL style sheet parameters.');\n        }\n\n        $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/blank.docx');\n\n        $xslDomDocument = new DOMDocument();\n        $xslDomDocument->load(__DIR__ . '/_files/xsl/passthrough.xsl');\n\n        /*\n         * We have to use error control below, because \\XSLTProcessor::setParameter omits warning on failure.\n         * This warning fails the test.\n         */\n        @$templateProcessor->applyXslStyleSheet($xslDomDocument, [1 => 'somevalue']);\n    }\n\n    /**\n     * XSL stylesheet can be applied on failure of loading XML from template.\n     *\n     * @covers                   ::applyXslStyleSheet\n     */\n    public function testXslStyleSheetCanNotBeAppliedOnFailureOfLoadingXmlFromTemplate(): void\n    {\n        $this->expectException(\\PhpOffice\\PhpWord\\Exception\\Exception::class);\n        $this->expectExceptionMessage('Could not load the given XML document.');\n        $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/corrupted_main_document_part.docx');\n\n        $xslDomDocument = new DOMDocument();\n        $xslDomDocument->load(__DIR__ . '/_files/xsl/passthrough.xsl');\n\n        /*\n         * We have to use error control below, because \\DOMDocument::loadXML omits warning on failure.\n         * This warning fails the test.\n         */\n        @$templateProcessor->applyXslStyleSheet($xslDomDocument);\n    }\n\n    /**\n     * @covers ::deleteRow\n     * @covers ::getVariables\n     * @covers ::saveAs\n     */\n    public function testDeleteRow(): void\n    {\n        $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/delete-row.docx');\n\n        self::assertEquals(\n            ['deleteMe', 'deleteMeToo'],\n            $templateProcessor->getVariables()\n        );\n\n        $docName = 'delete-row-test-result.docx';\n        $templateProcessor->deleteRow('deleteMe');\n        self::assertEquals(\n            [],\n            $templateProcessor->getVariables()\n        );\n        $templateProcessor->saveAs($docName);\n        $docFound = file_exists($docName);\n        unlink($docName);\n        self::assertTrue($docFound);\n    }\n\n    /**\n     * @covers ::cloneRow\n     * @covers ::saveAs\n     * @covers ::setValue\n     */\n    public function testCloneRow(): void\n    {\n        $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/clone-merge.docx');\n\n        self::assertEquals(\n            ['tableHeader', 'userId', 'userName', 'userLocation'],\n            $templateProcessor->getVariables()\n        );\n\n        $docName = 'clone-test-result.docx';\n        $templateProcessor->setValue('tableHeader', 'ééé');\n        $templateProcessor->cloneRow('userId', 1);\n        $templateProcessor->setValue('userId#1', 'Test');\n        $templateProcessor->saveAs($docName);\n        $docFound = file_exists($docName);\n        unlink($docName);\n        self::assertTrue($docFound);\n    }\n\n    /**\n     * @covers ::cloneRow\n     * @covers ::saveAs\n     * @covers ::setValue\n     */\n    public function testCloneRowWithCustomMacro(): void\n    {\n        $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/clone-merge-with-custom-macro.docx');\n\n        $templateProcessor->setMacroOpeningChars('{#');\n        $templateProcessor->setMacroClosingChars('#}');\n\n        self::assertEquals(\n            ['tableHeader', 'userId', 'userName', 'userLocation'],\n            $templateProcessor->getVariables()\n        );\n\n        $docName = 'clone-test-result.docx';\n        $templateProcessor->setValue('tableHeader', 'ééé');\n        $templateProcessor->cloneRow('userId', 1);\n        $templateProcessor->setValue('userId#1', 'Test');\n        $templateProcessor->saveAs($docName);\n        $docFound = file_exists($docName);\n        unlink($docName);\n        self::assertTrue($docFound);\n    }\n\n    /**\n     * @covers ::cloneRow\n     * @covers ::saveAs\n     * @covers ::setValue\n     */\n    public function testCloneRowAndSetValues(): void\n    {\n        $mainPart = '<w:tbl>\n            <w:tr>\n                <w:tc>\n                    <w:tcPr>\n                        <w:vMerge w:val=\"restart\"/>\n                    </w:tcPr>\n                    <w:p>\n                        <w:r>\n                            <w:t>${userId}</w:t>\n                        </w:r>\n                    </w:p>\n                </w:tc>\n                <w:tc>\n                    <w:p>\n                        <w:r>\n                            <w:t>${userName}</w:t>\n                        </w:r>\n                    </w:p>\n                </w:tc>\n            </w:tr>\n            <w:tr>\n                <w:tc>\n                    <w:tcPr>\n                        <w:vMerge/>\n                    </w:tcPr>\n                    <w:p/>\n                </w:tc>\n                <w:tc>\n                    <w:p>\n                        <w:r>\n                            <w:t>${userLocation}</w:t>\n                        </w:r>\n                    </w:p>\n                </w:tc>\n            </w:tr>\n        </w:tbl>';\n        $templateProcessor = new TestableTemplateProcesor($mainPart);\n\n        self::assertEquals(\n            ['userId', 'userName', 'userLocation'],\n            $templateProcessor->getVariables()\n        );\n\n        $values = [\n            ['userId' => 1, 'userName' => 'Batman', 'userLocation' => 'Gotham City'],\n            ['userId' => 2, 'userName' => 'Superman', 'userLocation' => 'Metropolis'],\n        ];\n        $templateProcessor->setValue('tableHeader', 'My clonable table');\n        $templateProcessor->cloneRowAndSetValues('userId', $values);\n        self::assertStringContainsString('<w:t>Superman</w:t>', $templateProcessor->getMainPart());\n        self::assertStringContainsString('<w:t>Metropolis</w:t>', $templateProcessor->getMainPart());\n    }\n\n    public function testCloneNotExistingRowShouldThrowException(): void\n    {\n        $this->expectException(Exception::class);\n        $mainPart = '<?xml version=\"1.0\" encoding=\"UTF-8\"?><w:p><w:r><w:rPr></w:rPr><w:t>text</w:t></w:r></w:p>';\n        $templateProcessor = new TestableTemplateProcesor($mainPart);\n\n        $templateProcessor->cloneRow('fake_search', 2);\n    }\n\n    /**\n     * @covers ::cloneRow\n     * @covers ::saveAs\n     * @covers ::setValue\n     */\n    public function testCloneRowAndSetValuesWithCustomMacro(): void\n    {\n        $mainPart = '<w:tbl>\n            <w:tr>\n                <w:tc>\n                    <w:tcPr>\n                        <w:vMerge w:val=\"restart\"/>\n                    </w:tcPr>\n                    <w:p>\n                        <w:r>\n                            <w:t>{{userId}}</w:t>\n                        </w:r>\n                    </w:p>\n                </w:tc>\n                <w:tc>\n                    <w:p>\n                        <w:r>\n                            <w:t>{{userName}}</w:t>\n                        </w:r>\n                    </w:p>\n                </w:tc>\n            </w:tr>\n            <w:tr>\n                <w:tc>\n                    <w:tcPr>\n                        <w:vMerge/>\n                    </w:tcPr>\n                    <w:p/>\n                </w:tc>\n                <w:tc>\n                    <w:p>\n                        <w:r>\n                            <w:t>{{userLocation}}</w:t>\n                        </w:r>\n                    </w:p>\n                </w:tc>\n            </w:tr>\n        </w:tbl>';\n        $templateProcessor = new TestableTemplateProcesor($mainPart);\n        $templateProcessor->setMacroOpeningChars('{{');\n        $templateProcessor->setMacroClosingChars('}}');\n\n        self::assertEquals(\n            ['userId', 'userName', 'userLocation'],\n            $templateProcessor->getVariables()\n        );\n\n        $values = [\n            ['userId' => 1, 'userName' => 'Batman', 'userLocation' => 'Gotham City'],\n            ['userId' => 2, 'userName' => 'Superman', 'userLocation' => 'Metropolis'],\n        ];\n        $templateProcessor->setValue('tableHeader', 'My clonable table');\n        $templateProcessor->cloneRowAndSetValues('userId', $values);\n        self::assertStringContainsString('<w:t>Superman</w:t>', $templateProcessor->getMainPart());\n        self::assertStringContainsString('<w:t>Metropolis</w:t>', $templateProcessor->getMainPart());\n    }\n\n    /**\n     * @covers ::saveAs\n     * @covers ::setValue\n     */\n    public function testMacrosCanBeReplacedInHeaderAndFooter(): void\n    {\n        $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/header-footer.docx');\n\n        self::assertEquals(['documentContent', 'headerValue:100:100', 'footerValue'], $templateProcessor->getVariables());\n\n        $macroNames = ['headerValue', 'documentContent', 'footerValue'];\n        $macroValues = ['Header Value', 'Document text.', 'Footer Value'];\n        $templateProcessor->setValue($macroNames, $macroValues);\n\n        $docName = 'header-footer-test-result.docx';\n        $templateProcessor->saveAs($docName);\n        $docFound = file_exists($docName);\n        unlink($docName);\n        self::assertTrue($docFound);\n    }\n\n    /**\n     * @covers ::saveAs\n     * @covers ::setValue\n     */\n    public function testCustomMacrosCanBeReplacedInHeaderAndFooter(): void\n    {\n        $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/header-footer-with-custom-macro.docx');\n        $templateProcessor->setMacroOpeningChars('{{');\n        $templateProcessor->setMacroClosingChars('}}');\n\n        self::assertEquals(['documentContent', 'headerValue:100:100', 'footerValue'], $templateProcessor->getVariables());\n\n        $macroNames = ['headerValue', 'documentContent', 'footerValue'];\n        $macroValues = ['Header Value', 'Document text.', 'Footer Value'];\n        $templateProcessor->setValue($macroNames, $macroValues);\n\n        $docName = 'header-footer-test-result.docx';\n        $templateProcessor->saveAs($docName);\n        $docFound = file_exists($docName);\n        unlink($docName);\n        self::assertTrue($docFound);\n    }\n\n    /**\n     * @covers ::setValue\n     */\n    public function testSetValue(): void\n    {\n        $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/clone-merge.docx');\n        Settings::setOutputEscapingEnabled(true);\n        $helloworld = \"hello\\nworld\";\n        $templateProcessor->setValue('userName', $helloworld);\n        self::assertEquals(\n            ['tableHeader', 'userId', 'userLocation'],\n            $templateProcessor->getVariables()\n        );\n    }\n\n    /**\n     * @covers ::setValue\n     */\n    public function testSetValueWithCustomMacro(): void\n    {\n        $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/clone-merge-with-custom-macro.docx');\n        $templateProcessor->setMacroChars('{#', '#}');\n        Settings::setOutputEscapingEnabled(true);\n        $helloworld = \"hello\\nworld\";\n        $templateProcessor->setValue('userName', $helloworld);\n        self::assertEquals(\n            ['tableHeader', 'userId', 'userLocation'],\n            $templateProcessor->getVariables()\n        );\n    }\n\n    public function testSetComplexValue(): void\n    {\n        $title = new TextRun();\n        $title->addText('This is my title');\n\n        $firstname = new Text('Donald');\n        $lastname = new Text('Duck');\n\n        $mainPart = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n        <w:p>\n            <w:r>\n                <w:t xml:space=\"preserve\">Hello ${document-title}</w:t>\n            </w:r>\n        </w:p>\n        <w:p>\n            <w:r>\n                <w:t xml:space=\"preserve\">Hello ${firstname} ${lastname}</w:t>\n            </w:r>\n        </w:p>';\n\n        $result = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n        <w:p>\n            <w:pPr/>\n            <w:r>\n                <w:rPr/>\n                <w:t xml:space=\"preserve\">This is my title</w:t>\n            </w:r>\n        </w:p>\n        <w:p>\n            <w:r>\n                <w:t xml:space=\"preserve\">Hello </w:t>\n            </w:r>\n            <w:r>\n                <w:rPr/>\n                <w:t xml:space=\"preserve\">Donald</w:t>\n            </w:r>\n            <w:r>\n                <w:t xml:space=\"preserve\"> </w:t>\n            </w:r>\n            <w:r>\n                <w:rPr/>\n                <w:t xml:space=\"preserve\">Duck</w:t>\n            </w:r>\n        </w:p>';\n\n        $templateProcessor = new TestableTemplateProcesor($mainPart);\n        $templateProcessor->setComplexBlock('document-title', $title);\n        $templateProcessor->setComplexValue('firstname', $firstname);\n        $templateProcessor->setComplexValue('lastname', $lastname);\n\n        self::assertEquals(preg_replace('/>\\s+</', '><', $result), preg_replace('/>\\s+</', '><', $templateProcessor->getMainPart()));\n    }\n\n    public function testSetComplexValueWithCustomMacro(): void\n    {\n        $title = new TextRun();\n        $title->addText('This is my title');\n\n        $firstname = new Text('Donald');\n        $lastname = new Text('Duck');\n\n        $mainPart = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n        <w:p>\n            <w:r>\n                <w:t xml:space=\"preserve\">Hello {{document-title}}</w:t>\n            </w:r>\n        </w:p>\n        <w:p>\n            <w:r>\n                <w:t xml:space=\"preserve\">Hello {{firstname}} {{lastname}}</w:t>\n            </w:r>\n        </w:p>';\n\n        $result = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n        <w:p>\n            <w:pPr/>\n            <w:r>\n                <w:rPr/>\n                <w:t xml:space=\"preserve\">This is my title</w:t>\n            </w:r>\n        </w:p>\n        <w:p>\n            <w:r>\n                <w:t xml:space=\"preserve\">Hello </w:t>\n            </w:r>\n            <w:r>\n                <w:rPr/>\n                <w:t xml:space=\"preserve\">Donald</w:t>\n            </w:r>\n            <w:r>\n                <w:t xml:space=\"preserve\"> </w:t>\n            </w:r>\n            <w:r>\n                <w:rPr/>\n                <w:t xml:space=\"preserve\">Duck</w:t>\n            </w:r>\n        </w:p>';\n\n        $templateProcessor = new TestableTemplateProcesor($mainPart);\n        $templateProcessor->setMacroChars('{{', '}}');\n        $templateProcessor->setComplexBlock('document-title', $title);\n        $templateProcessor->setComplexValue('firstname', $firstname);\n        $templateProcessor->setComplexValue('lastname', $lastname);\n\n        self::assertEquals(preg_replace('/>\\s+</', '><', $result), preg_replace('/>\\s+</', '><', $templateProcessor->getMainPart()));\n    }\n\n    /**\n     * @covers ::setValues\n     */\n    public function testSetValues(): void\n    {\n        $mainPart = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n        <w:p>\n            <w:r>\n                <w:t xml:space=\"preserve\">Hello ${firstname} ${lastname}</w:t>\n            </w:r>\n        </w:p>\n        <w:p>\n            <w:r>\n                <w:t xml:space=\"preserve\">Hello ${firstname} ${lastname}</w:t>\n            </w:r>\n        </w:p>\n        <w:p>\n            <w:r>\n                <w:t xml:space=\"preserve\">Hello ${firstname} ${lastname}</w:t>\n            </w:r>\n        </w:p>\n        ';\n\n        $templateProcessor = new TestableTemplateProcesor($mainPart);\n        $templateProcessor->setValues(['firstname' => 'John', 'lastname' => 'Doe']);\n        self::assertStringContainsString('Hello John Doe', $templateProcessor->getMainPart());\n        self::assertStringNotContainsString('Hello ${firstname} ${lastname}', $templateProcessor->getMainPart());\n\n        // test with a specific limit that is lower than the number of replacements\n        $templateProcessor = new TestableTemplateProcesor($mainPart);\n        $templateProcessor->setValues(['firstname' => 'Jane', 'lastname' => 'Smith'], 2);\n        $variablesCounts = $templateProcessor->getVariableCount();\n\n        self::assertStringContainsString('Hello Jane Smith', $templateProcessor->getMainPart());\n        self::assertStringContainsString('Hello ${firstname} ${lastname}', $templateProcessor->getMainPart());\n        self::assertEquals(1, $variablesCounts['firstname']);\n        self::assertEquals(1, $variablesCounts['lastname']);\n\n        // test with a limit for only one replacement\n        $templateProcessor = new TestableTemplateProcesor($mainPart);\n        $templateProcessor->setValues(['firstname' => 'Alice', 'lastname' => 'Wonderland'], 1);\n        $variablesCounts = $templateProcessor->getVariableCount();\n\n        self::assertStringContainsString('Hello Alice Wonderland', $templateProcessor->getMainPart());\n        self::assertStringContainsString('Hello ${firstname} ${lastname}', $templateProcessor->getMainPart());\n        self::assertEquals(2, $variablesCounts['firstname']);\n        self::assertEquals(2, $variablesCounts['lastname']);\n\n        // Test with a limit of 0 for a result with no replacements\n        $templateProcessor = new TestableTemplateProcesor($mainPart);\n        $templateProcessor->setValues(['firstname' => 'Test', 'lastname' => 'User'], 0);\n        $variablesCounts = $templateProcessor->getVariableCount();\n\n        self::assertStringContainsString('Hello ${firstname} ${lastname}', $templateProcessor->getMainPart());\n        self::assertStringNotContainsString('Hello Test User', $templateProcessor->getMainPart());\n        self::assertEquals(3, $variablesCounts['firstname']);\n        self::assertEquals(3, $variablesCounts['lastname']);\n    }\n\n    /**\n     * @covers ::setValues\n     */\n    public function testSetValuesMultiLine(): void\n    {\n        $mainPart = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n        <w:p>\n            <w:r>\n                <w:t xml:space=\"preserve\">Address: ${address}</w:t>\n            </w:r>\n        </w:p>';\n\n        $templateProcessor = new TestableTemplateProcesor($mainPart);\n        $templateProcessor->setValues(['address' => \"Peter Pan\\nNeverland\"]);\n\n        self::assertStringContainsString('Address: Peter Pan</w:t><w:br/><w:t>Neverland', $templateProcessor->getMainPart());\n    }\n\n    /**\n     * @covers ::setValues\n     */\n    public function testSetValuesWithCustomMacro(): void\n    {\n        $mainPart = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n        <w:p>\n            <w:r>\n                <w:t xml:space=\"preserve\">Hello {#firstname#} {#lastname#}</w:t>\n            </w:r>\n        </w:p>';\n\n        $templateProcessor = new TestableTemplateProcesor($mainPart);\n        $templateProcessor->setMacroChars('{#', '#}');\n        $templateProcessor->setValues(['firstname' => 'John', 'lastname' => 'Doe']);\n\n        self::assertStringContainsString('Hello John Doe', $templateProcessor->getMainPart());\n    }\n\n    /**\n     * @covers ::setCheckbox\n     */\n    public function testSetCheckbox(): void\n    {\n        $mainPart = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n        <w:p>\n            <w:sdt>\n                <w:sdtPr>\n                    <w:alias w:val=\"${checkbox}\"/>\n                    <w14:checkbox>\n                        <w14:checked w14:val=\"0\"/>\n                    </w14:checkbox>\n                </w:sdtPr>\n                <w:sdtContent>\n                    <w:r>\n                        <w:t>☐</w:t>\n                    </w:r>\n                </w:sdtContent>\n            </w:sdt>\n        </w:p>\n        <w:p>\n            <w:sdt>\n                <w:sdtPr>\n                    <w:alias w:val=\"${checkbox2}\"/>\n                    <w14:checkbox>\n                        <w14:checked w14:val=\"1\"/>\n                    </w14:checkbox>\n                </w:sdtPr>\n                <w:sdtContent>\n                    <w:r>\n                        <w:t>☒</w:t>\n                    </w:r>\n                </w:sdtContent>\n            </w:sdt>\n        </w:p>';\n\n        $result = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n        <w:p>\n            <w:sdt>\n                <w:sdtPr>\n                    <w:alias w:val=\"${checkbox}\"/>\n                    <w14:checkbox>\n                        <w14:checked w14:val=\"1\"/>\n                    </w14:checkbox>\n                </w:sdtPr>\n                <w:sdtContent>\n                    <w:r>\n                        <w:t>☒</w:t>\n                    </w:r>\n                </w:sdtContent>\n            </w:sdt>\n        </w:p>\n        <w:p>\n            <w:sdt>\n                <w:sdtPr>\n                    <w:alias w:val=\"${checkbox2}\"/>\n                    <w14:checkbox>\n                        <w14:checked w14:val=\"0\"/>\n                    </w14:checkbox>\n                </w:sdtPr>\n                <w:sdtContent>\n                    <w:r>\n                        <w:t>☐</w:t>\n                    </w:r>\n                </w:sdtContent>\n            </w:sdt>\n        </w:p>';\n\n        $templateProcessor = new TestableTemplateProcesor($mainPart);\n        $templateProcessor->setCheckbox('checkbox', true);\n        $templateProcessor->setCheckbox('checkbox2', false);\n\n        self::assertEquals(preg_replace('/>\\s+</', '><', $result), preg_replace('/>\\s+</', '><', $templateProcessor->getMainPart()));\n    }\n\n    /**\n     * @covers ::setCheckbox\n     */\n    public function testSetCheckboxWithCustomMacro(): void\n    {\n        $mainPart = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n        <w:p>\n            <w:sdt>\n                <w:sdtPr>\n                    <w:alias w:val=\"{#checkbox#}\"/>\n                    <w14:checkbox>\n                        <w14:checked w14:val=\"0\"/>\n                    </w14:checkbox>\n                </w:sdtPr>\n                <w:sdtContent>\n                    <w:r>\n                        <w:t>☐</w:t>\n                    </w:r>\n                </w:sdtContent>\n            </w:sdt>\n        </w:p>\n        <w:p>\n            <w:sdt>\n                <w:sdtPr>\n                    <w:alias w:val=\"{#checkbox2#}\"/>\n                    <w14:checkbox>\n                        <w14:checked w14:val=\"1\"/>\n                    </w14:checkbox>\n                </w:sdtPr>\n                <w:sdtContent>\n                    <w:r>\n                        <w:t>☒</w:t>\n                    </w:r>\n                </w:sdtContent>\n            </w:sdt>\n        </w:p>';\n\n        $result = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n        <w:p>\n            <w:sdt>\n                <w:sdtPr>\n                    <w:alias w:val=\"{#checkbox#}\"/>\n                    <w14:checkbox>\n                        <w14:checked w14:val=\"1\"/>\n                    </w14:checkbox>\n                </w:sdtPr>\n                <w:sdtContent>\n                    <w:r>\n                        <w:t>☒</w:t>\n                    </w:r>\n                </w:sdtContent>\n            </w:sdt>\n        </w:p>\n        <w:p>\n            <w:sdt>\n                <w:sdtPr>\n                    <w:alias w:val=\"{#checkbox2#}\"/>\n                    <w14:checkbox>\n                        <w14:checked w14:val=\"0\"/>\n                    </w14:checkbox>\n                </w:sdtPr>\n                <w:sdtContent>\n                    <w:r>\n                        <w:t>☐</w:t>\n                    </w:r>\n                </w:sdtContent>\n            </w:sdt>\n        </w:p>';\n\n        $templateProcessor = new TestableTemplateProcesor($mainPart);\n        $templateProcessor->setMacroChars('{#', '#}');\n        $templateProcessor->setCheckbox('checkbox', true);\n        $templateProcessor->setCheckbox('checkbox2', false);\n\n        self::assertEquals(preg_replace('/>\\s+</', '><', $result), preg_replace('/>\\s+</', '><', $templateProcessor->getMainPart()));\n    }\n\n    /**\n     * @covers ::setImageValue\n     */\n    public function testSetImageValue(): void\n    {\n        $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/header-footer.docx');\n        $imagePath = __DIR__ . '/_files/images/earth.jpg';\n\n        $variablesReplace = [\n            'headerValue' => function () use ($imagePath) {\n                return $imagePath;\n            },\n            'documentContent' => ['path' => $imagePath, 'width' => 500, 'height' => 500],\n            'footerValue' => ['path' => $imagePath, 'width' => 100, 'height' => 50, 'ratio' => false],\n        ];\n        $templateProcessor->setImageValue(array_keys($variablesReplace), $variablesReplace);\n\n        $docName = 'header-footer-images-test-result.docx';\n        $templateProcessor->saveAs($docName);\n\n        self::assertFileExists($docName, \"Generated file '{$docName}' not found!\");\n\n        $expectedDocumentZip = new ZipArchive();\n        $expectedDocumentZip->open($docName);\n        $expectedContentTypesXml = $expectedDocumentZip->getFromName('[Content_Types].xml');\n        $expectedDocumentRelationsXml = $expectedDocumentZip->getFromName('word/_rels/document.xml.rels');\n        $expectedHeaderRelationsXml = $expectedDocumentZip->getFromName('word/_rels/header1.xml.rels');\n        $expectedFooterRelationsXml = $expectedDocumentZip->getFromName('word/_rels/footer1.xml.rels');\n        $expectedMainPartXml = $expectedDocumentZip->getFromName('word/document.xml');\n        $expectedHeaderPartXml = $expectedDocumentZip->getFromName('word/header1.xml');\n        $expectedFooterPartXml = $expectedDocumentZip->getFromName('word/footer1.xml');\n        $expectedImage = $expectedDocumentZip->getFromName('word/media/image_rId11_document.jpeg');\n        if (false === $expectedDocumentZip->close()) {\n            throw new Exception(\"Could not close zip file \\\"{$docName}\\\".\");\n        }\n\n        self::assertNotEmpty($expectedImage, 'Embed image doesn\\'t found.');\n        self::assertStringContainsString('/word/media/image_rId11_document.jpeg', $expectedContentTypesXml, '[Content_Types].xml missed \"/word/media/image5_document.jpeg\"');\n        self::assertStringContainsString('/word/_rels/header1.xml.rels', $expectedContentTypesXml, '[Content_Types].xml missed \"/word/_rels/header1.xml.rels\"');\n        self::assertStringContainsString('/word/_rels/footer1.xml.rels', $expectedContentTypesXml, '[Content_Types].xml missed \"/word/_rels/footer1.xml.rels\"');\n        self::assertStringNotContainsString('${documentContent}', $expectedMainPartXml, 'word/document.xml has no image.');\n        self::assertStringNotContainsString('${headerValue}', $expectedHeaderPartXml, 'word/header1.xml has no image.');\n        self::assertStringNotContainsString('${footerValue}', $expectedFooterPartXml, 'word/footer1.xml has no image.');\n        self::assertStringContainsString('media/image_rId11_document.jpeg', $expectedDocumentRelationsXml, 'word/_rels/document.xml.rels missed \"media/image5_document.jpeg\"');\n        self::assertStringContainsString('media/image_rId11_document.jpeg', $expectedHeaderRelationsXml, 'word/_rels/header1.xml.rels missed \"media/image5_document.jpeg\"');\n        self::assertStringContainsString('media/image_rId11_document.jpeg', $expectedFooterRelationsXml, 'word/_rels/footer1.xml.rels missed \"media/image5_document.jpeg\"');\n\n        unlink($docName);\n\n        // dynamic generated doc\n        $testFileName = 'images-test-sample.docx';\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $section->addText('${Test:width=100:ratio=true}');\n        $objWriter = IOFactory::createWriter($phpWord, 'Word2007');\n        $objWriter->save($testFileName);\n        self::assertFileExists($testFileName, \"Generated file '{$testFileName}' not found!\");\n\n        $resultFileName = 'images-test-result.docx';\n        $templateProcessor = new TemplateProcessor($testFileName);\n        unlink($testFileName);\n        $templateProcessor->setImageValue('Test', $imagePath);\n        $templateProcessor->setImageValue('Test1', $imagePath);\n        $templateProcessor->setImageValue('Test2', $imagePath);\n        $templateProcessor->saveAs($resultFileName);\n        self::assertFileExists($resultFileName, \"Generated file '{$resultFileName}' not found!\");\n\n        $expectedDocumentZip = new ZipArchive();\n        $expectedDocumentZip->open($resultFileName);\n        $expectedMainPartXml = $expectedDocumentZip->getFromName('word/document.xml');\n        if (false === $expectedDocumentZip->close()) {\n            throw new Exception(\"Could not close zip file \\\"{$resultFileName}\\\".\");\n        }\n        unlink($resultFileName);\n\n        self::assertStringNotContainsString('${Test}', $expectedMainPartXml, 'word/document.xml has no image.');\n    }\n\n    /**\n     * @covers ::cloneBlock\n     * @covers ::deleteBlock\n     * @covers ::saveAs\n     */\n    public function testCloneDeleteBlock(): void\n    {\n        $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/clone-delete-block.docx');\n\n        self::assertEquals(\n            ['DELETEME', '/DELETEME', 'CLONEME', 'blockVariable', '/CLONEME'],\n            $templateProcessor->getVariables()\n        );\n\n        $docName = 'clone-delete-block-result.docx';\n        $templateProcessor->cloneBlock('CLONEME', 3);\n        $templateProcessor->deleteBlock('DELETEME');\n        $templateProcessor->setValue('blockVariable#3', 'Test');\n        $templateProcessor->saveAs($docName);\n        $docFound = file_exists($docName);\n        unlink($docName);\n        self::assertTrue($docFound);\n    }\n\n    /**\n     * @covers ::getVariableCount\n     */\n    public function testGetVariableCountCountsHowManyTimesEachPlaceholderIsPresent(): void\n    {\n        // create template with placeholders\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $header = $section->addHeader();\n        $header->addText('${a_field_that_is_present_three_times}');\n        $footer = $section->addFooter();\n        $footer->addText('${a_field_that_is_present_twice}');\n        $section2 = $phpWord->addSection();\n        $section2->addText('\n                ${a_field_that_is_present_one_time}\n                  ${a_field_that_is_present_three_times}\n              ${a_field_that_is_present_twice}\n                   ${a_field_that_is_present_three_times}\n        ');\n        $objWriter = IOFactory::createWriter($phpWord);\n        $templatePath = 'test.docx';\n        $objWriter->save($templatePath);\n\n        $templateProcessor = $this->getTemplateProcessor($templatePath);\n        $variableCount = $templateProcessor->getVariableCount();\n        unlink($templatePath);\n\n        self::assertEquals(\n            [\n                'a_field_that_is_present_three_times' => 3,\n                'a_field_that_is_present_twice' => 2,\n                'a_field_that_is_present_one_time' => 1,\n            ],\n            $variableCount\n        );\n    }\n\n    /**\n     * @covers ::getVariableCount\n     */\n    public function testGetVariableCountCountsHowManyTimesEachPlaceholderIsPresentWithCustomMacro(): void\n    {\n        // create template with placeholders\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $header = $section->addHeader();\n        $header->addText('{{a_field_that_is_present_three_times}}');\n        $footer = $section->addFooter();\n        $footer->addText('{{a_field_that_is_present_twice}}');\n        $section2 = $phpWord->addSection();\n        $section2->addText('\n                {{a_field_that_is_present_one_time}}\n                  {{a_field_that_is_present_three_times}}\n              {{a_field_that_is_present_twice}}\n                   {{a_field_that_is_present_three_times}}\n        ');\n        $objWriter = IOFactory::createWriter($phpWord);\n        $templatePath = 'test.docx';\n        $objWriter->save($templatePath);\n\n        $templateProcessor = $this->getTemplateProcessor($templatePath);\n        $templateProcessor->setMacroChars('{{', '}}');\n        $variableCount = $templateProcessor->getVariableCount();\n        unlink($templatePath);\n\n        self::assertEquals(\n            [\n                'a_field_that_is_present_three_times' => 3,\n                'a_field_that_is_present_twice' => 2,\n                'a_field_that_is_present_one_time' => 1,\n            ],\n            $variableCount\n        );\n    }\n\n    /**\n     * @covers ::cloneBlock\n     */\n    public function testCloneBlockCanCloneABlockTwice(): void\n    {\n        // create template with placeholders and block\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $documentElements = [\n            'Title: ${title}',\n            '${subreport}',\n            '${subreport.id}: ${subreport.text}. ',\n            '${/subreport}',\n        ];\n        foreach ($documentElements as $documentElement) {\n            $section->addText($documentElement);\n        }\n\n        $objWriter = IOFactory::createWriter($phpWord);\n        $templatePath = 'test.docx';\n        $objWriter->save($templatePath);\n\n        // replace placeholders and save the file\n        $templateProcessor = $this->getTemplateProcessor($templatePath);\n        $templateProcessor->setValue('title', 'Some title');\n        $templateProcessor->cloneBlock('subreport', 2);\n        $templateProcessor->setValue('subreport.id', '123', 1);\n        $templateProcessor->setValue('subreport.text', 'Some text', 1);\n        $templateProcessor->setValue('subreport.id', '456', 1);\n        $templateProcessor->setValue('subreport.text', 'Some other text', 1);\n        $templateProcessor->saveAs($templatePath);\n\n        // assert the block has been cloned twice\n        // and the placeholders have been replaced correctly\n        $phpWord = IOFactory::load($templatePath);\n        $sections = $phpWord->getSections();\n        /** @var TextRun[] $actualElements */\n        $actualElements = $sections[0]->getElements();\n        unlink($templatePath);\n        $expectedElements = [\n            'Title: Some title',\n            '123: Some text. ',\n            '456: Some other text. ',\n        ];\n        self::assertCount(count($expectedElements), $actualElements);\n        foreach ($expectedElements as $i => $expectedElement) {\n            self::assertEquals(\n                $expectedElement,\n                $actualElements[$i]->getElement(0)->getText()\n            );\n        }\n    }\n\n    /**\n     * @covers ::cloneBlock\n     */\n    public function testCloneBlockCanCloneABlockTwiceWithCustomMacro(): void\n    {\n        // create template with placeholders and block\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $documentElements = [\n            'Title: {{title}}',\n            '{{subreport}}',\n            '{{subreport.id}}: {{subreport.text}}. ',\n            '{{/subreport}}',\n        ];\n        foreach ($documentElements as $documentElement) {\n            $section->addText($documentElement);\n        }\n\n        $objWriter = IOFactory::createWriter($phpWord);\n        $templatePath = 'test.docx';\n        $objWriter->save($templatePath);\n\n        // replace placeholders and save the file\n        $templateProcessor = $this->getTemplateProcessor($templatePath);\n        $templateProcessor->setMacroChars('{{', '}}');\n        $templateProcessor->setValue('title', 'Some title');\n        $templateProcessor->cloneBlock('subreport', 2);\n        $templateProcessor->setValue('subreport.id', '123', 1);\n        $templateProcessor->setValue('subreport.text', 'Some text', 1);\n        $templateProcessor->setValue('subreport.id', '456', 1);\n        $templateProcessor->setValue('subreport.text', 'Some other text', 1);\n        $templateProcessor->saveAs($templatePath);\n\n        // assert the block has been cloned twice\n        // and the placeholders have been replaced correctly\n        $phpWord = IOFactory::load($templatePath);\n        $sections = $phpWord->getSections();\n        /** @var TextRun[] $actualElements */\n        $actualElements = $sections[0]->getElements();\n\n        unlink($templatePath);\n        $expectedElements = [\n            'Title: Some title',\n            '123: Some text. ',\n            '456: Some other text. ',\n        ];\n        self::assertCount(count($expectedElements), $actualElements);\n        foreach ($expectedElements as $i => $expectedElement) {\n            self::assertEquals(\n                $expectedElement,\n                $actualElements[$i]->getElement(0)->getText()\n            );\n        }\n    }\n\n    /**\n     * @covers ::cloneBlock\n     */\n    public function testCloneBlock(): void\n    {\n        $mainPart = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n        <w:p>\n            <w:r>\n                <w:rPr></w:rPr>\n                <w:t>${CLONEME}</w:t>\n            </w:r>\n        </w:p>\n        <w:p>\n            <w:r>\n                <w:t xml:space=\"preserve\">This block will be cloned with ${variable}</w:t>\n            </w:r>\n        </w:p>\n        <w:p>\n            <w:r w:rsidRPr=\"00204FED\">\n                <w:t>${/CLONEME}</w:t>\n            </w:r>\n        </w:p>';\n\n        $templateProcessor = new TestableTemplateProcesor($mainPart);\n        $templateProcessor->cloneBlock('CLONEME', 3);\n\n        self::assertEquals(3, substr_count($templateProcessor->getMainPart(), 'This block will be cloned with ${variable}'));\n    }\n\n    /**\n     * @covers ::cloneBlock\n     */\n    public function testCloneBlockWithCustomMacro(): void\n    {\n        $mainPart = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n        <w:p>\n            <w:r>\n                <w:rPr></w:rPr>\n                <w:t>{{CLONEME}}</w:t>\n            </w:r>\n        </w:p>\n        <w:p>\n            <w:r>\n                <w:t xml:space=\"preserve\">This block will be cloned with {{variable}}</w:t>\n            </w:r>\n        </w:p>\n        <w:p>\n            <w:r w:rsidRPr=\"00204FED\">\n                <w:t>{{/CLONEME}}</w:t>\n            </w:r>\n        </w:p>';\n\n        $templateProcessor = new TestableTemplateProcesor($mainPart);\n        $templateProcessor->setMacroChars('{{', '}}');\n        $templateProcessor->cloneBlock('CLONEME', 3);\n\n        self::assertEquals(3, substr_count($templateProcessor->getMainPart(), 'This block will be cloned with {{variable}}'));\n    }\n\n    /**\n     * @covers ::cloneBlock\n     */\n    public function testCloneBlockWithVariables(): void\n    {\n        $mainPart = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n        <w:p>\n            <w:r>\n                <w:rPr></w:rPr>\n                <w:t>${CLONEME}</w:t>\n            </w:r>\n        </w:p>\n        <w:p>\n            <w:r>\n                <w:t xml:space=\"preserve\">Address ${address}, Street ${street}</w:t>\n            </w:r>\n        </w:p>\n        <w:p>\n            <w:r w:rsidRPr=\"00204FED\">\n                <w:t>${/CLONEME}</w:t>\n            </w:r>\n        </w:p>';\n\n        $templateProcessor = new TestableTemplateProcesor($mainPart);\n        $templateProcessor->cloneBlock('CLONEME', 3, true, true);\n\n        self::assertStringContainsString('Address ${address#1}, Street ${street#1}', $templateProcessor->getMainPart());\n        self::assertStringContainsString('Address ${address#2}, Street ${street#2}', $templateProcessor->getMainPart());\n        self::assertStringContainsString('Address ${address#3}, Street ${street#3}', $templateProcessor->getMainPart());\n    }\n\n    /**\n     * @covers ::cloneBlock\n     */\n    public function testCloneBlockWithVariablesAndCustomMacro(): void\n    {\n        $mainPart = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n        <w:p>\n            <w:r>\n                <w:rPr></w:rPr>\n                <w:t>{{CLONEME}}</w:t>\n            </w:r>\n        </w:p>\n        <w:p>\n            <w:r>\n                <w:t xml:space=\"preserve\">Address {{address}}, Street {{street}}</w:t>\n            </w:r>\n        </w:p>\n        <w:p>\n            <w:r w:rsidRPr=\"00204FED\">\n                <w:t>{{/CLONEME}}</w:t>\n            </w:r>\n        </w:p>';\n\n        $templateProcessor = new TestableTemplateProcesor($mainPart);\n        $templateProcessor->setMacroChars('{{', '}}');\n        $templateProcessor->cloneBlock('CLONEME', 3, true, true);\n\n        self::assertStringContainsString('Address {{address#1}}, Street {{street#1}}', $templateProcessor->getMainPart());\n        self::assertStringContainsString('Address {{address#2}}, Street {{street#2}}', $templateProcessor->getMainPart());\n        self::assertStringContainsString('Address {{address#3}}, Street {{street#3}}', $templateProcessor->getMainPart());\n    }\n\n    public function testCloneBlockWithVariableReplacements(): void\n    {\n        $mainPart = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n        <w:p>\n            <w:r>\n                <w:rPr></w:rPr>\n                <w:t>${CLONEME}</w:t>\n            </w:r>\n        </w:p>\n        <w:p>\n            <w:r>\n                <w:t xml:space=\"preserve\">City: ${city}, Street: ${street}</w:t>\n            </w:r>\n        </w:p>\n        <w:p>\n            <w:r w:rsidRPr=\"00204FED\">\n                <w:t>${/CLONEME}</w:t>\n            </w:r>\n        </w:p>';\n\n        $replacements = [\n            ['city' => 'London', 'street' => 'Baker Street'],\n            ['city' => 'New York', 'street' => '5th Avenue'],\n            ['city' => 'Rome', 'street' => 'Via della Conciliazione'],\n        ];\n        $templateProcessor = new TestableTemplateProcesor($mainPart);\n        $templateProcessor->cloneBlock('CLONEME', 0, true, false, $replacements);\n\n        self::assertStringContainsString('City: London, Street: Baker Street', $templateProcessor->getMainPart());\n        self::assertStringContainsString('City: New York, Street: 5th Avenue', $templateProcessor->getMainPart());\n        self::assertStringContainsString('City: Rome, Street: Via della Conciliazione', $templateProcessor->getMainPart());\n    }\n\n    public function testCloneBlockWithVariableReplacementsAndCustomMacro(): void\n    {\n        $mainPart = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n        <w:p>\n            <w:r>\n                <w:rPr></w:rPr>\n                <w:t>{{CLONEME}}</w:t>\n            </w:r>\n        </w:p>\n        <w:p>\n            <w:r>\n                <w:t xml:space=\"preserve\">City: {{city}}, Street: {{street}}</w:t>\n            </w:r>\n        </w:p>\n        <w:p>\n            <w:r w:rsidRPr=\"00204FED\">\n                <w:t>{{/CLONEME}}</w:t>\n            </w:r>\n        </w:p>';\n\n        $replacements = [\n            ['city' => 'London', 'street' => 'Baker Street'],\n            ['city' => 'New York', 'street' => '5th Avenue'],\n            ['city' => 'Rome', 'street' => 'Via della Conciliazione'],\n        ];\n        $templateProcessor = new TestableTemplateProcesor($mainPart);\n        $templateProcessor->setMacroChars('{{', '}}');\n        $templateProcessor->cloneBlock('CLONEME', 0, true, false, $replacements);\n\n        self::assertStringContainsString('City: London, Street: Baker Street', $templateProcessor->getMainPart());\n        self::assertStringContainsString('City: New York, Street: 5th Avenue', $templateProcessor->getMainPart());\n        self::assertStringContainsString('City: Rome, Street: Via della Conciliazione', $templateProcessor->getMainPart());\n    }\n\n    /**\n     * Template macros can be fixed.\n     *\n     * @covers ::fixBrokenMacros\n     */\n    public function testFixBrokenMacros(): void\n    {\n        $templateProcessor = new TestableTemplateProcesor();\n\n        $fixed = $templateProcessor->fixBrokenMacros('<w:r><w:t>normal text</w:t></w:r>');\n        self::assertEquals('<w:r><w:t>normal text</w:t></w:r>', $fixed);\n\n        $fixed = $templateProcessor->fixBrokenMacros('<w:r><w:t>${documentContent}</w:t></w:r>');\n        self::assertEquals('<w:r><w:t>${documentContent}</w:t></w:r>', $fixed);\n\n        $fixed = $templateProcessor->fixBrokenMacros('<w:r><w:t>$</w:t><w:t>{documentContent}</w:t></w:r>');\n        self::assertEquals('<w:r><w:t>${documentContent}</w:t></w:r>', $fixed);\n\n        $fixed = $templateProcessor->fixBrokenMacros('<w:r><w:t>$1500</w:t><w:t>${documentContent}</w:t></w:r>');\n        self::assertEquals('<w:r><w:t>$1500</w:t><w:t>${documentContent}</w:t></w:r>', $fixed);\n\n        $fixed = $templateProcessor->fixBrokenMacros('<w:r><w:t>$1500</w:t><w:t>$</w:t><w:t>{documentContent}</w:t></w:r>');\n        self::assertEquals('<w:r><w:t>$1500</w:t><w:t>${documentContent}</w:t></w:r>', $fixed);\n\n        $fixed = $templateProcessor->fixBrokenMacros('<w:r><w:t>25$ plus some info {hint}</w:t></w:r>');\n        self::assertEquals('<w:r><w:t>25$ plus some info {hint}</w:t></w:r>', $fixed);\n\n        $fixed = $templateProcessor->fixBrokenMacros('<w:t>$</w:t></w:r><w:bookmarkStart w:id=\"0\" w:name=\"_GoBack\"/><w:bookmarkEnd w:id=\"0\"/><w:r><w:t xml:space=\"preserve\">15,000.00. </w:t></w:r><w:r w:rsidR=\"0056499B\"><w:t>$</w:t></w:r><w:r w:rsidR=\"00573DFD\" w:rsidRPr=\"00573DFD\"><w:rPr><w:iCs/></w:rPr><w:t>{</w:t></w:r><w:proofErr w:type=\"spellStart\"/><w:r w:rsidR=\"00573DFD\" w:rsidRPr=\"00573DFD\"><w:rPr><w:iCs/></w:rPr><w:t>variable_name</w:t></w:r><w:proofErr w:type=\"spellEnd\"/><w:r w:rsidR=\"00573DFD\" w:rsidRPr=\"00573DFD\"><w:rPr><w:iCs/></w:rPr><w:t>}</w:t></w:r>');\n        self::assertEquals('<w:t>$</w:t></w:r><w:bookmarkStart w:id=\"0\" w:name=\"_GoBack\"/><w:bookmarkEnd w:id=\"0\"/><w:r><w:t xml:space=\"preserve\">15,000.00. </w:t></w:r><w:r w:rsidR=\"0056499B\"><w:t>${variable_name}</w:t></w:r>', $fixed);\n    }\n\n    /**\n     * Template macros can be fixed even with cutome macro.\n     *\n     * @covers ::fixBrokenMacros\n     */\n    public function testFixBrokenMacrosWithCustomMacro(): void\n    {\n        $templateProcessor = new TestableTemplateProcesor();\n        $templateProcessor->setMacroChars('{{', '}}');\n\n        $fixed = $templateProcessor->fixBrokenMacros('<w:r><w:t>normal text</w:t></w:r>');\n        self::assertEquals('<w:r><w:t>normal text</w:t></w:r>', $fixed);\n\n        $fixed = $templateProcessor->fixBrokenMacros('<w:r><w:t>{{documentContent}}</w:t></w:r>');\n        self::assertEquals('<w:r><w:t>{{documentContent}}</w:t></w:r>', $fixed);\n\n        $fixed = $templateProcessor->fixBrokenMacros('<w:r><w:t>{</w:t><w:t>{documentContent}}</w:t></w:r>');\n        self::assertEquals('<w:r><w:t>{{documentContent}}</w:t></w:r>', $fixed);\n\n        $fixed = $templateProcessor->fixBrokenMacros('<w:r><w:t>$1500</w:t><w:t>{{documentContent}}</w:t></w:r>');\n        self::assertEquals('<w:r><w:t>$1500</w:t><w:t>{{documentContent}}</w:t></w:r>', $fixed);\n\n        $fixed = $templateProcessor->fixBrokenMacros('<w:r><w:t>$1500</w:t><w:t>{</w:t><w:t>{documentContent}}</w:t></w:r>');\n        self::assertEquals('<w:r><w:t>$1500</w:t><w:t>{{documentContent}}</w:t></w:r>', $fixed);\n\n        $fixed = $templateProcessor->fixBrokenMacros('<w:r><w:t>25$ plus some info {hint}</w:t></w:r>');\n        self::assertEquals('<w:r><w:t>25$ plus some info {hint}</w:t></w:r>', $fixed);\n\n        $fixed = $templateProcessor->fixBrokenMacros('<w:t>$</w:t></w:r><w:bookmarkStart w:id=\"0\" w:name=\"_GoBack\"/><w:bookmarkEnd w:id=\"0\"/><w:r><w:t xml:space=\"preserve\">15,000.00. </w:t></w:r><w:r w:rsidR=\"0056499B\"><w:t>{</w:t></w:r><w:r w:rsidR=\"00573DFD\" w:rsidRPr=\"00573DFD\"><w:rPr><w:iCs/></w:rPr><w:t>{</w:t></w:r><w:proofErr w:type=\"spellStart\"/><w:r w:rsidR=\"00573DFD\" w:rsidRPr=\"00573DFD\"><w:rPr><w:iCs/></w:rPr><w:t>variable_name</w:t></w:r><w:proofErr w:type=\"spellEnd\"/><w:r w:rsidR=\"00573DFD\" w:rsidRPr=\"00573DFD\"><w:rPr><w:iCs/></w:rPr><w:t>}}</w:t></w:r>');\n        self::assertEquals('<w:t>$</w:t></w:r><w:bookmarkStart w:id=\"0\" w:name=\"_GoBack\"/><w:bookmarkEnd w:id=\"0\"/><w:r><w:t xml:space=\"preserve\">15,000.00. </w:t></w:r><w:r w:rsidR=\"0056499B\"><w:t>{{variable_name}}</w:t></w:r>', $fixed);\n    }\n\n    /**\n     * @covers ::getMainPartName\n     */\n    public function testMainPartNameDetection(): void\n    {\n        $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/document22-xml.docx');\n\n        $variables = ['test'];\n\n        self::assertEquals($variables, $templateProcessor->getVariables());\n    }\n\n    /**\n     * @covers ::getMainPartName\n     */\n    public function testMainPartNameDetectionWithCustomMacro(): void\n    {\n        $templateProcessor = $this->getTemplateProcessor(__DIR__ . '/_files/templates/document22-with-custom-macro-xml.docx');\n        $templateProcessor->setMacroOpeningChars('{#');\n        $templateProcessor->setMacroClosingChars('#}');\n        $variables = ['test'];\n\n        self::assertEquals($variables, $templateProcessor->getVariables());\n    }\n\n    /**\n     * @covers ::getVariables\n     */\n    public function testGetVariables(): void\n    {\n        $templateProcessor = new TestableTemplateProcesor();\n\n        $variables = $templateProcessor->getVariablesForPart('<w:r><w:t>normal text</w:t></w:r>');\n        self::assertEquals([], $variables);\n\n        $variables = $templateProcessor->getVariablesForPart('<w:r><w:t>${documentContent}</w:t></w:r>');\n        self::assertEquals(['documentContent'], $variables);\n\n        $variables = $templateProcessor->getVariablesForPart('<w:t>$</w:t></w:r><w:bookmarkStart w:id=\"0\" w:name=\"_GoBack\"/><w:bookmarkEnd w:id=\"0\"/><w:r><w:t xml:space=\"preserve\">15,000.00. </w:t></w:r><w:r w:rsidR=\"0056499B\"><w:t>$</w:t></w:r><w:r w:rsidR=\"00573DFD\" w:rsidRPr=\"00573DFD\"><w:rPr><w:iCs/></w:rPr><w:t>{</w:t></w:r><w:proofErr w:type=\"spellStart\"/><w:r w:rsidR=\"00573DFD\" w:rsidRPr=\"00573DFD\"><w:rPr><w:iCs/></w:rPr><w:t>variable_name</w:t></w:r><w:proofErr w:type=\"spellEnd\"/><w:r w:rsidR=\"00573DFD\" w:rsidRPr=\"00573DFD\"><w:rPr><w:iCs/></w:rPr><w:t>}</w:t></w:r>');\n        self::assertEquals(['variable_name'], $variables);\n    }\n\n    /**\n     * @covers ::getVariables\n     */\n    public function testGetVariablesWithCustomMacro(): void\n    {\n        $templateProcessor = new TestableTemplateProcesor();\n        $templateProcessor->setMacroOpeningChars('{{');\n        $templateProcessor->setMacroClosingChars('}}');\n\n        $variables = $templateProcessor->getVariablesForPart('<w:r><w:t>normal text</w:t></w:r>');\n        self::assertEquals([], $variables);\n\n        $variables = $templateProcessor->getVariablesForPart('<w:r><w:t>{{documentContent}}</w:t></w:r>');\n        self::assertEquals(['documentContent'], $variables);\n\n        $variables = $templateProcessor->getVariablesForPart('<w:t>{</w:t></w:r><w:bookmarkStart w:id=\"0\" w:name=\"_GoBack\"/><w:bookmarkEnd w:id=\"0\"/><w:r><w:t xml:space=\"preserve\">15,000.00. </w:t></w:r><w:r w:rsidR=\"0056499B\"><w:t>{</w:t></w:r><w:r w:rsidR=\"00573DFD\" w:rsidRPr=\"00573DFD\"><w:rPr><w:iCs/></w:rPr><w:t>{</w:t></w:r><w:proofErr w:type=\"spellStart\"/><w:r w:rsidR=\"00573DFD\" w:rsidRPr=\"00573DFD\"><w:rPr><w:iCs/></w:rPr><w:t>variable_name</w:t></w:r><w:proofErr w:type=\"spellEnd\"/><w:r w:rsidR=\"00573DFD\" w:rsidRPr=\"00573DFD\"><w:rPr><w:iCs/></w:rPr><w:t>}}</w:t></w:r>');\n        self::assertEquals(['variable_name'], $variables);\n    }\n\n    /**\n     * @covers ::textNeedsSplitting\n     */\n    public function testTextNeedsSplitting(): void\n    {\n        $templateProcessor = new TestableTemplateProcesor();\n\n        self::assertFalse($templateProcessor->textNeedsSplitting('<w:r><w:rPr><w:b/><w:i/></w:rPr><w:t xml:space=\"preserve\">${nothing-to-replace}</w:t></w:r>'));\n\n        $text = '<w:r><w:rPr><w:b/><w:i/></w:rPr><w:t xml:space=\"preserve\">Hello ${firstname} ${lastname}</w:t></w:r>';\n        self::assertTrue($templateProcessor->textNeedsSplitting($text));\n        $splitText = $templateProcessor->splitTextIntoTexts($text);\n        self::assertFalse($templateProcessor->textNeedsSplitting($splitText));\n    }\n\n    /**\n     * @covers ::textNeedsSplitting\n     */\n    public function testTextNeedsSplittingWithCustomMacro(): void\n    {\n        $templateProcessor = new TestableTemplateProcesor();\n        $templateProcessor->setMacroChars('{{', '}}');\n\n        self::assertFalse($templateProcessor->textNeedsSplitting('<w:r><w:rPr><w:b/><w:i/></w:rPr><w:t xml:space=\"preserve\">{{nothing-to-replace}}</w:t></w:r>'));\n\n        $text = '<w:r><w:rPr><w:b/><w:i/></w:rPr><w:t xml:space=\"preserve\">Hello {{firstname}} {{lastname}}</w:t></w:r>';\n        self::assertTrue($templateProcessor->textNeedsSplitting($text));\n        $splitText = $templateProcessor->splitTextIntoTexts($text);\n        self::assertFalse($templateProcessor->textNeedsSplitting($splitText));\n    }\n\n    /**\n     * @covers ::splitTextIntoTexts\n     */\n    public function testSplitTextIntoTexts(): void\n    {\n        $templateProcessor = new TestableTemplateProcesor();\n\n        $splitText = $templateProcessor->splitTextIntoTexts('<w:r><w:rPr><w:b/><w:i/></w:rPr><w:t xml:space=\"preserve\">${nothing-to-replace}</w:t></w:r>');\n        self::assertEquals('<w:r><w:rPr><w:b/><w:i/></w:rPr><w:t xml:space=\"preserve\">${nothing-to-replace}</w:t></w:r>', $splitText);\n\n        $splitText = $templateProcessor->splitTextIntoTexts('<w:r><w:rPr><w:b/><w:i/></w:rPr><w:t xml:space=\"preserve\">Hello ${firstname} ${lastname}</w:t></w:r>');\n        self::assertEquals('<w:r><w:rPr><w:b/><w:i/></w:rPr><w:t xml:space=\"preserve\">Hello </w:t></w:r><w:r><w:rPr><w:b/><w:i/></w:rPr><w:t xml:space=\"preserve\">${firstname}</w:t></w:r><w:r><w:rPr><w:b/><w:i/></w:rPr><w:t xml:space=\"preserve\"> </w:t></w:r><w:r><w:rPr><w:b/><w:i/></w:rPr><w:t xml:space=\"preserve\">${lastname}</w:t></w:r>', $splitText);\n    }\n\n    /**\n     * @covers ::splitTextIntoTexts\n     */\n    public function testSplitTextIntoTextsWithCustomMacro(): void\n    {\n        $templateProcessor = new TestableTemplateProcesor();\n        $templateProcessor->setMacroChars('{{', '}}');\n\n        $splitText = $templateProcessor->splitTextIntoTexts('<w:r><w:rPr><w:b/><w:i/></w:rPr><w:t xml:space=\"preserve\">{{nothing-to-replace}}</w:t></w:r>');\n        self::assertEquals('<w:r><w:rPr><w:b/><w:i/></w:rPr><w:t xml:space=\"preserve\">{{nothing-to-replace}}</w:t></w:r>', $splitText);\n\n        $splitText = $templateProcessor->splitTextIntoTexts('<w:r><w:rPr><w:b/><w:i/></w:rPr><w:t xml:space=\"preserve\">Hello {{firstname}} {{lastname}}</w:t></w:r>');\n        self::assertEquals('<w:r><w:rPr><w:b/><w:i/></w:rPr><w:t xml:space=\"preserve\">Hello </w:t></w:r><w:r><w:rPr><w:b/><w:i/></w:rPr><w:t xml:space=\"preserve\">{{firstname}}</w:t></w:r><w:r><w:rPr><w:b/><w:i/></w:rPr><w:t xml:space=\"preserve\"> </w:t></w:r><w:r><w:rPr><w:b/><w:i/></w:rPr><w:t xml:space=\"preserve\">{{lastname}}</w:t></w:r>', $splitText);\n    }\n\n    public function testFindXmlBlockStart(): void\n    {\n        $toFind = '<w:r>\n                    <w:rPr>\n                        <w:rFonts w:ascii=\"Calibri\" w:hAnsi=\"Calibri\" w:cs=\"Calibri\"/>\n                        <w:lang w:val=\"en-GB\"/>\n                    </w:rPr>\n                    <w:t>This whole paragraph will be replaced with my ${title}</w:t>\n                </w:r>';\n        $mainPart = '<w:document xmlns:wpc=\"http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas\" xmlns:cx=\"http://schemas.microsoft.com/office/drawing/2014/chartex\" xmlns:cx1=\"http://schemas.microsoft.com/office/drawing/2015/9/8/chartex\" xmlns:cx2=\"http://schemas.microsoft.com/office/drawing/2015/10/21/chartex\" xmlns:cx3=\"http://schemas.microsoft.com/office/drawing/2016/5/9/chartex\" xmlns:cx4=\"http://schemas.microsoft.com/office/drawing/2016/5/10/chartex\" xmlns:cx5=\"http://schemas.microsoft.com/office/drawing/2016/5/11/chartex\" xmlns:cx6=\"http://schemas.microsoft.com/office/drawing/2016/5/12/chartex\" xmlns:cx7=\"http://schemas.microsoft.com/office/drawing/2016/5/13/chartex\" xmlns:cx8=\"http://schemas.microsoft.com/office/drawing/2016/5/14/chartex\" xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" xmlns:aink=\"http://schemas.microsoft.com/office/drawing/2016/ink\" xmlns:am3d=\"http://schemas.microsoft.com/office/drawing/2017/model3d\" xmlns:o=\"urn:schemas-microsoft-com:office:office\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\" xmlns:v=\"urn:schemas-microsoft-com:vml\" xmlns:wp14=\"http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing\" xmlns:wp=\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\" xmlns:w10=\"urn:schemas-microsoft-com:office:word\" xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" xmlns:w14=\"http://schemas.microsoft.com/office/word/2010/wordml\" xmlns:w15=\"http://schemas.microsoft.com/office/word/2012/wordml\" xmlns:w16cid=\"http://schemas.microsoft.com/office/word/2016/wordml/cid\" xmlns:w16se=\"http://schemas.microsoft.com/office/word/2015/wordml/symex\" xmlns:wpg=\"http://schemas.microsoft.com/office/word/2010/wordprocessingGroup\" xmlns:wpi=\"http://schemas.microsoft.com/office/word/2010/wordprocessingInk\" xmlns:wne=\"http://schemas.microsoft.com/office/word/2006/wordml\" xmlns:wps=\"http://schemas.microsoft.com/office/word/2010/wordprocessingShape\" mc:Ignorable=\"w14 w15 w16se w16cid wp14\">\n            <w:p w14:paraId=\"165D45AF\" w14:textId=\"7FEC9B41\" w:rsidR=\"005B1098\" w:rsidRDefault=\"005B1098\">\n                <w:r w:rsidR=\"00A045B2\">\n                    <w:rPr>\n                        <w:rFonts w:ascii=\"Calibri\" w:hAnsi=\"Calibri\" w:cs=\"Calibri\"/>\n                        <w:lang w:val=\"en-GB\"/>\n                    </w:rPr>\n                    <w:t xml:space=\"preserve\"> ${value1} ${value2}</w:t>\n                </w:r>\n                <w:r>\n                    <w:rPr>\n                        <w:rFonts w:ascii=\"Calibri\" w:hAnsi=\"Calibri\" w:cs=\"Calibri\"/>\n                        <w:lang w:val=\"en-GB\"/>\n                    </w:rPr>\n                    <w:t>.</w:t>\n                </w:r>\n            </w:p>\n            <w:p w14:paraId=\"330D1954\" w14:textId=\"0AB1D347\" w:rsidR=\"00156568\" w:rsidRDefault=\"00156568\">\n                <w:pPr>\n                    <w:rPr>\n                        <w:rFonts w:ascii=\"Calibri\" w:hAnsi=\"Calibri\" w:cs=\"Calibri\"/>\n                        <w:lang w:val=\"en-GB\"/>\n                    </w:rPr>\n                </w:pPr>\n                ' . $toFind . '\n            </w:p>\n        </w:document>';\n\n        $templateProcessor = new TestableTemplateProcesor($mainPart);\n        $position = $templateProcessor->findContainingXmlBlockForMacro('${title}', 'w:r');\n\n        self::assertEquals($toFind, $templateProcessor->getSlice($position['start'], $position['end']));\n    }\n\n    public function testFindXmlBlockStartWithCustomMacro(): void\n    {\n        $toFind = '<w:r>\n                    <w:rPr>\n                        <w:rFonts w:ascii=\"Calibri\" w:hAnsi=\"Calibri\" w:cs=\"Calibri\"/>\n                        <w:lang w:val=\"en-GB\"/>\n                    </w:rPr>\n                    <w:t>This whole paragraph will be replaced with my {{title}}</w:t>\n                </w:r>';\n        $mainPart = '<w:document xmlns:wpc=\"http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas\" xmlns:cx=\"http://schemas.microsoft.com/office/drawing/2014/chartex\" xmlns:cx1=\"http://schemas.microsoft.com/office/drawing/2015/9/8/chartex\" xmlns:cx2=\"http://schemas.microsoft.com/office/drawing/2015/10/21/chartex\" xmlns:cx3=\"http://schemas.microsoft.com/office/drawing/2016/5/9/chartex\" xmlns:cx4=\"http://schemas.microsoft.com/office/drawing/2016/5/10/chartex\" xmlns:cx5=\"http://schemas.microsoft.com/office/drawing/2016/5/11/chartex\" xmlns:cx6=\"http://schemas.microsoft.com/office/drawing/2016/5/12/chartex\" xmlns:cx7=\"http://schemas.microsoft.com/office/drawing/2016/5/13/chartex\" xmlns:cx8=\"http://schemas.microsoft.com/office/drawing/2016/5/14/chartex\" xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" xmlns:aink=\"http://schemas.microsoft.com/office/drawing/2016/ink\" xmlns:am3d=\"http://schemas.microsoft.com/office/drawing/2017/model3d\" xmlns:o=\"urn:schemas-microsoft-com:office:office\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\" xmlns:v=\"urn:schemas-microsoft-com:vml\" xmlns:wp14=\"http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing\" xmlns:wp=\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\" xmlns:w10=\"urn:schemas-microsoft-com:office:word\" xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" xmlns:w14=\"http://schemas.microsoft.com/office/word/2010/wordml\" xmlns:w15=\"http://schemas.microsoft.com/office/word/2012/wordml\" xmlns:w16cid=\"http://schemas.microsoft.com/office/word/2016/wordml/cid\" xmlns:w16se=\"http://schemas.microsoft.com/office/word/2015/wordml/symex\" xmlns:wpg=\"http://schemas.microsoft.com/office/word/2010/wordprocessingGroup\" xmlns:wpi=\"http://schemas.microsoft.com/office/word/2010/wordprocessingInk\" xmlns:wne=\"http://schemas.microsoft.com/office/word/2006/wordml\" xmlns:wps=\"http://schemas.microsoft.com/office/word/2010/wordprocessingShape\" mc:Ignorable=\"w14 w15 w16se w16cid wp14\">\n            <w:p w14:paraId=\"165D45AF\" w14:textId=\"7FEC9B41\" w:rsidR=\"005B1098\" w:rsidRDefault=\"005B1098\">\n                <w:r w:rsidR=\"00A045B2\">\n                    <w:rPr>\n                        <w:rFonts w:ascii=\"Calibri\" w:hAnsi=\"Calibri\" w:cs=\"Calibri\"/>\n                        <w:lang w:val=\"en-GB\"/>\n                    </w:rPr>\n                    <w:t xml:space=\"preserve\"> {{value1}} {{value2}}</w:t>\n                </w:r>\n                <w:r>\n                    <w:rPr>\n                        <w:rFonts w:ascii=\"Calibri\" w:hAnsi=\"Calibri\" w:cs=\"Calibri\"/>\n                        <w:lang w:val=\"en-GB\"/>\n                    </w:rPr>\n                    <w:t>.</w:t>\n                </w:r>\n            </w:p>\n            <w:p w14:paraId=\"330D1954\" w14:textId=\"0AB1D347\" w:rsidR=\"00156568\" w:rsidRDefault=\"00156568\">\n                <w:pPr>\n                    <w:rPr>\n                        <w:rFonts w:ascii=\"Calibri\" w:hAnsi=\"Calibri\" w:cs=\"Calibri\"/>\n                        <w:lang w:val=\"en-GB\"/>\n                    </w:rPr>\n                </w:pPr>\n                ' . $toFind . '\n            </w:p>\n        </w:document>';\n\n        $templateProcessor = new TestableTemplateProcesor($mainPart);\n        $templateProcessor->setMacroChars('{{', '}}');\n        $position = $templateProcessor->findContainingXmlBlockForMacro('{{title}}', 'w:r');\n\n        self::assertEquals($toFind, $templateProcessor->getSlice($position['start'], $position['end']));\n    }\n\n    public function testShouldReturnFalseIfXmlBlockNotFound(): void\n    {\n        $mainPart = '<w:document xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\">\n            <w:p>\n                <w:r>\n                    <w:rPr>\n                        <w:lang w:val=\"en-GB\"/>\n                    </w:rPr>\n                    <w:t xml:space=\"preserve\">this is my text containing a ${macro}</w:t>\n                </w:r>\n            </w:p>\n        </w:document>';\n        $templateProcessor = new TestableTemplateProcesor($mainPart);\n\n        //non-existing macro\n        $result = $templateProcessor->findContainingXmlBlockForMacro('${fake-macro}', 'w:p');\n        self::assertFalse($result);\n\n        //existing macro but not inside node looked for\n        $result = $templateProcessor->findContainingXmlBlockForMacro('${macro}', 'w:fake-node');\n        self::assertFalse($result);\n\n        //existing macro but end tag not found after macro\n        $result = $templateProcessor->findContainingXmlBlockForMacro('${macro}', 'w:rPr');\n        self::assertFalse($result);\n    }\n\n    public function testShouldReturnFalseIfXmlBlockNotFoundWithCustomMacro(): void\n    {\n        $mainPart = '<w:document xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\">\n            <w:p>\n                <w:r>\n                    <w:rPr>\n                        <w:lang w:val=\"en-GB\"/>\n                    </w:rPr>\n                    <w:t xml:space=\"preserve\">this is my text containing a ${macro}</w:t>\n                </w:r>\n            </w:p>\n        </w:document>';\n        $templateProcessor = new TestableTemplateProcesor($mainPart);\n        $templateProcessor->setMacroChars('{{', '}}');\n\n        //non-existing macro\n        $result = $templateProcessor->findContainingXmlBlockForMacro('{{fake-macro}}', 'w:p');\n        self::assertFalse($result);\n\n        //existing macro but not inside node looked for\n        $result = $templateProcessor->findContainingXmlBlockForMacro('{{macro}}', 'w:fake-node');\n        self::assertFalse($result);\n\n        //existing macro but end tag not found after macro\n        $result = $templateProcessor->findContainingXmlBlockForMacro('{{macro}}', 'w:rPr');\n        self::assertFalse($result);\n    }\n\n    public function testShouldMakeFieldsUpdateOnOpen(): void\n    {\n        $settingsPart = '<w:settings xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\">\n            <w:zoom w:percent=\"100\"/>\n        </w:settings>';\n        $templateProcessor = new TestableTemplateProcesor(null, $settingsPart);\n\n        $templateProcessor->setUpdateFields(true);\n        self::assertStringContainsString('<w:updateFields w:val=\"true\"/>', $templateProcessor->getSettingsPart());\n\n        $templateProcessor->setUpdateFields(false);\n        self::assertStringContainsString('<w:updateFields w:val=\"false\"/>', $templateProcessor->getSettingsPart());\n    }\n\n    public function testShouldMakeFieldsUpdateOnOpenWithCustomMacro(): void\n    {\n        $settingsPart = '<w:settings xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\">\n            <w:zoom w:percent=\"100\"/>\n        </w:settings>';\n        $templateProcessor = new TestableTemplateProcesor(null, $settingsPart);\n        $templateProcessor->setMacroChars('{{', '}}');\n\n        $templateProcessor->setUpdateFields(true);\n        self::assertStringContainsString('<w:updateFields w:val=\"true\"/>', $templateProcessor->getSettingsPart());\n\n        $templateProcessor->setUpdateFields(false);\n        self::assertStringContainsString('<w:updateFields w:val=\"false\"/>', $templateProcessor->getSettingsPart());\n    }\n\n    public function testEnsureUtf8Encoded(): void\n    {\n        $mainPart = '<w:tbl>\n            <w:tr>\n                <w:tc>\n                    <w:tcPr>\n                        <w:vMerge w:val=\"restart\"/>\n                    </w:tcPr>\n                    <w:p>\n                        <w:r>\n                            <w:t t=1>${stringZero}</w:t>\n                        </w:r>\n                    </w:p>\n                </w:tc>\n                <w:tc>\n                    <w:p>\n                        <w:r>\n                            <w:t t=2>${intZero}</w:t>\n                        </w:r>\n                    </w:p>\n                </w:tc>\n                <w:tc>\n                    <w:p>\n                        <w:r>\n                            <w:t t=3>${stringTest}</w:t>\n                        </w:r>\n                    </w:p>\n                </w:tc>\n                <w:tc>\n                    <w:p>\n                        <w:r>\n                            <w:t t=4>${null}</w:t>\n                        </w:r>\n                    </w:p>\n                </w:tc>\n                <w:tc>\n                    <w:p>\n                        <w:r>\n                            <w:t t=5>${floatZero}</w:t>\n                        </w:r>\n                    </w:p>\n                </w:tc>\n                <w:tc>\n                    <w:p>\n                        <w:r>\n                            <w:t t=6>${intTen}</w:t>\n                        </w:r>\n                    </w:p>\n                </w:tc>\n                <w:tc>\n                    <w:p>\n                        <w:r>\n                            <w:t t=7>${boolFalse}</w:t>\n                        </w:r>\n                    </w:p>\n                </w:tc>\n                <w:tc>\n                    <w:p>\n                        <w:r>\n                            <w:t t=8>${boolTrue}</w:t>\n                        </w:r>\n                    </w:p>\n                </w:tc>\n            </w:tr>\n        </w:tbl>';\n        $templateProcessor = new TestableTemplateProcesor($mainPart);\n\n        self::assertEquals(\n            ['stringZero', 'intZero', 'stringTest', 'null', 'floatZero', 'intTen', 'boolFalse', 'boolTrue'],\n            $templateProcessor->getVariables()\n        );\n\n        $templateProcessor->setValue('stringZero', '0');\n        self::assertStringContainsString('<w:t t=1>0</w:t>', $templateProcessor->getMainPart());\n\n        $templateProcessor->setValue('intZero', 0);\n        self::assertStringContainsString('<w:t t=2>0</w:t>', $templateProcessor->getMainPart());\n\n        $templateProcessor->setValue('stringTest', 'test');\n        self::assertStringContainsString('<w:t t=3>test</w:t>', $templateProcessor->getMainPart());\n\n        $templateProcessor->setValue('null', null);\n        self::assertStringContainsString('<w:t t=4></w:t>', $templateProcessor->getMainPart());\n\n        $templateProcessor->setValue('floatZero', 0.00);\n        self::assertStringContainsString('<w:t t=5>0</w:t>', $templateProcessor->getMainPart());\n\n        $templateProcessor->setValue('intTen', 10);\n        self::assertStringContainsString('<w:t t=6>10</w:t>', $templateProcessor->getMainPart());\n\n        $templateProcessor->setValue('boolFalse', false);\n        self::assertStringContainsString('<w:t t=7></w:t>', $templateProcessor->getMainPart());\n\n        $templateProcessor->setValue('boolTrue', true);\n        self::assertStringContainsString('<w:t t=8>1</w:t>', $templateProcessor->getMainPart());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/TestHelperDOCX.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests;\n\nuse PhpOffice\\PhpWord\\Exception\\CreateTemporaryFileException;\nuse PhpOffice\\PhpWord\\IOFactory;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Settings;\nuse ZipArchive;\n\n/**\n * Test helper class.\n */\nclass TestHelperDOCX\n{\n    /**\n     * Temporary file name.\n     *\n     * @var string\n     */\n    protected static $file;\n\n    /**\n     * Get document content.\n     *\n     * @since 0.12.0 Throws CreateTemporaryFileException.\n     *\n     * @param string $writerName\n     *\n     * @return XmlDocument\n     */\n    public static function getDocument(PhpWord $phpWord, $writerName = 'Word2007')\n    {\n        self::$file = tempnam(Settings::getTempDir(), 'PhpWord');\n        if (false === self::$file) {\n            throw new CreateTemporaryFileException();\n        }\n\n        if (!is_dir(Settings::getTempDir() . '/PhpWord_Unit_Test/')) {\n            mkdir(Settings::getTempDir() . '/PhpWord_Unit_Test/');\n        }\n\n        $xmlWriter = IOFactory::createWriter($phpWord, $writerName);\n        $xmlWriter->save(self::$file);\n\n        $zip = new ZipArchive();\n        $res = $zip->open(self::$file);\n        if (true === $res) {\n            $zip->extractTo(Settings::getTempDir() . '/PhpWord_Unit_Test/');\n            $zip->close();\n        }\n\n        $doc = new XmlDocument(Settings::getTempDir() . '/PhpWord_Unit_Test/');\n        if ($writerName === 'ODText') {\n            $doc->setDefaultFile('content.xml');\n        }\n\n        return $doc;\n    }\n\n    /**\n     * Clear document.\n     */\n    public static function clear(): void\n    {\n        if (self::$file && file_exists(self::$file)) {\n            unlink(self::$file);\n            self::$file = '';\n        }\n        if (is_dir(Settings::getTempDir() . '/PhpWord_Unit_Test/')) {\n            self::deleteDir(Settings::getTempDir() . '/PhpWord_Unit_Test/');\n        }\n    }\n\n    /**\n     * Delete directory.\n     *\n     * @param string $dir\n     */\n    public static function deleteDir($dir): void\n    {\n        foreach (scandir($dir) as $file) {\n            if ('.' === $file || '..' === $file) {\n                continue;\n            } elseif (is_file($dir . '/' . $file)) {\n                unlink($dir . '/' . $file);\n            } elseif (is_dir($dir . '/' . $file)) {\n                self::deleteDir($dir . '/' . $file);\n            }\n        }\n\n        @rmdir($dir);\n    }\n\n    /**\n     * Get file.\n     *\n     * @return string\n     */\n    public static function getFile()\n    {\n        return self::$file;\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/TestableTemplateProcesor.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests;\n\nuse PhpOffice\\PhpWord\\TemplateProcessor;\n\n/**\n * This class is used to expose publicly methods that are otherwise private or protected.\n * This makes testing those methods easier.\n *\n * @author troosan\n */\nclass TestableTemplateProcesor extends TemplateProcessor\n{\n    public function __construct($mainPart = null, $settingsPart = null)\n    {\n        $this->tempDocumentMainPart = $mainPart;\n        $this->tempDocumentSettingsPart = $settingsPart;\n    }\n\n    public function fixBrokenMacros($documentPart)\n    {\n        return parent::fixBrokenMacros($documentPart);\n    }\n\n    public function splitTextIntoTexts($text)\n    {\n        return parent::splitTextIntoTexts($text);\n    }\n\n    public function textNeedsSplitting($text)\n    {\n        return parent::textNeedsSplitting($text);\n    }\n\n    public function getVariablesForPart($documentPartXML)\n    {\n        $documentPartXML = parent::fixBrokenMacros($documentPartXML);\n\n        return parent::getVariablesForPart($documentPartXML);\n    }\n\n    public function findXmlBlockStart($offset, $blockType)\n    {\n        return parent::findXmlBlockStart($offset, $blockType);\n    }\n\n    public function findContainingXmlBlockForMacro($macro, $blockType = 'w:p')\n    {\n        return parent::findContainingXmlBlockForMacro($macro, $blockType);\n    }\n\n    public function getSlice($startPosition, $endPosition = 0)\n    {\n        return parent::getSlice($startPosition, $endPosition);\n    }\n\n    /**\n     * @return string\n     */\n    public function getMainPart()\n    {\n        return $this->tempDocumentMainPart;\n    }\n\n    /**\n     * @return string\n     */\n    public function getSettingsPart()\n    {\n        return $this->tempDocumentSettingsPart;\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/WriteReadback/ODTextTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\WriteReadback;\n\nuse PhpOffice\\PhpWord\\Element\\TextRun;\nuse PhpOffice\\PhpWord\\IOFactory;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Writer\\ODText;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Reader\\ODText and PhpOffice\\PhpWord\\Writer\\ODText.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Reader\\ODText\n *\n * @runTestsInSeparateProcesses\n */\nclass ODTextTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test a document with one section and text.\n     */\n    public function testOneSectionWithText(): void\n    {\n        $phpWordWriter = new PhpWord();\n        $testText = 'Hello World!';\n        $sectionWriter = $phpWordWriter->addSection();\n        $sectionWriter->addText($testText);\n\n        $writer = new ODText($phpWordWriter);\n        $file = __DIR__ . '/../_files/temp.odt';\n        $writer->save($file);\n\n        self::assertFileExists($file);\n\n        $phpWordReader = IOFactory::load($file, 'ODText');\n\n        self::assertCount(1, $phpWordReader->getSections());\n        self::assertCount(1, $phpWordReader->getSections()[0]->getElements());\n        self::assertInstanceOf(TextRun::class, $phpWordReader->getSections()[0]->getElements()[0]);\n        self::assertEquals($testText, $phpWordReader->getSections()[0]->getElements()[0]->getText());\n        unlink($file);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/WriteReadback/Word2007Test.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\WriteReadback;\n\nuse PhpOffice\\PhpWord\\Element\\TextRun;\nuse PhpOffice\\PhpWord\\IOFactory;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Style\\Font;\nuse PhpOffice\\PhpWord\\Writer\\Word2007;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Reader\\Word2007 and PhpOffice\\PhpWord\\Writer\\Word2007.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Reader\\Word2007\n *\n * @runTestsInSeparateProcesses\n */\nclass Word2007Test extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test default font name.\n     */\n    public function testDefaultFontName(): void\n    {\n        $phpWordWriter = new PhpWord();\n        $testDefaultFontName = 'Times New Roman';\n        $phpWordWriter->setDefaultFontName($testDefaultFontName);\n\n        $writer = new Word2007($phpWordWriter);\n        $file = __DIR__ . '/../_files/temp.docx';\n        $writer->save($file);\n\n        self::assertFileExists($file);\n\n        $phpWordReader = IOFactory::load($file, 'Word2007');\n\n        self::assertEquals($testDefaultFontName, $phpWordReader->getDefaultFontName());\n\n        unlink($file);\n    }\n\n    /**\n     * Test default Asian font name.\n     */\n    public function testDefaultAsianFontName(): void\n    {\n        $phpWordWriter = new PhpWord();\n        $testDefaultFontName = '標楷體';\n        $phpWordWriter->setDefaultAsianFontName($testDefaultFontName);\n\n        $writer = new Word2007($phpWordWriter);\n        $file = __DIR__ . '/../_files/temp.docx';\n        $writer->save($file);\n\n        self::assertFileExists($file);\n\n        $phpWordReader = IOFactory::load($file, 'Word2007');\n\n        self::assertEquals($testDefaultFontName, $phpWordReader->getDefaultAsianFontName());\n\n        unlink($file);\n    }\n\n    /**\n     * Test default font size.\n     */\n    public function testDefaulFontSize(): void\n    {\n        $phpWordWriter = new PhpWord();\n        $testDefaultFontSize = 144;\n        $phpWordWriter->setDefaultFontSize($testDefaultFontSize);\n\n        $writer = new Word2007($phpWordWriter);\n        $file = __DIR__ . '/../_files/temp.docx';\n        $writer->save($file);\n\n        self::assertFileExists($file);\n\n        $phpWordReader = IOFactory::load($file, 'Word2007');\n\n        self::assertEquals($testDefaultFontSize, $phpWordReader->getDefaultFontSize());\n\n        unlink($file);\n    }\n\n    /**\n     * Test default font color.\n     */\n    public function testDefaultFontColor(): void\n    {\n        $phpWordWriter = new PhpWord();\n        $testDefaultFontColor = '00FF00';\n        $phpWordWriter->setDefaultFontColor($testDefaultFontColor);\n\n        $writer = new Word2007($phpWordWriter);\n        $file = __DIR__ . '/../_files/temp.docx';\n        $writer->save($file);\n\n        self::assertFileExists($file);\n\n        $phpWordReader = IOFactory::load($file, 'Word2007');\n\n        self::assertEquals($testDefaultFontColor, $phpWordReader->getDefaultFontColor());\n\n        unlink($file);\n    }\n\n    /**\n     * Test Zoom.\n     */\n    public function testZoom(): void\n    {\n        $phpWordWriter = new PhpWord();\n        $zoomLevel = 75;\n        $phpWordWriter->getSettings()->setZoom($zoomLevel);\n\n        $writer = new Word2007($phpWordWriter);\n        $file = __DIR__ . '/../_files/temp.docx';\n        $writer->save($file);\n\n        self::assertFileExists($file);\n\n        $phpWordReader = IOFactory::load($file, 'Word2007');\n\n        self::assertEquals($zoomLevel, $phpWordReader->getSettings()->getZoom());\n\n        unlink($file);\n    }\n\n    /**\n     * Test a document with one section and text.\n     */\n    public function testOneSectionWithText(): void\n    {\n        $phpWordWriter = new PhpWord();\n        $testText = 'Hello World!';\n        $sectionWriter = $phpWordWriter->addSection();\n        $sectionWriter->addText($testText);\n\n        $writer = new Word2007($phpWordWriter);\n        $file = __DIR__ . '/../_files/temp.docx';\n        $writer->save($file);\n\n        self::assertFileExists($file);\n\n        $phpWordReader = IOFactory::load($file, 'Word2007');\n\n        self::assertCount(1, $phpWordReader->getSections());\n        self::assertCount(1, $phpWordReader->getSections()[0]->getElements());\n        self::assertInstanceOf(TextRun::class, $phpWordReader->getSections()[0]->getElements()[0]);\n        self::assertEquals($testText, $phpWordReader->getSections()[0]->getElements()[0]->getText());\n        unlink($file);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/EPub3/Element/ImageTest.php",
    "content": "<?php\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\EPub3\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\Image;\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\nuse PhpOffice\\PhpWord\\Style\\Image as ImageStyle;\nuse PhpOffice\\PhpWord\\Writer\\EPub3\\Element\\Image as ImageWriter;\nuse PHPUnit\\Framework\\TestCase;\n\nclass ImageTest extends TestCase\n{\n    /**\n     * @var XMLWriter\n     */\n    private $xmlWriter;\n\n    /**\n     * @var Image\n     */\n    private $element;\n\n    /**\n     * @var ImageWriter\n     */\n    private $writer;\n\n    protected function setUp(): void\n    {\n        $this->xmlWriter = new XMLWriter();\n        $style = new ImageStyle();\n        $style->setWidth(100);\n        $style->setHeight(100);\n        $this->element = new Image('tests/PhpWordTests/_files/images/earth.jpg', $style);\n        $this->writer = new ImageWriter($this->xmlWriter, $this->element);\n    }\n\n    public function testWrite(): void\n    {\n        $this->writer->write();\n\n        $expected = '<p><img src=\"media/image.jpg\" style=\"width:500px;height:500px;\"/></p>';\n        self::assertEquals($expected, $this->xmlWriter->getData());\n    }\n\n    public function testWriteWithoutP(): void\n    {\n        $style = new ImageStyle();\n        $style->setWidth(100);\n        $style->setHeight(100);\n        $this->element = new Image('tests/PhpWordTests/_files/images/earth.jpg', $style);\n        $this->writer = new ImageWriter($this->xmlWriter, $this->element, true);\n\n        $this->writer->write();\n\n        $expected = '<img src=\"media/image.jpg\" style=\"width:500px;height:500px;\"/>';\n        self::assertEquals($expected, $this->xmlWriter->getData());\n    }\n\n    public function testWriteWithInvalidElement(): void\n    {\n        $invalidElement = $this->createMock(\\PhpOffice\\PhpWord\\Element\\AbstractElement::class);\n        $writer = new ImageWriter($this->xmlWriter, $invalidElement);\n\n        $writer->write();\n\n        self::assertEquals('', $this->xmlWriter->getData());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/EPub3/Element/TextTest.php",
    "content": "<?php\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\EPub3\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\Text;\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\nuse PhpOffice\\PhpWord\\Writer\\EPub3\\Element\\Text as TextWriter;\nuse PHPUnit\\Framework\\TestCase;\n\nclass TextTest extends TestCase\n{\n    /**\n     * @var XMLWriter\n     */\n    private $xmlWriter;\n\n    /**\n     * @var Text\n     */\n    private $element;\n\n    /**\n     * @var TextWriter\n     */\n    private $writer;\n\n    protected function setUp(): void\n    {\n        $this->xmlWriter = new XMLWriter();\n        $this->element = new Text('Sample Text');\n        $this->writer = new TextWriter($this->xmlWriter, $this->element);\n    }\n\n    public function testWrite(): void\n    {\n        $this->writer->write();\n\n        $expected = \"<p>\\n  <span>Sample Text</span>\\n</p>\\n\";\n        self::assertEquals($expected, $this->xmlWriter->getData());\n    }\n\n    public function testWriteWithFontStyle(): void\n    {\n        $this->element->setFontStyle('customStyle');\n\n        $this->writer->write();\n\n        $expected = \"<p>\\n  <span class=\\\"customStyle\\\">Sample Text</span>\\n</p>\\n\";\n        self::assertEquals($expected, $this->xmlWriter->getData());\n    }\n\n    public function testWriteWithParagraphStyle(): void\n    {\n        $this->element->setParagraphStyle('paragraphStyle');\n\n        $this->writer->write();\n\n        $expected = \"<p class=\\\"paragraphStyle\\\">\\n  <span>Sample Text</span>\\n</p>\\n\";\n        self::assertEquals($expected, $this->xmlWriter->getData());\n    }\n\n    public function testWriteWithoutP(): void\n    {\n        $text = new Text('Sample Text');\n        $xmlWriter = new XMLWriter();\n        $this->writer = new TextWriter($xmlWriter, $text, true);\n\n        $this->writer->write();\n\n        $expected = \"<span>Sample Text</span>\\n\";\n        self::assertEquals($expected, $xmlWriter->getData());\n    }\n\n    public function testWriteWithInvalidElement(): void\n    {\n        $invalidElement = $this->createMock(\\PhpOffice\\PhpWord\\Element\\AbstractElement::class);\n        $writer = new TextWriter($this->xmlWriter, $invalidElement);\n\n        $writer->write();\n\n        self::assertEquals('', $this->xmlWriter->getData());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/EPub3/ElementTest.php",
    "content": "<?php\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\EPub3;\n\nuse PhpOffice\\PhpWord\\Element\\AbstractElement;\nuse PhpOffice\\PhpWord\\Element\\Text;\nuse PhpOffice\\PhpWord\\Writer\\EPub3\\Element\\AbstractElement as WriterElement;\nuse PHPUnit\\Framework\\TestCase;\n\nclass ElementTest extends TestCase\n{\n    public function testGetElementClass(): void\n    {\n        $element = new Text('test');\n        $class = WriterElement::getElementClass($element);\n        self::assertEquals('PhpOffice\\\\PhpWord\\\\Writer\\\\EPub3\\\\Element\\\\Text', $class);\n    }\n\n    public function testGetElementClassWithInvalidElement(): void\n    {\n        $this->expectException(\\PhpOffice\\PhpWord\\Exception\\Exception::class);\n\n        $element = $this->createMock(AbstractElement::class);\n        WriterElement::getElementClass($element);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/EPub3/Part/AbstractPartTest.php",
    "content": "<?php\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\EPub3\\Part;\n\nuse PhpOffice\\PhpWord\\Writer\\EPub3;\nuse PhpOffice\\PhpWord\\Writer\\EPub3\\Part\\AbstractPart;\nuse PHPUnit\\Framework\\TestCase;\n\nclass AbstractPartTest extends TestCase\n{\n    /**\n     * @var AbstractPart\n     */\n    private $part;\n\n    protected function setUp(): void\n    {\n        // @phpstan-ignore-next-line\n        if (method_exists($this, 'getMockForAbstractClass')) {\n            $this->part = $this->getMockForAbstractClass(AbstractPart::class);\n        } else {\n            $this->part = new class() extends AbstractPart {\n                public function write(): string\n                {\n                    return '';\n                }\n            };\n        }\n    }\n\n    public function testParentWriter(): void\n    {\n        $writer = new EPub3();\n        $this->part->setParentWriter($writer);\n\n        self::assertInstanceOf(EPub3::class, $this->part->getParentWriter());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/EPub3/Part/ContentTest.php",
    "content": "<?php\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\EPub3\\Part;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Writer\\EPub3;\nuse PhpOffice\\PhpWord\\Writer\\EPub3\\Part\\Content;\nuse PHPUnit\\Framework\\TestCase;\n\nclass ContentTest extends TestCase\n{\n    /**\n     * @var Content\n     */\n    private $content;\n\n    protected function setUp(): void\n    {\n        $phpWord = new PhpWord();\n        $this->content = new Content($phpWord);\n        $section = $phpWord->addSection();\n        $section->addText('Test content');\n\n        $writer = new EPub3($phpWord);\n        $this->content->setParentWriter($writer);\n    }\n\n    public function testWrite(): void\n    {\n        $result = $this->content->write();\n\n        self::assertIsString($result);\n        self::assertStringContainsString('<?xml version=\"1.0\" encoding=\"UTF-8\"?>', $result);\n        self::assertStringContainsString('<package', $result);\n        self::assertStringContainsString('<manifest>', $result);\n        self::assertStringContainsString('<spine>', $result);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/EPub3/Part/ManifestTest.php",
    "content": "<?php\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\EPub3\\Part;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Writer\\EPub3;\nuse PhpOffice\\PhpWord\\Writer\\EPub3\\Part\\Manifest;\nuse PHPUnit\\Framework\\TestCase;\n\nclass ManifestTest extends TestCase\n{\n    /**\n     * @var Manifest\n     */\n    private $manifest;\n\n    protected function setUp(): void\n    {\n        $this->manifest = new Manifest();\n        $phpWord = new PhpWord();\n        $writer = new EPub3($phpWord);\n        $this->manifest->setParentWriter($writer);\n    }\n\n    public function testWrite(): void\n    {\n        $result = $this->manifest->write();\n\n        self::assertStringContainsString('<?xml version=\"1.0\" encoding=\"UTF-8\"?>', $result);\n        self::assertIsString($result);\n        self::assertStringContainsString('<container version=\"1.0\"', $result);\n        self::assertStringContainsString('<rootfiles>', $result);\n        self::assertStringContainsString('<rootfile full-path=\"content.opf\"', $result);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/EPub3/Part/MetaTest.php",
    "content": "<?php\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\EPub3\\Part;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Writer\\EPub3;\nuse PhpOffice\\PhpWord\\Writer\\EPub3\\Part\\Meta;\nuse PHPUnit\\Framework\\TestCase;\n\nclass MetaTest extends TestCase\n{\n    /**\n     * @var Meta\n     */\n    private $meta;\n\n    protected function setUp(): void\n    {\n        $this->meta = new Meta();\n        $phpWord = new PhpWord();\n        $writer = new EPub3($phpWord);\n        $this->meta->setParentWriter($writer);\n    }\n\n    public function testWrite(): void\n    {\n        $result = $this->meta->write();\n\n        self::assertIsString($result);\n        self::assertStringContainsString('<?xml version=\"1.0\" encoding=\"UTF-8\"?>', $result);\n        self::assertStringContainsString('<metadata', $result);\n        self::assertStringContainsString('xmlns:dc=\"http://purl.org/dc/elements/1.1/\"', $result);\n    }\n\n    public function testWriteWithDocInfo(): void\n    {\n        $phpWord = new PhpWord();\n        $properties = $phpWord->getDocInfo();\n        $properties->setCreator('PHPWord');\n        $properties->setTitle('Test Title');\n        $properties->setKeywords('test, keywords');\n\n        $writer = new EPub3($phpWord);\n        $this->meta->setParentWriter($writer);\n\n        $expected = '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n<metadata xmlns=\"http://www.idpf.org/2007/opf\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\"><dc:title>Test Title</dc:title><dc:language>en</dc:language><dc:identifier>urn:uuid:12345</dc:identifier><dc:creator>PHPWord</dc:creator><meta property=\"dcterms:modified\">2023-01-01T00:00:00Z</meta></metadata>';\n\n        $result = $this->meta->write();\n\n        self::assertStringContainsString('<dc:creator>PHPWord</dc:creator>', $result);\n        self::assertStringContainsString('<dc:title>Test Title</dc:title>', $result);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/EPub3/Part/MimetypeTest.php",
    "content": "<?php\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\EPub3\\Part;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Writer\\EPub3;\nuse PhpOffice\\PhpWord\\Writer\\EPub3\\Part\\Mimetype;\nuse PHPUnit\\Framework\\TestCase;\n\nclass MimetypeTest extends TestCase\n{\n    /**\n     * @var Mimetype\n     */\n    private $mimetype;\n\n    protected function setUp(): void\n    {\n        $this->mimetype = new Mimetype();\n        $phpWord = new PhpWord();\n        $writer = new EPub3($phpWord);\n        $this->mimetype->setParentWriter($writer);\n    }\n\n    public function testWrite(): void\n    {\n        $result = $this->mimetype->write();\n\n        self::assertIsString($result);\n        self::assertEquals('application/epub+zip', $result);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/EPub3/Part/NavTest.php",
    "content": "<?php\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\EPub3\\Part;\n\nuse DOMDocument;\nuse PhpOffice\\PhpWord\\Writer\\EPub3\\Part\\Nav;\nuse PHPUnit\\Framework\\TestCase;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\EPub3\\Part\\Nav.\n */\nclass NavTest extends TestCase\n{\n    public function testWrite(): void\n    {\n        $nav = new Nav();\n        $xml = $nav->write();\n\n        // Test that valid XML is generated\n        $dom = new DOMDocument();\n        $dom->loadXML($xml);\n\n        // Test required XML elements and attributes exist\n        self::assertEquals('html', $dom->documentElement->nodeName);\n        self::assertEquals('http://www.w3.org/1999/xhtml', $dom->documentElement->getAttribute('xmlns'));\n        self::assertEquals('http://www.idpf.org/2007/ops', $dom->documentElement->getAttribute('xmlns:epub'));\n\n        // Test nav element\n        $navElements = $dom->getElementsByTagName('nav');\n        self::assertEquals(1, $navElements->length);\n        $navElement = $navElements->item(0);\n        self::assertEquals('toc', $navElement->getAttribute('epub:type'));\n        self::assertEquals('toc', $navElement->getAttribute('id'));\n\n        // Test title exists\n        $titleElements = $dom->getElementsByTagName('title');\n        self::assertEquals(1, $titleElements->length);\n        self::assertEquals('Navigation', $titleElements->item(0)->nodeValue);\n\n        // Test TOC header exists\n        $h1Elements = $dom->getElementsByTagName('h1');\n        self::assertEquals(1, $h1Elements->length);\n        self::assertEquals('Table of Contents', $h1Elements->item(0)->nodeValue);\n\n        // Test TOC list structure exists\n        $olElements = $dom->getElementsByTagName('ol');\n        self::assertEquals(1, $olElements->length);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/EPub3/PartTest.php",
    "content": "<?php\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\EPub3;\n\nuse PhpOffice\\PhpWord\\Writer\\EPub3\\Part;\nuse PHPUnit\\Framework\\TestCase;\n\nclass PartTest extends TestCase\n{\n    public function testGetPartClass(): void\n    {\n        $types = ['Content', 'Manifest', 'Meta', 'Mimetype'];\n\n        foreach ($types as $type) {\n            $class = Part::getPartClass($type);\n            $expectedClass = 'PhpOffice\\\\PhpWord\\\\Writer\\\\EPub3\\\\Part\\\\' . $type;\n\n            self::assertEquals($expectedClass, $class);\n        }\n    }\n\n    public function testGetPartClassWithInvalidType(): void\n    {\n        $this->expectException(\\PhpOffice\\PhpWord\\Exception\\Exception::class);\n\n        Part::getPartClass('InvalidType');\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/EPub3/Style/AbstractStyleTest.php",
    "content": "<?php\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\EPub3\\Style;\n\nuse PhpOffice\\PhpWord\\Writer\\EPub3;\nuse PhpOffice\\PhpWord\\Writer\\EPub3\\Style\\AbstractStyle;\nuse PHPUnit\\Framework\\TestCase;\n\nclass AbstractStyleTest extends TestCase\n{\n    /**\n     * Test setParentWriter and getParentWriter methods.\n     */\n    public function testParentWriter(): void\n    {\n        $parentWriter = new EPub3();\n        // @phpstan-ignore-next-line\n        if (method_exists($this, 'getMockForAbstractClass')) {\n            $style = $this->getMockForAbstractClass(AbstractStyle::class);\n        } else {\n            /** @var AbstractStyle $style */\n            $style = new class() extends AbstractStyle {\n                public function write(): string\n                {\n                    return '';\n                }\n            };\n        }\n\n        $result = $style->setParentWriter($parentWriter);\n\n        self::assertSame($style, $result);\n        self::assertSame($parentWriter, $style->getParentWriter());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/EPub3/Style/FontTest.php",
    "content": "<?php\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\EPub3\\Style;\n\nuse PhpOffice\\PhpWord\\Writer\\EPub3\\Style\\Font;\nuse PHPUnit\\Framework\\TestCase;\n\nclass FontTest extends TestCase\n{\n    /**\n     * Test write method.\n     */\n    public function testWrite(): void\n    {\n        $style = new Font();\n\n        $content = $style->write();\n\n        self::assertStringContainsString('font-family: \"Times New Roman\", Times, serif;', $content);\n        self::assertStringContainsString('font-size: 12pt;', $content);\n        self::assertStringContainsString('color: #000000;', $content);\n        self::assertStringStartsWith('body {', $content);\n        self::assertStringEndsWith('}', $content);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/EPub3/Style/ParagraphTest.php",
    "content": "<?php\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\EPub3\\Style;\n\nuse PhpOffice\\PhpWord\\Writer\\EPub3\\Style\\Paragraph;\nuse PHPUnit\\Framework\\TestCase;\n\nclass ParagraphTest extends TestCase\n{\n    /**\n     * Test write method.\n     */\n    public function testWrite(): void\n    {\n        $style = new Paragraph();\n\n        $content = $style->write();\n\n        self::assertStringContainsString('margin-top: 0;', $content);\n        self::assertStringContainsString('margin-bottom: 1em;', $content);\n        self::assertStringContainsString('text-align: left;', $content);\n        self::assertStringStartsWith('p {', $content);\n        self::assertStringEndsWith('}', $content);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/EPub3/Style/TableTest.php",
    "content": "<?php\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\EPub3\\Style;\n\nuse PhpOffice\\PhpWord\\Writer\\EPub3\\Style\\Table;\nuse PHPUnit\\Framework\\TestCase;\n\nclass TableTest extends TestCase\n{\n    /**\n     * Test write method.\n     */\n    public function testWrite(): void\n    {\n        $style = new Table();\n\n        $content = $style->write();\n\n        self::assertStringContainsString('border-collapse: collapse;', $content);\n        self::assertStringContainsString('width: 100%;', $content);\n        self::assertStringContainsString('border: 1px solid black;', $content);\n        self::assertStringContainsString('padding: 8px;', $content);\n        self::assertStringContainsString('text-align: left;', $content);\n        self::assertStringContainsString('table {', $content);\n        self::assertStringContainsString('th, td {', $content);\n        self::assertStringEndsWith('}', $content);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/EPub3/StyleTest.php",
    "content": "<?php\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\EPub3;\n\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\nuse PHPUnit\\Framework\\TestCase;\n\nclass StyleTest extends TestCase\n{\n    public function testEmptyStyles(): void\n    {\n        $styles = ['Font', 'Paragraph', 'Table'];\n        foreach ($styles as $style) {\n            $objectClass = 'PhpOffice\\\\PhpWord\\\\Writer\\\\EPub3\\\\Style\\\\' . $style;\n            $xmlWriter = new XMLWriter();\n            $object = new $objectClass();\n            $object->setXmlWriter($xmlWriter);\n            $object->write();\n\n            self::assertEquals('', $xmlWriter->getData());\n        }\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/EPub3Test.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer;\n\nuse PhpOffice\\PhpWord\\Exception\\Exception;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\nuse PhpOffice\\PhpWord\\Writer\\EPub3;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\Epub3.\n *\n * @runTestsInSeparateProcesses\n */\nclass EPub3Test extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test document construction.\n     */\n    public function testConstruct(): void\n    {\n        $object = new EPub3(new PhpWord());\n        self::assertInstanceOf(PhpWord::class, $object->getPhpWord());\n        self::assertEquals('./', $object->getDiskCachingDirectory());\n        foreach (['Content', 'Manifest', 'Mimetype'] as $part) {\n            self::assertInstanceOf(\n                \"PhpOffice\\\\PhpWord\\\\Writer\\\\Epub3\\\\Part\\\\{$part}\",\n                $object->getWriterPart($part)\n            );\n            self::assertInstanceOf(\n                'PhpOffice\\\\PhpWord\\\\Writer\\\\Epub3',\n                $object->getWriterPart($part)->getParentWriter()\n            );\n        }\n    }\n\n    /**\n     * Test construction with null.\n     */\n    public function testConstructWithNull(): void\n    {\n        $this->expectException(Exception::class);\n        $this->expectExceptionMessage('No PhpWord assigned.');\n\n        $writer = new EPub3();\n        $writer->getWriterPart('content')->write();\n    }\n\n    /**\n     * Test saving document.\n     */\n    public function testSave(): void\n    {\n        $imageSrc = __DIR__ . '/../_files/images/PhpWord.png';\n        $file = __DIR__ . '/../_files/temp.epub';\n\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $section->addText('Test 1');\n        $section->addTextBreak();\n        $section->addText('Test 2', null, ['alignment' => Jc::CENTER]);\n        $section->addLink('https://github.com/PHPOffice/PHPWord');\n        $section->addTitle('Test', 1);\n        $section->addPageBreak();\n        $section->addImage($imageSrc);\n        $writer = new EPub3($phpWord);\n        $writer->save($file);\n        self::assertFileExists($file);\n        unlink($file);\n    }\n\n    /**\n     * Test PHP output.\n     */\n    public function testSavePhpOutput(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $section->addText('Test');\n        $writer = new EPub3($phpWord);\n        ob_start();\n        $writer->save('php://output');\n        $contents = ob_get_contents();\n        self::assertTrue(ob_end_clean());\n        self::assertNotEmpty($contents);\n    }\n\n    /**\n     * Test disk caching.\n     */\n    public function testSetGetUseDiskCaching(): void\n    {\n        $object = new EPub3();\n        $object->setUseDiskCaching(true, PHPWORD_TESTS_BASE_DIR);\n        self::assertTrue($object->isUseDiskCaching());\n        self::assertEquals(PHPWORD_TESTS_BASE_DIR, $object->getDiskCachingDirectory());\n    }\n\n    /**\n     * Test disk caching exception.\n     */\n    public function testSetUseDiskCachingException(): void\n    {\n        $this->expectException(Exception::class);\n        $dir = implode(DIRECTORY_SEPARATOR, [PHPWORD_TESTS_BASE_DIR, 'foo']);\n\n        $object = new EPub3();\n        $object->setUseDiskCaching(true, $dir);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/HTML/DirectionTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\HTML;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Shared\\Html as SharedHtml;\nuse PhpOffice\\PhpWord\\Writer\\HTML;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\HTML\\Element subnamespace.\n */\nclass DirectionTest extends \\PHPUnit\\Framework\\TestCase\n{\n    protected function tearDown(): void\n    {\n        Settings::setDefaultRtl(null);\n    }\n\n    /**\n     * Test unmatched elements.\n     */\n    public function testDirection(): void\n    {\n        $doc = new PhpWord();\n        Settings::setDefaultRtl(true);\n        $section = $doc->addSection();\n        $html = '<p>  الألم الذي ربما تنجم عنه بعض ا.</p>';\n        SharedHtml::addHtml($section, $html, false, false);\n        $english = '<p style=\"text-align: left; direction: ltr;\">LTR in RTL document.</p>';\n        SharedHtml::addHtml($section, $english, false, false);\n        SharedHtml::addHtml($section, $english, false, false);\n        SharedHtml::addHtml($section, $html, false, false);\n        SharedHtml::addHtml($section, $html, false, false);\n        $writer = new HTML($doc);\n        $content = $writer->getContent();\n        self::assertSame(3, substr_count($content, '<span style=\"direction: rtl;\">'));\n        self::assertSame(2, substr_count($content, '<span style=\"direction: ltr;\">'));\n        self::assertSame(3, substr_count($content, '<p style=\"direction: rtl;\">'));\n        self::assertSame(2, substr_count($content, '<p style=\"text-align: left;\">'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/HTML/Element/PageBreakTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\HTML\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\PageBreak as BasePageBreak;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Writer\\HTML;\nuse PhpOffice\\PhpWord\\Writer\\HTML\\Element\\PageBreak;\nuse PhpOffice\\PhpWord\\Writer\\PDF;\nuse PHPUnit\\Framework\\TestCase;\n\nclass PageBreakTest extends TestCase\n{\n    public function testHTML(): void\n    {\n        $writer = new HTML();\n        $object = new PageBreak($writer, new BasePageBreak());\n\n        self::assertEquals('<div style=\"page-break-before: always; height: 0; margin: 0; padding: 0; overflow: hidden;\">&#160;</div>' . PHP_EOL, $object->write());\n    }\n\n    public function testMPDF(): void\n    {\n        $rendererName = Settings::PDF_RENDERER_MPDF;\n        $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/mpdf/mpdf');\n        Settings::setPdfRenderer($rendererName, $rendererLibraryPath);\n        $writer = new PDF(new PhpWord());\n\n        $object = new PageBreak($writer->getRenderer(), new BasePageBreak());\n\n        self::assertEquals('<pagebreak style=\"page-break-before: always;\" pagebreak=\"true\"></pagebreak>', $object->write());\n    }\n\n    public function testDOMPDF(): void\n    {\n        $rendererName = Settings::PDF_RENDERER_DOMPDF;\n        $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/dompdf/dompdf');\n        Settings::setPdfRenderer($rendererName, $rendererLibraryPath);\n        $writer = new PDF(new PhpWord());\n\n        $object = new PageBreak($writer->getRenderer(), new BasePageBreak());\n\n        self::assertEquals('<pagebreak style=\"page-break-before: always;\" pagebreak=\"true\"></pagebreak>', $object->write());\n    }\n\n    public function testTCPDF(): void\n    {\n        $rendererName = Settings::PDF_RENDERER_TCPDF;\n        $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/tecnickcom/tcpdf');\n        Settings::setPdfRenderer($rendererName, $rendererLibraryPath);\n        $writer = new PDF(new PhpWord());\n\n        $object = new PageBreak($writer->getRenderer(), new BasePageBreak());\n\n        self::assertEquals('<br pagebreak=\"true\"/>', $object->write());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/HTML/Element/RubyTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\HTML\\Element;\n\nuse DOMXPath;\nuse PhpOffice\\PhpWord\\ComplexType\\RubyProperties;\nuse PhpOffice\\PhpWord\\Element\\TextRun;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWordTests\\Writer\\HTML\\Helper;\nuse PHPUnit\\Framework\\TestCase;\n\nclass RubyTest extends TestCase\n{\n    /**\n     * Tests writing ruby HTML.\n     */\n    public function testWriteRubyHtml(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $properties = new RubyProperties();\n        $properties->setAlignment(RubyProperties::ALIGNMENT_CENTER);\n        $properties->setFontFaceSize(10);\n        $properties->setFontPointsAboveBaseText(4);\n        $properties->setFontSizeForBaseText(20);\n        $properties->setLanguageId('ja-JP');\n\n        $baseTextRun = new TextRun(null);\n        $baseTextRun->addText('私');\n        $rubyTextRun = new TextRun(null);\n        $rubyTextRun->addText('わたし');\n        $section->addRuby($baseTextRun, $rubyTextRun, $properties);\n\n        $dom = Helper::getAsHTML($phpWord, '', '', ['ruby', 'rt', 'rp']);\n        $xpath = new DOMXPath($dom);\n        self::assertEquals(1, $xpath->query('/html/body/div/ruby')->length);\n        // ensure text is right\n        $rubyElement = $dom->getElementsByTagName('ruby')->item(0);\n        $rtElement = $dom->getElementsByTagName('rt')->item(0);\n        self::assertNotNull($rubyElement);\n        self::assertNotNull($rtElement);\n        self::assertEquals($baseTextRun->getText() . ' (' . $rubyTextRun->getText() . ')', $rubyElement->textContent);\n        self::assertEquals($rubyTextRun->getText(), $rtElement->textContent);\n        // check style\n        self::assertEquals('font-size:20pt;ruby-align:center;', $rubyElement->attributes->getNamedItem('style')->textContent);\n        self::assertEquals('font-size:10pt;', $rtElement->attributes->getNamedItem('style')->textContent);\n    }\n\n    /**\n     * Tests writing ruby HTML.\n     */\n    public function testWriteRubyHtmlParagraphStyle(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $properties = new RubyProperties();\n        $properties->setAlignment(RubyProperties::ALIGNMENT_CENTER);\n        $properties->setFontFaceSize(10);\n        $properties->setFontPointsAboveBaseText(4);\n        $properties->setFontSizeForBaseText(20);\n        $properties->setLanguageId('ja-JP');\n\n        $baseTextRun = new TextRun(['lineHeight' => '8']);\n        $baseTextRun->addText('私');\n        $rubyTextRun = new TextRun(['lineHeight' => '4']);\n        $rubyTextRun->addText('わたし');\n        $section->addRuby($baseTextRun, $rubyTextRun, $properties);\n\n        $dom = Helper::getAsHTML($phpWord, '', '', ['ruby', 'rt', 'rp']);\n        $xpath = new DOMXPath($dom);\n        self::assertEquals(1, $xpath->query('/html/body/div/ruby')->length);\n        // ensure text is right\n        $rubyElement = $dom->getElementsByTagName('ruby')->item(0);\n        $rtElement = $dom->getElementsByTagName('rt')->item(0);\n        self::assertNotNull($rubyElement);\n        self::assertNotNull($rtElement);\n        self::assertEquals($baseTextRun->getText() . ' (' . $rubyTextRun->getText() . ')', $rubyElement->textContent);\n        self::assertEquals($rubyTextRun->getText(), $rtElement->textContent);\n        // check style\n        self::assertEquals('line-height: 8;font-size:20pt;ruby-align:center;', $rubyElement->attributes->getNamedItem('style')->textContent);\n        self::assertEquals('line-height: 4;font-size:10pt;', $rtElement->attributes->getNamedItem('style')->textContent);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/HTML/Element/TableTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\HTML\\Element;\n\nuse DOMXPath;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\SimpleType\\VerticalJc;\nuse PhpOffice\\PhpWord\\Style;\nuse PhpOffice\\PhpWordTests\\Writer\\HTML\\Helper;\nuse PHPUnit\\Framework\\TestCase;\n\nclass TableTest extends TestCase\n{\n    /**\n     * Tests writing table with border styles.\n     */\n    public function testWriteTableBorders(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        $bsnone = ['borderStyle' => 'none'];\n        $table1 = $section->addTable($bsnone);\n        $row1 = $table1->addRow();\n        $row1->addCell(null, $bsnone)->addText('Row 1 Cell 1');\n        $row1->addCell(null, $bsnone)->addText('Row 1 Cell 2');\n        $row2 = $table1->addRow();\n        $row2->addCell(null, $bsnone)->addText('Row 2 Cell 1');\n        $row2->addCell(null, $bsnone)->addText('Row 2 Cell 2');\n\n        $table1 = $section->addTable();\n        $row1 = $table1->addRow();\n        $row1->addCell()->addText('Row 1 Cell 1');\n        $row1->addCell()->addText('Row 1 Cell 2');\n        $row2 = $table1->addRow();\n        $row2->addCell()->addText('Row 2 Cell 1');\n        $row2->addCell()->addText('Row 2 Cell 2');\n\n        $bstyle = ['borderStyle' => 'dashed', 'borderColor' => 'red'];\n        $table1 = $section->addTable($bstyle);\n        $row1 = $table1->addRow();\n        $row1->addCell(null, $bstyle)->addText('Row 1 Cell 1');\n        $row1->addCell(null, $bstyle)->addText('Row 1 Cell 2');\n        $row2 = $table1->addRow();\n        $row2->addCell(null, $bstyle)->addText('Row 2 Cell 1');\n        $row2->addCell(null, $bstyle)->addText('Row 2 Cell 2');\n\n        $bstyle = [\n            'borderTopStyle' => 'dotted',\n            'borderLeftStyle' => 'dashed',\n            'borderRightStyle' => 'dashed',\n            'borderBottomStyle' => 'dotted',\n            'borderTopColor' => 'blue',\n            'borderLeftColor' => 'green',\n            'borderRightColor' => 'green',\n            'borderBottomColor' => 'blue',\n        ];\n        $table1 = $section->addTable($bstyle);\n        $row1 = $table1->addRow();\n        $row1->addCell(null, $bstyle)->addText('Row 1 Cell 1');\n        $row1->addCell(null, $bstyle)->addText('Row 1 Cell 2');\n        $row2 = $table1->addRow();\n        $row2->addCell(null, $bstyle)->addText('Row 2 Cell 1');\n        $row2->addCell(null, $bstyle)->addText('Row 2 Cell 2');\n\n        $bstyle = ['borderStyle' => 'solid', 'borderSize' => 5];\n        $table1 = $section->addTable($bstyle);\n        $row1 = $table1->addRow();\n        $row1->addCell(null, $bstyle)->addText('Row 1 Cell 1');\n        $row1->addCell(null, $bstyle)->addText('Row 1 Cell 2');\n        $row2 = $table1->addRow();\n        $row2->addCell(null, $bstyle)->addText('Row 2 Cell 1');\n        $row2->addCell(null, $bstyle)->addText('Row 2 Cell 2');\n\n        $phpWord->addTableStyle('tstyle', ['borderStyle' => 'solid', 'borderSize' => 5]);\n        $table1 = $section->addTable('tstyle');\n        $row1 = $table1->addRow();\n        $row1->addCell(null, 'tstyle')->addText('Row 1 Cell 1');\n        $row1->addCell(null, 'tstyle')->addText('Row 1 Cell 2');\n        $row2 = $table1->addRow();\n        $row2->addCell(null, 'tstyle')->addText('Row 2 Cell 1');\n        $row2->addCell(null, 'tstyle')->addText('Row 2 Cell 2');\n\n        $dom = Helper::getAsHTML($phpWord);\n        $xpath = new DOMXPath($dom);\n\n        $cssnone = 'border-top-style: none;'\n            . ' border-left-style: none;'\n            . ' border-bottom-style: none;'\n            . ' border-right-style: none;';\n        self::assertEquals(\"table-layout: auto; $cssnone\", Helper::getTextContent($xpath, '/html/body/div/table[1]', 'style'));\n        self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[1]/tr[1]/td[1]', 'style'));\n        self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[1]/tr[1]/td[2]', 'style'));\n        self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[1]/tr[2]/td[1]', 'style'));\n        self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[1]/tr[2]/td[2]', 'style'));\n\n        self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/table[2]', 'style'));\n        self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/table[2]/tr[1]/td[1]', 'style'));\n        self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/table[2]/tr[1]/td[2]', 'style'));\n        self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/table[2]/tr[2]/td[1]', 'style'));\n        self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/table[2]/tr[2]/td[2]', 'style'));\n\n        $cssnone = 'border-top-style: dashed;'\n            . ' border-top-color: red;'\n            . ' border-left-style: dashed;'\n            . ' border-left-color: red;'\n            . ' border-bottom-style: dashed;'\n            . ' border-bottom-color: red;'\n            . ' border-right-style: dashed;'\n            . ' border-right-color: red;';\n        self::assertEquals(\"table-layout: auto; $cssnone\", Helper::getTextContent($xpath, '/html/body/div/table[3]', 'style'));\n        self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[3]/tr[1]/td[1]', 'style'));\n        self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[3]/tr[1]/td[2]', 'style'));\n        self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[3]/tr[2]/td[1]', 'style'));\n        self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[3]/tr[2]/td[2]', 'style'));\n\n        $cssnone = 'border-top-style: dotted;'\n            . ' border-top-color: blue;'\n            . ' border-left-style: dashed;'\n            . ' border-left-color: green;'\n            . ' border-bottom-style: dotted;'\n            . ' border-bottom-color: blue;'\n            . ' border-right-style: dashed;'\n            . ' border-right-color: green;';\n        self::assertEquals(\"table-layout: auto; $cssnone\", Helper::getTextContent($xpath, '/html/body/div/table[4]', 'style'));\n        self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[4]/tr[1]/td[1]', 'style'));\n        self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[4]/tr[1]/td[2]', 'style'));\n        self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[4]/tr[2]/td[1]', 'style'));\n        self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[4]/tr[2]/td[2]', 'style'));\n\n        $cssnone = 'border-top-style: solid;'\n            . ' border-top-width: 0.25pt;'\n            . ' border-left-style: solid;'\n            . ' border-left-width: 0.25pt;'\n            . ' border-bottom-style: solid;'\n            . ' border-bottom-width: 0.25pt;'\n            . ' border-right-style: solid;'\n            . ' border-right-width: 0.25pt;';\n        self::assertEquals(\"table-layout: auto; $cssnone\", Helper::getTextContent($xpath, '/html/body/div/table[5]', 'style'));\n        self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[5]/tr[1]/td[1]', 'style'));\n        self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[5]/tr[1]/td[2]', 'style'));\n        self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[5]/tr[2]/td[1]', 'style'));\n        self::assertEquals($cssnone, Helper::getTextContent($xpath, '/html/body/div/table[5]/tr[2]/td[2]', 'style'));\n\n        self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/table[6]', 'style'));\n        self::assertEquals('tstyle', Helper::getTextContent($xpath, '/html/body/div/table[6]', 'class'));\n        $style = Helper::getTextContent($xpath, '/html/head/style');\n        self::assertNotFalse(preg_match('/^[.]tstyle[^\\\\r\\\\n]*/m', $style, $matches));\n        self::assertEquals(\".tstyle {table-layout: auto; $cssnone}\", $matches[0]);\n    }\n\n    public function testWriteTableCellVAlign(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        $table = $section->addTable();\n        $row = $table->addRow();\n\n        $cell = $row->addCell();\n        $cell->addText('top text');\n        $cell->getStyle()->setVAlign(VerticalJc::TOP);\n\n        $cell = $row->addCell();\n        $cell->addText('bottom text');\n        $cell->getStyle()->setVAlign(VerticalJc::BOTTOM);\n\n        $cell = $row->addCell();\n        $cell->addText('no vAlign');\n        $cell->getStyle()->setVAlign(VerticalJc::BOTTOM);\n        $cell->getStyle()->setVAlign();\n\n        $dom = Helper::getAsHTML($phpWord);\n        $xpath = new DOMXPath($dom);\n\n        $cell1Style = Helper::getTextContent($xpath, '//table/tr/td[1]', 'style');\n        $cell2Style = Helper::getTextContent($xpath, '//table/tr/td[2]', 'style');\n        self::assertSame('vertical-align: top;', $cell1Style);\n        self::assertSame('vertical-align: bottom;', $cell2Style);\n\n        $cell3Query = $xpath->query('//table/tr/td[3]');\n        self::assertNotFalse($cell3Query);\n        self::assertCount(1, $cell3Query);\n\n        $cell3Style = $cell3Query->item(0)->attributes->getNamedItem('style');\n        self::assertNull($cell3Style);\n    }\n\n    public function testWriteTableCellVMerge(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        $table = $section->addTable();\n\n        $cell = $table->addRow()->addCell();\n        $cell->addText('text');\n        $cell->getStyle()->setVMerge(Style\\Cell::VMERGE_RESTART);\n\n        $cell = $table->addRow()->addCell();\n        $cell->getStyle()->setVMerge(Style\\Cell::VMERGE_CONTINUE);\n\n        $cell = $table->addRow()->addCell();\n        $cell->addText('no vMerge');\n        $cell->getStyle()->setVMerge(Style\\Cell::VMERGE_CONTINUE);\n        $cell->getStyle()->setVMerge();\n\n        $dom = Helper::getAsHTML($phpWord);\n        $xpath = new DOMXPath($dom);\n\n        $cell1Style = Helper::getTextContent($xpath, '//table/tr[1]/td[1]', 'rowspan');\n        self::assertSame('2', $cell1Style);\n\n        $cell3Query = $xpath->query('//table/tr[3]/td[1]');\n        self::assertNotFalse($cell3Query);\n        self::assertCount(1, $cell3Query);\n        self::assertNull($cell3Query->item(0)->attributes->getNamedItem('rowspan'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/HTML/Element/TextTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\HTML\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\Text as BaseText;\nuse PhpOffice\\PhpWord\\Writer\\HTML;\nuse PhpOffice\\PhpWord\\Writer\\HTML\\Element\\Text;\nuse PHPUnit\\Framework\\TestCase;\n\nclass TextTest extends TestCase\n{\n    public function testHTMLNullString(): void\n    {\n        $writer = new HTML();\n        $object = new Text($writer, new BaseText());\n\n        self::assertEquals('<p>&nbsp;</p>' . PHP_EOL, $object->write());\n    }\n\n    public function testHTMLEmptyString(): void\n    {\n        $writer = new HTML();\n        $object = new Text($writer, new BaseText(''));\n\n        self::assertEquals('<p>&nbsp;</p>' . PHP_EOL, $object->write());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/HTML/ElementTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\HTML;\n\nuse DateTime;\nuse DOMDocument;\nuse DOMXPath;\nuse PhpOffice\\PhpWord\\Element\\Text as TextElement;\nuse PhpOffice\\PhpWord\\Element\\TextRun;\nuse PhpOffice\\PhpWord\\Element\\TrackChange;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Writer\\HTML;\nuse PhpOffice\\PhpWord\\Writer\\HTML\\Element\\Text;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\HTML\\Element subnamespace.\n */\nclass ElementTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test unmatched elements.\n     */\n    public function testUnmatchedElements(): void\n    {\n        $elements = ['Container', 'Footnote', 'Image', 'Link', 'ListItem', 'ListItemRun', 'Table', 'Title', 'Bookmark'];\n        foreach ($elements as $element) {\n            $objectClass = 'PhpOffice\\\\PhpWord\\\\Writer\\\\HTML\\\\Element\\\\' . $element;\n            $parentWriter = new HTML();\n            $newElement = new \\PhpOffice\\PhpWord\\Element\\PageBreak();\n            $object = new $objectClass($parentWriter, $newElement);\n\n            self::assertEquals('', $object->write());\n        }\n    }\n\n    /**\n     * Test write element text.\n     */\n    public function testWriteTextElement(): void\n    {\n        $object = new Text(new HTML(), new TextElement(htmlspecialchars('A', ENT_COMPAT, 'UTF-8')));\n        $object->setOpeningText(htmlspecialchars('-', ENT_COMPAT, 'UTF-8'));\n        $object->setClosingText(htmlspecialchars('-', ENT_COMPAT, 'UTF-8'));\n        $object->setWithoutP(true);\n\n        self::assertEquals(htmlspecialchars('-A-', ENT_COMPAT, 'UTF-8'), $object->write());\n    }\n\n    /**\n     * Test write TrackChange.\n     */\n    public function testWriteTrackChanges(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $text = $section->addText('my dummy text');\n        $text->setChangeInfo(TrackChange::INSERTED, 'author name');\n        $text2 = $section->addText('my other text');\n        $text2->setTrackChange(new TrackChange(TrackChange::DELETED, 'another author', new DateTime()));\n\n        $dom = Helper::getAsHTML($phpWord);\n        $xpath = new DOMXPath($dom);\n\n        self::assertEquals(1, $xpath->query('/html/body/div/p[1]/ins')->length);\n        self::assertEquals(1, $xpath->query('/html/body/div/p[2]/del')->length);\n    }\n\n    /**\n     * Tests writing table with col span.\n     */\n    public function testWriteColSpan(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $table = $section->addTable();\n        $row1 = $table->addRow();\n        $cell11 = $row1->addCell(1000, ['gridSpan' => 2, 'bgColor' => '6086B8']);\n        $cell11->addText('cell spanning 2 bellow');\n        $row2 = $table->addRow();\n        $cell21 = $row2->addCell(500, ['bgColor' => 'ffffff']);\n        $cell21->addText('first cell');\n        $cell22 = $row2->addCell(500);\n        $cell22->addText('second cell');\n\n        $dom = Helper::getAsHTML($phpWord);\n        $xpath = new DOMXPath($dom);\n\n        self::assertEquals(1, $xpath->query('/html/body/div/table/tr[1]/td')->length);\n        self::assertEquals('2', $xpath->query('/html/body/div/table/tr/td[1]')->item(0)->attributes->getNamedItem('colspan')->textContent);\n        self::assertEquals(2, $xpath->query('/html/body/div/table/tr[2]/td')->length);\n\n        self::assertEquals('#6086B8', $xpath->query('/html/body/div/table/tr[1]/td')->item(0)->attributes->getNamedItem('bgcolor')->textContent);\n        self::assertEquals('#ffffff', $xpath->query('/html/body/div/table/tr[1]/td')->item(0)->attributes->getNamedItem('color')->textContent);\n        self::assertEquals('#ffffff', $xpath->query('/html/body/div/table/tr[2]/td')->item(0)->attributes->getNamedItem('bgcolor')->textContent);\n        self::assertNull($xpath->query('/html/body/div/table/tr[2]/td')->item(0)->attributes->getNamedItem('color'));\n    }\n\n    /**\n     * Tests writing table with row span.\n     */\n    public function testWriteRowSpan(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $table = $section->addTable();\n\n        $row1 = $table->addRow();\n        $row1->addCell(1000, ['vMerge' => 'restart'])->addText('row spanning 3 bellow');\n        $row1->addCell(500)->addText('first cell being spanned');\n\n        $row2 = $table->addRow();\n        $row2->addCell(null, ['vMerge' => 'continue']);\n        $row2->addCell(500)->addText('second cell being spanned');\n\n        $row3 = $table->addRow();\n        $row3->addCell(null, ['vMerge' => 'continue']);\n        $row3->addCell(500)->addText('third cell being spanned');\n\n        $dom = Helper::getAsHTML($phpWord);\n        $xpath = new DOMXPath($dom);\n\n        self::assertEquals(2, $xpath->query('/html/body/div/table/tr[1]/td')->length);\n        self::assertEquals('3', $xpath->query('/html/body/div/table/tr[1]/td[1]')->item(0)->attributes->getNamedItem('rowspan')->textContent);\n        self::assertEquals(1, $xpath->query('/html/body/div/table/tr[2]/td')->length);\n    }\n\n    /**\n     * Tests writing table with rowspan and colspan.\n     */\n    public function testWriteRowSpanAndColSpan(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $table = $section->addTable();\n\n        $row1 = $table->addRow();\n        $row1->addCell(500)->addText('A');\n        $row1->addCell(1000, ['gridSpan' => 2])->addText('B');\n        $row1->addCell(500, ['vMerge' => 'restart'])->addText('C');\n\n        $row2 = $table->addRow();\n        $row2->addCell(1500, ['gridSpan' => 3])->addText('D');\n        $row2->addCell(null, ['vMerge' => 'continue']);\n\n        $row3 = $table->addRow();\n        $row3->addCell(500)->addText('E');\n        $row3->addCell(500)->addText('F');\n        $row3->addCell(500)->addText('G');\n        $row3->addCell(null, ['vMerge' => 'continue']);\n\n        $dom = Helper::getAsHTML($phpWord);\n        $xpath = new DOMXPath($dom);\n\n        self::assertEquals(3, $xpath->query('/html/body/div/table/tr[1]/td')->length);\n        self::assertEquals('2', $xpath->query('/html/body/div/table/tr[1]/td[2]')->item(0)->attributes->getNamedItem('colspan')->textContent);\n        self::assertEquals('3', $xpath->query('/html/body/div/table/tr[1]/td[3]')->item(0)->attributes->getNamedItem('rowspan')->textContent);\n\n        self::assertEquals(1, $xpath->query('/html/body/div/table/tr[2]/td')->length);\n        self::assertEquals('3', $xpath->query('/html/body/div/table/tr[2]/td[1]')->item(0)->attributes->getNamedItem('colspan')->textContent);\n\n        self::assertEquals(3, $xpath->query('/html/body/div/table/tr[3]/td')->length);\n    }\n\n    public function testWriteTitleTextRun(): void\n    {\n        $expected = 'Title with TextRun';\n\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        $textRun = new TextRun();\n        $textRun->addText($expected);\n\n        $section->addTitle($textRun);\n\n        $htmlWriter = new HTML($phpWord);\n        $content = $htmlWriter->getContent();\n\n        self::assertStringContainsString($expected, $content);\n    }\n\n    /**\n     * Test write element ListItemRun.\n     */\n    public function testListItemRun(): void\n    {\n        $expected1 = 'List item run 1';\n        $expected2 = 'List item run 1 in bold';\n\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        $listItemRun = $section->addListItemRun(0, null, 'MyParagraphStyle');\n        $listItemRun->addText($expected1);\n        $listItemRun->addText($expected2, ['bold' => true]);\n\n        $htmlWriter = new HTML($phpWord);\n        $content = $htmlWriter->getContent();\n\n        $dom = new DOMDocument();\n        $dom->loadHTML($content);\n\n        self::assertEquals($expected1, $dom->getElementsByTagName('p')->item(0)->textContent);\n        self::assertEquals($expected2, $dom->getElementsByTagName('p')->item(1)->textContent);\n    }\n\n    /**\n     * Tests writing table with layout.\n     */\n    public function testWriteTableLayout(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $section->addTable();\n\n        $table1 = $section->addTable(['layout' => \\PhpOffice\\PhpWord\\Style\\Table::LAYOUT_FIXED]);\n        $row1 = $table1->addRow();\n        $row1->addCell()->addText('fixed layout table');\n\n        $table2 = $section->addTable(['layout' => \\PhpOffice\\PhpWord\\Style\\Table::LAYOUT_AUTO]);\n        $row2 = $table2->addRow();\n        $row2->addCell()->addText('auto layout table');\n\n        $dom = Helper::getAsHTML($phpWord);\n        $xpath = new DOMXPath($dom);\n\n        self::assertEquals('table-layout: fixed;', $xpath->query('/html/body/div/table[1]')->item(0)->attributes->getNamedItem('style')->textContent);\n        self::assertEquals('table-layout: auto;', $xpath->query('/html/body/div/table[2]')->item(0)->attributes->getNamedItem('style')->textContent);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/HTML/FontTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\HTML;\n\nuse DOMXPath;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Style\\Language;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\HTML\\Style\\Font.\n */\nclass FontTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /** @var string */\n    private $defaultFontName;\n\n    /** @var float|int */\n    private $defaultFontSize;\n\n    /** @var string */\n    private $defaultFontColor;\n\n    /**\n     * Executed before each method of the class.\n     */\n    protected function setUp(): void\n    {\n        $this->defaultFontName = Settings::getDefaultFontName();\n        $this->defaultFontSize = Settings::getDefaultFontSize();\n        $this->defaultFontColor = Settings::getDefaultFontColor();\n    }\n\n    /**\n     * Executed after each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        Settings::setDefaultFontName($this->defaultFontName);\n        Settings::setDefaultFontSize($this->defaultFontSize);\n        Settings::setDefaultFontColor($this->defaultFontColor);\n    }\n\n    public function testDefaultDefaults(): void\n    {\n        $phpWord = new PhpWord();\n\n        $dom = Helper::getAsHTML($phpWord);\n        $xpath = new DOMXPath($dom);\n        $style = Helper::getTextContent($xpath, '/html/head/style[1]');\n\n        $prg = preg_match('/body {(.*?)}/', $style, $matches);\n        self::assertNotEmpty($matches);\n        self::assertNotFalse($prg);\n        self::assertEquals('body {font-family: \\'Arial\\'; font-size: 12pt; color: #000000;}', $matches[0]);\n    }\n\n    public function testSettingDefaultFontColor(): void\n    {\n        $phpWord = new PhpWord();\n\n        $defaultFontColor = '00FF00';\n        $phpWord->setDefaultFontColor($defaultFontColor);\n\n        $dom = Helper::getAsHTML($phpWord);\n        $xpath = new DOMXPath($dom);\n        $style = Helper::getTextContent($xpath, '/html/head/style[1]');\n\n        $prg = preg_match('/body {(.*?)}/', $style, $matches);\n        self::assertNotEmpty($matches);\n        self::assertNotFalse($prg);\n        self::assertEquals('body {font-family: \\'Arial\\'; font-size: 12pt; color: #00FF00;}', $matches[0]);\n    }\n\n    /**\n     * Tests font names - without generics.\n     */\n    public function testFontNames1(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->setDefaultFontName('Courier New');\n        $phpWord->setDefaultFontSize(12);\n        $phpWord->addFontStyle('style1', ['name' => 'Tahoma', 'size' => 10, 'color' => '1B2232', 'bold' => true]);\n        $phpWord->addFontStyle('style2', ['name' => 'Arial', 'size' => 10]);\n        $phpWord->addFontStyle('style3', ['name' => 'hack attempt\\'}; display:none', 'size' => 10]);\n        $phpWord->addFontStyle('style4', ['name' => 'padmaa 1.1', 'size' => 10, 'bold' => true]);\n        $phpWord->addFontStyle('style5', ['name' => 'MingLiU-ExtB', 'size' => 10, 'bold' => true]);\n        $section1 = $phpWord->addSection();\n        $section1->addText('Default font');\n        $section1->addText('Tahoma', 'style1');\n        $section1->addText('Arial', 'style2');\n        $section1->addText('hack attempt', 'style3');\n        $section1->addText('padmaa 1.1 bold', 'style4');\n        $section1->addText('MingLiu-ExtB bold', 'style5');\n\n        $dom = Helper::getAsHTML($phpWord);\n        $xpath = new DOMXPath($dom);\n\n        self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/p[1]', 'class'));\n        self::assertEquals(0, Helper::getLength($xpath, '/html/body/div/p[1]/span'));\n        self::assertEquals('style1', Helper::getTextContent($xpath, '/html/body/div/p[2]/span', 'class'));\n        self::assertEquals('style2', Helper::getTextContent($xpath, '/html/body/div/p[3]/span', 'class'));\n        self::assertEquals('style3', Helper::getTextContent($xpath, '/html/body/div/p[4]/span', 'class'));\n        self::assertEquals('style4', Helper::getTextContent($xpath, '/html/body/div/p[5]/span', 'class'));\n        self::assertEquals('style5', Helper::getTextContent($xpath, '/html/body/div/p[6]/span', 'class'));\n\n        $style = Helper::getTextContent($xpath, '/html/head/style');\n        $prg = preg_match('/^[*][^\\\\r\\\\n]*/m', $style, $matches);\n        self::assertNotEmpty($matches);\n        self::assertNotFalse($prg);\n        self::assertEquals('* {font-family: \\'Courier New\\'; font-size: 12pt; color: #000000;}', $matches[0]);\n        $prg = preg_match('/^[.]style1[^\\\\r\\\\n]*/m', $style, $matches);\n        self::assertNotEmpty($matches);\n        self::assertNotFalse($prg);\n        self::assertEquals('.style1 {font-family: \\'Tahoma\\'; font-size: 10pt; color: #1B2232; font-weight: bold;}', $matches[0]);\n        $prg = preg_match('/^[.]style2[^\\\\r\\\\n]*/m', $style, $matches);\n        self::assertNotEmpty($matches);\n        self::assertNotFalse($prg);\n        self::assertEquals('.style2 {font-family: \\'Arial\\'; font-size: 10pt;}', $matches[0]);\n        $prg = preg_match('/^[.]style3[^\\\\r\\\\n]*/m', $style, $matches);\n        self::assertNotEmpty($matches);\n        self::assertNotFalse($prg);\n        self::assertEquals('.style3 {font-family: \\'hack attempt&#039;}; display:none\\'; font-size: 10pt;}', $matches[0]);\n        $prg = preg_match('/^[.]style4[^\\\\r\\\\n]*/m', $style, $matches);\n        self::assertNotEmpty($matches);\n        self::assertNotFalse($prg);\n        self::assertEquals('.style4 {font-family: \\'padmaa 1.1\\'; font-size: 10pt; font-weight: bold;}', $matches[0]);\n        $prg = preg_match('/^[.]style5[^\\\\r\\\\n]*/m', $style, $matches);\n        self::assertNotEmpty($matches);\n        self::assertNotFalse($prg);\n        self::assertEquals('.style5 {font-family: \\'MingLiU-ExtB\\'; font-size: 10pt; font-weight: bold;}', $matches[0]);\n    }\n\n    /**\n     * Tests font names - with generics.\n     */\n    public function testFontNames2(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->setDefaultFontName('Courier New');\n        $phpWord->setDefaultFontSize(12);\n        $phpWord->addFontStyle('style1', ['name' => 'Tahoma', 'size' => 10, 'color' => '1B2232', 'bold' => true]);\n        $phpWord->addFontStyle('style2', ['name' => 'Arial', 'size' => 10, 'fallbackFont' => 'sans-serif']);\n        $phpWord->addFontStyle('style3', ['name' => 'DejaVu Sans Monospace', 'size' => 10, 'fallbackFont' => 'monospace']);\n        $phpWord->addFontStyle('style4', ['name' => 'Arial', 'size' => 10, 'fallbackFont' => 'invalid']);\n        $section1 = $phpWord->addSection();\n        $section1->addText('Default font');\n        $section1->addText('Tahoma', 'style1');\n        $section1->addText('Arial', 'style2');\n        $section1->addText('DejaVu Sans Monospace', 'style3');\n        $section1->addText('Arial with invalid fallback', 'style4');\n\n        $dom = Helper::getAsHTML($phpWord);\n        $xpath = new DOMXPath($dom);\n\n        self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/p[1]', 'class'));\n        self::assertEquals(0, Helper::getLength($xpath, '/html/body/div/p[1]/span'));\n        self::assertEquals('style1', Helper::getTextContent($xpath, '/html/body/div/p[2]/span', 'class'));\n        self::assertEquals('style2', Helper::getTextContent($xpath, '/html/body/div/p[3]/span', 'class'));\n        self::assertEquals('style3', Helper::getTextContent($xpath, '/html/body/div/p[4]/span', 'class'));\n        self::assertEquals('style4', Helper::getTextContent($xpath, '/html/body/div/p[5]/span', 'class'));\n\n        $style = Helper::getTextContent($xpath, '/html/head/style');\n        $prg = preg_match('/^[*][^\\\\r\\\\n]*/m', $style, $matches);\n        self::assertNotEmpty($matches);\n        self::assertNotFalse($prg);\n        self::assertEquals('* {font-family: \\'Courier New\\'; font-size: 12pt; color: #000000;}', $matches[0]);\n        $prg = preg_match('/^[.]style1[^\\\\r\\\\n]*/m', $style, $matches);\n        self::assertNotEmpty($matches);\n        self::assertNotFalse($prg);\n        self::assertEquals('.style1 {font-family: \\'Tahoma\\'; font-size: 10pt; color: #1B2232; font-weight: bold;}', $matches[0]);\n        $prg = preg_match('/^[.]style2[^\\\\r\\\\n]*/m', $style, $matches);\n        self::assertNotEmpty($matches);\n        self::assertNotFalse($prg);\n        self::assertEquals('.style2 {font-family: \\'Arial\\', sans-serif; font-size: 10pt;}', $matches[0]);\n        $prg = preg_match('/^[.]style3[^\\\\r\\\\n]*/m', $style, $matches);\n        self::assertNotEmpty($matches);\n        self::assertNotFalse($prg);\n        self::assertEquals('.style3 {font-family: \\'DejaVu Sans Monospace\\', monospace; font-size: 10pt;}', $matches[0]);\n        $prg = preg_match('/^[.]style4[^\\\\r\\\\n]*/m', $style, $matches);\n        self::assertNotEmpty($matches);\n        self::assertNotFalse($prg);\n        self::assertEquals('.style4 {font-family: \\'Arial\\'; font-size: 10pt;}', $matches[0]);\n    }\n\n    /**\n     * Tests font names - with generics including for default font.\n     */\n    public function testFontNames3(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->setDefaultFontName('Courier New');\n        $phpWord->setDefaultFontSize(12);\n        $phpWord->addFontStyle('style1', ['name' => 'Tahoma', 'size' => 10, 'color' => '1B2232', 'bold' => true]);\n        $phpWord->addFontStyle('style2', ['name' => 'Arial', 'size' => 10, 'fallbackFont' => 'sans-serif']);\n        $phpWord->addFontStyle('style3', ['name' => 'DejaVu Sans Monospace', 'size' => 10, 'fallbackFont' => 'monospace']);\n        $phpWord->addFontStyle('style4', ['name' => 'Arial', 'size' => 10, 'fallbackFont' => 'invalid']);\n        $section1 = $phpWord->addSection();\n        $section1->addText('Default font');\n        $section1->addText('Tahoma', 'style1');\n        $section1->addText('Arial', 'style2');\n        $section1->addText('DejaVu Sans Monospace', 'style3');\n        $section1->addText('Arial with invalid fallback', 'style4');\n\n        $dom = Helper::getAsHTML($phpWord, '', 'monospace');\n        $xpath = new DOMXPath($dom);\n\n        self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/p[1]', 'class'));\n        self::assertEquals(0, Helper::getLength($xpath, '/html/body/div/p[1]/span'));\n        self::assertEquals('style1', Helper::getTextContent($xpath, '/html/body/div/p[2]/span', 'class'));\n        self::assertEquals('style2', Helper::getTextContent($xpath, '/html/body/div/p[3]/span', 'class'));\n        self::assertEquals('style3', Helper::getTextContent($xpath, '/html/body/div/p[4]/span', 'class'));\n        self::assertEquals('style4', Helper::getTextContent($xpath, '/html/body/div/p[5]/span', 'class'));\n\n        $style = Helper::getTextContent($xpath, '/html/head/style');\n        $prg = preg_match('/^[*][^\\\\r\\\\n]*/m', $style, $matches);\n        self::assertNotEmpty($matches);\n        self::assertNotFalse($prg);\n        self::assertEquals('* {font-family: \\'Courier New\\', monospace; font-size: 12pt; color: #000000;}', $matches[0]);\n        $prg = preg_match('/^[.]style1[^\\\\r\\\\n]*/m', $style, $matches);\n        self::assertNotEmpty($matches);\n        self::assertNotFalse($prg);\n        self::assertEquals('.style1 {font-family: \\'Tahoma\\'; font-size: 10pt; color: #1B2232; font-weight: bold;}', $matches[0]);\n        $prg = preg_match('/^[.]style2[^\\\\r\\\\n]*/m', $style, $matches);\n        self::assertNotEmpty($matches);\n        self::assertNotFalse($prg);\n        self::assertEquals('.style2 {font-family: \\'Arial\\', sans-serif; font-size: 10pt;}', $matches[0]);\n        $prg = preg_match('/^[.]style3[^\\\\r\\\\n]*/m', $style, $matches);\n        self::assertNotEmpty($matches);\n        self::assertNotFalse($prg);\n        self::assertEquals('.style3 {font-family: \\'DejaVu Sans Monospace\\', monospace; font-size: 10pt;}', $matches[0]);\n        $prg = preg_match('/^[.]style4[^\\\\r\\\\n]*/m', $style, $matches);\n        self::assertNotEmpty($matches);\n        self::assertNotFalse($prg);\n        self::assertEquals('.style4 {font-family: \\'Arial\\'; font-size: 10pt;}', $matches[0]);\n    }\n\n    /**\n     * Tests white space.\n     */\n    public function testWhiteSpace(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->setDefaultFontSize(12);\n        $phpWord->addFontStyle('style1', ['name' => 'Courier New', 'size' => 10, 'whiteSpace' => 'pre-wrap']);\n        $phpWord->addFontStyle('style2', ['name' => 'Courier New', 'size' => 10, 'whiteSpace' => 'invalid']);\n        $phpWord->addFontStyle('style3', ['name' => 'Courier New', 'size' => 10, 'whiteSpace' => 'normal']);\n        $phpWord->addFontStyle('style4', ['name' => 'Courier New', 'size' => 10, 'whiteSpace' => 'invalid']);\n        $text = 'This                  is                 a               long                      line                                              which                     will                      be              split over 2 lines with pre-wrap';\n        $section1 = $phpWord->addSection();\n        $section1->addText($text);\n        $section1->addText($text, 'style1');\n        $section1->addText($text, 'style2');\n        $section1->addText($text, 'style3');\n        $section1->addText($text, 'style4');\n\n        $dom = Helper::getAsHTML($phpWord, 'pre-wrap');\n        $xpath = new DOMXPath($dom);\n\n        $style = Helper::getTextContent($xpath, '/html/head/style');\n        self::assertNotFalse(preg_match('/^[*][^\\\\r\\\\n]*/m', $style, $matches));\n        self::assertEquals('* {font-family: \\'Arial\\'; font-size: 12pt; color: #000000; white-space: pre-wrap;}', $matches[0]);\n        $prg = preg_match('/^[.]style1[^\\\\r\\\\n]*/m', $style, $matches);\n        self::assertNotEmpty($matches);\n        self::assertNotFalse($prg);\n        self::assertEquals('.style1 {font-family: \\'Courier New\\'; font-size: 10pt; white-space: pre-wrap;}', $matches[0]);\n        $prg = preg_match('/^[.]style2[^\\\\r\\\\n]*/m', $style, $matches);\n        self::assertNotEmpty($matches);\n        self::assertNotFalse($prg);\n        self::assertEquals('.style2 {font-family: \\'Courier New\\'; font-size: 10pt;}', $matches[0]);\n        $prg = preg_match('/^[.]style3[^\\\\r\\\\n]*/m', $style, $matches);\n        self::assertNotEmpty($matches);\n        self::assertNotFalse($prg);\n        self::assertEquals('.style3 {font-family: \\'Courier New\\'; font-size: 10pt; white-space: normal;}', $matches[0]);\n        $prg = preg_match('/^[.]style4[^\\\\r\\\\n]*/m', $style, $matches);\n        self::assertNotEmpty($matches);\n        self::assertNotFalse($prg);\n        self::assertEquals('.style4 {font-family: \\'Courier New\\'; font-size: 10pt;}', $matches[0]);\n    }\n\n    /**\n     * Tests inline font style.\n     */\n    public function testInline(): void\n    {\n        $phpWord = new PhpWord();\n        $style1 = ['name' => 'Courier New', 'size' => 10, 'whiteSpace' => 'pre-wrap'];\n        $style2 = ['name' => 'Verdana', 'size' => 8.5];\n        $text = 'This is a paragraph.';\n        $section1 = $phpWord->addSection();\n        $section1->addText($text, $style1);\n        $section1->addText($text, $style2);\n        $section1->addText($text);\n\n        $dom = Helper::getAsHTML($phpWord);\n        $xpath = new DOMXPath($dom);\n\n        self::assertEquals('font-family: \\'Courier New\\'; font-size: 10pt; white-space: pre-wrap;', Helper::getTextContent($xpath, '/html/body/div/p[1]/span', 'style'));\n        self::assertEquals('font-family: \\'Verdana\\'; font-size: 8.5pt;', Helper::getTextContent($xpath, '/html/body/div/p[2]/span', 'style'));\n        self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/p[3]', 'class'));\n        self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/p[3]', 'style'));\n        self::assertEquals(0, Helper::getLength($xpath, '/html/body/div/p[3]/span'));\n    }\n\n    /**\n     * Tests languages.\n     */\n    public function testLanguages(): void\n    {\n        $phpWord = new PhpWord();\n        $langarabic = new Language('', '', 'ar-DZ');\n        $phpWord->addFontStyle('arabic', ['lang' => $langarabic]);\n        $langhindi = new Language('', 'hi-IN');\n        $phpWord->addFontStyle('hindi', ['lang' => $langhindi, 'name' => 'Arial']);\n        $phpWord->addFontStyle('nolang', ['name' => 'Verdana', 'size' => '10']);\n        $section = $phpWord->addSection();\n        $textrun = $section->addTextRun();\n        $textrun->addText('سلام این یک پاراگراف راست به چپ است', ['rtl' => true, 'lang' => $langarabic]);\n        $section->addText('Ce texte-ci est en français.', ['lang' => 'fr-BE']);\n        $section->addText('Ce texte-ci aussi.', ['lang' => 'fr-BE', 'name' => 'Verdana']);\n        $section->addText('Text with no language');\n        $section->addText('पाठ हिंदी में', 'hindi');\n        $section->addText('Non-existent style', 'nonexistent');\n        $section->addText('Style without language', 'nolang');\n\n        $dom = Helper::getAsHTML($phpWord);\n        $xpath = new DOMXPath($dom);\n        self::assertEquals('ar-DZ', Helper::getTextContent($xpath, '/html/body/div/p[1]/span', 'lang'));\n        self::assertEquals('fr-BE', Helper::getTextContent($xpath, '/html/body/div/p[2]/span', 'lang'));\n        self::assertEquals('fr-BE', Helper::getTextContent($xpath, '/html/body/div/p[3]/span', 'lang'));\n        self::assertEquals('font-family: \\'Verdana\\';', Helper::getTextContent($xpath, '/html/body/div/p[3]/span', 'style'));\n        self::assertEquals(0, Helper::getLength($xpath, '/html/body/div/p[4]/span'));\n        self::assertEquals('hi-IN', Helper::getTextContent($xpath, '/html/body/div/p[5]/span', 'lang'));\n        self::assertEquals('hindi', Helper::getTextContent($xpath, '/html/body/div/p[5]/span', 'class'));\n        self::assertEquals('nonexistent', Helper::getTextContent($xpath, '/html/body/div/p[6]/span', 'class'));\n        self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/p[6]/span', 'lang'));\n        self::assertEquals('nolang', Helper::getTextContent($xpath, '/html/body/div/p[7]/span', 'class'));\n        self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/p[7]/span', 'lang'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/HTML/Helper.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\HTML;\n\nuse DOMDocument;\nuse DOMXPath;\nuse Exception;\nuse LibXMLError;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Writer\\HTML;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\HTML\\Style subnamespace.\n */\nclass Helper extends \\PHPUnit\\Framework\\TestCase\n{\n    public static function getTextContent(DOMXPath $xpath, string $query, string $namedItem = '', int $itemNumber = 0): string\n    {\n        $returnVal = '';\n        $item = $xpath->query($query);\n        if ($item === false) {\n            self::fail('Unexpected false return from xpath query');\n        } else {\n            $item2 = $item->item($itemNumber);\n            if ($item2 === null) {\n                self::fail('Unexpected null return requesting item');\n            } elseif ($namedItem !== '') {\n                $item3 = $item2->attributes->getNamedItem($namedItem);\n                if ($item3 === null) {\n                    self::fail('Unexpected null return requesting namedItem');\n                } else {\n                    $returnVal = $item3->textContent;\n                }\n            } else {\n                $returnVal = $item2->textContent;\n            }\n        }\n\n        return $returnVal;\n    }\n\n    /** @return mixed */\n    public static function getNamedItem(DOMXPath $xpath, string $query, string $namedItem, int $itemNumber = 0)\n    {\n        $returnVal = '';\n        $item = $xpath->query($query);\n        if ($item === false) {\n            self::fail('Unexpected false return from xpath query');\n        } else {\n            $item2 = $item->item($itemNumber);\n            if ($item2 === null) {\n                self::fail('Unexpected null return requesting item');\n            } else {\n                $returnValue = $item2->attributes->getNamedItem($namedItem);\n            }\n        }\n\n        return $returnVal;\n    }\n\n    public static function getLength(DOMXPath $xpath, string $query): int\n    {\n        $returnVal = 0;\n        $item = $xpath->query($query);\n        if ($item === false) {\n            self::fail('Unexpected false return from xpath query');\n        } else {\n            $returnVal = $item->length;\n        }\n\n        return $returnVal;\n    }\n\n    public static function getAsHTML(PhpWord $phpWord, string $defaultWhiteSpace = '', string $defaultGenericFont = '', array $validTags = []): DOMDocument\n    {\n        $htmlWriter = new HTML($phpWord);\n        $htmlWriter->setDefaultWhiteSpace($defaultWhiteSpace);\n        $htmlWriter->setDefaultGenericFont($defaultGenericFont);\n        $dom = new DOMDocument();\n        // DOMDocument does not always accept HTML5 tags like <ruby>\n        // So, we can manually filter out those errors for testing purposes ONLY.\n        $original = libxml_use_internal_errors(true);\n        $dom->loadHTML($htmlWriter->getContent());\n        $errors = libxml_get_errors();\n        $errorsToReport = [];\n        foreach ($errors as $error) {\n            /** @var LibXMLError $error */\n            if ($error->code === 801) {\n                $didFindValidTag = false;\n                foreach ($validTags as $tag) {\n                    if (trim($error->message) === ('Tag ' . $tag . ' invalid')) {\n                        $didFindValidTag = true;\n\n                        break;\n                    }\n                }\n                if (!$didFindValidTag) {\n                    $errorsToReport[] = $error;\n                }\n            } else {\n                $errorsToReport[] = $error;\n            }\n        }\n        libxml_clear_errors();\n        libxml_use_internal_errors($original);\n        if (count($errorsToReport) > 0) {\n            throw new Exception('Errors when loading DOMDocument: ' . print_r($errors, true));\n        }\n\n        return $dom;\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/HTML/ParagraphTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\HTML;\n\nuse DOMXPath;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Shared\\Converter;\nuse PhpOffice\\PhpWord\\Writer\\HTML;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\HTML\\Style\\Font.\n */\nclass ParagraphTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Tests indentation, line-height, spaceBefore, spaceAfter, both inline and named.\n     */\n    public function testParagraphStyles(): void\n    {\n        $phpWord = new PhpWord();\n        $pstyle1 = ['spaceBefore' => 0, 'spaceAfter' => 0, 'lineHeight' => 1.08];\n        $phpWord->addParagraphStyle('indented', [\n            'indentation' => ['left' => 0.50 * Converter::INCH_TO_TWIP, 'right' => 0.60 * Converter::INCH_TO_TWIP],\n        ]);\n        $text = 'This is a paragraph. It should be long enough to show the effects of indentation on both the right and left sides.';\n        $section1 = $phpWord->addSection();\n        $section1->addText($text, null, $pstyle1);\n        $section1->addText($text, null, 'indented');\n\n        $dom = Helper::getAsHTML($phpWord);\n        $xpath = new DOMXPath($dom);\n\n        self::assertEquals(0, Helper::getLength($xpath, '/html/body/div/p[1]/span'));\n        self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/p[1]', 'class'));\n        self::assertEquals('margin-top: 0pt; margin-bottom: 0pt; line-height: 1.08;', Helper::getTextContent($xpath, '/html/body/div/p[1]', 'style'));\n        self::assertEquals(0, Helper::getLength($xpath, '/html/body/div/p[2]/span'));\n        self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/p[2]', 'style'));\n        self::assertEquals('indented', Helper::getTextContent($xpath, '/html/body/div/p[2]', 'class'));\n\n        $style = Helper::getTextContent($xpath, '/html/head/style');\n        self::assertNotFalse(preg_match('/^[.]indented[^\\\\r\\\\n]*/m', $style, $matches));\n        self::assertEquals('.indented {margin-left: 0.5in; margin-right: 0.6in;}', $matches[0]);\n    }\n\n    /**\n     * Tests paragraph and font styles specified togeter, both inline and named.\n     */\n    public function testParagraphAndFontStyles(): void\n    {\n        $phpWord = new PhpWord();\n        $pstyle1 = ['spaceBefore' => 0, 'spaceAfter' => 0, 'lineHeight' => 1.08];\n        $phpWord->addParagraphStyle('indented', [\n            'indentation' => ['left' => 0.50 * Converter::INCH_TO_TWIP, 'right' => 0.60 * Converter::INCH_TO_TWIP],\n        ]);\n        $phpWord->addFontStyle('style1', ['name' => 'Courier New', 'size' => 10, 'whiteSpace' => 'pre-wrap', 'fallbackFont' => 'monospace']);\n        $text = 'This is a paragraph. It should be long enough to show the effects of indentation on both the right and left sides.';\n        $section1 = $phpWord->addSection();\n        $section1->addText($text, 'style1', $pstyle1);\n        $section1->addText($text, ['name' => 'Verdana', 'size' => '12'], 'indented');\n\n        $dom = Helper::getAsHTML($phpWord);\n        $xpath = new DOMXPath($dom);\n\n        self::assertEquals(1, Helper::getLength($xpath, '/html/body/div/p[1]/span'));\n        self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/p[1]', 'class'));\n        self::assertEquals('margin-top: 0pt; margin-bottom: 0pt; line-height: 1.08;', Helper::getTextContent($xpath, '/html/body/div/p[1]', 'style'));\n        self::assertEquals('style1', Helper::getTextContent($xpath, '/html/body/div/p[1]/span', 'class'));\n        self::assertEquals(1, Helper::getLength($xpath, '/html/body/div/p[2]/span'));\n        self::assertEmpty(Helper::getNamedItem($xpath, '/html/body/div/p[2]', 'style'));\n        self::assertEquals('indented', Helper::getTextContent($xpath, '/html/body/div/p[2]', 'class'));\n        self::assertEquals('font-family: \\'Verdana\\'; font-size: 12pt;', Helper::getTextContent($xpath, '/html/body/div/p[2]/span', 'style'));\n\n        $style = Helper::getTextContent($xpath, '/html/head/style');\n        self::assertNotFalse(preg_match('/^[.]indented[^\\\\r\\\\n]*/m', $style, $matches));\n        self::assertEquals('.indented {margin-left: 0.5in; margin-right: 0.6in;}', $matches[0]);\n        self::assertNotFalse(preg_match('/^[.]style1[^\\\\r\\\\n]*/m', $style, $matches));\n        self::assertEquals('.style1 {font-family: \\'Courier New\\', monospace; font-size: 10pt; white-space: pre-wrap;}', $matches[0]);\n    }\n\n    /**\n     * Tests page break before.\n     */\n    public function testPageBreakBefore(): void\n    {\n        $phpWord = new PhpWord();\n        $pstyle1 = ['lineHeight' => 1.08];\n        $pstyle2 = ['lineHeight' => 1.08, 'pageBreakBefore' => true];\n\n        $section1 = $phpWord->addSection();\n        $section1->addText('1st paragraph 1st page', null, $pstyle1);\n        $section1->addText('2nd paragraph 1st page', null, $pstyle1);\n        $section1->addText('1st paragraph 2nd page', null, $pstyle2);\n        $section1->addText('2nd paragraph 2nd page', null, $pstyle1);\n\n        $dom = Helper::getAsHTML($phpWord);\n        $xpath = new DOMXPath($dom);\n        self::assertEquals('line-height: 1.08;', Helper::getTextContent($xpath, '/html/body/div/p[1]', 'style'));\n        self::assertEquals('line-height: 1.08;', Helper::getTextContent($xpath, '/html/body/div/p[2]', 'style'));\n        self::assertEquals('line-height: 1.08; page-break-before: always;', Helper::getTextContent($xpath, '/html/body/div/p[3]', 'style'));\n        self::assertEquals('line-height: 1.08;', Helper::getTextContent($xpath, '/html/body/div/p[4]', 'style'));\n    }\n\n    /**\n     * Tests blank paragraph.\n     */\n    public function testBlankParagraph(): void\n    {\n        $phpWord = new PhpWord();\n\n        $section1 = $phpWord->addSection();\n        $section1->addText('Text before blank text');\n        $section1->addText('');\n        $section1->addText('Text after blank text');\n\n        $htmlWriter = new HTML($phpWord);\n        $body = $htmlWriter->getWriterPart('Body')->write();\n        $bodylines = explode(PHP_EOL, $body);\n        self::assertEquals('<p>Text before blank text</p>', $bodylines[2]);\n        self::assertEquals('<p>&nbsp;</p>', $bodylines[3]);\n        self::assertEquals('<p>Text after blank text</p>', $bodylines[4]);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/HTML/PartTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\HTML;\n\nuse DOMXPath;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Shared\\Converter;\nuse PhpOffice\\PhpWord\\Writer\\HTML\\Part\\Body;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\HTML\\Part subnamespace.\n */\nclass PartTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test get parent writer exception.\n     */\n    public function testGetParentWriterException(): void\n    {\n        $this->expectException(\\PhpOffice\\PhpWord\\Exception\\Exception::class);\n        $object = new Body();\n        $object->getParentWriter();\n    }\n\n    /**\n     * Tests writing multiple sections.\n     */\n    public function testWriteSections(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->getSettings()->setThemeFontLang(new \\PhpOffice\\PhpWord\\Style\\Language('en-US'));\n        $section1 = $phpWord->addSection();\n        $mtop = 0.5 * Converter::INCH_TO_TWIP;\n        $mbot = 0.5 * Converter::INCH_TO_TWIP;\n        $mrig = 0.75 * Converter::INCH_TO_TWIP;\n        $mlef = 0.75 * Converter::INCH_TO_TWIP;\n        $section1\n            ->getStyle()\n            ->setPaperSize('Letter')\n            ->setMarginTop($mtop)\n            ->setMarginBottom($mbot)\n            ->setMarginLeft($mlef)\n            ->setMarginRight($mrig);\n        $section1->getStyle()->setPortrait();\n        $section1->addText('In theory, this will be printed portrait on letter paper');\n\n        $section2 = $phpWord->addSection();\n        $mtop = 0.6 * Converter::INCH_TO_TWIP;\n        $mbot = 0.6 * Converter::INCH_TO_TWIP;\n        $mrig = 0.65 * Converter::INCH_TO_TWIP;\n        $mlef = 0.65 * Converter::INCH_TO_TWIP;\n        $section2\n            ->getStyle()\n            ->setPaperSize('A4')\n            ->setMarginTop($mtop)\n            ->setMarginBottom($mbot)\n            ->setMarginLeft($mlef)\n            ->setMarginRight($mrig);\n        $section2->getStyle()->setLandscape();\n        $section2->addText('In theory, this will be printed landscape on A4 paper');\n\n        $dom = Helper::getAsHTML($phpWord);\n        $xpath = new DOMXPath($dom);\n\n        self::assertEquals('en-US', Helper::getTextContent($xpath, '/html', 'lang'));\n        self::assertEquals(2, Helper::getLength($xpath, '/html/body/div'));\n        self::assertEquals('page: page1', Helper::getTextContent($xpath, '/html/body/div[1]', 'style'));\n        self::assertEquals('page: page2', Helper::getTextContent($xpath, '/html/body/div[2]', 'style'));\n\n        $style = Helper::getTextContent($xpath, '/html/head/style');\n        self::assertNotFalse(strpos($style, 'body > div + div {page-break-before: always;}'));\n        self::assertNotFalse(strpos($style, 'div > *:first-child {page-break-before: auto;}'));\n        self::assertNotFalse(strpos($style, '@page page1 {size: Letter portrait; margin-right: 0.75in; margin-left: 0.75in; margin-top: 0.5in; margin-bottom: 0.5in; }'));\n        self::assertNotFalse(strpos($style, '@page page2 {size: A4 landscape; margin-right: 0.65in; margin-left: 0.65in; margin-top: 0.6in; margin-bottom: 0.6in; }'));\n    }\n\n    /**\n     * Tests theme font East Asian.\n     */\n    public function testThemeFontEastAsian(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->getSettings()->setThemeFontLang(new \\PhpOffice\\PhpWord\\Style\\Language('', 'hi-IN'));\n        $section1 = $phpWord->addSection();\n        $section1->addText('??? ????? ???');\n\n        $dom = Helper::getAsHTML($phpWord);\n        $xpath = new DOMXPath($dom);\n\n        self::assertEquals('hi-IN', Helper::getTextContent($xpath, '/html', 'lang'));\n    }\n\n    /**\n     * Tests theme font bidirectional.\n     */\n    public function testThemeBidirecional(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->getSettings()->setThemeFontLang(new \\PhpOffice\\PhpWord\\Style\\Language('', '', 'he-IL'));\n        $section1 = $phpWord->addSection();\n        $section1->addText('????');\n\n        $dom = Helper::getAsHTML($phpWord);\n        $xpath = new DOMXPath($dom);\n\n        self::assertEquals('he-IL', Helper::getTextContent($xpath, '/html', 'lang'));\n    }\n\n    /**\n     * Tests writing when default paragraph style is specified.\n     */\n    public function testDefaultParagraphStyle(): void\n    {\n        $phpWord = new PhpWord();\n        $nospacebeforeafter = ['spaceBefore' => 0, 'spaceAfter' => 0];\n        $phpWord->setDefaultParagraphStyle($nospacebeforeafter);\n        $section1 = $phpWord->addSection();\n        $section1->addText('First paragraph with no space before or after');\n        $section1->addText('Second paragraph with no space before or after');\n\n        $dom = Helper::getAsHTML($phpWord);\n        $xpath = new DOMXPath($dom);\n\n        self::assertEmpty(Helper::getNamedItem($xpath, '/html', 'lang'));\n        $style = Helper::getTextContent($xpath, '/html/head/style');\n        self::assertNotFalse(strpos($style, 'p, .Normal {margin-top: 0pt; margin-bottom: 0pt;}'));\n    }\n\n    /**\n     * Tests writing when default paragraph style is omitted.\n     */\n    public function testNoDefaultParagraphStyle(): void\n    {\n        $phpWord = new PhpWord();\n        $section1 = $phpWord->addSection();\n        $section1->addText('First paragraph with no space before or after');\n        $section1->addText('Second paragraph with no space before or after');\n\n        $dom = Helper::getAsHTML($phpWord);\n        $xpath = new DOMXPath($dom);\n\n        $style = Helper::getTextContent($xpath, '/html/head/style');\n        self::assertFalse(strpos($style, 'Normal'));\n    }\n\n    /**\n     * Tests title styles.\n     */\n    public function testTitleStyles(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->setDefaultParagraphStyle(['spaceBefore' => 0, 'spaceAfter' => 0]);\n        $phpWord->addTitleStyle(1, ['bold' => true, 'name' => 'Calibri'], ['spaceBefore' => 10, 'spaceAfter' => 10]);\n        $phpWord->addTitleStyle(2, ['italic' => true, 'name' => 'Times New Roman'], ['spaceBefore' => 5, 'spaceAfter' => 5]);\n        $section1 = $phpWord->addSection();\n        $section1->addTitle('Header 1 #1', 1);\n        $section1->addTitle('Header 2 #1', 2);\n        $section1->addText('Paragraph under header 2 #1');\n        $section1->addTitle('Header 2 #2', 2);\n        $section1->addText('Paragraph under header 2 #2');\n\n        $dom = Helper::getAsHTML($phpWord);\n        $xpath = new DOMXPath($dom);\n\n        $style = Helper::getTextContent($xpath, '/html/head/style');\n        self::assertNotFalse(strpos($style, 'h1 {font-family: \\'Calibri\\'; font-weight: bold;}'));\n        self::assertNotFalse(strpos($style, 'h1 {margin-top: 0.5pt; margin-bottom: 0.5pt;}'));\n        self::assertNotFalse(strpos($style, 'h2 {font-family: \\'Times New Roman\\'; font-style: italic;}'));\n        self::assertNotFalse(strpos($style, 'h2 {margin-top: 0.25pt; margin-bottom: 0.25pt;}'));\n        self::assertEquals(1, Helper::getLength($xpath, '/html/body/div/h1'));\n        self::assertEquals(2, Helper::getLength($xpath, '/html/body/div/h2'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/HTML/StyleTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\HTML;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\HTML\\Style subnamespace.\n */\nclass StyleTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test empty styles.\n     */\n    public function testEmptyStyles(): void\n    {\n        $styles = ['Font', 'Paragraph', 'Image', 'Table'];\n        foreach ($styles as $style) {\n            $objectClass = 'PhpOffice\\\\PhpWord\\\\Writer\\\\HTML\\\\Style\\\\' . $style;\n            $object = new $objectClass();\n\n            self::assertEquals('', $object->write());\n        }\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/HTMLTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\nuse PhpOffice\\PhpWord\\Writer\\HTML;\nuse PhpOffice\\PhpWordTests\\AbstractWebServerEmbedded;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\HTML.\n *\n * @runTestsInSeparateProcesses\n */\nclass HTMLTest extends AbstractWebServerEmbedded\n{\n    /**\n     * Construct.\n     */\n    public function testConstruct(): void\n    {\n        $object = new HTML(new PhpWord());\n\n        self::assertInstanceOf(PhpWord::class, $object->getPhpWord());\n    }\n\n    /**\n     * Construct with null.\n     */\n    public function testConstructWithNull(): void\n    {\n        $this->expectException(\\PhpOffice\\PhpWord\\Exception\\Exception::class);\n        $this->expectExceptionMessage('No PhpWord assigned.');\n        $object = new HTML();\n        $object->getPhpWord();\n    }\n\n    public function testEditCallback(): void\n    {\n        $object = new HTML(new PhpWord());\n\n        self::assertNull($object->getEditCallback());\n\n        $object->setEditCallback(function (string $html): string {\n            return $html;\n        });\n        self::assertIsCallable($object->getEditCallback());\n\n        $object->setEditCallback(null);\n        self::assertNull($object->getEditCallback());\n    }\n\n    public function testDefaultGenericFont(): void\n    {\n        $object = new HTML(new PhpWord());\n\n        self::assertEquals('', $object->getDefaultGenericFont());\n\n        $object->setDefaultGenericFont('test');\n        self::assertEquals('', $object->getDefaultGenericFont());\n\n        $object->setDefaultGenericFont('cursive');\n        self::assertEquals('cursive', $object->getDefaultGenericFont());\n    }\n\n    public function testDefaultWhiteSpace(): void\n    {\n        $object = new HTML(new PhpWord());\n\n        self::assertEquals('', $object->getDefaultWhiteSpace());\n\n        $object->setDefaultWhiteSpace('test');\n        self::assertEquals('', $object->getDefaultWhiteSpace());\n\n        $object->setDefaultWhiteSpace('pre-line');\n        self::assertEquals('pre-line', $object->getDefaultWhiteSpace());\n    }\n\n    /**\n     * Save.\n     */\n    public function testSave(): void\n    {\n        $localImage = __DIR__ . '/../_files/images/PhpWord.png';\n        $archiveImage = 'zip://' . __DIR__ . '/../_files/documents/reader.docx#word/media/image1.jpeg';\n        $gdImage = self::getRemoteGifImageUrl();\n        $objectSrc = __DIR__ . '/../_files/documents/sheet.xls';\n        $file = __DIR__ . '/../_files/temp.html';\n\n        $phpWord = new PhpWord();\n\n        $docProps = $phpWord->getDocInfo();\n        $docProps->setTitle(htmlspecialchars('HTML Test', ENT_COMPAT, 'UTF-8'));\n\n        $phpWord->addTitleStyle(1, ['bold' => true]);\n        $phpWord->addFontStyle(\n            'Font',\n            ['name' => 'Verdana', 'size' => 11, 'color' => 'FF0000', 'fgColor' => 'FF0000']\n        );\n        $phpWord->addParagraphStyle('Paragraph', ['alignment' => Jc::CENTER, 'spaceAfter' => 20, 'spaceBefore' => 20]);\n        $section = $phpWord->addSection();\n        $section->addBookmark('top');\n        $section->addText(htmlspecialchars('Test 1', ENT_COMPAT, 'UTF-8'), 'Font', 'Paragraph');\n        $section->addTextBreak();\n        $section->addText(\n            htmlspecialchars('Test 2', ENT_COMPAT, 'UTF-8'),\n            ['name' => 'Tahoma', 'bold' => true, 'italic' => true, 'subscript' => true]\n        );\n        $section->addLink('https://github.com/PHPOffice/PHPWord');\n        $section->addTitle(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8'), 1);\n        $section->addPageBreak();\n        $section->addListItem(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8'));\n        $section->addImage($localImage);\n        $section->addImage($archiveImage);\n        $section->addImage($gdImage);\n        $section->addObject($objectSrc);\n        $section->addFootnote();\n        $section->addEndnote();\n\n        $section = $phpWord->addSection();\n\n        $textrun = $section->addTextRun(['alignment' => Jc::CENTER]);\n        $textrun->addText(htmlspecialchars('Test 3', ENT_COMPAT, 'UTF-8'));\n        $textrun->addTextBreak();\n\n        $textrun = $section->addTextRun(['alignment' => Jc::START]);\n        $textrun->addText(htmlspecialchars('Text left aligned', ENT_COMPAT, 'UTF-8'));\n\n        $textrun = $section->addTextRun(['alignment' => Jc::BOTH]);\n        $textrun->addText(htmlspecialchars('Text justified', ENT_COMPAT, 'UTF-8'));\n\n        $textrun = $section->addTextRun(['alignment' => Jc::END]);\n        $textrun->addText(htmlspecialchars('Text right aligned', ENT_COMPAT, 'UTF-8'));\n\n        $textrun = $section->addTextRun('Paragraph');\n        $textrun->addLink('https://github.com/PHPOffice/PHPWord');\n        $textrun->addImage($localImage);\n        $textrun->addFootnote()->addText(htmlspecialchars('Footnote', ENT_COMPAT, 'UTF-8'));\n        $textrun->addEndnote()->addText(htmlspecialchars('Endnote', ENT_COMPAT, 'UTF-8'));\n\n        $section = $phpWord->addSection();\n\n        $table = $section->addTable();\n        $cell = $table->addRow()->addCell();\n        $cell->addText(\n            htmlspecialchars('Test 1', ENT_COMPAT, 'UTF-8'),\n            ['superscript' => true, 'underline' => 'dash', 'strikethrough' => true]\n        );\n        $cell->addTextRun();\n        $cell->addLink('https://github.com/PHPOffice/PHPWord');\n        $cell->addTextBreak();\n        $cell->addListItem(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8'));\n        $cell->addImage($localImage);\n        $cell->addObject($objectSrc);\n        $cell->addFootnote();\n        $cell->addEndnote();\n        $cell = $table->addRow()->addCell();\n        $section->addLink('top', 'back to top', null, null, true);\n\n        $writer = new HTML($phpWord);\n\n        $writer->save($file);\n        self::assertFileExists($file);\n        unlink($file);\n\n        Settings::setOutputEscapingEnabled(true);\n        $writer->save($file);\n        self::assertFileExists($file);\n        unlink($file);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/ODText/Element/FieldTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\ODText\\Element;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\nuse PHPUnit\\Framework\\TestCase;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\ODText\\Element subnamespace.\n */\nclass FieldTest extends TestCase\n{\n    /**\n     * Executed before each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    public function testFieldFilename(): void\n    {\n        $phpWord = new PhpWord();\n\n        $section = $phpWord->addSection();\n        $section->addField('FILENAME');\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n\n        self::assertTrue($doc->elementExists('/office:document-content/office:body/office:text/text:section/text:span/text:file-name'));\n        self::assertEquals('false', $doc->getElementAttribute('/office:document-content/office:body/office:text/text:section/text:span/text:file-name', 'text:fixed'));\n        self::assertEquals('name', $doc->getElementAttribute('/office:document-content/office:body/office:text/text:section/text:span/text:file-name', 'text:display'));\n    }\n\n    public function testFieldFilenameOptionPath(): void\n    {\n        $phpWord = new PhpWord();\n\n        $section = $phpWord->addSection();\n        $section->addField('FILENAME', [], ['Path']);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n\n        self::assertTrue($doc->elementExists('/office:document-content/office:body/office:text/text:section/text:span/text:file-name'));\n        self::assertEquals('false', $doc->getElementAttribute('/office:document-content/office:body/office:text/text:section/text:span/text:file-name', 'text:fixed'));\n        self::assertEquals('full', $doc->getElementAttribute('/office:document-content/office:body/office:text/text:section/text:span/text:file-name', 'text:display'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/ODText/Element/FormulaTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\ODText\\Element;\n\nuse PhpOffice\\Math\\Element;\nuse PhpOffice\\Math\\Math;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\nuse PHPUnit\\Framework\\TestCase;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\ODText\\Element subnamespace.\n */\nclass FormulaTest extends TestCase\n{\n    /**\n     * Executed before each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    public function testBasicFormula(): void\n    {\n        $math = new Math();\n        $math\n            ->add(\n                new Element\\Fraction(\n                    new Element\\Numeric(2),\n                    new Element\\Identifier('π')\n                )\n            )\n            ->add(\n                new Element\\Operator('+')\n            )\n            ->add(\n                new Element\\Identifier('a')\n            )\n            ->add(\n                new Element\\Operator('∗')\n            )\n            ->add(\n                new Element\\Numeric(2)\n            );\n\n        $phpWord = new PhpWord();\n\n        $section = $phpWord->addSection();\n        $section->addFormula($math);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n\n        self::assertTrue($doc->elementExists('/office:document-content/office:body/office:text/text:section/text:p/draw:frame/draw:object'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/ODText/Element/ImageTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\ODText\\Style;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Style\\Image;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\ODText\\Element\\Image.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Writer\\ODText\\Element\\Image\n */\nclass ImageTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Executed after each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        Settings::setDefaultRtl(null);\n        TestHelperDOCX::clear();\n    }\n\n    /**\n     * Test writing image.\n     */\n    public function testImage1(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $section->addImage(__DIR__ . '/../../../_files/images/earth.jpg');\n        $section->addImage(__DIR__ . '/../../../_files/images/mario.gif', ['align' => 'end']);\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n        $s2a = '/office:document-content/office:automatic-styles';\n        $element = \"$s2a/style:style[3]\";\n        self::assertEquals('IM1', $doc->getElementAttribute($element, 'style:name'));\n        $element .= '/style:paragraph-properties';\n        self::assertEquals('', $doc->getElementAttribute($element, 'fo:text-align'));\n        $element = \"$s2a/style:style[4]\";\n        self::assertEquals('IM2', $doc->getElementAttribute($element, 'style:name'));\n        $element .= '/style:paragraph-properties';\n        self::assertEquals('end', $doc->getElementAttribute($element, 'fo:text-align'));\n\n        $path = '/office:document-content/office:body/office:text/text:section/text:p[2]';\n        self::assertTrue($doc->elementExists($path));\n        self::assertFalse($doc->hasElementAttribute($path, 'draw:text-style-name'));\n        self::assertEquals('IM1', $doc->getElementAttribute($path, 'text:style-name'));\n        $path = '/office:document-content/office:body/office:text/text:section/text:p[3]';\n        self::assertTrue($doc->elementExists($path));\n        self::assertFalse($doc->hasElementAttribute($path, 'draw:text-style-name'));\n        self::assertEquals('IM2', $doc->getElementAttribute($path, 'text:style-name'));\n    }\n\n    /**\n     * Test writing image, with non-default bidi.\n     */\n    public function testImage2(): void\n    {\n        $phpWord = new PhpWord();\n        Settings::setDefaultRtl(false);\n        $section = $phpWord->addSection();\n        $section->addImage(__DIR__ . '/../../../_files/images/earth.jpg');\n        $section->addImage(__DIR__ . '/../../../_files/images/mario.gif', ['align' => 'end']);\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n        $s2a = '/office:document-content/office:automatic-styles';\n        $element = \"$s2a/style:style[3]\";\n        self::assertEquals('IM1', $doc->getElementAttribute($element, 'style:name'));\n        $element .= '/style:paragraph-properties';\n        self::assertEquals('left', $doc->getElementAttribute($element, 'fo:text-align'));\n        $element = \"$s2a/style:style[4]\";\n        self::assertEquals('IM2', $doc->getElementAttribute($element, 'style:name'));\n        $element .= '/style:paragraph-properties';\n        self::assertEquals('right', $doc->getElementAttribute($element, 'fo:text-align'));\n\n        $path = '/office:document-content/office:body/office:text/text:section/text:p[2]';\n        self::assertTrue($doc->elementExists($path));\n        self::assertEquals('IM1', $doc->getElementAttribute($path, 'text:style-name'));\n        self::assertFalse($doc->hasElementAttribute($path, 'draw:text-style-name'));\n        $path = '/office:document-content/office:body/office:text/text:section/text:p[3]';\n        self::assertTrue($doc->elementExists($path));\n        self::assertEquals('IM2', $doc->getElementAttribute($path, 'text:style-name'));\n        self::assertFalse($doc->hasElementAttribute($path, 'draw:text-style-name'));\n    }\n\n    /**\n     * Test writing image not in a section.\n     */\n    public function testImageInTextRun(): void\n    {\n        $phpWord = new PhpWord();\n        Settings::setDefaultRtl(false);\n        $section = $phpWord->addSection();\n        $textRun = $section->addTextRun();\n        $textRun->addImage(__DIR__ . '/../../../_files/images/earth.jpg');\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n        $s2a = '/office:document-content/office:automatic-styles';\n        $element = \"$s2a/style:style[4]\";\n        self::assertEquals('IM1', $doc->getElementAttribute($element, 'style:name'));\n        $element .= '/style:paragraph-properties';\n        self::assertEquals('left', $doc->getElementAttribute($element, 'fo:text-align'));\n\n        $path = '/office:document-content/office:body/office:text/text:section/text:p[2]';\n        self::assertTrue($doc->elementExists($path));\n        self::assertEquals('P1', $doc->getElementAttribute($path, 'text:style-name'));\n        $path = '/office:document-content/office:body/office:text/text:section/text:p[2]/draw:frame';\n        self::assertTrue($doc->elementExists($path));\n        self::assertTrue($doc->hasElementAttribute($path, 'draw:text-style-name'));\n        self::assertEquals('IM1', $doc->getElementAttribute($path, 'draw:text-style-name'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/ODText/Element/ListItemRunTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\ODText\\Element;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\nuse PHPUnit\\Framework\\TestCase;\n\nclass ListItemRunTest extends TestCase\n{\n    /**\n     * Executed after each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    public function testAddListItemRun(): void\n    {\n        $expected = 'List item run 1';\n\n        $phpWord = new PhpWord();\n        $phpWord\n            ->addSection()\n            ->addListItemRun()\n            ->addText($expected);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n\n        $xPath = '/office:document-content/office:body/office:text/text:section/text:list';\n\n        self::assertTrue($doc->elementExists($xPath));\n        self::assertTrue($doc->hasElementAttribute($xPath, 'text:style-name'));\n        self::assertEquals('PHPWordListType3', $doc->getElementAttribute($xPath, 'text:style-name'));\n        self::assertTrue($doc->elementExists($xPath . '/text:list-item'));\n        self::assertTrue($doc->elementExists($xPath . '/text:list-item/text:p'));\n        self::assertTrue($doc->elementExists($xPath . '/text:list-item/text:p/text:span'));\n        self::assertEquals($expected, $doc->getElement($xPath . '/text:list-item/text:p/text:span')->nodeValue);\n    }\n\n    public function testAddListItemRunLevels(): void\n    {\n        $expected = 'List item run : ';\n\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $section->addListItemRun(0)->addText($expected . '1');\n        $section->addListItemRun(1)->addText($expected . '2');\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n\n        $xPath = '/office:document-content/office:body/office:text/text:section/text:list';\n\n        self::assertTrue($doc->elementExists($xPath));\n        self::assertTrue($doc->hasElementAttribute($xPath, 'text:style-name'));\n        self::assertEquals('PHPWordListType3', $doc->getElementAttribute($xPath, 'text:style-name'));\n        self::assertTrue($doc->elementExists($xPath . '/text:list-item'));\n        self::assertTrue($doc->elementExists($xPath . '/text:list-item/text:p'));\n        self::assertTrue($doc->elementExists($xPath . '/text:list-item/text:p/text:span'));\n        self::assertEquals($expected . '1', $doc->getElement($xPath . '/text:list-item/text:p/text:span')->nodeValue);\n        self::assertTrue($doc->elementExists($xPath . '/text:list-item/text:list/text:list-item'));\n        self::assertTrue($doc->elementExists($xPath . '/text:list-item/text:list/text:list-item/text:p'));\n        self::assertTrue($doc->elementExists($xPath . '/text:list-item/text:list/text:list-item/text:p/text:span'));\n        self::assertEquals($expected . '2', $doc->getElement($xPath . '/text:list-item/text:list/text:list-item/text:p/text:span')->nodeValue);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/ODText/ElementTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\ODText;\n\nuse DateTime;\nuse PhpOffice\\PhpWord\\ComplexType\\RubyProperties;\nuse PhpOffice\\PhpWord\\Element\\TextRun;\nuse PhpOffice\\PhpWord\\Element\\TrackChange;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\ODText\\Element subnamespace.\n */\nclass ElementTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Executed after each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    /**\n     * Test unmatched elements.\n     */\n    public function testUnmatchedElements(): void\n    {\n        $elements = ['Image', 'Link', 'Table', 'Text', 'Title', 'Field'];\n        foreach ($elements as $element) {\n            $objectClass = 'PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Element\\\\' . $element;\n            $xmlWriter = new XMLWriter();\n            $newElement = new \\PhpOffice\\PhpWord\\Element\\PageBreak();\n            $object = new $objectClass($xmlWriter, $newElement);\n            $object->write();\n\n            self::assertEquals('', $xmlWriter->getData());\n        }\n    }\n\n    // ODT Line Element not yet implemented\n    // ODT Bookmark not yet implemented\n    // ODT Table with style name not yet implemented (Word test defective)\n    // ODT Shape Elements not yet implemented\n    // ODT Chart Elements not yet implemented\n    // ODT adding Field to Section not yet implemented\n    // ODT List not yet implemented\n    // ODT Macro Button not yet implemented\n    // ODT Form Field not yet implemented\n    // ODT SDT not yet implemented\n    // ODT Comment not yet implemented\n    // ODT Track Changes implemented, possibly not correctly\n    // ODT List Item not yet implemented\n\n    /**\n     * Test link element.\n     */\n    public function testLinkElement(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        $extlink = 'https://github.com/PHPOffice/PHPWord';\n        $section->addLink($extlink);\n        $intlink = 'internal_link';\n        $section->addLink($intlink, null, null, null, true);\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n\n        $p2t = '/office:document-content/office:body/office:text/text:section';\n        $element = \"$p2t/text:p[2]/text:a\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals($extlink, $doc->getElementAttribute($element, 'xlink:href'));\n\n        $element = \"$p2t/text:p[3]/text:a\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals(\"#$intlink\", $doc->getElementAttribute($element, 'xlink:href'));\n    }\n\n    /**\n     * Basic test for table element.\n     */\n    public function testTableElements(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        $table = $section->addTable(['alignment' => \\PhpOffice\\PhpWord\\SimpleType\\JcTable::CENTER]);\n        $table->addRow(900);\n        $table->addCell(2000)->addText('Row 1');\n        $table->addCell(2000)->addText('Row 2');\n        $table->addCell(2000)->addText('Row 3');\n        $table->addCell(2000)->addText('Row 4');\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n\n        $p2s = '/office:document-content/office:automatic-styles';\n        $tableStyleNum = 1;\n        /** @var null|string $tableStyleName */\n        $tableStyleName = null;\n        $element = '';\n        while ($tableStyleName === null) {\n            $element = \"$p2s/style:style[$tableStyleNum]\";\n            if (!$doc->elementExists($element)) {\n                break;\n            }\n            if ($doc->getElementAttribute($element, 'style:family') === 'table') {\n                $tableStyleName = $doc->getElementAttribute($element, 'style:name');\n\n                break;\n            }\n            ++$tableStyleNum;\n        }\n        self::assertNotNull($tableStyleName);\n        $element = \"$element/style:table-properties\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals(\\PhpOffice\\PhpWord\\SimpleType\\JcTable::CENTER, $doc->getElementAttribute($element, 'table:align'));\n        $p2t = '/office:document-content/office:body/office:text/text:section';\n        $tableRootElement = \"$p2t/table:table\";\n        self::assertTrue($doc->elementExists($tableRootElement));\n        self::assertEquals($tableStyleName, $doc->getElementAttribute($tableRootElement, 'table:style-name'));\n        self::assertTrue($doc->elementExists($tableRootElement . '/table:table-column[4]'));\n    }\n\n    /**\n     * Test Title and Headings.\n     */\n    public function testTitleAndHeading(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->addTitleStyle(0, ['size' => 14, 'italic' => true]);\n        $phpWord->addTitleStyle(1, ['size' => 20, 'color' => '333333', 'bold' => true]);\n\n        $section = $phpWord->addSection();\n        $section->addTitle('This is a title', 0);\n        $section->addTitle('Heading 1', 1);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n\n        $p2t = '/office:document-content/office:body/office:text/text:section';\n        $element = \"$p2t/text:h[1]\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('HE0', $doc->getElementAttribute($element, 'text:style-name'));\n        self::assertEquals('0', $doc->getElementAttribute($element, 'text:outline-level'));\n        $span = \"$element/text:span\";\n        self::assertTrue($doc->elementExists($span));\n        self::assertEquals('This is a title', $doc->getElement($span)->textContent);\n        self::assertEquals('Title', $doc->getElementAttribute($span, 'text:style-name'));\n\n        $element = \"$p2t/text:h[2]\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('HD1', $doc->getElementAttribute($element, 'text:style-name'));\n        self::assertEquals('1', $doc->getElementAttribute($element, 'text:outline-level'));\n        $span = \"$element/text:span\";\n        self::assertTrue($doc->elementExists($span));\n        self::assertEquals('Heading 1', $doc->getElement($span)->textContent);\n        self::assertEquals('Heading_1', $doc->getElementAttribute($span, 'text:style-name'));\n\n        $doc->setDefaultFile('styles.xml');\n        $element = '/office:document-styles/office:styles/style:style[1]';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('Title', $doc->getElementAttribute($element, 'style:name'));\n        $element .= '/style:text-properties';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('14pt', $doc->getElementAttribute($element, 'fo:font-size'));\n        self::assertEquals('italic', $doc->getElementAttribute($element, 'fo:font-style'));\n        self::assertEquals('', $doc->getElementAttribute($element, 'fo:font-weight'));\n        self::assertEquals('', $doc->getElementAttribute($element, 'fo:color'));\n\n        $element = '/office:document-styles/office:styles/style:style[2]';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('Heading_1', $doc->getElementAttribute($element, 'style:name'));\n        $element .= '/style:text-properties';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('20pt', $doc->getElementAttribute($element, 'fo:font-size'));\n        self::assertEquals('', $doc->getElementAttribute($element, 'fo:font-style'));\n        self::assertEquals('bold', $doc->getElementAttribute($element, 'fo:font-weight'));\n        self::assertEquals('#333333', $doc->getElementAttribute($element, 'fo:color'));\n    }\n\n    /**\n     * Test title specified as text run rather than text.\n     */\n    public function testTextRunTitle(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->addTitleStyle(1, ['name' => 'Times New Roman', 'size' => 18, 'bold' => true]);\n        $section = $phpWord->addSection();\n        $section->addTitle('Text Title', 1);\n        $section->addText('Text following Text Title');\n        $textRun = new TextRun();\n        $textRun->addText('Text Run');\n        $textRun->addText(' Title');\n        $section->addTitle($textRun, 1);\n        $section->addText('Text following Text Run Title');\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n\n        $p2t = '/office:document-content/office:body/office:text/text:section';\n\n        $element = \"$p2t/text:h[1]\";\n        self::assertEquals('HE1', $doc->getElementAttribute($element, 'text:style-name'));\n        self::assertEquals('1', $doc->getElementAttribute($element, 'text:outline-level'));\n        $span = \"$element/text:span\";\n        self::assertEquals('Text Title', $doc->getElement($span)->textContent);\n        self::assertEquals('Heading_1', $doc->getElementAttribute($span, 'text:style-name'));\n        $element = \"$p2t/text:p[2]/text:span\";\n        self::assertEquals('Text following Text Title', $doc->getElement($element)->nodeValue);\n\n        $element = \"$p2t/text:h[2]\";\n        self::assertEquals('HD1', $doc->getElementAttribute($element, 'text:style-name'));\n        self::assertEquals('1', $doc->getElementAttribute($element, 'text:outline-level'));\n        $span = \"$element/text:span\";\n        self::assertEquals('Text Run', $doc->getElement(\"$span/text:span[1]\")->textContent);\n        self::assertTrue($doc->elementExists(\"$span/text:span[2]/text:s\"));\n        self::assertEquals('Title', $doc->getElement(\"$span/text:span[2]\")->textContent);\n        self::assertEquals('Heading_1', $doc->getElementAttribute($span, 'text:style-name'));\n        $element = \"$p2t/text:p[3]/text:span\";\n        self::assertEquals('Text following Text Run Title', $doc->getElement($element)->nodeValue);\n    }\n\n    /**\n     * Test correct writing of text with ampersand in it.\n     */\n    public function testTextWithAmpersand(): void\n    {\n        $esc = \\PhpOffice\\PhpWord\\Settings::isOutputEscapingEnabled();\n        \\PhpOffice\\PhpWord\\Settings::setOutputEscapingEnabled(true);\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $txt = 'this text contains an & (ampersand)';\n        $section->addText($txt);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n        \\PhpOffice\\PhpWord\\Settings::setOutputEscapingEnabled($esc);\n        $p2t = '/office:document-content/office:body/office:text/text:section';\n        $element = \"$p2t/text:p[2]\";\n        self::assertTrue($doc->elementExists($element));\n        $span = \"$element/text:span\";\n        self::assertTrue($doc->elementExists($span));\n        self::assertEquals($txt, $doc->getElement($span)->nodeValue);\n    }\n\n    /**\n     * Test PageBreak.\n     */\n    public function testPageBreak(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $section->addText('test');\n        $section->addPageBreak();\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n\n        $element = '/office:document-content/office:body/office:text/text:section/text:p[3]';\n        self::assertTrue($doc->elementExists($element, 'content.xml'));\n        self::assertEquals('PB', $doc->getElementAttribute($element, 'text:style-name', 'content.xml'));\n    }\n\n    /**\n     * Test tracked changes.\n     */\n    public function testTrackedChanges(): void\n    {\n        $phpWord = new PhpWord();\n\n        // New portrait section\n        $section = $phpWord->addSection();\n        $textRun = $section->addTextRun();\n\n        $text = $textRun->addText('Hello World! Time to ');\n\n        $text = $textRun->addText('wake ', ['bold' => true]);\n        $text->setChangeInfo(TrackChange::INSERTED, 'Fred', time() - 1800);\n\n        $text = $textRun->addText('up');\n        $text->setTrackChange(new TrackChange(TrackChange::INSERTED, 'Fred'));\n\n        $text = $textRun->addText('go to sleep');\n        $text->setChangeInfo(TrackChange::DELETED, 'Barney', new DateTime('@' . (time() - 3600)));\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n\n        $tcs = '/office:document-content/office:body/office:text/text:tracked-changes';\n        $tc1 = \"$tcs/text:changed-region[1]\";\n        $tc1id = $doc->getElementAttribute($tc1, 'text:id');\n        $element = \"$tc1/text:insertion\";\n        self::assertTrue($doc->elementExists($element));\n        $element .= '/office:change-info';\n        self::AssertEquals('Fred', $doc->getElement(\"$element/dc:creator\")->nodeValue);\n        self::assertTrue($doc->elementExists(\"$element/dc:date\"));\n\n        $tc2 = \"$tcs/text:changed-region[2]\";\n        $tc2id = $doc->getElementAttribute($tc2, 'text:id');\n        $element = \"$tc2/text:insertion\";\n        self::assertTrue($doc->elementExists($element));\n        $element .= '/office:change-info';\n        self::AssertEquals('Fred', $doc->getElement(\"$element/dc:creator\")->nodeValue);\n        //self::assertTrue($doc->elementExists(\"$element/dc:date\"));\n\n        $tc3 = \"$tcs/text:changed-region[3]\";\n        $tc3id = $doc->getElementAttribute($tc3, 'text:id');\n        $element = \"$tc3/text:deletion\";\n        self::assertTrue($doc->elementExists($element));\n        $element .= '/office:change-info';\n        self::AssertEquals('Barney', $doc->getElement(\"$element/dc:creator\")->nodeValue);\n        self::assertTrue($doc->elementExists(\"$element/dc:date\"));\n\n        $p2t = '/office:document-content/office:body/office:text/text:section/text:p[2]';\n        $element = \"$p2t/text:span[2]/text:change-start\";\n        self::AssertEquals($tc1id, $doc->getElementAttribute($element, 'text:change-id'));\n        $element = \"$p2t/text:span[3]/text:change-start\";\n        self::AssertEquals($tc2id, $doc->getElementAttribute($element, 'text:change-id'));\n        $element = \"$p2t/text:change\";\n        self::AssertEquals($tc3id, $doc->getElementAttribute($element, 'text:change-id'));\n    }\n\n    /**\n     * Test ruby output.\n     * Note that this test will need to be updated when ODT Ruby output supports\n     * ODT's native ruby functionality.\n     */\n    public function testRubyText(): void\n    {\n        $esc = \\PhpOffice\\PhpWord\\Settings::isOutputEscapingEnabled();\n        \\PhpOffice\\PhpWord\\Settings::setOutputEscapingEnabled(true);\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $properties = new RubyProperties();\n        $properties->setAlignment(RubyProperties::ALIGNMENT_RIGHT_VERTICAL);\n        $properties->setFontFaceSize(10);\n        $properties->setFontPointsAboveBaseText(4);\n        $properties->setFontSizeForBaseText(18);\n        $properties->setLanguageId('ja-JP');\n\n        $baseTextRun = new TextRun(null);\n        $baseTextRun->addText('私');\n        $rubyTextRun = new TextRun(null);\n        $rubyTextRun->addText('わたし');\n        $section->addRuby($baseTextRun, $rubyTextRun, $properties);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n        \\PhpOffice\\PhpWord\\Settings::setOutputEscapingEnabled($esc);\n        $p2t = '/office:document-content/office:body/office:text/text:section';\n        $element = \"$p2t/text:p[2]\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('私 (わたし)', $doc->getElement($element)->nodeValue);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/ODText/Part/AbstractPartTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\ODText\\Part;\n\nuse Exception;\nuse PhpOffice\\PhpWord\\Writer\\ODText;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\ODText\\Part\\AbstractPart.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Writer\\ODText\\Part\\AbstractPart\n */\nclass AbstractPartTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * covers   ::setParentWriter\n     * covers   ::getParentWriter.\n     */\n    public function testSetGetParentWriter(): void\n    {\n        // @phpstan-ignore-next-line\n        if (method_exists($this, 'getMockForAbstractClass')) {\n            $object = $this->getMockForAbstractClass(ODText\\Part\\AbstractPart::class);\n        } else {\n            /** @var ODText\\Part\\AbstractPart $object */\n            $object = new class() extends ODText\\Part\\AbstractPart {\n                public function write(): string\n                {\n                    return '';\n                }\n            };\n        }\n        $object->setParentWriter(new ODText());\n        self::assertEquals(new ODText(), $object->getParentWriter());\n    }\n\n    /**\n     * covers   ::getParentWriter.\n     */\n    public function testSetGetParentWriterNull(): void\n    {\n        $this->expectException(Exception::class);\n        $this->expectExceptionMessage('No parent WriterInterface assigned.');\n        // @phpstan-ignore-next-line\n        if (method_exists($this, 'getMockForAbstractClass')) {\n            $object = $this->getMockForAbstractClass(ODText\\Part\\AbstractPart::class);\n        } else {\n            /** @var ODText\\Part\\AbstractPart $object */\n            $object = new class() extends ODText\\Part\\AbstractPart {\n                public function write(): string\n                {\n                    return '';\n                }\n            };\n        }\n        $object->getParentWriter();\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/ODText/Part/ContentTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\ODText\\Part;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\ODText\\Part\\Content.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Writer\\ODText\\Part\\Content\n */\nclass ContentTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Executed before each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    /**\n     * Test write content.\n     */\n    public function testWriteContent(): void\n    {\n        $imageSrc = __DIR__ . '/../../../_files/images/PhpWord.png';\n        $objectSrc = __DIR__ . '/../../../_files/documents/sheet.xls';\n        $expected = 'Expected';\n\n        $phpWord = new PhpWord();\n\n        $docProps = $phpWord->getDocInfo();\n        $docProps->setCustomProperty('Company', 'PHPWord');\n\n        $phpWord->setDefaultFontName('Verdana');\n        $phpWord->addFontStyle('Font', ['size' => 11]);\n        $phpWord->addParagraphStyle('Paragraph', ['alignment' => Jc::CENTER]);\n        $phpWord->addTableStyle('tblStyle', ['width' => 100]);\n\n        $section = $phpWord->addSection(['colsNum' => 2]);\n        $section->addText($expected);\n        $section->addText('Test font style', 'Font');\n        $section->addText('Test paragraph style', null, 'Paragraph');\n        $section->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub');\n        $section->addTitle('Test title', 1);\n        $section->addTextBreak();\n        $section->addPageBreak();\n        $section->addListItem('Test list item');\n        $section->addImage($imageSrc, ['width' => 50]);\n        $section->addObject($objectSrc);\n        $section->addTOC();\n\n        $textrun = $section->addTextRun();\n        $textrun->addText('Test text run');\n\n        $table = $section->addTable(['width' => 50]);\n        $cell = $table->addRow()->addCell();\n        $cell = $table->addRow()->addCell();\n        $cell->addText('Test');\n        $cell->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub');\n        $cell->addTextBreak();\n        $cell->addListItem('Test list item');\n        $cell->addImage($imageSrc);\n        $cell->addObject($objectSrc);\n        $textrun = $cell->addTextRun();\n        $textrun->addText('Test text run');\n        $section->addPageBreak();\n\n        $footer = $section->addFooter();\n        $footer->addPreserveText('{PAGE}');\n\n        $table = $section->addTable('tblStyle')->addRow()->addCell();\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n\n        $element = '/office:document-content/office:body/office:text/text:section/text:p[2]';\n        self::assertEquals($expected, $doc->getElement($element, 'content.xml')->nodeValue);\n    }\n\n    /**\n     * Test no paragraph style.\n     */\n    public function testWriteNoStyle(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->addFontStyle('Font', ['size' => 11]);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n\n        $element = '/office:document-content/office:automatic-styles/style:style';\n        self::assertTrue($doc->elementExists($element, 'content.xml'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/ODText/Part/ManifestTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\ndeclare(strict_types=1);\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\ODText\\Part;\n\nuse PhpOffice\\Math\\Element;\nuse PhpOffice\\Math\\Math;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\ODText\\Part\\Manifest.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Writer\\ODText\\Part\\Manifest\n */\nclass ManifestTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Executed before each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    public function testWriteBasic(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n\n        self::assertFalse($doc->elementExists(\n            '/manifest:manifest/manifest:file-entry[@manifest:full-path=\"Formula0/content.xml\"]',\n            'META-INF/manifest.xml'\n        ));\n        self::assertFalse($doc->elementExists(\n            '/manifest:manifest/manifest:file-entry[@manifest:full-path=\"Formula0/\"]',\n            'META-INF/manifest.xml'\n        ));\n    }\n\n    public function testWriteFormula(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        $math = new Math();\n        $math->add(\n            new Element\\Fraction(\n                new Element\\Numeric(2),\n                new Element\\Identifier('π')\n            )\n        );\n        $section->addFormula($math);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n\n        self::assertTrue($doc->elementExists(\n            '/manifest:manifest/manifest:file-entry[@manifest:full-path=\"Formula0/content.xml\"]',\n            'META-INF/manifest.xml'\n        ));\n        self::assertEquals('text/xml', $doc->getElementAttribute(\n            '/manifest:manifest/manifest:file-entry[@manifest:full-path=\"Formula0/content.xml\"]',\n            'manifest:media-type',\n            'META-INF/manifest.xml'\n        ));\n\n        self::assertTrue($doc->elementExists(\n            '/manifest:manifest/manifest:file-entry[@manifest:full-path=\"Formula0/\"]',\n            'META-INF/manifest.xml'\n        ));\n        self::assertEquals('1.2', $doc->getElementAttribute(\n            '/manifest:manifest/manifest:file-entry[@manifest:full-path=\"Formula0/\"]',\n            'manifest:version',\n            'META-INF/manifest.xml'\n        ));\n        self::assertEquals('application/vnd.oasis.opendocument.formula', $doc->getElementAttribute(\n            '/manifest:manifest/manifest:file-entry[@manifest:full-path=\"Formula0/\"]',\n            'manifest:media-type',\n            'META-INF/manifest.xml'\n        ));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/ODText/Style/FontTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\ODText\\Style;\n\nuse PhpOffice\\PhpWord\\Style\\Font;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for Headers, Footers, Tabs in ODT.\n */\nclass FontTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Executed after each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    public function testDefaultDefaults(): void\n    {\n        $phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n\n        $file = 'styles.xml';\n\n        $path = '/office:document-styles/office:styles/style:default-style/style:text-properties';\n        self::assertTrue($doc->elementExists($path, $file));\n        $element = $doc->getElement($path, $file);\n\n        self::assertEquals('#000000', $element->getAttribute('fo:color'));\n        self::assertEquals('false', $element->getAttribute('style:use-window-font-color')); //has to be set to false so that fo:color can take effect\n    }\n\n    public function testSettingDefaults(): void\n    {\n        $phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n\n        $defaultFontColor = '00FF00';\n        $phpWord->setDefaultFontColor($defaultFontColor);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n\n        $file = 'styles.xml';\n\n        $path = '/office:document-styles/office:styles/style:default-style/style:text-properties';\n        self::assertTrue($doc->elementExists($path, $file));\n        $element = $doc->getElement($path, $file);\n\n        self::assertEquals('#' . $defaultFontColor, $element->getAttribute('fo:color'));\n    }\n\n    /**\n     * Test colors.\n     */\n    public function testColors(): void\n    {\n        $phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n        $section = $phpWord->addSection();\n        $section->addText('This is red (800) in rtf/html, default in docx/odt', ['color' => '800']);\n        $section->addText('This should be cyanish (008787)', ['color' => '008787']);\n        $section->addText('This should be dark green (FGCOLOR_DARKGREEN)', ['color' => Font::FGCOLOR_DARKGREEN]);\n        $section->addText('This color is default (unknow)', ['color' => 'unknow']);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n        $s2a = '/office:document-content/office:automatic-styles';\n        self::assertTrue($doc->elementExists($s2a));\n        $s2t = '/office:document-content/office:body/office:text/text:section';\n        self::assertTrue($doc->elementExists($s2t));\n\n        $element = \"$s2a/style:style[5]\";\n        self::assertTrue($doc->elementExists($element));\n        $style = $doc->getElementAttribute($element, 'style:name');\n        $element .= '/style:text-properties';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('#008787', $doc->getElementAttribute($element, 'fo:color'));\n        $span = \"$s2t/text:p[3]/text:span\";\n        self::assertTrue($doc->elementExists($span));\n        self::assertEquals($style, $doc->getElementAttribute($span, 'text:style-name'));\n        self::assertEquals('This should be cyanish (008787)', $doc->getElement($span)->nodeValue);\n\n        $element = \"$s2a/style:style[7]\";\n        self::assertTrue($doc->elementExists($element));\n        $style = $doc->getElementAttribute($element, 'style:name');\n        $element .= '/style:text-properties';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('#006400', $doc->getElementAttribute($element, 'fo:color'));\n        $span = \"$s2t/text:p[4]/text:span\";\n        self::assertTrue($doc->elementExists($span));\n        self::assertEquals($style, $doc->getElementAttribute($span, 'text:style-name'));\n        self::assertEquals('This should be dark green (FGCOLOR_DARKGREEN)', $doc->getElement($span)->nodeValue);\n    }\n\n    public static function providerAllNamedColors()\n    {\n        return [\n            [Font::FGCOLOR_YELLOW, 'FFFF00'],\n            [Font::FGCOLOR_LIGHTGREEN, '90EE90'],\n            [Font::FGCOLOR_CYAN, '00FFFF'],\n            [Font::FGCOLOR_MAGENTA, 'FF00FF'],\n            [Font::FGCOLOR_BLUE, '0000FF'],\n            [Font::FGCOLOR_RED, 'FF0000'],\n            [Font::FGCOLOR_DARKBLUE, '00008B'],\n            [Font::FGCOLOR_DARKCYAN, '008B8B'],\n            [Font::FGCOLOR_DARKGREEN, '006400'],\n            [Font::FGCOLOR_DARKMAGENTA, '8B008B'],\n            [Font::FGCOLOR_DARKRED, '8B0000'],\n            [Font::FGCOLOR_DARKYELLOW, '8B8B00'],\n            [Font::FGCOLOR_DARKGRAY, 'A9A9A9'],\n            [Font::FGCOLOR_LIGHTGRAY, 'D3D3D3'],\n            [Font::FGCOLOR_BLACK, '000000'],\n            ['unknow', 'unknow'],\n            ['unknown', 'unknown'],\n        ];\n    }\n\n    /**\n     * @dataProvider providerAllNamedColors\n     *\n     * @param string $namedColor\n     * @param string $rgbColor\n     */\n    public function testAllNamedColors($namedColor, $rgbColor): void\n    {\n        $phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n        $section = $phpWord->addSection();\n        $section->addText('This is red (800) in rtf/html, default in docx/odt', ['color' => '800']);\n        $section->addText('This should be cyanish (008787)', ['color' => '008787']);\n        $section->addText($namedColor, ['color' => $namedColor]);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n        $s2a = '/office:document-content/office:automatic-styles';\n        self::assertTrue($doc->elementExists($s2a));\n        $s2t = '/office:document-content/office:body/office:text/text:section';\n        self::assertTrue($doc->elementExists($s2t));\n\n        $element = \"$s2a/style:style[7]\";\n        self::assertTrue($doc->elementExists($element));\n        $style = $doc->getElementAttribute($element, 'style:name');\n        $element .= '/style:text-properties';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals(\"#$rgbColor\", $doc->getElementAttribute($element, 'fo:color'));\n        $span = \"$s2t/text:p[4]/text:span\";\n        self::assertTrue($doc->elementExists($span));\n        self::assertEquals($style, $doc->getElementAttribute($span, 'text:style-name'));\n        self::assertEquals($namedColor, $doc->getElement($span)->nodeValue);\n    }\n\n    /**\n     * Test noproof.\n     */\n    public function testNoProof(): void\n    {\n        $phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n        $section = $phpWord->addSection();\n        $section->addText('Noproof not specified', ['color' => 'black']);\n        $section->addText('Noproof is true', ['color' => 'black', 'noproof' => true]);\n        $section->addText('Noproof is false', ['color' => 'black', 'noproof' => false]);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n        $s2a = '/office:document-content/office:automatic-styles';\n        self::assertTrue($doc->elementExists($s2a));\n        $s2t = '/office:document-content/office:body/office:text/text:section';\n        self::assertTrue($doc->elementExists($s2t));\n\n        $element = \"$s2a/style:style[3]\";\n        self::assertTrue($doc->elementExists($element));\n        $style = $doc->getElementAttribute($element, 'style:name');\n        $element .= '/style:text-properties';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('', $doc->getElementAttribute($element, 'fo:language'));\n        $span = \"$s2t/text:p[2]/text:span\";\n        self::assertTrue($doc->elementExists($span));\n        self::assertEquals($style, $doc->getElementAttribute($span, 'text:style-name'));\n        self::assertEquals('Noproof not specified', $doc->getElement($span)->nodeValue);\n\n        $element = \"$s2a/style:style[5]\";\n        self::assertTrue($doc->elementExists($element));\n        $style = $doc->getElementAttribute($element, 'style:name');\n        $element .= '/style:text-properties';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('zxx', $doc->getElementAttribute($element, 'fo:language'));\n        self::assertEquals('zxx', $doc->getElementAttribute($element, 'style:language-asian'));\n        self::assertEquals('zxx', $doc->getElementAttribute($element, 'style:language-complex'));\n        self::assertEquals('none', $doc->getElementAttribute($element, 'fo:country'));\n        self::assertEquals('none', $doc->getElementAttribute($element, 'style:country-asian'));\n        self::assertEquals('none', $doc->getElementAttribute($element, 'style:country-complex'));\n        $span = \"$s2t/text:p[3]/text:span\";\n        self::assertTrue($doc->elementExists($span));\n        self::assertEquals($style, $doc->getElementAttribute($span, 'text:style-name'));\n        self::assertEquals('Noproof is true', $doc->getElement($span)->nodeValue);\n\n        $element = \"$s2a/style:style[7]\";\n        self::assertTrue($doc->elementExists($element));\n        $style = $doc->getElementAttribute($element, 'style:name');\n        $element .= '/style:text-properties';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('', $doc->getElementAttribute($element, 'fo:language'));\n        $span = \"$s2t/text:p[4]/text:span\";\n        self::assertTrue($doc->elementExists($span));\n        self::assertEquals($style, $doc->getElementAttribute($span, 'text:style-name'));\n        self::assertEquals('Noproof is false', $doc->getElement($span)->nodeValue);\n    }\n\n    /**\n     * Test using object with a name as font style for addText.\n     */\n    public function testNamedStyleAsObject(): void\n    {\n        $phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n        $named = $phpWord->addFontStyle('namedobject', ['color' => '008787']);\n        $section = $phpWord->addSection();\n        $section->addText('Let us see what color we wind up with', $named);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n        $s2t = '/office:document-content/office:body/office:text/text:section';\n        self::assertTrue($doc->elementExists($s2t));\n        $element = \"$s2t/text:p[2]/text:span\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('namedobject', $doc->getElementAttribute($element, 'text:style-name'));\n    }\n\n    /**\n     * Test supplying field font style as array or object or string.\n     */\n    public function testFieldStyles(): void\n    {\n        $phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n        $namedstyle = $phpWord->addFontStyle('namedstyle', ['color' => '800000']);\n        $section = $phpWord->addSection();\n        $textrun = $section->addTextRun();\n        $fld = $textrun->addField('DATE');\n        $fld->setFontStyle('namedstyle');\n        $textrun = $section->addTextRun();\n        $fld = $textrun->addField('DATE');\n        $fld->setFontStyle(['color' => '008000']);\n        $textrun = $section->addTextRun();\n        $fld = $textrun->addField('DATE');\n        $font = new Font();\n        $font->setColor('000080');\n        $fld->setFontStyle($font);\n        $textrun = $section->addTextRun();\n        $fld = $textrun->addField('DATE');\n        $fld->setFontStyle($namedstyle);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n        $s2a = '/office:document-content/office:automatic-styles';\n        $s2t = '/office:document-content/office:body/office:text/text:section';\n\n        $element = \"$s2a/style:style[5]\";\n        self::assertEquals('T1', $doc->getElementAttribute($element, 'style:name'));\n        self::assertEquals('#008000', $doc->getElementAttribute(\"$element/style:text-properties\", 'fo:color'));\n        $element = \"$s2a/style:style[7]\";\n        self::assertEquals('T2', $doc->getElementAttribute($element, 'style:name'));\n        self::assertEquals('#000080', $doc->getElementAttribute(\"$element/style:text-properties\", 'fo:color'));\n\n        $element = \"$s2t/text:p[2]/text:span\";\n        self::assertEquals('namedstyle', $doc->getElementAttribute($element, 'text:style-name'));\n        self::assertTrue($doc->elementExists(\"$element/text:date\"));\n        $element = \"$s2t/text:p[3]/text:span\";\n        self::assertEquals('T1', $doc->getElementAttribute($element, 'text:style-name'));\n        self::assertTrue($doc->elementExists(\"$element/text:date\"));\n        $element = \"$s2t/text:p[4]/text:span\";\n        self::assertEquals('T2', $doc->getElementAttribute($element, 'text:style-name'));\n        self::assertTrue($doc->elementExists(\"$element/text:date\"));\n        $element = \"$s2t/text:p[5]/text:span\";\n        self::assertEquals('namedstyle', $doc->getElementAttribute($element, 'text:style-name'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/ODText/Style/NumberingTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\ODText\\Style;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\nclass NumberingTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Executed after each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    public function testAddListItemRun(): void\n    {\n        $expected = 'MyOwnNumberingStyle';\n\n        $phpWord = new PhpWord();\n        $phpWord->addNumberingStyle($expected, [\n            'type' => 'multilevel',\n            'levels' => [\n                [\n                    'start' => 1,\n                    'format' => 'decimal',\n                    'restart' => 1,\n                    'suffix' => 'space',\n                    'text' => '%1.',\n                    'alignment' => Jc::START,\n                ],\n            ],\n        ]);\n        $phpWord->addSection()\n            ->addListItemRun(0, $expected)\n            ->addText('List item run 1');\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n        $doc->setDefaultFile('styles.xml');\n\n        $xPath = '/office:document-styles/office:styles';\n        self::assertTrue($doc->elementExists($xPath));\n        self::assertTrue($doc->elementExists($xPath . '/text:list-style'));\n        self::assertTrue($doc->hasElementAttribute($xPath . '/text:list-style', 'style:name'));\n        self::assertEquals($expected, $doc->getElementAttribute($xPath . '/text:list-style', 'style:name'));\n        self::assertTrue($doc->elementExists($xPath . '/text:list-style/text:list-level-style-bullet'));\n        self::assertTrue($doc->elementExists($xPath . '/text:list-style/text:list-level-style-bullet/style:list-level-properties'));\n        self::assertTrue($doc->elementExists($xPath . '/text:list-style/text:list-level-style-bullet/style:list-level-properties/style:list-level-label-alignment'));\n        self::assertTrue($doc->elementExists($xPath . '/text:list-style/text:list-level-style-bullet/style:text-properties'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/ODText/Style/Paragraph2Test.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\ODText\\Style;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Style;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\nclass Paragraph2Test extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test textAlign.\n     */\n    public function testTextAlign(): void\n    {\n        $phpWord = new PhpWord();\n        Settings::setDefaultRtl(true);\n        $align1 = ['alignment' => 'end'];\n        $align2 = ['alignment' => 'start'];\n        $phpWord->setDefaultParagraphStyle($align1);\n        $section = $phpWord->addSection();\n        $section->addText('Should use default alignment (right for this doc)');\n        $section->addText('Explicit right alignment', null, $align2);\n        $section->addText('Explicit left alignment', null, $align1);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n        $s2a = '/office:document-content/office:automatic-styles';\n        self::assertTrue($doc->elementExists($s2a));\n\n        $element = \"$s2a/style:style[4]\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('Normal', $doc->getElementAttribute($element, 'style:parent-style-name'));\n        $element .= '/style:paragraph-properties';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('right', $doc->getElementAttribute($element, 'fo:text-align'));\n\n        $element = \"$s2a/style:style[6]/style:paragraph-properties\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('right', $doc->getElementAttribute($element, 'fo:text-align'));\n\n        $element = \"$s2a/style:style[8]/style:paragraph-properties\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('left', $doc->getElementAttribute($element, 'fo:text-align'));\n\n        $doc->setDefaultFile('styles.xml');\n        $element = '/office:document-styles/office:styles/style:style';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('Normal', $doc->getElementAttribute($element, 'style:name'));\n        $element .= '/style:paragraph-properties';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('left', $doc->getElementAttribute($element, 'fo:text-align'));\n    }\n\n    /**\n     * Test text run paragraph style using named style.\n     */\n    public function testTextRun(): void\n    {\n        $phpWord = new PhpWord();\n        Settings::setDefaultRtl(false);\n        $phpWord->addParagraphStyle('parstyle1', ['align' => 'start']);\n        $phpWord->addParagraphStyle('parstyle2', ['align' => 'end']);\n        $section = $phpWord->addSection();\n        $trx = $section->addTextRun('parstyle1');\n        $trx->addText('First text in textrun. ');\n        $trx->addText('Second text - paragraph style is specified but ignored.', null, 'parstyle2');\n        $section->addText('Third text added to section not textrun - paragraph style is specified and used.', null, 'parstyle2');\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n        $s2a = '/office:document-content/office:automatic-styles';\n        $element = \"$s2a/style:style[3]\";\n        self::assertEquals('P1_parstyle1', $doc->getElementAttribute($element, 'style:name'));\n        self::assertEquals('parstyle1', $doc->getElementAttribute($element, 'style:parent-style-name'));\n        $element = \"$s2a/style:style[9]\";\n        self::assertEquals('P4_parstyle2', $doc->getElementAttribute($element, 'style:name'));\n        self::assertEquals('parstyle2', $doc->getElementAttribute($element, 'style:parent-style-name'));\n\n        $s2a = '/office:document-content/office:body/office:text/text:section';\n        $element = \"$s2a/text:p[2]\";\n        self::assertEquals('P1_parstyle1', $doc->getElementAttribute($element, 'text:style-name'));\n        $element = \"$s2a/text:p[3]\";\n        self::assertEquals('P4_parstyle2', $doc->getElementAttribute($element, 'text:style-name'));\n\n        $doc->setDefaultFile('styles.xml');\n        $element = '/office:document-styles/office:styles/style:style[1]';\n        self::assertEquals('parstyle1', $doc->getElementAttribute($element, 'style:name'));\n        $element .= '/style:paragraph-properties';\n        self::assertEquals('left', $doc->getElementAttribute($element, 'fo:text-align'));\n        $element = '/office:document-styles/office:styles/style:style[2]';\n        self::assertEquals('parstyle2', $doc->getElementAttribute($element, 'style:name'));\n        $element .= '/style:paragraph-properties';\n        self::assertEquals('right', $doc->getElementAttribute($element, 'fo:text-align'));\n    }\n\n    /**\n     * Test text run paragraph style using unnamed style.\n     */\n    public function testTextRunUnnamed(): void\n    {\n        $phpWord = new PhpWord();\n        Settings::setDefaultRtl(false);\n        $parstyle1 = ['align' => 'start'];\n        $parstyle2 = ['align' => 'end'];\n        $section = $phpWord->addSection();\n        $trx = $section->addTextRun($parstyle1);\n        $trx->addText('First text in textrun. ');\n        $trx->addText('Second text - paragraph style is specified but ignored.', null, $parstyle2);\n        $section->addText('Third text added to section not textrun - paragraph style is specified and used.', null, $parstyle2);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n        $s2a = '/office:document-content/office:automatic-styles';\n        $element = \"$s2a/style:style[3]\";\n        self::assertEquals('P1', $doc->getElementAttribute($element, 'style:name'));\n        self::assertEquals('Normal', $doc->getElementAttribute($element, 'style:parent-style-name'));\n        $element .= '/style:paragraph-properties';\n        self::assertEquals('left', $doc->getElementAttribute($element, 'fo:text-align'));\n        $element = \"$s2a/style:style[9]\";\n        self::assertEquals('P4', $doc->getElementAttribute($element, 'style:name'));\n        self::assertEquals('Normal', $doc->getElementAttribute($element, 'style:parent-style-name'));\n        $element .= '/style:paragraph-properties';\n        self::assertEquals('right', $doc->getElementAttribute($element, 'fo:text-align'));\n\n        $s2a = '/office:document-content/office:body/office:text/text:section';\n        $element = \"$s2a/text:p[2]\";\n        self::assertEquals('P1', $doc->getElementAttribute($element, 'text:style-name'));\n        $element = \"$s2a/text:p[3]\";\n        self::assertEquals('P4', $doc->getElementAttribute($element, 'text:style-name'));\n    }\n\n    public function testWhenNullifed(): void\n    {\n        $dflt1 = Settings::isDefaultRtl();\n        self::assertFalse($dflt1);\n        $phpWord = new PhpWord();\n        $dflt2 = Settings::isDefaultRtl();\n        self::assertNull($dflt2);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/ODText/Style/ParagraphTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\ODText\\Style;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Shared\\Converter;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for Headers, Footers, Tabs in ODT.\n */\nclass ParagraphTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Executed after each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    /**\n     * Test page break.\n     */\n    public function testPageBreak(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $section->addText('Text on first page');\n        $section->addPageBreak();\n        $section->addText('Text on second page');\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n\n        $s2a = '/office:document-content/office:automatic-styles';\n        $element = \"$s2a/style:style[1]\";\n        self::assertEquals('PB', $doc->getElementAttribute($element, 'style:name'));\n        $element .= '/style:paragraph-properties';\n        self::assertEquals('page', $doc->getElementAttribute($element, 'fo:break-after'));\n        self::assertEquals('0cm', $doc->getElementAttribute($element, 'fo:margin-top'));\n        self::assertEquals('0cm', $doc->getElementAttribute($element, 'fo:margin-bottom'));\n\n        $s2a = '/office:document-content/office:body/office:text/text:section';\n        $element = \"$s2a/text:p[3]\";\n        self::assertEquals('PB', $doc->getElementAttribute($element, 'text:style-name'));\n    }\n\n    /**\n     * Test normal/indent.\n     */\n    public function testNormalIndent(): void\n    {\n        $phpWord = new PhpWord();\n        $cvt = Converter::INCH_TO_TWIP;\n        $indent1 = ['indentation' => ['left' => 0.50 * $cvt]];\n        $indent2 = ['indentation' => ['left' => 1.00 * $cvt, 'right' => 1.05 * $cvt]];\n        $indent3 = ['indentation' => ['left' => -0.50 * $cvt]];\n        $indent4 = ['indentation' => ['left' => 0 * $cvt]];\n        $phpWord->setDefaultParagraphStyle($indent1);\n        $section = $phpWord->addSection();\n        $section->addText('Should use default indent (0.5)');\n        $section->addText('Should use non-default indent (1.0) on both sides, and here\\'s an extra long line to prove it', null, $indent2);\n        $section->addText('Should use non-default indent (-0.5)', null, $indent3);\n        $section->addText('Should use non-default indent (0)', null, $indent4);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n        $s2a = '/office:document-content/office:automatic-styles';\n        self::assertTrue($doc->elementExists($s2a));\n\n        $element = \"$s2a/style:style[4]\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('Normal', $doc->getElementAttribute($element, 'style:parent-style-name'));\n        $element .= '/style:paragraph-properties';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('', $doc->getElementAttribute($element, 'fo:margin-left'));\n        self::assertEquals('', $doc->getElementAttribute($element, 'fo:margin-right'));\n\n        $element = \"$s2a/style:style[6]/style:paragraph-properties\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('1in', $doc->getElementAttribute($element, 'fo:margin-left'));\n        self::assertEquals('1.05in', $doc->getElementAttribute($element, 'fo:margin-right'));\n\n        $element = \"$s2a/style:style[8]/style:paragraph-properties\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('-0.5in', $doc->getElementAttribute($element, 'fo:margin-left'));\n        self::assertEquals('0in', $doc->getElementAttribute($element, 'fo:margin-right'));\n\n        $element = \"$s2a/style:style[10]/style:paragraph-properties\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('0in', $doc->getElementAttribute($element, 'fo:margin-left'));\n        self::assertEquals('0in', $doc->getElementAttribute($element, 'fo:margin-right'));\n\n        $doc->setDefaultFile('styles.xml');\n        $element = '/office:document-styles/office:styles/style:style';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('Normal', $doc->getElementAttribute($element, 'style:name'));\n        $element .= '/style:paragraph-properties';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('0.5in', $doc->getElementAttribute($element, 'fo:margin-left'));\n        self::assertEquals('0in', $doc->getElementAttribute($element, 'fo:margin-right'));\n    }\n\n    /**\n     * Test textAlign.\n     */\n    public function testTextAlign(): void\n    {\n        $phpWord = new PhpWord();\n        $align1 = ['alignment' => 'end'];\n        $align2 = ['alignment' => 'start'];\n        $phpWord->setDefaultParagraphStyle($align1);\n        $section = $phpWord->addSection();\n        $section->addText('Should use default alignment (right for this doc)');\n        $section->addText('Explicit left alignment', null, $align2);\n        $section->addText('Explicit right alignment', null, $align1);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n        $s2a = '/office:document-content/office:automatic-styles';\n        self::assertTrue($doc->elementExists($s2a));\n\n        $element = \"$s2a/style:style[4]\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('Normal', $doc->getElementAttribute($element, 'style:parent-style-name'));\n        $element .= '/style:paragraph-properties';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('', $doc->getElementAttribute($element, 'fo:text-align'));\n\n        $element = \"$s2a/style:style[6]/style:paragraph-properties\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('start', $doc->getElementAttribute($element, 'fo:text-align'));\n\n        $element = \"$s2a/style:style[8]/style:paragraph-properties\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('end', $doc->getElementAttribute($element, 'fo:text-align'));\n\n        $doc->setDefaultFile('styles.xml');\n        $element = '/office:document-styles/office:styles/style:style';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('Normal', $doc->getElementAttribute($element, 'style:name'));\n        $element .= '/style:paragraph-properties';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('end', $doc->getElementAttribute($element, 'fo:text-align'));\n    }\n\n    /**\n     * Test lineHeight.\n     */\n    public function testLineHeight(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $section->addText('Should use line height 1.08, and here\\'s a long line which ought to overflow onto a second line to prove it', null, ['lineHeight' => 1.08]);\n        $section->addText('Should use line height 1.20, and here\\'s a long line which ought to overflow onto a second line to prove it', null, ['lineHeight' => 1.20]);\n        $section->addText('Should use line height 0.90, and here\\'s a long line which ought to overflow onto a second line to prove it', null, ['lineHeight' => 0.90]);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n        $s2a = '/office:document-content/office:automatic-styles';\n        self::assertTrue($doc->elementExists($s2a));\n\n        $element = \"$s2a/style:style[4]/style:paragraph-properties\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('108%', $doc->getElementAttribute($element, 'fo:line-height'));\n\n        $element = \"$s2a/style:style[6]/style:paragraph-properties\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('120%', $doc->getElementAttribute($element, 'fo:line-height'));\n\n        $element = \"$s2a/style:style[8]/style:paragraph-properties\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('90%', $doc->getElementAttribute($element, 'fo:line-height'));\n    }\n\n    /**\n     * Test SpaceBeforeAfter.\n     */\n    public function testSpaceBeforeAfter(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->setDefaultParagraphStyle(['spaceBefore' => 0, 'spaceAfter' => 0]);\n        $section = $phpWord->addSection();\n        $section->addText('No spacing between this paragraph and next');\n        $section->addText('No spacing between this paragraph and previous');\n        $section->addText('No spacing before this but 100 after', null, ['spaceAfter' => 100]);\n        $section->addText('No spacing for this paragraph but previous specified 100 after and next specifies 100 before');\n        $section->addText('No spacing after this but 100 before', null, ['spaceBefore' => 100]);\n        $section->addText('No spacing before this paragraph');\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n        $s2a = '/office:document-content/office:automatic-styles';\n        self::assertTrue($doc->elementExists($s2a));\n\n        $element = \"$s2a/style:style[8]/style:paragraph-properties\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('', $doc->getElementAttribute($element, 'fo:margin-top'));\n        self::assertEquals('5pt', $doc->getElementAttribute($element, 'fo:margin-bottom'));\n\n        $element = \"$s2a/style:style[12]/style:paragraph-properties\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('5pt', $doc->getElementAttribute($element, 'fo:margin-top'));\n        self::assertEquals('', $doc->getElementAttribute($element, 'fo:margin-bottom'));\n\n        $doc->setDefaultFile('styles.xml');\n        $element = '/office:document-styles/office:styles/style:style';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('Normal', $doc->getElementAttribute($element, 'style:name'));\n        $element .= '/style:paragraph-properties';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('0pt', $doc->getElementAttribute($element, 'fo:margin-top'));\n        self::assertEquals('0pt', $doc->getElementAttribute($element, 'fo:margin-bottom'));\n    }\n\n    /**\n     * Test Page Break Before.\n     */\n    public function testPageBreakBefore(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $section->addText('This is my first paragraph.');\n        $section->addText('This is my second paragraph, on a new page.', null, ['pageBreakBefore' => true]);\n        $section->addText('This is my third paragraph, on same page as second.');\n        $section->addText('This is my fourth paragraph, on a new page.', null, ['pageBreakBefore' => true]);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n        $s2a = '/office:document-content/office:automatic-styles';\n        self::assertTrue($doc->elementExists($s2a));\n\n        $element = \"$s2a/style:style[4]/style:paragraph-properties\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('', $doc->getElementAttribute($element, 'fo:break-before'));\n        $element = \"$s2a/style:style[6]/style:paragraph-properties\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('page', $doc->getElementAttribute($element, 'fo:break-before'));\n        $element = \"$s2a/style:style[8]/style:paragraph-properties\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('', $doc->getElementAttribute($element, 'fo:break-before'));\n        $element = \"$s2a/style:style[10]/style:paragraph-properties\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('page', $doc->getElementAttribute($element, 'fo:break-before'));\n    }\n\n    /**\n     * Test Heading Page Break Before.\n     */\n    public function testHeadingPageBreakBefore(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->addTitleStyle(1, null, ['pageBreakBefore' => true]);\n        $phpWord->addTitleStyle(2, null, []);\n        $section = $phpWord->addSection();\n        $section->addTitle('Section1 Heading1 #1', 1);\n        $section->addTitle('Section1 Heading2 #1', 2);\n        $section->addTitle('Section1 Heading1 #2', 1);\n        $section->addTitle('Section1 Heading2 #2', 2);\n        $section = $phpWord->addSection();\n        $section->addTitle('Section2 Heading1 #1', 1);\n        $section->addTitle('Section2 Heading2 #1', 2);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n        $s2a = '/office:document-content/office:automatic-styles';\n        self::assertTrue($doc->elementExists($s2a));\n\n        $element = \"$s2a/style:style[4]\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('HD1', $doc->getElementAttribute($element, 'style:name'));\n        self::assertEquals('Heading_1', $doc->getElementAttribute($element, 'style:parent-style-name'));\n        $element .= '/style:paragraph-properties';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('page', $doc->getElementAttribute($element, 'fo:break-before'));\n\n        $element = \"$s2a/style:style[5]\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('HE1', $doc->getElementAttribute($element, 'style:name'));\n        self::assertEquals('Heading_1', $doc->getElementAttribute($element, 'style:parent-style-name'));\n        $element .= '/style:paragraph-properties';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('auto', $doc->getElementAttribute($element, 'fo:break-before'));\n\n        $element = \"$s2a/style:style[6]\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('HD2', $doc->getElementAttribute($element, 'style:name'));\n        self::assertEquals('Heading_2', $doc->getElementAttribute($element, 'style:parent-style-name'));\n        $element .= '/style:paragraph-properties';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('', $doc->getElementAttribute($element, 'fo:break-before'));\n\n        $element = \"$s2a/style:style[7]\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('HE2', $doc->getElementAttribute($element, 'style:name'));\n        self::assertEquals('Heading_2', $doc->getElementAttribute($element, 'style:parent-style-name'));\n        $element .= '/style:paragraph-properties';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('auto', $doc->getElementAttribute($element, 'fo:break-before'));\n\n        $s2a = '/office:document-content/office:body/office:text/text:section[1]';\n        self::assertTrue($doc->elementExists($s2a));\n        $element = \"$s2a/text:h[1]\";\n        self::assertEquals('HE1', $doc->getElementAttribute($element, 'text:style-name'));\n        self::assertEquals('1', $doc->getElementAttribute($element, 'text:outline-level'));\n        $element .= '/text:span';\n        self::assertEquals('Heading_1', $doc->getElementAttribute($element, 'text:style-name'));\n        $element = \"$s2a/text:h[2]\";\n        self::assertEquals('HD2', $doc->getElementAttribute($element, 'text:style-name'));\n        self::assertEquals('2', $doc->getElementAttribute($element, 'text:outline-level'));\n        $element .= '/text:span';\n        self::assertEquals('Heading_2', $doc->getElementAttribute($element, 'text:style-name'));\n        $element = \"$s2a/text:h[3]\";\n        self::assertEquals('HD1', $doc->getElementAttribute($element, 'text:style-name'));\n        self::assertEquals('1', $doc->getElementAttribute($element, 'text:outline-level'));\n        $element .= '/text:span';\n        self::assertEquals('Heading_1', $doc->getElementAttribute($element, 'text:style-name'));\n        $element = \"$s2a/text:h[4]\";\n        self::assertEquals('HD2', $doc->getElementAttribute($element, 'text:style-name'));\n        self::assertEquals('2', $doc->getElementAttribute($element, 'text:outline-level'));\n        $element .= '/text:span';\n        self::assertEquals('Heading_2', $doc->getElementAttribute($element, 'text:style-name'));\n\n        $s2a = '/office:document-content/office:body/office:text/text:section[2]';\n        self::assertTrue($doc->elementExists($s2a));\n        $element = \"$s2a/text:h[1]\";\n        self::assertEquals('HE1', $doc->getElementAttribute($element, 'text:style-name'));\n        self::assertEquals('1', $doc->getElementAttribute($element, 'text:outline-level'));\n        $element .= '/text:span';\n        self::assertEquals('Heading_1', $doc->getElementAttribute($element, 'text:style-name'));\n        $element = \"$s2a/text:h[2]\";\n        self::assertEquals('HD2', $doc->getElementAttribute($element, 'text:style-name'));\n        self::assertEquals('2', $doc->getElementAttribute($element, 'text:outline-level'));\n        $element .= '/text:span';\n        self::assertEquals('Heading_2', $doc->getElementAttribute($element, 'text:style-name'));\n\n        $doc->setDefaultFile('styles.xml');\n        $s2a = '/office:document-styles/office:styles';\n        self::assertTrue($doc->elementExists($s2a));\n        $element = \"$s2a/style:style[1]\";\n        self::assertEquals('Heading_1', $doc->getElementAttribute($element, 'style:name'));\n        self::assertEquals('paragraph', $doc->getElementAttribute($element, 'style:family'));\n        $element .= '/style:paragraph-properties';\n        self::assertEquals('page', $doc->getElementAttribute($element, 'fo:break-before'));\n        $element = \"$s2a/style:style[3]\";\n        self::assertEquals('Heading_2', $doc->getElementAttribute($element, 'style:name'));\n        self::assertEquals('paragraph', $doc->getElementAttribute($element, 'style:family'));\n        $element .= '/style:paragraph-properties';\n        self::assertEquals('', $doc->getElementAttribute($element, 'fo:break-before'));\n    }\n\n    /**\n     * Test text run paragraph style using named style.\n     */\n    public function testTextRun(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->addParagraphStyle('parstyle1', ['align' => 'start']);\n        $phpWord->addParagraphStyle('parstyle2', ['align' => 'end']);\n        $section = $phpWord->addSection();\n        $trx = $section->addTextRun('parstyle1');\n        $trx->addText('First text in textrun. ');\n        $trx->addText('Second text - paragraph style is specified but ignored.', null, 'parstyle2');\n        $section->addText('Third text added to section not textrun - paragraph style is specified and used.', null, 'parstyle2');\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n        $s2a = '/office:document-content/office:automatic-styles';\n        $element = \"$s2a/style:style[3]\";\n        self::assertEquals('P1_parstyle1', $doc->getElementAttribute($element, 'style:name'));\n        self::assertEquals('parstyle1', $doc->getElementAttribute($element, 'style:parent-style-name'));\n        $element = \"$s2a/style:style[9]\";\n        self::assertEquals('P4_parstyle2', $doc->getElementAttribute($element, 'style:name'));\n        self::assertEquals('parstyle2', $doc->getElementAttribute($element, 'style:parent-style-name'));\n\n        $s2a = '/office:document-content/office:body/office:text/text:section';\n        $element = \"$s2a/text:p[2]\";\n        self::assertEquals('P1_parstyle1', $doc->getElementAttribute($element, 'text:style-name'));\n        $element = \"$s2a/text:p[3]\";\n        self::assertEquals('P4_parstyle2', $doc->getElementAttribute($element, 'text:style-name'));\n\n        $doc->setDefaultFile('styles.xml');\n        $element = '/office:document-styles/office:styles/style:style[1]';\n        self::assertEquals('parstyle1', $doc->getElementAttribute($element, 'style:name'));\n        $element .= '/style:paragraph-properties';\n        self::assertEquals('start', $doc->getElementAttribute($element, 'fo:text-align'));\n        $element = '/office:document-styles/office:styles/style:style[2]';\n        self::assertEquals('parstyle2', $doc->getElementAttribute($element, 'style:name'));\n        $element .= '/style:paragraph-properties';\n        self::assertEquals('end', $doc->getElementAttribute($element, 'fo:text-align'));\n    }\n\n    /**\n     * Test text run paragraph style using unnamed style.\n     */\n    public function testTextRunUnnamed(): void\n    {\n        $phpWord = new PhpWord();\n        $parstyle1 = ['align' => 'start'];\n        $parstyle2 = ['align' => 'end'];\n        $section = $phpWord->addSection();\n        $trx = $section->addTextRun($parstyle1);\n        $trx->addText('First text in textrun. ');\n        $trx->addText('Second text - paragraph style is specified but ignored.', null, $parstyle2);\n        $section->addText('Third text added to section not textrun - paragraph style is specified and used.', null, $parstyle2);\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n        $s2a = '/office:document-content/office:automatic-styles';\n        $element = \"$s2a/style:style[3]\";\n        self::assertEquals('P1', $doc->getElementAttribute($element, 'style:name'));\n        self::assertEquals('Normal', $doc->getElementAttribute($element, 'style:parent-style-name'));\n        $element .= '/style:paragraph-properties';\n        self::assertEquals('start', $doc->getElementAttribute($element, 'fo:text-align'));\n        $element = \"$s2a/style:style[9]\";\n        self::assertEquals('P4', $doc->getElementAttribute($element, 'style:name'));\n        self::assertEquals('Normal', $doc->getElementAttribute($element, 'style:parent-style-name'));\n        $element .= '/style:paragraph-properties';\n        self::assertEquals('end', $doc->getElementAttribute($element, 'fo:text-align'));\n\n        $s2a = '/office:document-content/office:body/office:text/text:section';\n        $element = \"$s2a/text:p[2]\";\n        self::assertEquals('P1', $doc->getElementAttribute($element, 'text:style-name'));\n        $element = \"$s2a/text:p[3]\";\n        self::assertEquals('P4', $doc->getElementAttribute($element, 'text:style-name'));\n    }\n\n    /**\n     * Test Empty font and paragraph styles.\n     */\n    public function testEmptyFontAndParagraphStyles(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $phpWord->addFontStyle('namedfont', ['name' => 'Courier New', 'size' => 8]);\n        $phpWord->addParagraphStyle('namedpar', ['lineHeight' => 1.08]);\n        $section->addText('Empty Font Style     and Empty Paragraph Style', '', '');\n        $section->addText('Named Font Style     and Empty Paragraph Style', 'namedfont', '');\n        $section->addText('Empty Font Style     and Named Paragraph Style', '', 'namedpar');\n        $section->addText('Named Font Style     and Named Paragraph Style', 'namedfont', 'namedpar');\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n        $s2a = '/office:document-content/office:body/office:text/text:section';\n        $element = \"$s2a/text:p[2]\";\n        self::assertEquals('Normal', $doc->getElementAttribute($element, 'text:style-name'));\n        self::assertEquals(5, $doc->getElementAttribute(\"$element/text:s\", 'text:c'));\n        self::assertFalse($doc->elementExists(\"$element/text:span\"));\n        $element = \"$s2a/text:p[3]\";\n        self::assertEquals('Normal', $doc->getElementAttribute($element, 'text:style-name'));\n        self::assertEquals('namedfont', $doc->getElementAttribute(\"$element/text:span\", 'text:style-name'));\n        $element = \"$s2a/text:p[4]\";\n        self::assertEquals('P1_namedpar', $doc->getElementAttribute($element, 'text:style-name'));\n        self::assertFalse($doc->elementExists(\"$element/text:span\"));\n        $element = \"$s2a/text:p[5]\";\n        self::assertEquals('P2_namedpar', $doc->getElementAttribute($element, 'text:style-name'));\n        self::assertEquals('namedfont', $doc->getElementAttribute(\"$element/text:span\", 'text:style-name'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/ODText/Style/SectionTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\ODText\\Style;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for Headers, Footers, Tabs in ODT.\n */\nclass SectionTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Executed after each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    /**\n     * Test various section styles, including header, footer, and tabs.\n     */\n    public function testHeaderFooterTabs(): void\n    {\n        $phpWord = new PhpWord();\n        $margins = \\PhpOffice\\PhpWord\\Shared\\Converter::INCH_TO_TWIP;\n        $phpWord->addFontStyle('hdrstyle1', ['name' => 'Courier New', 'size' => 8]);\n        $section = $phpWord->addSection(['paperSize' => 'Letter', 'marginTop' => $margins, 'marginBottom' => $margins]);\n        $header = $section->addHeader();\n        $phpWord->addParagraphStyle('centerheader', ['align' => 'center']);\n        $header->addText('Centered Header', 'hdrstyle1', 'centerheader');\n        $footer = $section->addFooter();\n        $sizew = $section->getStyle()->getPageSizeW();\n        $sizel = $section->getStyle()->getMarginLeft();\n        $sizer = $section->getStyle()->getMarginRight();\n        $footerwidth = $sizew - $sizel - $sizer;\n        $phpWord->addParagraphStyle(\n            'footerTab',\n            [\n                'tabs' => [\n                    new \\PhpOffice\\PhpWord\\Style\\Tab('center', (int) ($footerwidth / 2)),\n                    new \\PhpOffice\\PhpWord\\Style\\Tab('right', (int) $footerwidth),\n                ],\n            ]\n        );\n        $textrun = $footer->addTextRun('footerTab');\n        $textrun->addText('Left footer', 'hdrstyle1');\n        $textrun->addText(\"\\t\", 'hdrstyle1');\n        $fld = $textrun->addField('DATE');\n        $fld->setFontStyle('hdrstyle1');\n        $textrun->addText(\"\\t\", 'hdrstyle1');\n        $textrun->addText('Page ', 'hdrstyle1');\n        $fld = $textrun->addField('PAGE');\n        $fld->setFontStyle('hdrstyle1');\n        $textrun->addText(' of ', 'hdrstyle1');\n        $fld = $textrun->addField('NUMPAGES');\n        $fld->setFontStyle('hdrstyle1');\n        $section->addText('First page');\n        $section->addPageBreak();\n        $section->addText('Second page');\n        $section->addPageBreak();\n        $section->addText('Third page');\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n        $doc->setDefaultFile('styles.xml');\n        $s2a = '/office:document-styles/office:automatic-styles';\n        $element = \"$s2a/style:page-layout/style:page-layout-properties\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('8.5in', $doc->getElementAttribute($element, 'fo:page-width'));\n        self::assertEquals('11in', $doc->getElementAttribute($element, 'fo:page-height'));\n        self::assertEquals('0.5in', $doc->getElementAttribute($element, 'fo:margin-top'));\n        self::assertEquals('0.5in', $doc->getElementAttribute($element, 'fo:margin-bottom'));\n\n        $s2s = '/office:document-styles/office:styles';\n        $element = \"$s2s/style:style[1]\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('hdrstyle1', $doc->getElementAttribute($element, 'style:name'));\n        $tprop = \"$element/style:text-properties\";\n        self::assertTrue($doc->elementExists($tprop));\n        self::assertEquals('Courier New', $doc->getElementAttribute($tprop, 'style:font-name'));\n\n        $element = \"$s2s/style:style[2]\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('centerheader', $doc->getElementAttribute($element, 'style:name'));\n        $tprop = \"$element/style:paragraph-properties\";\n        self::assertTrue($doc->elementExists($tprop));\n        self::assertEquals('center', $doc->getElementAttribute($tprop, 'fo:text-align'));\n\n        $element = \"$s2s/style:style[3]\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('footerTab', $doc->getElementAttribute($element, 'style:name'));\n        $tprop = \"$element/style:paragraph-properties/style:tab-stops\";\n        self::assertTrue($doc->elementExists($tprop));\n        $tstop = \"$tprop/style:tab-stop[1]\";\n        self::assertTrue($doc->elementExists($tstop));\n        self::assertEquals('center', $doc->getElementAttribute($tstop, 'style:type'));\n        self::assertEquals('3.25in', $doc->getElementAttribute($tstop, 'style:position'));\n        $tstop = \"$tprop/style:tab-stop[2]\";\n        self::assertTrue($doc->elementExists($tstop));\n        self::assertEquals('right', $doc->getElementAttribute($tstop, 'style:type'));\n        self::assertEquals('6.5in', $doc->getElementAttribute($tstop, 'style:position'));\n\n        $s2s = '/office:document-styles/office:master-styles/style:master-page/style:footer/text:p';\n        self::assertTrue($doc->elementExists($s2s));\n        $element = \"$s2s/text:span[1]\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('hdrstyle1', $doc->getElementAttribute($element, 'text:style-name'));\n        self::assertEquals('Left footer', $doc->getElement($element)->nodeValue);\n        $element = \"$s2s/text:span[2]/text:tab\";\n        self::assertTrue($doc->elementExists($element));\n        $element = \"$s2s/text:span[3]/text:date\";\n        self::assertTrue($doc->elementExists($element));\n        $element = \"$s2s/text:span[4]/text:tab\";\n        self::assertTrue($doc->elementExists($element));\n        $element = \"$s2s/text:span[5]\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('Page', $doc->getElement($element)->nodeValue);\n        self::assertTrue($doc->elementExists(\"$element/text:s\"));\n        $element = \"$s2s/text:span[6]/text:page-number\";\n        self::assertTrue($doc->elementExists($element));\n        $element = \"$s2s/text:span[7]\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('of', $doc->getElement($element)->nodeValue);\n        self::assertTrue($doc->elementExists(\"$element/text:s\"));\n        self::assertTrue($doc->elementExists(\"$element/text:s[2]\"));\n        $element = \"$s2s/text:span[8]/text:page-count\";\n        self::assertTrue($doc->elementExists($element));\n    }\n\n    /**\n     * Test HideErrors.\n     */\n    public function testHideErrors(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->getSettings()->setHideGrammaticalErrors(true);\n        $phpWord->getSettings()->setHideSpellingErrors(true);\n        $phpWord->getSettings()->setThemeFontLang(new \\PhpOffice\\PhpWord\\Style\\Language('en-US'));\n        $phpWord->getSettings()->getThemeFontLang()->setLangId(\\PhpOffice\\PhpWord\\Style\\Language::EN_US_ID);\n        $section = $phpWord->addSection();\n        $section->addText('Here is a paragraph with some speling errorz');\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n        $doc->setDefaultFile('styles.xml');\n        $element = '/office:document-styles/office:styles/style:default-style/style:text-properties';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('zxx', $doc->getElementAttribute($element, 'fo:language'));\n        self::assertEquals('zxx', $doc->getElementAttribute($element, 'style:language-asian'));\n        self::assertEquals('zxx', $doc->getElementAttribute($element, 'style:language-complex'));\n        self::assertEquals('none', $doc->getElementAttribute($element, 'fo:country'));\n        self::assertEquals('none', $doc->getElementAttribute($element, 'style:country-asian'));\n        self::assertEquals('none', $doc->getElementAttribute($element, 'style:country-complex'));\n    }\n\n    /**\n     * Test SpaceBeforeAfter.\n     */\n    public function testMultipleSections(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection(['paperSize' => 'Letter', 'Orientation' => 'portrait']);\n        $section->addText('This section uses Letter paper in portrait orientation.');\n        $section = $phpWord->addSection(['paperSize' => 'A4', 'Orientation' => 'landscape', 'pageNumberingStart' => '9']);\n        $header = $section->addHeader();\n        $header->addField('PAGE');\n        $section->addText('This section uses A4 paper in landscape orientation. It should have a page break beforehand. It artificially starts on page 9.');\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'ODText');\n        $s2a = '/office:document-content/office:automatic-styles';\n        $s2t = '/office:document-content/office:body/office:text';\n        self::assertTrue($doc->elementExists($s2a));\n        self::assertTrue($doc->elementExists($s2t));\n\n        $element = \"$s2a/style:style[2]\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('SB1', $doc->getElementAttribute($element, 'style:name'));\n        self::assertEquals('Standard1', $doc->getElementAttribute($element, 'style:master-page-name'));\n        $element .= '/style:text-properties';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('none', $doc->getElementAttribute($element, 'text:display'));\n        $element = \"$s2a/style:style[3]\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('SB2', $doc->getElementAttribute($element, 'style:name'));\n        self::assertEquals('Standard2', $doc->getElementAttribute($element, 'style:master-page-name'));\n        $elemen2 = \"$element/style:paragraph-properties\";\n        self::assertEquals('9', $doc->getElementAttribute($elemen2, 'style:page-number'));\n        $element .= '/style:text-properties';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('none', $doc->getElementAttribute($element, 'text:display'));\n\n        $element = \"$s2t/text:section[1]\";\n        self::assertTrue($doc->elementExists($element));\n        $element .= '/text:p[1]';\n        self::assertEquals('SB1', $doc->getElementAttribute($element, 'text:style-name'));\n        $element = \"$s2t/text:section[2]\";\n        self::assertTrue($doc->elementExists($element));\n        $element .= '/text:p[1]';\n        self::assertEquals('SB2', $doc->getElementAttribute($element, 'text:style-name'));\n\n        $doc->setDefaultFile('styles.xml');\n        $s2a = '/office:document-styles/office:automatic-styles';\n        self::assertTrue($doc->elementExists($s2a));\n\n        $element = \"$s2a/style:page-layout[1]\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('Mpm1', $doc->getElementAttribute($element, 'style:name'));\n        $element .= '/style:page-layout-properties';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('8.5in', $doc->getElementAttribute($element, 'fo:page-width'));\n        self::assertEquals('11in', $doc->getElementAttribute($element, 'fo:page-height'));\n        self::assertEquals('portrait', $doc->getElementAttribute($element, 'style:print-orientation'));\n\n        $element = \"$s2a/style:page-layout[2]\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('Mpm2', $doc->getElementAttribute($element, 'style:name'));\n        $element .= '/style:page-layout-properties';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('29.7cm', $doc->getElementAttribute($element, 'fo:page-width'));\n        self::assertEquals('21cm', $doc->getElementAttribute($element, 'fo:page-height'));\n        self::assertEquals('landscape', $doc->getElementAttribute($element, 'style:print-orientation'));\n\n        $s2a = '/office:document-styles/office:master-styles';\n        self::assertTrue($doc->elementExists($s2a));\n        $element = \"$s2a/style:master-page[1]\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('Standard1', $doc->getElementAttribute($element, 'style:name'));\n        self::assertEquals('Mpm1', $doc->getElementAttribute($element, 'style:page-layout-name'));\n        $element = \"$s2a/style:master-page[2]\";\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('Standard2', $doc->getElementAttribute($element, 'style:name'));\n        self::assertEquals('Mpm2', $doc->getElementAttribute($element, 'style:page-layout-name'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/ODText/StyleTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\ODText;\n\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\ODText\\Style subnamespace.\n */\nclass StyleTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test empty styles.\n     */\n    public function testEmptyStyles(): void\n    {\n        $styles = ['Font', 'Paragraph', 'Image', 'Section', 'Table'];\n        foreach ($styles as $style) {\n            $objectClass = 'PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Style\\\\' . $style;\n            $xmlWriter = new XMLWriter();\n            $object = new $objectClass($xmlWriter);\n            $object->write();\n\n            self::assertEquals('', $xmlWriter->getData());\n        }\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/ODTextTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\nuse PhpOffice\\PhpWord\\Writer\\ODText;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\ODText.\n *\n * @runTestsInSeparateProcesses\n */\nclass ODTextTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Construct.\n     */\n    public function testConstruct(): void\n    {\n        $object = new ODText(new PhpWord());\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\PhpWord', $object->getPhpWord());\n\n        self::assertEquals('./', $object->getDiskCachingDirectory());\n        foreach (['Content', 'Manifest', 'Meta', 'Mimetype', 'Styles'] as $part) {\n            self::assertInstanceOf(\n                \"PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Part\\\\{$part}\",\n                $object->getWriterPart($part)\n            );\n            self::assertInstanceOf(\n                'PhpOffice\\\\PhpWord\\\\Writer\\\\ODText',\n                $object->getWriterPart($part)->getParentWriter()\n            );\n        }\n    }\n\n    /**\n     * Construct with null.\n     */\n    public function testConstructWithNull(): void\n    {\n        $this->expectException(\\PhpOffice\\PhpWord\\Exception\\Exception::class);\n        $this->expectExceptionMessage('No PhpWord assigned.');\n        $object = new ODText();\n        $object->getPhpWord();\n    }\n\n    /**\n     * Save.\n     */\n    public function testSave(): void\n    {\n        $imageSrc = __DIR__ . '/../_files/images/PhpWord.png';\n        $objectSrc = __DIR__ . '/../_files/documents/sheet.xls';\n        $file = __DIR__ . '/../_files/temp.odt';\n\n        $phpWord = new PhpWord();\n        $phpWord->addFontStyle('Font', ['size' => 11]);\n        $phpWord->addParagraphStyle('Paragraph', ['alignment' => Jc::CENTER]);\n        $section = $phpWord->addSection();\n        $section->addText('Test 1', 'Font');\n        $section->addTextBreak();\n        $section->addText('Test 2', null, 'Paragraph');\n        $section->addLink('https://github.com/PHPOffice/PHPWord');\n        $section->addTitle('Test', 1);\n        $section->addPageBreak();\n        $section->addTable()->addRow()->addCell()->addText('Test');\n        $section->addListItem('Test');\n        $section->addImage($imageSrc);\n        $section->addObject($objectSrc);\n        $section->addTOC();\n        $section = $phpWord->addSection();\n        $textrun = $section->addTextRun();\n        $textrun->addText('Test 3');\n        $writer = new ODText($phpWord);\n        $writer->save($file);\n\n        self::assertFileExists($file);\n\n        unlink($file);\n    }\n\n    /**\n     * Save php output.\n     *\n     * @todo   Haven't got any method to test this\n     */\n    public function testSavePhpOutput(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $section->addText('Test');\n        $writer = new ODText($phpWord);\n        ob_start();\n        $writer->save('php://output');\n        $contents = ob_get_contents();\n        self::assertTrue(ob_end_clean());\n        self::assertNotEmpty($contents);\n    }\n\n    /**\n     * Get writer part return null value.\n     */\n    public function testGetWriterPartNull(): void\n    {\n        $object = new ODText();\n        self::assertNull($object->getWriterPart('foo'));\n    }\n\n    /**\n     * Set/get use disk caching.\n     */\n    public function testSetGetUseDiskCaching(): void\n    {\n        $object = new ODText();\n        $object->setUseDiskCaching(true, PHPWORD_TESTS_BASE_DIR);\n        self::assertTrue($object->isUseDiskCaching());\n        self::assertEquals(PHPWORD_TESTS_BASE_DIR, $object->getDiskCachingDirectory());\n    }\n\n    /**\n     * Use disk caching exception.\n     */\n    public function testSetUseDiskCachingException(): void\n    {\n        $this->expectException(\\PhpOffice\\PhpWord\\Exception\\Exception::class);\n        $dir = implode(DIRECTORY_SEPARATOR, [PHPWORD_TESTS_BASE_DIR, 'foo']);\n\n        $object = new ODText();\n        $object->setUseDiskCaching(true, $dir);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/PDF/DomPDFTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\PDF;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Writer\\PDF;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\PDF\\DomPDF.\n *\n * @runTestsInSeparateProcesses\n */\nclass DomPDFTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test construct.\n     */\n    public function testConstruct(): void\n    {\n        define('DOMPDF_ENABLE_AUTOLOAD', false);\n        $file = __DIR__ . '/../../_files/dompdf.pdf';\n\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $section->addText('Test 1');\n\n        $rendererName = Settings::PDF_RENDERER_DOMPDF;\n        $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/dompdf/dompdf');\n        Settings::setPdfRenderer($rendererName, $rendererLibraryPath);\n        $writer = new PDF($phpWord);\n        $writer->save($file);\n\n        self::assertFileExists($file);\n\n        unlink($file);\n    }\n\n    /**\n     * Test set/get abstract renderer properties.\n     */\n    public function testSetGetAbstractRendererProperties(): void\n    {\n        define('DOMPDF_ENABLE_AUTOLOAD', false);\n\n        $rendererName = Settings::PDF_RENDERER_DOMPDF;\n        $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/dompdf/dompdf');\n        Settings::setPdfRenderer($rendererName, $rendererLibraryPath);\n        $writer = new PDF(new PhpWord());\n\n        $writer->setFont('arial');\n        self::assertEquals('arial', $writer->getFont());\n\n        $writer->setPaperSize();\n        self::assertEquals(9, $writer->getPaperSize());\n\n        $writer->setOrientation();\n        self::assertEquals('default', $writer->getOrientation());\n\n        $writer->setTempDir(Settings::getTempDir());\n        self::assertEquals(Settings::getTempDir(), $writer->getTempDir());\n    }\n\n    /**\n     * Test set/get abstract renderer options.\n     */\n    public function testSetGetAbstractRendererOptions(): void\n    {\n        define('DOMPDF_ENABLE_AUTOLOAD', false);\n\n        $rendererName = Settings::PDF_RENDERER_DOMPDF;\n        $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/dompdf/dompdf');\n        Settings::setPdfRenderer($rendererName, $rendererLibraryPath);\n        Settings::setPdfRendererOptions([\n            'font' => 'Arial',\n        ]);\n        $writer = new PDF(new PhpWord());\n        self::assertEquals('Arial', $writer->getFont());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/PDF/MPDFTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\PDF;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Writer\\PDF;\nuse PhpOffice\\PhpWord\\Writer\\PDF\\MPDF;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\PDF\\MPDF.\n *\n * @runTestsInSeparateProcesses\n */\nclass MPDFTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test construct.\n     */\n    public function testConstruct(): void\n    {\n        $file = __DIR__ . '/../../_files/mpdf.pdf';\n\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $section->addText('Test 1');\n        $section->addPageBreak();\n        $section->addText('Test 2');\n        $oSettings = new \\PhpOffice\\PhpWord\\Style\\Section();\n        $oSettings->setSettingValue('orientation', 'landscape');\n        $section = $phpWord->addSection($oSettings); // @phpstan-ignore-line\n        $section->addText('Section 2 - landscape');\n\n        $writer = new MPDF($phpWord);\n        $writer->save($file);\n\n        self::assertFileExists($file);\n\n        unlink($file);\n    }\n\n    public function testEditCallback(): void\n    {\n        $file = __DIR__ . '/../../_files/mpdf.pdf';\n\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $section->addText('Test 1');\n        $section->addPageBreak();\n        $section->addText('Test 2');\n        $oSettings = new \\PhpOffice\\PhpWord\\Style\\Section();\n        $oSettings->setSettingValue('orientation', 'landscape');\n        $section = $phpWord->addSection($oSettings); // @phpstan-ignore-line\n        $section->addText('Section 2 - landscape');\n\n        $writer = new MPDF($phpWord);\n        /** @var callable */\n        $callback = [self::class, 'cbEditContent'];\n        $writer->setEditCallback($callback);\n        $writer->save($file);\n\n        self::assertFileExists($file);\n\n        unlink($file);\n    }\n\n    // add a footer\n    public static function cbEditContent(string $html): string\n    {\n        $afterBody = '<htmlpagefooter name=\"myFooter1\"><div style=\\'text-align: right;\\'>{PAGENO}</div></htmlpagefooter>' . MPDF::SIMULATED_BODY_START;\n        $beforeBody = '<style>@page page1 {odd-footer-name: html_myFooter1;}</style>';\n        $needle = '</head>';\n        $pos = strpos($html, $needle);\n        if ($pos !== false) {\n            $html = (string) substr_replace($html, \"$beforeBody\\n$needle\", $pos, strlen($needle));\n        }\n        $needle = '<body>';\n        $pos = strpos($html, $needle);\n        if ($pos !== false) {\n            $html = (string) substr_replace($html, \"$needle\\n$afterBody\", $pos, strlen($needle));\n        }\n\n        return $html;\n    }\n\n    /**\n     * Test set/get abstract renderer options.\n     */\n    public function testSetGetAbstractRendererOptions(): void\n    {\n        $rendererName = Settings::PDF_RENDERER_MPDF;\n        $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/mpdf/mpdf');\n        Settings::setPdfRenderer($rendererName, $rendererLibraryPath);\n        Settings::setPdfRendererOptions([\n            'font' => 'Arial',\n        ]);\n        $writer = new PDF(new PhpWord());\n        self::assertEquals('Arial', $writer->getFont());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/PDF/TCPDFTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\PDF;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Writer\\PDF;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\PDF\\TCPDF.\n *\n * @runTestsInSeparateProcesses\n */\nclass TCPDFTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test construct.\n     */\n    public function testConstruct(): void\n    {\n        $file = __DIR__ . '/../../_files/tcpdf.pdf';\n\n        $phpWord = new PhpWord();\n        $phpWord->setDefaultParagraphStyle(['spaceBefore' => 0, 'spaceAfter' => 0]);\n        $section = $phpWord->addSection();\n        $section->addText('Test 1');\n\n        $rendererName = Settings::PDF_RENDERER_TCPDF;\n        $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/tecnickcom/tcpdf');\n        Settings::setPdfRenderer($rendererName, $rendererLibraryPath);\n        $writer = new PDF($phpWord);\n        $writer->save($file);\n\n        self::assertFileExists($file);\n\n        unlink($file);\n    }\n\n    /**\n     * Test set/get abstract renderer options.\n     */\n    public function testSetGetAbstractRendererOptions(): void\n    {\n        $rendererName = Settings::PDF_RENDERER_TCPDF;\n        $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/tecnickcom/tcpdf');\n        Settings::setPdfRenderer($rendererName, $rendererLibraryPath);\n        Settings::setPdfRendererOptions([\n            'font' => 'Arial',\n        ]);\n        $writer = new PDF(new PhpWord());\n        self::assertEquals('Arial', $writer->getFont());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/PDFTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Writer\\PDF;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\PDF.\n *\n * @runTestsInSeparateProcesses\n */\nclass PDFTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test normal construct.\n     */\n    public function testConstruct(): void\n    {\n        define('DOMPDF_ENABLE_AUTOLOAD', false);\n        $file = __DIR__ . '/../_files/temp.pdf';\n\n        $rendererName = Settings::PDF_RENDERER_DOMPDF;\n        $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/dompdf/dompdf');\n        Settings::setPdfRenderer($rendererName, $rendererLibraryPath);\n        $writer = new PDF(new PhpWord());\n        $writer->save($file);\n\n        self::assertFileExists($file);\n\n        unlink($file);\n    }\n\n    /**\n     * Test construct exception.\n     */\n    public function testConstructException(): void\n    {\n        $this->expectException(\\PhpOffice\\PhpWord\\Exception\\Exception::class);\n        $this->expectExceptionMessage('PDF rendering library or library path has not been defined.');\n        $writer = new PDF(new PhpWord());\n        $writer->save('unknown.file');\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/RTF/Element/TableTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\RTF\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\Table;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\SimpleType\\Border;\nuse PhpOffice\\PhpWord\\Style;\nuse PhpOffice\\PhpWord\\Writer\\RTF;\nuse PhpOffice\\PhpWord\\Writer\\RTF\\Element\\Table as WriterTable;\n\nclass TableTest extends \\PHPUnit\\Framework\\TestCase\n{\n    protected function tearDown(): void\n    {\n        Settings::setDefaultRtl(null);\n    }\n\n    public function removeCr(WriterTable $field): string\n    {\n        return str_replace(\"\\r\\n\", \"\\n\", $field->write());\n    }\n\n    public function testTable(): void\n    {\n        Settings::setDefaultRtl(false);\n        $parentWriter = new RTF();\n        $element = new Table();\n        $width = 100;\n        $width2 = 2 * $width;\n        $element->addRow();\n        $tce = $element->addCell($width);\n        $tce->addText('1');\n        $tce = $element->addCell($width);\n        $tce->addText('2');\n        $element->addRow();\n        $tce = $element->addCell($width);\n        $tce->addText('3');\n        $tce = $element->addCell($width);\n        $tce->addText('4');\n        $table = new WriterTable($parentWriter, $element);\n        $expect = implode(\"\\n\", [\n            '\\\\pard',\n            \"\\\\trowd \\\\cellx$width \\\\cellx$width2 \",\n            '\\\\intbl',\n            '\\\\ql{\\\\cf0\\\\f0 1}\\\\par',\n            '\\\\cell',\n            '\\\\intbl',\n            '{\\\\cf0\\\\f0 2}\\\\par',\n            '\\\\cell',\n            '\\\\row',\n            \"\\\\trowd \\\\cellx$width \\\\cellx$width2 \",\n            '\\\\intbl',\n            '\\\\ql{\\\\cf0\\\\f0 3}\\\\par',\n            '\\\\cell',\n            '\\\\intbl',\n            '{\\\\cf0\\\\f0 4}\\par',\n            '\\\\cell',\n            '\\\\row',\n            '\\\\pard',\n            '',\n        ]);\n\n        self::assertEquals($expect, $this->removeCr($table));\n    }\n\n    public function testTableStyle(): void\n    {\n        $width = 100;\n\n        Settings::setDefaultRtl(false);\n        $parentWriter = new RTF();\n\n        Style::addTableStyle('TableStyle', ['borderSize' => 6, 'borderColor' => '006699']);\n\n        $element = new Table('TableStyle');\n        $element->addRow();\n        $elementCell = $element->addCell($width);\n        $elementCell->addText('1');\n\n        $expect = implode(\"\\n\", [\n            '\\\\pard',\n            '\\\\trowd \\\\clbrdrt\\\\brdrs\\\\brdrw2\\\\brdrcf0',\n            '\\\\clbrdrl\\\\brdrs\\\\brdrw2\\\\brdrcf0',\n            '\\\\clbrdrb\\\\brdrs\\\\brdrw2\\\\brdrcf0',\n            '\\\\clbrdrr\\\\brdrs\\\\brdrw2\\\\brdrcf0',\n            \"\\\\cellx$width \",\n            '\\\\intbl',\n            '\\\\ql{\\\\cf0\\\\f0 1}\\\\par',\n            '\\\\cell',\n            '\\\\row',\n            '\\\\pard',\n            '',\n        ]);\n\n        self::assertEquals($expect, $this->removeCr(new WriterTable($parentWriter, $element)));\n    }\n\n    public function testTableStyleNotExisting(): void\n    {\n        $width = 100;\n\n        Settings::setDefaultRtl(false);\n        $parentWriter = new RTF();\n\n        $element = new Table('TableStyleNotExisting');\n        $element->addRow();\n        $elementCell = $element->addCell($width);\n        $elementCell->addText('1');\n\n        $expect = implode(\"\\n\", [\n            '\\\\pard',\n            \"\\\\trowd \\\\cellx$width \",\n            '\\\\intbl',\n            '\\\\ql{\\\\cf0\\\\f0 1}\\\\par',\n            '\\\\cell',\n            '\\\\row',\n            '\\\\pard',\n            '',\n        ]);\n\n        self::assertEquals($expect, $this->removeCr(new WriterTable($parentWriter, $element)));\n    }\n\n    public function testTableCellStyle(): void\n    {\n        $width = 100;\n\n        Settings::setDefaultRtl(false);\n        $parentWriter = new RTF();\n\n        $element = new Table();\n        $element->addRow();\n        $elementCell = $element->addCell($width, ['borderSize' => 6, 'borderColor' => '006699', 'borderStyle' => Border::DOTTED]);\n        $elementCell->addText('1');\n\n        $expect = implode(\"\\n\", [\n            '\\\\pard',\n            '\\\\trowd \\\\clbrdrt\\\\brdrdot\\\\brdrw2\\\\brdrcf0',\n            '\\\\clbrdrl\\\\brdrdot\\\\brdrw2\\\\brdrcf0',\n            '\\\\clbrdrb\\\\brdrdot\\\\brdrw2\\\\brdrcf0',\n            '\\\\clbrdrr\\\\brdrdot\\\\brdrw2\\\\brdrcf0',\n            \"\\\\cellx$width \",\n            '\\\\intbl',\n            '\\\\ql{\\\\cf0\\\\f0 1}\\\\par',\n            '\\\\cell',\n            '\\\\row',\n            '\\\\pard',\n            '',\n        ]);\n\n        self::assertEquals($expect, $this->removeCr(new WriterTable($parentWriter, $element)));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/RTF/Element2Test.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\RTF;\n\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Writer\\RTF;\nuse PhpOffice\\PhpWord\\Writer\\RTF\\Element\\TextRun as WriterTextRun;\nuse PhpOffice\\PhpWord\\Writer\\RTF\\Element\\Title as WriterTitle;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\RTF\\Element subnamespace.\n */\nclass Element2Test extends \\PHPUnit\\Framework\\TestCase\n{\n    protected function tearDown(): void\n    {\n        Settings::setDefaultRtl(null);\n    }\n\n    /** @param WriterTextRun|WriterTitle $field */\n    public function removeCr($field): string\n    {\n        return str_replace(\"\\r\\n\", \"\\n\", $field->write());\n    }\n\n    public function testTextRun(): void\n    {\n        Settings::setDefaultRtl(false);\n        $parentWriter = new RTF();\n        $element = new \\PhpOffice\\PhpWord\\Element\\TextRun();\n        $element->addText('Hello ');\n        $element->addText('there.');\n        $textrun = new WriterTextRun($parentWriter, $element);\n        $expect = \"\\\\pard\\\\nowidctlpar \\\\ql{{\\\\cf0\\\\f0 Hello }{\\\\cf0\\\\f0 there.}}\\\\par\\n\";\n        self::assertEquals($expect, $this->removeCr($textrun));\n    }\n\n    public function testTextRunParagraphStyle(): void\n    {\n        Settings::setDefaultRtl(false);\n        $parentWriter = new RTF();\n        $element = new \\PhpOffice\\PhpWord\\Element\\TextRun(['spaceBefore' => 0, 'spaceAfter' => 0]);\n        $element->addText('Hello ');\n        $element->addText('there.');\n        $textrun = new WriterTextRun($parentWriter, $element);\n        $expect = \"\\\\pard\\\\nowidctlpar \\\\ql\\\\sb0\\\\sa0{{\\\\cf0\\\\f0 Hello }{\\\\cf0\\\\f0 there.}}\\\\par\\n\";\n        self::assertEquals($expect, $this->removeCr($textrun));\n    }\n\n    public function testTitle(): void\n    {\n        $parentWriter = new RTF();\n        $phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n        Settings::setDefaultRtl(false);\n        $phpWord->addTitleStyle(1, [], ['spaceBefore' => 0, 'spaceAfter' => 0]);\n        $section = $phpWord->addSection();\n        $element = $section->addTitle('First Heading', 1);\n        $elwrite = new WriterTitle($parentWriter, $element);\n        $expect = \"\\\\pard\\\\nowidctlpar \\\\ql\\\\sb0\\\\sa0{\\\\outlinelevel0{\\\\cf0\\\\f0 First Heading}\\\\par\\n}\";\n        self::assertEquals($expect, $this->removeCr($elwrite));\n        Settings::setDefaultRtl(null);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/RTF/ElementTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\RTF;\n\nuse PhpOffice\\PhpWord\\Writer\\RTF;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\RTF\\Element subnamespace.\n */\nclass ElementTest extends \\PHPUnit\\Framework\\TestCase\n{\n    public function removeCr($field)\n    {\n        return str_replace(\"\\r\\n\", \"\\n\", $field->write());\n    }\n\n    /**\n     * Test unmatched elements.\n     */\n    public function testUnmatchedElements(): void\n    {\n        $elements = ['Container', 'Text', 'Title', 'Link', 'Image', 'Table', 'Field'];\n        foreach ($elements as $element) {\n            $objectClass = 'PhpOffice\\\\PhpWord\\\\Writer\\\\RTF\\\\Element\\\\' . $element;\n            $parentWriter = new RTF();\n            $newElement = new \\PhpOffice\\PhpWord\\Element\\PageBreak();\n            $object = new $objectClass($parentWriter, $newElement);\n\n            self::assertEquals('', $object->write());\n        }\n    }\n\n    public function testFilenameField(): void\n    {\n        $parentWriter = new RTF();\n        $element = new \\PhpOffice\\PhpWord\\Element\\Field('FILENAME');\n        $field = new RTF\\Element\\Field($parentWriter, $element);\n\n        self::assertEquals(\"{\\\\field{\\\\*\\\\fldinst FILENAME}{\\\\fldrslt}}\\\\par\\n\", $this->removeCr($field));\n    }\n\n    public function testFilenameFieldOptionsPath(): void\n    {\n        $parentWriter = new RTF();\n        $element = new \\PhpOffice\\PhpWord\\Element\\Field('FILENAME', [], ['Path']);\n        $field = new RTF\\Element\\Field($parentWriter, $element);\n\n        self::assertEquals(\"{\\\\field{\\\\*\\\\fldinst FILENAME \\\\\\\\p}{\\\\fldrslt}}\\\\par\\n\", $this->removeCr($field));\n    }\n\n    public function testPageField(): void\n    {\n        $parentWriter = new RTF();\n        $element = new \\PhpOffice\\PhpWord\\Element\\Field('PAGE');\n        $field = new RTF\\Element\\Field($parentWriter, $element);\n\n        self::assertEquals(\"{\\\\field{\\\\*\\\\fldinst PAGE}{\\\\fldrslt}}\\\\par\\n\", $this->removeCr($field));\n    }\n\n    public function testNumpageField(): void\n    {\n        $parentWriter = new RTF();\n        $element = new \\PhpOffice\\PhpWord\\Element\\Field('NUMPAGES');\n        $field = new RTF\\Element\\Field($parentWriter, $element);\n\n        self::assertEquals(\"{\\\\field{\\\\*\\\\fldinst NUMPAGES}{\\\\fldrslt}}\\\\par\\n\", $this->removeCr($field));\n    }\n\n    public function testDateField(): void\n    {\n        $parentWriter = new RTF();\n        $element = new \\PhpOffice\\PhpWord\\Element\\Field('DATE', ['dateformat' => 'd MM yyyy H:mm:ss']);\n        $field = new RTF\\Element\\Field($parentWriter, $element);\n\n        self::assertEquals(\"{\\\\field{\\\\*\\\\fldinst DATE \\\\\\\\@ \\\"d MM yyyy H:mm:ss\\\"}{\\\\fldrslt}}\\\\par\\n\", $this->removeCr($field));\n    }\n\n    public function testIndexField(): void\n    {\n        $parentWriter = new RTF();\n        $element = new \\PhpOffice\\PhpWord\\Element\\Field('INDEX');\n        $field = new RTF\\Element\\Field($parentWriter, $element);\n\n        self::assertEquals(\"{}\\\\par\\n\", $this->removeCr($field));\n    }\n\n    public function testTable(): void\n    {\n        $parentWriter = new RTF();\n        $element = new \\PhpOffice\\PhpWord\\Element\\Table();\n        $width = 100;\n        $width2 = 2 * $width;\n        $element->addRow();\n        $tce = $element->addCell($width);\n        $tce->addText('1');\n        $tce = $element->addCell($width);\n        $tce->addText('2');\n        $element->addRow();\n        $tce = $element->addCell($width);\n        $tce->addText('3');\n        $tce = $element->addCell($width);\n        $tce->addText('4');\n        $table = new RTF\\Element\\Table($parentWriter, $element);\n        $expect = implode(\"\\n\", [\n            '\\\\pard',\n            \"\\\\trowd \\\\cellx$width \\\\cellx$width2 \",\n            '\\\\intbl',\n            '{\\\\cf0\\\\f0 1}\\\\par',\n            '\\\\cell',\n            '\\\\intbl',\n            '{\\\\cf0\\\\f0 2}\\\\par',\n            '\\\\cell',\n            '\\\\row',\n            \"\\\\trowd \\\\cellx$width \\\\cellx$width2 \",\n            '\\\\intbl',\n            '{\\\\cf0\\\\f0 3}\\\\par',\n            '\\\\cell',\n            '\\\\intbl',\n            '{\\\\cf0\\\\f0 4}\\par',\n            '\\\\cell',\n            '\\\\row',\n            '\\\\pard',\n            '',\n        ]);\n\n        self::assertEquals($expect, $this->removeCr($table));\n    }\n\n    public function testTextRun(): void\n    {\n        $parentWriter = new RTF();\n        $element = new \\PhpOffice\\PhpWord\\Element\\TextRun();\n        $element->addText('Hello ');\n        $element->addText('there.');\n        $textrun = new RTF\\Element\\TextRun($parentWriter, $element);\n        $expect = \"\\\\pard\\\\nowidctlpar {{\\\\cf0\\\\f0 Hello }{\\\\cf0\\\\f0 there.}}\\\\par\\n\";\n        self::assertEquals($expect, $this->removeCr($textrun));\n    }\n\n    public function testTextRunParagraphStyle(): void\n    {\n        $parentWriter = new RTF();\n        $element = new \\PhpOffice\\PhpWord\\Element\\TextRun(['spaceBefore' => 0, 'spaceAfter' => 0]);\n        $element->addText('Hello ');\n        $element->addText('there.');\n        $textrun = new RTF\\Element\\TextRun($parentWriter, $element);\n        $expect = \"\\\\pard\\\\nowidctlpar \\\\sb0\\\\sa0{{\\\\cf0\\\\f0 Hello }{\\\\cf0\\\\f0 there.}}\\\\par\\n\";\n        self::assertEquals($expect, $this->removeCr($textrun));\n    }\n\n    public function testTitle(): void\n    {\n        $parentWriter = new RTF();\n        $phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n        $phpWord->addTitleStyle(1, [], ['spaceBefore' => 0, 'spaceAfter' => 0]);\n        $section = $phpWord->addSection();\n        $element = $section->addTitle('First Heading', 1);\n        $elwrite = new RTF\\Element\\Title($parentWriter, $element);\n        $expect = \"\\\\pard\\\\nowidctlpar \\\\sb0\\\\sa0{\\\\outlinelevel0{\\\\cf0\\\\f0 First Heading}\\\\par\\n}\";\n        self::assertEquals($expect, $this->removeCr($elwrite));\n    }\n\n    public function testRuby(): void\n    {\n        $parentWriter = new RTF();\n        $properties = new \\PhpOffice\\PhpWord\\ComplexType\\RubyProperties();\n        $baseTextRun = new \\PhpOffice\\PhpWord\\Element\\TextRun(null);\n        $baseTextRun->addText('base text');\n        $rubyTextRun = new \\PhpOffice\\PhpWord\\Element\\TextRun(null);\n        $rubyTextRun->addText('ruby');\n        $element = new \\PhpOffice\\PhpWord\\Element\\TextRun();\n        $element->addRuby($baseTextRun, $rubyTextRun, $properties);\n\n        $textrun = new RTF\\Element\\TextRun($parentWriter, $element);\n        $expect = \"\\\\pard\\\\nowidctlpar {{base text (ruby)}}\\\\par\\n\";\n        self::assertEquals($expect, $this->removeCr($textrun));\n    }\n\n    public function testRubyTitle(): void\n    {\n        $parentWriter = new RTF();\n        $properties = new \\PhpOffice\\PhpWord\\ComplexType\\RubyProperties();\n        $baseTextRun = new \\PhpOffice\\PhpWord\\Element\\TextRun(null);\n        $baseTextRun->addText('base text');\n        $rubyTextRun = new \\PhpOffice\\PhpWord\\Element\\TextRun(null);\n        $rubyTextRun->addText('ruby');\n        $textRun = new \\PhpOffice\\PhpWord\\Element\\TextRun();\n        $textRun->addRuby($baseTextRun, $rubyTextRun, $properties);\n\n        $phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n        $phpWord->addTitleStyle(\n            1,\n            ['size' => 24, 'bold' => true, 'color' => '000099'],\n            ['spaceBefore' => 0, 'spaceAfter' => 2]\n        );\n        $section = $phpWord->addSection();\n        $element = $section->addTitle($textRun, 1);\n        $elwrite = new RTF\\Element\\Title($parentWriter, $element);\n\n        $expect = \"\\\\pard\\\\nowidctlpar \\\\sb0\\\\sa2{\\\\outlinelevel0{\\\\cf0\\\\f0\\\\fs48\\\\b base text (ruby)}\\\\par\\n}\";\n        self::assertEquals($expect, $this->removeCr($elwrite));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/RTF/HeaderFooterTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\RTF;\n\nuse PhpOffice\\PhpWord\\Element\\Footer;\nuse PhpOffice\\PhpWord\\Writer\\RTF;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\RTF\\Element subnamespace.\n */\nclass HeaderFooterTest extends \\PHPUnit\\Framework\\TestCase\n{\n    public function testNoHeaderNoFooter(): void\n    {\n        $phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n        $parentWriter = new RTF($phpWord);\n        $section = $phpWord->addSection();\n        $section->addText('Doc without header or footer');\n        $contents = $parentWriter->getWriterPart('Document')->write();\n        self::assertEquals(0, preg_match('/\\\\\\\\header[rlf]?\\\\b/', $contents));\n        self::assertEquals(0, preg_match('/\\\\\\\\footer[rlf]?\\\\b/', $contents));\n        self::assertEquals(0, preg_match('/\\\\\\\\titlepg\\\\b/', $contents));\n        self::assertEquals(0, preg_match('/\\\\\\\\facingp\\\\b/', $contents));\n    }\n\n    public function testNoHeaderYesFooter(): void\n    {\n        $phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n        $parentWriter = new RTF($phpWord);\n        $section = $phpWord->addSection();\n        $footer = $section->addFooter();\n        $footer->addText('Auto footer');\n        $section->addText('Doc without header but with footer');\n        $contents = $parentWriter->getWriterPart('Document')->write();\n        self::assertEquals(0, preg_match('/\\\\\\\\header[rlf]?\\\\b/', $contents));\n        self::assertEquals(1, preg_match('/\\\\\\\\footer[rlf]?\\\\b/', $contents));\n        self::assertEquals(0, preg_match('/\\\\\\\\titlepg\\\\b/', $contents));\n        self::assertEquals(0, preg_match('/\\\\\\\\facingp\\\\b/', $contents));\n    }\n\n    public function testEvenHeaderFirstFooter(): void\n    {\n        $phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n        $phpWord->getSettings()->setEvenAndOddHeaders(true);\n        $parentWriter = new RTF($phpWord);\n        $section = $phpWord->addSection();\n        $footer = $section->addFooter(Footer::FIRST);\n        $footer->addText('First footer');\n        $footer = $section->addHeader(Footer::EVEN);\n        $footer->addText('Even footer');\n        $footer = $section->addHeader(Footer::AUTO);\n        $footer->addText('Odd footer');\n        $section->addText('Doc with even/odd header and first footer');\n        $contents = $parentWriter->getWriterPart('Document')->write();\n        self::assertEquals(1, preg_match('/\\\\\\\\headerr\\\\b/', $contents));\n        self::assertEquals(1, preg_match('/\\\\\\\\headerl\\\\b/', $contents));\n        self::assertEquals(0, preg_match('/\\\\\\\\header[f]?\\\\b/', $contents));\n        self::assertEquals(1, preg_match('/\\\\\\\\footerf\\\\b/', $contents));\n        self::assertEquals(0, preg_match('/\\\\\\\\footer[rl]?\\\\b/', $contents));\n        self::assertEquals(1, preg_match('/\\\\\\\\titlepg\\\\b/', $contents));\n        self::assertEquals(1, preg_match('/\\\\\\\\facingp\\\\b/', $contents));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/RTF/StyleTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\RTF;\n\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Writer\\RTF;\nuse PhpOffice\\PhpWord\\Writer\\RTF\\Style\\Border;\nuse PHPUnit\\Framework\\Assert;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\RTF\\Style subnamespace.\n */\nclass StyleTest extends \\PHPUnit\\Framework\\TestCase\n{\n    protected function tearDown(): void\n    {\n        Settings::setDefaultRtl(null);\n    }\n\n    public function removeCr($field)\n    {\n        return str_replace(\"\\r\\n\", \"\\n\", $field->write());\n    }\n\n    /**\n     * Test empty styles.\n     */\n    public function testEmptyStyles(): void\n    {\n        $styles = ['Font', 'Paragraph', 'Section', 'Tab', 'Indentation'];\n        foreach ($styles as $style) {\n            $objectClass = 'PhpOffice\\\\PhpWord\\\\Writer\\\\RTF\\\\Style\\\\' . $style;\n            $object = new $objectClass();\n\n            self::assertEquals('', $object->write());\n        }\n    }\n\n    public function testBorderWithNonRegisteredColors(): void\n    {\n        $border = new Border();\n        $border->setSizes([1, 2, 3, 4]);\n        $border->setColors(['#FF0000', '#FF0000', '#FF0000', '#FF0000']);\n        $border->setSizes([20, 20, 20, 20]);\n\n        $content = $border->write();\n\n        $expected = '\\pgbrdropt32';\n        $expected .= '\\pgbrdrt\\brdrs\\brdrw20\\brdrcf0\\brsp480 ';\n        $expected .= '\\pgbrdrl\\brdrs\\brdrw20\\brdrcf0\\brsp480 ';\n        $expected .= '\\pgbrdrr\\brdrs\\brdrw20\\brdrcf0\\brsp480 ';\n        $expected .= '\\pgbrdrb\\brdrs\\brdrw20\\brdrcf0\\brsp480 ';\n\n        self::assertEquals($expected, $content);\n    }\n\n    public function testIndentation(): void\n    {\n        $indentation = new \\PhpOffice\\PhpWord\\Style\\Indentation();\n        $indentation->setLeft(1);\n        $indentation->setRight(2);\n        $indentation->setFirstLine(3);\n\n        $indentWriter = new RTF\\Style\\Indentation($indentation);\n        $indentWriter->setParentWriter(new RTF());\n        $result = $indentWriter->write();\n\n        Assert::assertEquals('\\fi3\\li1\\ri2 ', $result);\n    }\n\n    public function testRightTab(): void\n    {\n        $tabRight = new \\PhpOffice\\PhpWord\\Style\\Tab();\n        $tabRight->setType(\\PhpOffice\\PhpWord\\Style\\Tab::TAB_STOP_RIGHT);\n        $tabRight->setPosition(5);\n\n        $tabWriter = new RTF\\Style\\Tab($tabRight);\n        $tabWriter->setParentWriter(new RTF());\n        $result = $tabWriter->write();\n\n        Assert::assertEquals('\\tqr\\tx5', $result);\n    }\n\n    public function testCenterTab(): void\n    {\n        $tabRight = new \\PhpOffice\\PhpWord\\Style\\Tab();\n        $tabRight->setType(\\PhpOffice\\PhpWord\\Style\\Tab::TAB_STOP_CENTER);\n\n        $tabWriter = new RTF\\Style\\Tab($tabRight);\n        $tabWriter->setParentWriter(new RTF());\n        $result = $tabWriter->write();\n\n        Assert::assertEquals('\\tqc\\tx0', $result);\n    }\n\n    public function testDecimalTab(): void\n    {\n        $tabRight = new \\PhpOffice\\PhpWord\\Style\\Tab();\n        $tabRight->setType(\\PhpOffice\\PhpWord\\Style\\Tab::TAB_STOP_DECIMAL);\n\n        $tabWriter = new RTF\\Style\\Tab($tabRight);\n        $tabWriter->setParentWriter(new RTF());\n        $result = $tabWriter->write();\n\n        Assert::assertEquals('\\tqdec\\tx0', $result);\n    }\n\n    public function testRTL(): void\n    {\n        $parentWriter = new RTF();\n        $element = new \\PhpOffice\\PhpWord\\Element\\Text('אב גד', ['RTL' => true]);\n        $text = new RTF\\Element\\Text($parentWriter, $element);\n        $expect = \"\\\\pard\\\\nowidctlpar {\\\\rtlch\\\\cf0\\\\f0 \\\\uc0{\\\\u1488}\\\\uc0{\\\\u1489} \\\\uc0{\\\\u1490}\\\\uc0{\\\\u1491}}\\\\par\\n\";\n        self::assertEquals($expect, $this->removeCr($text));\n    }\n\n    public function testRTL2(): void\n    {\n        Settings::setDefaultRtl(true);\n        $parentWriter = new RTF();\n        $element = new \\PhpOffice\\PhpWord\\Element\\Text('אב גד');\n        $text = new RTF\\Element\\Text($parentWriter, $element);\n        $expect = \"\\\\pard\\\\nowidctlpar \\\\qr{\\\\rtlch\\\\cf0\\\\f0 \\\\uc0{\\\\u1488}\\\\uc0{\\\\u1489} \\\\uc0{\\\\u1490}\\\\uc0{\\\\u1491}}\\\\par\\n\";\n        self::assertEquals($expect, $this->removeCr($text));\n    }\n\n    public function testPageBreakLineHeight(): void\n    {\n        $parentWriter = new RTF();\n        $element = new \\PhpOffice\\PhpWord\\Element\\Text('New page', null, ['lineHeight' => 1.08, 'pageBreakBefore' => true]);\n        $text = new RTF\\Element\\Text($parentWriter, $element);\n        $expect = \"\\\\pard\\\\nowidctlpar \\\\sl259\\\\slmult1\\\\page{\\\\cf0\\\\f0 New page}\\\\par\\n\";\n        self::assertEquals($expect, $this->removeCr($text));\n    }\n\n    public function testPageBreakLineHeight2(): void\n    {\n        Settings::setDefaultRtl(false);\n        $parentWriter = new RTF();\n        $element = new \\PhpOffice\\PhpWord\\Element\\Text('New page', null, ['lineHeight' => 1.08, 'pageBreakBefore' => true]);\n        $text = new RTF\\Element\\Text($parentWriter, $element);\n        $expect = \"\\\\pard\\\\nowidctlpar \\\\ql\\\\sl259\\\\slmult1\\\\page{\\\\cf0\\\\f0 New page}\\\\par\\n\";\n        self::assertEquals($expect, $this->removeCr($text));\n    }\n\n    public function testPageNumberRestart(): void\n    {\n        //$parentWriter = new RTF();\n        $phpword = new \\PhpOffice\\PhpWord\\PhpWord();\n        $section = $phpword->addSection(['pageNumberingStart' => 5]);\n        $styleWriter = new RTF\\Style\\Section($section->getStyle());\n        $wstyle = $this->removeCr($styleWriter);\n        // following have default values which might change so don't use them\n        $wstyle = preg_replace('/\\\\\\\\pgwsxn\\\\d+/', '', $wstyle);\n        $wstyle = preg_replace('/\\\\\\\\pghsxn\\\\d+/', '', $wstyle);\n        $wstyle = preg_replace('/\\\\\\\\margtsxn\\\\d+/', '', $wstyle);\n        $wstyle = preg_replace('/\\\\\\\\margrsxn\\\\d+/', '', $wstyle);\n        $wstyle = preg_replace('/\\\\\\\\margbsxn\\\\d+/', '', $wstyle);\n        $wstyle = preg_replace('/\\\\\\\\marglsxn\\\\d+/', '', $wstyle);\n        $wstyle = preg_replace('/\\\\\\\\headery\\\\d+/', '', $wstyle);\n        $wstyle = preg_replace('/\\\\\\\\footery\\\\d+/', '', $wstyle);\n        $wstyle = preg_replace('/\\\\\\\\guttersxn\\\\d+/', '', $wstyle);\n        $wstyle = preg_replace('/  +/', ' ', $wstyle);\n        $expect = \"\\\\sectd \\\\pgnstarts5\\\\pgnrestart \\n\";\n        self::assertEquals($expect, $wstyle);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/RTFTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\nuse PhpOffice\\PhpWord\\Writer\\RTF;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\RTF.\n *\n * @runTestsInSeparateProcesses\n */\nclass RTFTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Construct.\n     */\n    public function testConstruct(): void\n    {\n        $object = new RTF(new PhpWord());\n\n        self::assertInstanceOf('PhpOffice\\\\PhpWord\\\\PhpWord', $object->getPhpWord());\n    }\n\n    /**\n     * Construct with null.\n     */\n    public function testConstructWithNull(): void\n    {\n        $this->expectException(\\PhpOffice\\PhpWord\\Exception\\Exception::class);\n        $this->expectExceptionMessage('No PhpWord assigned.');\n        $object = new RTF();\n        $object->getPhpWord();\n    }\n\n    /**\n     * Save.\n     */\n    public function testSave(): void\n    {\n        $imageSrc = __DIR__ . '/../_files/images/PhpWord.png';\n        $objectSrc = __DIR__ . '/../_files/documents/sheet.xls';\n        $file = __DIR__ . '/../_files/temp.rtf';\n\n        $phpWord = new PhpWord();\n        $phpWord->addFontStyle(\n            'Font',\n            ['name' => 'Verdana', 'size' => 11, 'color' => 'FF0000', 'fgColor' => '00FF00']\n        );\n        $phpWord->addParagraphStyle('Paragraph', ['alignment' => Jc::CENTER]);\n        $section = $phpWord->addSection();\n        $section->addText(htmlspecialchars('Test 1', ENT_COMPAT, 'UTF-8'), 'Font', 'Paragraph');\n        $section->addTextBreak();\n        $section->addText(htmlspecialchars('Test 2', ENT_COMPAT, 'UTF-8'), ['name' => 'Tahoma', 'bold' => true, 'italic' => true]);\n        $section->addLink('https://github.com/PHPOffice/PHPWord');\n        $section->addTitle(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8'), 1);\n        $section->addPageBreak();\n\n        // Rowspan\n        $table = $section->addTable();\n        $table->addRow()->addCell(null, ['vMerge' => 'restart'])->addText('Test');\n        $table->addRow()->addCell(null, ['vMerge' => 'continue'])->addText('Test');\n\n        // Nested table\n        $cell = $section->addTable()->addRow()->addCell();\n        $cell->addTable()->addRow()->addCell();\n\n        $section->addListItem(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8'));\n        $section->addImage($imageSrc);\n        $section->addObject($objectSrc);\n        $section->addTOC();\n        $section = $phpWord->addSection();\n        $textrun = $section->addTextRun();\n        $textrun->addText(htmlspecialchars('Test 3', ENT_COMPAT, 'UTF-8'));\n        $textrun->addTextBreak();\n        $writer = new RTF($phpWord);\n        $writer->save($file);\n\n        self::assertFileExists($file);\n\n        @unlink($file);\n    }\n\n    /**\n     * Save.\n     *\n     * @todo   Haven't got any method to test this\n     */\n    public function testSavePhpOutput(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $section->addText(htmlspecialchars('Test', ENT_COMPAT, 'UTF-8'));\n        $writer = new RTF($phpWord);\n        ob_start();\n        $writer->save('php://output');\n        $contents = ob_get_contents();\n        self::assertTrue(ob_end_clean());\n        self::assertNotEmpty($contents);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/Word2007/Element/ChartTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\Word2007\\Element;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\Word2007\\Element subnamespace.\n */\nclass ChartTest extends \\PHPUnit\\Framework\\TestCase\n{\n    private $outputEscapingEnabled;\n\n    /**\n     * Executed before each method of the class.\n     */\n    protected function setUp(): void\n    {\n        $this->outputEscapingEnabled = Settings::isOutputEscapingEnabled();\n    }\n\n    /**\n     * Executed after each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        Settings::setOutputEscapingEnabled($this->outputEscapingEnabled);\n        TestHelperDOCX::clear();\n    }\n\n    /**\n     * Test chart elements.\n     */\n    public function testChartElements(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $style = [\n            'width' => 5000000,\n            'height' => 5000000,\n            'showAxisLabels' => true,\n            'showGridX' => true,\n            'showGridY' => true,\n            'showLegend' => false,\n        ];\n\n        $chartTypes = ['pie', 'doughnut', 'bar', 'line', 'area', 'scatter', 'radar'];\n        $categories = ['A', 'B', 'C', 'D', 'E'];\n        $series1 = [1, 3, 2, 5, 4];\n        foreach ($chartTypes as $chartType) {\n            $section->addChart($chartType, $categories, $series1, $style);\n        }\n        $colorArray = ['FFFFFF', '000000', 'FF0000', '00FF00', '0000FF'];\n        $numColor = count($colorArray);\n        $chart = $section->addChart('pie', $categories, $series1, $style);\n        $chart->getStyle()->setColors($colorArray)->setTitle('3d chart')->set3d(true);\n        $chart = $section->addChart('stacked_bar', $categories, $series1, $style);\n        $chart->getStyle()->setColors($colorArray)->setShowLegend(true);\n        $chart = $section->addChart('scatter', $categories, $series1, $style);\n        $chart->getStyle()->setMajorTickPosition('cross');\n        $section->addChart('scatter', $categories, $series1, $style, 'seriesname');\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $index = 0;\n        foreach ($chartTypes as $chartType) {\n            ++$index;\n            $file = \"word/charts/chart{$index}.xml\";\n            $path = \"/c:chartSpace/c:chart/c:plotArea/c:{$chartType}Chart\";\n            self::assertTrue($doc->elementExists($path, $file), \"chart type $chartType\");\n        }\n\n        $index = 11;\n        $file = \"word/charts/chart{$index}.xml\";\n        $doc->setDefaultFile($file);\n        $chartType = 'scatter';\n        $path = \"/c:chartSpace/c:chart/c:plotArea/c:{$chartType}Chart\";\n        self::assertEquals('seriesname', $doc->getElement($path . '/c:ser/c:tx/c:strRef/c:strCache/c:pt/c:v')->nodeValue);\n\n        $index = 8;\n        $file = \"word/charts/chart{$index}.xml\";\n        $doc->setDefaultFile($file);\n        $chartType = 'pie3D';\n        $path = \"/c:chartSpace/c:chart/c:plotArea/c:{$chartType}Chart\";\n        for ($idx = 0; $idx < $numColor; ++$idx) {\n            $idxp1 = $idx + 1;\n            $element = $path . \"/c:ser/c:dPt[$idxp1]/c:spPr/a:solidFill/a:srgbClr\";\n            self::assertEquals($colorArray[$idx], $doc->getElementAttribute($element, 'val'), \"pie3d chart idx=$idx\");\n        }\n\n        $index = 9;\n        $file = \"word/charts/chart{$index}.xml\";\n        $doc->setDefaultFile($file);\n        $chartType = 'bar';\n        $path = \"/c:chartSpace/c:chart/c:plotArea/c:{$chartType}Chart\";\n        for ($idxp1 = 1; $idxp1 < $numColor; ++$idxp1) {\n            $idx = $idxp1; // stacked bar chart is shifted\n            $element = $path . \"/c:ser/c:dPt[$idxp1]/c:spPr/a:solidFill/a:srgbClr\";\n            self::assertEquals($colorArray[$idx - 1], $doc->getElementAttribute($element, 'val'), \"bar chart idx=$idx\");\n        }\n    }\n\n    public function testChartEscapingEnabled(): void\n    {\n        Settings::setOutputEscapingEnabled(true);\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $style = [\n            'width' => 5000000,\n            'height' => 5000000,\n            'showAxisLabels' => true,\n            'showGridX' => true,\n            'showGridY' => true,\n            'showLegend' => false,\n            'valueAxisTitle' => 'Values',\n        ];\n        $categories = ['A&B', 'C<D>', 'E', 'F', 'G'];\n        $series1 = [1, 3, 2, 5, 4];\n        $section->addChart('bar', $categories, $series1, $style);\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $index = 1;\n        $file = \"word/charts/chart{$index}.xml\";\n        $doc->setDefaultFile($file);\n        $chartType = 'bar';\n        $path = \"/c:chartSpace/c:chart/c:plotArea/c:{$chartType}Chart/c:ser/c:cat/c:strLit\";\n        $element = \"$path/c:pt[1]/c:v\";\n        self::assertEquals('A&B', $doc->getElement($element)->nodeValue);\n        $element = \"$path/c:pt[2]/c:v\";\n        self::assertEquals('C<D>', $doc->getElement($element)->nodeValue);\n    }\n\n    public function testChartEscapingDisabled(): void\n    {\n        Settings::setOutputEscapingEnabled(false);\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $style = [\n            'width' => 5000000,\n            'height' => 5000000,\n            'showAxisLabels' => true,\n            'showGridX' => true,\n            'showGridY' => true,\n            'showLegend' => false,\n            'valueAxisTitle' => 'Values',\n        ];\n        $categories = ['A&amp;B', 'C&lt;D&gt;', 'E', 'F', 'G'];\n        $series1 = [1, 3, 2, 5, 4];\n        $section->addChart('bar', $categories, $series1, $style);\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $index = 1;\n        $file = \"word/charts/chart{$index}.xml\";\n        $doc->setDefaultFile($file);\n        $chartType = 'bar';\n        $path = \"/c:chartSpace/c:chart/c:plotArea/c:{$chartType}Chart/c:ser/c:cat/c:strLit\";\n        $element = \"$path/c:pt[1]/c:v\";\n        self::assertEquals('A&B', $doc->getElement($element)->nodeValue);\n        $element = \"$path/c:pt[2]/c:v\";\n        self::assertEquals('C<D>', $doc->getElement($element)->nodeValue);\n    }\n\n    public function testValueAxisTitle(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $style = [\n            'width' => 5000000,\n            'height' => 5000000,\n            'showAxisLabels' => true,\n            'showGridX' => true,\n            'showGridY' => true,\n            'showLegend' => false,\n            'valueAxisTitle' => 'Values',\n        ];\n        $chartType = 'line';\n        $categories = ['A', 'B', 'C', 'D', 'E'];\n        $series1 = [1, 3, 2, 5, 4];\n        $section->addChart($chartType, $categories, $series1, $style);\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $index = 1;\n        $file = \"word/charts/chart{$index}.xml\";\n        $doc->setDefaultFile($file);\n        $chartType = 'line';\n        $path = '/c:chartSpace/c:chart/c:plotArea';\n        $element = \"$path/c:{$chartType}Chart\";\n        self::assertTrue($doc->elementExists($path));\n        $element = \"$path/c:valAx\";\n        self::assertTrue($doc->elementExists($element));\n        $element .= '/c:title/c:tx/c:rich/a:p/a:r/a:t';\n        self::assertEquals('Values', $doc->getElement($element)->nodeValue);\n    }\n\n    public function testNoAxisLabels(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $style = [\n            'width' => 5000000,\n            'height' => 5000000,\n            'showAxisLabels' => false,\n            'showGridX' => true,\n            'showGridY' => true,\n            'showLegend' => false,\n            'valueAxisTitle' => 'Values',\n        ];\n        $chartType = 'line';\n        $categories = ['A', 'B', 'C', 'D', 'E'];\n        $series1 = [1, 3, 2, 5, 4];\n        $section->addChart($chartType, $categories, $series1, $style);\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $index = 1;\n        $file = \"word/charts/chart{$index}.xml\";\n        $doc->setDefaultFile($file);\n        $chartType = 'line';\n        $path = '/c:chartSpace/c:chart/c:plotArea';\n        $element = \"$path/c:{$chartType}Chart\";\n        $element = \"$path/c:valAx\";\n        $element .= '/c:tickLblPos';\n        self::assertEquals('none', $doc->getElementAttribute($element, 'val'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/Word2007/Element/FieldTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\Word2007\\Element;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\nuse PHPUnit\\Framework\\TestCase;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\Word2007\\Field.\n */\nclass FieldTest extends TestCase\n{\n    /**\n     * Executed before each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    /**\n     * Test Field write.\n     */\n    public function testWriteWithRefType(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $section->addField(\n            'REF',\n            [\n                'name' => 'my-bookmark',\n            ],\n            [\n                'InsertParagraphNumberRelativeContext',\n                'CreateHyperLink',\n            ]\n        );\n\n        $section->addListItem('line one item');\n        $section->addListItem('line two item');\n        $section->addBookmark('my-bookmark');\n        $section->addListItem('line three item');\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $refFieldPath = '/w:document/w:body/w:p[1]/w:r[2]/w:instrText';\n        self::assertTrue($doc->elementExists($refFieldPath));\n\n        $bookMarkElement = $doc->getElement($refFieldPath);\n        self::assertNotNull($bookMarkElement);\n        self::assertEquals(' REF my-bookmark \\r \\h ', $bookMarkElement->textContent);\n\n        $bookmarkPath = '/w:document/w:body/w:bookmarkStart';\n        self::assertTrue($doc->elementExists($bookmarkPath));\n        self::assertEquals('my-bookmark', $doc->getElementAttribute(\"$bookmarkPath\", 'w:name'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/Word2007/Element/FormFieldTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\Word2007;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\Word2007\\Element subnamespace.\n */\nclass FormFieldTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Executed before each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    /**\n     * Test form fields.\n     */\n    public function testFormFieldElements(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        $section->addFormField('textinput')->setName('MyTextBox');\n        $section->addFormField('checkbox')->setDefault(true)->setValue('Your name');\n        $section->addFormField('checkbox')->setDefault(true);\n        $section->addFormField('dropdown')->setEntries(['Choice 1', 'Choice 2', 'Choice 3', '']);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $path = '/w:document/w:body/w:p[1]/w:r/w:fldChar/w:ffData';\n        self::assertTrue($doc->elementExists(\"$path/w:textInput\"));\n        self::assertEquals('MyTextBox', $doc->getElementAttribute(\"$path/w:name\", 'w:val'));\n\n        $path = '/w:document/w:body/w:p[2]/w:r/w:fldChar/w:ffData';\n        self::assertTrue($doc->elementExists(\"$path/w:checkBox\"));\n        $path = '/w:document/w:body/w:p[2]/w:r[4]/w:t';\n        self::assertEquals('Your name', $doc->getElement($path)->textContent);\n\n        $path = '/w:document/w:body/w:p[3]/w:r/w:fldChar/w:ffData';\n        self::assertTrue($doc->elementExists(\"$path/w:checkBox\"));\n\n        $path = '/w:document/w:body/w:p[4]/w:r/w:fldChar/w:ffData/w:ddList';\n        self::assertTrue($doc->elementExists($path));\n        self::assertEquals('Choice 1', $doc->getElementAttribute(\"$path/w:listEntry[1]\", 'w:val'));\n        self::assertEquals('Choice 2', $doc->getElementAttribute(\"$path/w:listEntry[2]\", 'w:val'));\n        self::assertEquals('Choice 3', $doc->getElementAttribute(\"$path/w:listEntry[3]\", 'w:val'));\n        self::assertEquals('', trim($doc->getElementAttribute(\"$path/w:listEntry[4]\", 'w:val'), ' '));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/Word2007/Element/FormulaTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\Word2007\\Element;\n\nuse PhpOffice\\Math\\Element;\nuse PhpOffice\\Math\\Math;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\nuse PHPUnit\\Framework\\TestCase;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\Word2007\\Element subnamespace.\n */\nclass FormulaTest extends TestCase\n{\n    /**\n     * Executed before each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    public function testBasicFormula(): void\n    {\n        $math = new Math();\n        $math\n            ->add(\n                new Element\\Fraction(\n                    new Element\\Numeric(2),\n                    new Element\\Identifier('π')\n                )\n            )\n            ->add(\n                new Element\\Operator('+')\n            )\n            ->add(\n                new Element\\Identifier('a')\n            )\n            ->add(\n                new Element\\Operator('∗')\n            )\n            ->add(\n                new Element\\Numeric(2)\n            );\n\n        $phpWord = new PhpWord();\n\n        $section = $phpWord->addSection();\n        $section->addFormula($math);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/m:oMathPara'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/m:oMathPara/m:oMath'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/Word2007/Element/TOCTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\ndeclare(strict_types=1);\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\Word2007\\Element;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\Word2007\\Element subnamespace.\n */\nclass TOCTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Executed after each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    public function testWriteTitlePageNumber(): void\n    {\n        $expectedPageNum = mt_rand(1, 1000);\n\n        $phpWord = new PhpWord();\n\n        $section = $phpWord->addSection();\n        $section->addTOC();\n        $section->addTitle('TestTitle 1', 1, $expectedPageNum);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:hyperlink/w:r[1]/w:t'));\n        self::assertEquals('TestTitle 1', $doc->getElement('/w:document/w:body/w:p[1]/w:hyperlink/w:r[1]/w:t')->textContent);\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:hyperlink/w:r[5]/w:fldChar'));\n        self::assertEquals('separate', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:hyperlink/w:r[5]/w:fldChar', 'w:fldCharType'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:hyperlink/w:r[6]/w:t'));\n        self::assertEquals($expectedPageNum, $doc->getElement('/w:document/w:body/w:p[1]/w:hyperlink/w:r[6]/w:t')->textContent);\n    }\n\n    public function testWriteTitleWithoutpageNumber(): void\n    {\n        $phpWord = new PhpWord();\n\n        $section = $phpWord->addSection();\n        $section->addTOC();\n\n        $staticHtml = '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. \n            Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor. \n            Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi.</p>\n            <p>Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. \n            Duis semper. Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim.</p>';\n\n        //more than one title and random text for create more than one page\n        for ($i = 1; $i <= 10; ++$i) {\n            $section->addTitle('Title ' . $i, 1);\n            \\PhpOffice\\PhpWord\\Shared\\Html::addHtml($section, $staticHtml, false, false);\n            $section->addPageBreak();\n        }\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        for ($i = 1; $i <= 10; ++$i) {\n            self::assertTrue($doc->elementExists('/w:document/w:body/w:p[' . $i . ']/w:hyperlink/w:r[1]/w:t'));\n            self::assertEquals('Title ' . $i, $doc->getElement('/w:document/w:body/w:p[' . $i . ']/w:hyperlink/w:r[1]/w:t')->textContent);\n            self::assertTrue($doc->elementExists('/w:document/w:body/w:p[' . $i . ']/w:hyperlink/w:r[4]/w:instrText'));\n            self::assertEquals('preserve', $doc->getElementAttribute('/w:document/w:body/w:p[' . $i . ']/w:hyperlink/w:r[4]/w:instrText', 'xml:space'));\n            self::assertEquals('PAGEREF ' . ($i - 1) . ' \\\\h', $doc->getElement('/w:document/w:body/w:p[' . $i . ']/w:hyperlink/w:r[4]/w:instrText')->nodeValue);\n        }\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/Word2007/Element/TableTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\ndeclare(strict_types=1);\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\Word2007\\Element;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\SimpleType\\TblWidth;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\Word2007\\Element subnamespace.\n */\nclass TableTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Executed after each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    public static function testTableNormal(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $section->addText('Before table (normal).');\n        $table = $section->addTable(['width' => 5000, 'unit' => TblWidth::PERCENT]);\n        $row = $table->addRow();\n        $tc = $table->addCell();\n        $tc->addText('R1C1');\n        $tc = $table->addCell();\n        $tc->addText('R1C2');\n        $row = $table->addRow();\n        $tc = $table->addCell();\n        $tc->addText('R2C1');\n        $tc = $table->addCell();\n        $tc->addText('R2C2');\n        $row = $table->addRow();\n        $tc = $table->addCell();\n        $tc->addText('R3C1');\n        $tc = $table->addCell();\n        $tc->addText('R3C2');\n        $section->addText('After table.');\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n        self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl[2]'), 'should be only 1 table');\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]'));\n        self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]'));\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[2]'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[2]/w:tc'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[2]/w:tc[2]'));\n        self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[2]/w:tc[3]'));\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[3]'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[3]/w:tc'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[3]/w:tc[2]'));\n        self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[3]/w:tc[3]'));\n    }\n\n    public static function testSomeRowWithNoCells(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $section->addText('Before table (row 2 has no cells).');\n        $table = $section->addTable(['width' => 5000, 'unit' => TblWidth::PERCENT]);\n        $row = $table->addRow();\n        $tc = $table->addCell();\n        $tc->addText('R1C1');\n        $tc = $table->addCell();\n        $tc->addText('R1C2');\n        $row = $table->addRow();\n        $row = $table->addRow();\n        $tc = $table->addCell();\n        $tc->addText('R3C1');\n        $tc = $table->addCell();\n        $tc->addText('R3C2');\n        $section->addText('After table.');\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n        self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl[2]'), 'should be only 1 table');\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]'));\n        self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc[3]'));\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[2]'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[2]/w:tc'));\n        self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[2]/w:tc[2]'));\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[3]'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[3]/w:tc'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[3]/w:tc[2]'));\n        self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[3]/w:tc[3]'));\n    }\n\n    public static function testOnly1RowWithNoCells(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $section->addText('Before table (only 1 row and it has no cells).');\n        $table = $section->addTable(['width' => 5000, 'unit' => TblWidth::PERCENT]);\n        $row = $table->addRow();\n        $section->addText('After table.');\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n        self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl[2]'), 'only 1 table should be written');\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc'));\n        self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[1]/w:tc[2]'));\n\n        self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl/w:tr[2]'));\n    }\n\n    public static function testNoRows(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $section->addText('Before table (no rows therefore omitted).');\n        $table = $section->addTable(['width' => 5000, 'unit' => TblWidth::PERCENT]);\n        $section->addText('After table.');\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n        self::assertFalse($doc->elementExists('/w:document/w:body/w:tbl[1]'), 'no table should be written');\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/Word2007/Element/TextBoxTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\Word2007\\Element;\n\nuse PhpOffice\\PhpWord\\Element\\TextBox as TextBoxElement;\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\nuse PhpOffice\\PhpWord\\Style\\TextBox as TextBoxStyle;\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\TextBox;\nuse PHPUnit\\Framework\\TestCase;\n\nclass TextBoxTest extends TestCase\n{\n    /**\n     * @dataProvider textBoxColorProvider\n     */\n    public function testTextBoxGeneratesCorrectXml(\n        ?string $bgColor,\n        ?string $borderColor,\n        string $expectedFillColorAttribute,\n        string $expectedBorderColorAttribute\n    ): void {\n        // Arrange\n        $xmlWriter = new XMLWriter();\n        $style = new TextBoxStyle();\n\n        if ($bgColor !== null) {\n            $style->setBgColor($bgColor);\n        }\n\n        if ($borderColor !== null) {\n            $style->setBorderColor($borderColor);\n        }\n\n        $textBoxElement = new TextBoxElement($style);\n        $textBox = new TextBox($xmlWriter, $textBoxElement);\n\n        // Act\n        $textBox->write();\n        $output = $xmlWriter->getData();\n\n        // Assert\n        self::assertStringContainsString($expectedFillColorAttribute, $output, 'Background color should be applied.');\n        self::assertStringContainsString($expectedBorderColorAttribute, $output, 'Border color should be applied correctly.');\n    }\n\n    /**\n     * Data provider for testing different combinations of background and border colors.\n     */\n    public static function textBoxColorProvider(): array\n    {\n        return [\n            // Case 1: Background color set, border color set\n            'With both colors' => [\n                '#FF0000',\n                '#000000',\n                'fillcolor=\"#FF0000\"',\n                'stroke color=\"#000000\"',\n            ],\n            // Case 2: Background color set, no border color\n            'With background only' => [\n                '#00FF00',\n                null,\n                'fillcolor=\"#00FF00\"',\n                'stroked=\"f\" strokecolor=\"white\"',\n            ],\n            // Case 3: No background color, border color set\n            'With border only' => [\n                null,\n                '#123456',\n                'filled=\"f\"',\n                'stroke color=\"#123456\"',\n            ],\n            // Case 4: Neither background nor border color set\n            'Without any colors' => [\n                null,\n                null,\n                'filled=\"f\"',\n                'stroked=\"f\" strokecolor=\"white\"',\n            ],\n        ];\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/Word2007/Element/TitleTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\ndeclare(strict_types=1);\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\Word2007\\Element;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\Word2007\\Element subnamespace.\n */\nclass TitleTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Executed after each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    public function testWriteTitleWithStyle(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->addTitleStyle(0, ['size' => 14, 'italic' => true]);\n\n        $section = $phpWord->addSection();\n        $section->addTitle('Test Title0', 0);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:r/w:t'));\n        self::assertEquals('Test Title0', $doc->getElement('/w:document/w:body/w:p[1]/w:r/w:t')->textContent);\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:pPr/w:pStyle'));\n        self::assertEquals('Title', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:pStyle', 'w:val'));\n    }\n\n    public function testWriteTitleWithoutStyle(): void\n    {\n        $phpWord = new PhpWord();\n\n        $section = $phpWord->addSection();\n        $section->addTitle('Test Title0', 0);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:r/w:t'));\n        self::assertEquals('Test Title0', $doc->getElement('/w:document/w:body/w:p[1]/w:r/w:t')->textContent);\n        self::assertFalse($doc->elementExists('/w:document/w:body/w:p[1]/w:pPr'));\n    }\n\n    public function testWriteHeadingWithStyle(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->addTitleStyle(1, ['bold' => true], ['spaceAfter' => 240]);\n\n        $section = $phpWord->addSection();\n        $section->addTitle('TestHeading 1', 1);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:r/w:t'));\n        self::assertEquals('TestHeading 1', $doc->getElement('/w:document/w:body/w:p[1]/w:r/w:t')->textContent);\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:pPr/w:pStyle'));\n        self::assertEquals('Heading1', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:pStyle', 'w:val'));\n    }\n\n    public function testWriteHeadingWithoutStyle(): void\n    {\n        $phpWord = new PhpWord();\n\n        $section = $phpWord->addSection();\n        $section->addTitle('TestHeading 1', 1);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:r/w:t'));\n        self::assertEquals('TestHeading 1', $doc->getElement('/w:document/w:body/w:p[1]/w:r/w:t')->textContent);\n        self::assertFalse($doc->elementExists('/w:document/w:body/w:p[1]/w:pPr'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/Word2007/ElementTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\Word2007;\n\nuse DateTime;\nuse PhpOffice\\PhpWord\\ComplexType\\RubyProperties;\nuse PhpOffice\\PhpWord\\Element\\Comment;\nuse PhpOffice\\PhpWord\\Element\\Ruby;\nuse PhpOffice\\PhpWord\\Element\\TextRun;\nuse PhpOffice\\PhpWord\\Element\\TrackChange;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\Word2007\\Element subnamespace.\n */\nclass ElementTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Executed before each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    /**\n     * Test unmatched element.\n     */\n    public function testUnmatchedElements(): void\n    {\n        $elements = [\n            'CheckBox', 'Container', 'Footnote', 'Image', 'Link', 'ListItem', 'ListItemRun',\n            'OLEObject', 'PreserveText', 'Table', 'Text', 'TextBox', 'TextBreak', 'Title', 'TOC',\n            'Field', 'Line', 'Shape', 'Chart', 'FormField', 'SDT', 'Bookmark',\n        ];\n        foreach ($elements as $element) {\n            $objectClass = 'PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007\\\\Element\\\\' . $element;\n            $xmlWriter = new XMLWriter();\n            $newElement = new \\PhpOffice\\PhpWord\\Element\\PageBreak();\n            $object = new $objectClass($xmlWriter, $newElement);\n            $object->write();\n\n            self::assertEquals('', $xmlWriter->getData());\n        }\n    }\n\n    /**\n     * Test line element.\n     */\n    public function testLineElement(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        $section->addLine(['width' => 1000, 'height' => 1000, 'positioning' => 'absolute', 'flip' => true]);\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $element = '/w:document/w:body/w:p/w:r/w:pict/v:shapetype';\n        self::assertTrue($doc->elementExists($element));\n    }\n\n    /**\n     * Test bookmark element.\n     */\n    public function testBookmark(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        $section->addBookmark('test_bookmark');\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $element = '/w:document/w:body/w:bookmarkStart';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('test_bookmark', $doc->getElementAttribute($element, 'w:name'));\n\n        $element = '/w:document/w:body/w:bookmarkEnd';\n        self::assertTrue($doc->elementExists($element));\n    }\n\n    /**\n     * Test link element.\n     */\n    public function testLinkElement(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        $section->addLink('https://github.com/PHPOffice/PHPWord');\n        $section->addLink('internal_link', null, null, null, true);\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $element = '/w:document/w:body/w:p[1]/w:hyperlink/w:r/w:t';\n        self::assertTrue($doc->elementExists($element));\n\n        $element = '/w:document/w:body/w:p[2]/w:hyperlink/w:r/w:t';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('internal_link', $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:hyperlink', 'w:anchor'));\n    }\n\n    /**\n     * Basic test for table element.\n     */\n    public function testTableElements(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        $table = $section->addTable(['alignment' => \\PhpOffice\\PhpWord\\SimpleType\\JcTable::CENTER]);\n        $table->addRow(900);\n        $table->addCell(2000)->addText('Row 1');\n        $table->addCell(2000)->addText('Row 2');\n        $table->addCell(2000)->addText('Row 3');\n        $table->addCell(2000)->addText('Row 4');\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $tableRootElement = '/w:document/w:body/w:tbl';\n        self::assertTrue($doc->elementExists($tableRootElement . '/w:tblGrid/w:gridCol'));\n        self::assertTrue($doc->elementExists($tableRootElement . '/w:tblPr/w:jc'));\n        self::assertEquals('center', $doc->getElementAttribute($tableRootElement . '/w:tblPr/w:jc', 'w:val'));\n    }\n\n    /**\n     * Tests that the style name gets added.\n     */\n    public function testTableWithStyleName(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        $table = $section->addTable('my_predefined_style');\n        $table->setWidth(75);\n        $table->addRow(900);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $tableRootElement = '/w:document/w:body/w:tbl';\n        self::assertTrue($doc->elementExists($tableRootElement . '/w:tblPr/w:tblStyle'));\n        self::assertEquals('my_predefined_style', $doc->getElementAttribute($tableRootElement . '/w:tblPr/w:tblStyle', 'w:val'));\n    }\n\n    /**\n     * Test shape elements.\n     */\n    public function testShapeElements(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        // Arc\n        $section->addShape(\n            'arc',\n            [\n                'points' => '-90 20',\n                'frame' => ['width' => 120, 'height' => 120],\n                'outline' => ['color' => '#333333', 'weight' => 2, 'startArrow' => 'oval', 'endArrow' => 'open'],\n            ]\n        );\n\n        // Curve\n        $section->addShape(\n            'curve',\n            [\n                'points' => '1,100 200,1 1,50 200,50', 'connector' => 'elbow',\n                'outline' => [\n                    'color' => '#66cc00',\n                    'weight' => 2,\n                    'dash' => 'dash',\n                    'startArrow' => 'diamond',\n                    'endArrow' => 'block',\n                ],\n            ]\n        );\n\n        // Line\n        $section->addShape(\n            'line',\n            [\n                'points' => '1,1 150,30',\n                'outline' => [\n                    'color' => '#cc00ff',\n                    'line' => 'thickThin',\n                    'weight' => 3,\n                    'startArrow' => 'oval',\n                    'endArrow' => 'classic',\n                    'endCap' => 'round',\n                ],\n            ]\n        );\n\n        // Polyline\n        $section->addShape(\n            'polyline',\n            [\n                'points' => '1,30 20,10 55,20 75,10 100,40 115,50, 120,15 200,50',\n                'outline' => [\n                    'color' => '#cc6666',\n                    'weight' => 2,\n                    'startArrow' => 'none',\n                    'endArrow' => 'classic',\n                ],\n            ]\n        );\n\n        // Rectangle\n        $section->addShape(\n            'rect',\n            [\n                'roundness' => 0.2,\n                'frame' => ['width' => 100, 'height' => 100, 'left' => 1, 'top' => 1],\n                'fill' => ['color' => '#FFCC33'],\n                'outline' => ['color' => '#990000', 'weight' => 1],\n                'shadow' => ['color' => '#EEEEEE', 'offset' => '3pt,3pt'],\n            ]\n        );\n\n        // Oval\n        $section->addShape(\n            'oval',\n            [\n                'frame' => ['width' => 100, 'height' => 70, 'left' => 1, 'top' => 1],\n                'fill' => ['color' => '#33CC99'],\n                'outline' => ['color' => '#333333', 'weight' => 2],\n                'extrusion' => ['type' => 'perspective', 'color' => '#EEEEEE'],\n            ]\n        );\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $elements = ['arc', 'curve', 'line', 'polyline', 'roundrect', 'oval'];\n        foreach ($elements as $element) {\n            $path = \"/w:document/w:body/w:p/w:r/w:pict/v:{$element}\";\n            self::assertTrue($doc->elementExists($path));\n        }\n    }\n\n    // testChartElements moved to Writer/Word2007/Element/ChartTest\n\n    public function testFieldElement(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        $section->addField('INDEX', [], ['\\\\c \"3\"']);\n        $section->addField('XE', [], ['Bold', 'Italic'], 'Index Entry');\n        $section->addField('DATE', ['dateformat' => 'd-M-yyyy'], ['PreserveFormat', 'LastUsedFormat']);\n        $section->addField('DATE', [], ['LunarCalendar']);\n        $section->addField('DATE', [], ['SakaEraCalendar']);\n        $section->addField('NUMPAGES', ['format' => 'roman', 'numformat' => '0,00'], ['SakaEraCalendar']);\n        $section->addField('STYLEREF', ['StyleIdentifier' => 'Heading 1']);\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $element = '/w:document/w:body/w:p/w:r/w:instrText';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals(' INDEX \\\\c \"3\" ', $doc->getElement($element)->textContent);\n    }\n\n    public function testUnstyledFieldElement(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->addFontStyle('h1', ['name' => 'Courier New', 'size' => 8]);\n        $section = $phpWord->addSection();\n\n        $section->addField('PAGE');\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $element = '/w:document/w:body/w:p/w:r[2]/w:instrText';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals(' PAGE ', $doc->getElement($element)->textContent);\n        $sty = '/w:document/w:body/w:p/w:r[2]/w:rPr';\n        self::assertFalse($doc->elementExists($sty));\n    }\n\n    public function testStyledFieldElement(): void\n    {\n        $phpWord = new PhpWord();\n        $stnam = 'h1';\n        $phpWord->addFontStyle($stnam, ['name' => 'Courier New', 'size' => 8]);\n        $section = $phpWord->addSection();\n\n        $fld = $section->addField('PAGE');\n        $fld->setFontStyle($stnam);\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $element = '/w:document/w:body/w:p/w:r[2]/w:instrText';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals(' PAGE ', $doc->getElement($element)->textContent);\n        $sty = '/w:document/w:body/w:p/w:r[2]/w:rPr';\n        self::assertTrue($doc->elementExists($sty));\n        self::assertEquals($stnam, $doc->getElementAttribute($sty . '/w:rStyle', 'w:val'));\n    }\n\n    public function testFieldElementFilename(): void\n    {\n        $phpWord = new PhpWord();\n        $stnam = 'h1';\n        $phpWord->addFontStyle($stnam, ['name' => 'Courier New', 'size' => 8]);\n        $section = $phpWord->addSection();\n\n        $fld = $section->addField('FILENAME');\n        $fld->setFontStyle($stnam);\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $element = '/w:document/w:body/w:p/w:r[2]/w:instrText';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals(' FILENAME ', $doc->getElement($element)->textContent);\n        $sty = '/w:document/w:body/w:p/w:r[2]/w:rPr';\n        self::assertTrue($doc->elementExists($sty));\n        self::assertEquals($stnam, $doc->getElementAttribute($sty . '/w:rStyle', 'w:val'));\n    }\n\n    public function testFieldElementFilenameOptionsPath(): void\n    {\n        $phpWord = new PhpWord();\n        $stnam = 'h1';\n        $phpWord->addFontStyle($stnam, ['name' => 'Courier New', 'size' => 8]);\n        $section = $phpWord->addSection();\n\n        $fld = $section->addField('FILENAME', [], ['Path']);\n        $fld->setFontStyle($stnam);\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $element = '/w:document/w:body/w:p/w:r[2]/w:instrText';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals(' FILENAME \\p ', $doc->getElement($element)->textContent);\n        $sty = '/w:document/w:body/w:p/w:r[2]/w:rPr';\n        self::assertTrue($doc->elementExists($sty));\n        self::assertEquals($stnam, $doc->getElementAttribute($sty . '/w:rStyle', 'w:val'));\n    }\n\n    public function testFieldElementWithComplexText(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        $text = new TextRun();\n        $text->addText('test string', ['bold' => true]);\n\n        $section->addField('XE', [], ['Bold', 'Italic'], $text);\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $element = '/w:document/w:body/w:p/w:r[2]/w:instrText';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals(' XE \"', $doc->getElement($element)->textContent);\n\n        $element = '/w:document/w:body/w:p/w:r[3]/w:rPr/w:b';\n        self::assertTrue($doc->elementExists($element));\n\n        $element = '/w:document/w:body/w:p/w:r[3]/w:t';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('test string', $doc->getElement($element)->textContent);\n\n        $element = '/w:document/w:body/w:p/w:r[4]/w:instrText';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals('\"\\\\b \\\\i ', $doc->getElement($element)->textContent);\n    }\n\n    /**\n     * Test writing the macrobutton field.\n     */\n    public function testMacroButtonField(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        $macroText = new TextRun();\n        $macroText->addText('Double click', ['bold' => true]);\n        $macroText->addText(' to ');\n        $macroText->addText('zoom to 100%', ['italic' => true]);\n\n        $section->addField('MACROBUTTON', ['macroname' => 'Zoom100'], [], $macroText);\n        $section->addField('MACROBUTTON', ['macroname' => 'Zoom100'], [], 'double click to zoom');\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $element = '/w:document/w:body/w:p[1]/w:r[2]/w:instrText';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals(' MACROBUTTON Zoom100 ', $doc->getElement($element)->textContent);\n\n        $element = '/w:document/w:body/w:p[1]/w:r[3]/';\n        self::assertTrue($doc->elementExists($element . 'w:t'));\n        self::assertEquals('Double click', $doc->getElement($element . 'w:t')->textContent);\n        self::assertTrue($doc->elementExists($element . 'w:rPr/w:b'));\n\n        $element = '/w:document/w:body/w:p[2]/w:r[2]/w:instrText';\n        self::assertTrue($doc->elementExists($element));\n        self::assertEquals(' MACROBUTTON Zoom100 double click to zoom ', $doc->getElement($element)->textContent);\n    }\n\n    // testFormFieldElements moved to Writer/Word2007/Element/FormFieldTest\n\n    /**\n     * Test SDT elements.\n     */\n    public function testSDTElements(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        $section->addSDT('comboBox')->setListItems(['1' => 'Choice 1', '2' => 'Choice 2'])->setValue('select value');\n        $section->addSDT('dropDownList');\n        $section->addSDT('date')->setAlias('date_alias')->setTag('my_tag');\n        $section->addSDT('plainText');\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $path = '/w:document/w:body/w:p';\n\n        self::assertTrue($doc->elementExists($path . '[1]/w:sdt/w:sdtContent/w:r/w:t'));\n        self::assertEquals('select value', $doc->getElement($path . '[1]/w:sdt/w:sdtContent/w:r/w:t')->nodeValue);\n        self::assertTrue($doc->elementExists($path . '[1]/w:sdt/w:sdtPr/w:comboBox'));\n        self::assertTrue($doc->elementExists($path . '[1]/w:sdt/w:sdtPr/w:comboBox/w:listItem'));\n        self::assertEquals('1', $doc->getElementAttribute($path . '[1]/w:sdt/w:sdtPr/w:comboBox/w:listItem[1]', 'w:value'));\n        self::assertEquals('Choice 1', $doc->getElementAttribute($path . '[1]/w:sdt/w:sdtPr/w:comboBox/w:listItem[1]', 'w:displayText'));\n\n        self::assertTrue($doc->elementExists($path . '[2]/w:sdt/w:sdtPr/w:dropDownList'));\n        self::assertFalse($doc->elementExists($path . '[2]/w:sdt/w:sdtPr/w:alias'));\n\n        self::assertTrue($doc->elementExists($path . '[3]/w:sdt/w:sdtPr/w:date'));\n        self::assertTrue($doc->elementExists($path . '[3]/w:sdt/w:sdtPr/w:alias'));\n        self::assertTrue($doc->elementExists($path . '[3]/w:sdt/w:sdtPr/w:tag'));\n\n        self::assertTrue($doc->elementExists($path . '[4]/w:sdt/w:sdtPr/w:text'));\n    }\n\n    /**\n     * Test Comment element.\n     */\n    public function testCommentWithoutEndElement(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        $comment = new Comment('tester');\n        $phpWord->addComment($comment);\n\n        $element = $section->addText('this is a test');\n        $element->setCommentRangeStart($comment);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:commentRangeStart'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:commentRangeEnd'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:commentReference'));\n    }\n\n    /**\n     * Test Comment element.\n     */\n    public function testCommentWithEndElement(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        $comment = new Comment('tester');\n        $phpWord->addComment($comment);\n\n        $element = $section->addText('this is a test');\n        $element->setCommentRangeStart($comment);\n        $element->setCommentRangeEnd($comment);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:commentRangeStart'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:commentRangeEnd'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:commentReference'));\n    }\n\n    /**\n     * Test Track changes.\n     */\n    public function testTrackChange(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $text = $section->addText('my dummy text');\n        $text->setChangeInfo(TrackChange::INSERTED, 'author name');\n        $text2 = $section->addText('my other text');\n        $text2->setTrackChange(new TrackChange(TrackChange::DELETED, 'another author', new DateTime()));\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:ins/w:r'));\n        self::assertEquals('author name', $doc->getElementAttribute('/w:document/w:body/w:p/w:ins', 'w:author'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:del/w:r/w:delText'));\n    }\n\n    /**\n     * Test correct writing of text with ampersant in it.\n     */\n    public function testTextWithAmpersant(): void\n    {\n        \\PhpOffice\\PhpWord\\Settings::setOutputEscapingEnabled(true);\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $section->addText('this text contains an & (ampersant)');\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:t'));\n        self::assertEquals('this text contains an & (ampersant)', $doc->getElement('/w:document/w:body/w:p/w:r/w:t')->nodeValue);\n    }\n\n    /**\n     * Test ListItemRun paragraph style writing.\n     */\n    public function testListItemRunStyleWriting(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->addParagraphStyle('MyParagraphStyle', ['spaceBefore' => 400]);\n\n        $section = $phpWord->addSection();\n        $listItemRun = $section->addListItemRun(0, null, 'MyParagraphStyle');\n        $listItemRun->addText('List item');\n        $listItemRun->addText(' in bold', ['bold' => true]);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n        self::assertFalse($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:pPr'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:pStyle'));\n        self::assertEquals('List item', $doc->getElement('/w:document/w:body/w:p/w:r[1]/w:t')->nodeValue);\n        self::assertEquals(' in bold', $doc->getElement('/w:document/w:body/w:p/w:r[2]/w:t')->nodeValue);\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r[2]/w:rPr/w:b'));\n    }\n\n    /**\n     * Test Ruby writing.\n     */\n    public function testRubyWriting(): void\n    {\n        $phpWord = new PhpWord();\n\n        $section = $phpWord->addSection();\n        $properties = new RubyProperties();\n        $properties->setAlignment(RubyProperties::ALIGNMENT_RIGHT_VERTICAL);\n        $properties->setFontFaceSize(10);\n        $properties->setFontPointsAboveBaseText(4);\n        $properties->setFontSizeForBaseText(18);\n        $properties->setLanguageId('ja-JP');\n\n        $baseTextRun = new TextRun(null);\n        $baseTextRun->addText('私');\n        $rubyTextRun = new TextRun(null);\n        $rubyTextRun->addText('わたし');\n        $section->addRuby($baseTextRun, $rubyTextRun, $properties);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby'));\n        // check props\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr'));\n        self::assertEquals(\n            RubyProperties::ALIGNMENT_RIGHT_VERTICAL,\n            $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:rubyAlign', 'w:val')\n        );\n        self::assertEquals(\n            10,\n            $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:hps', 'w:val')\n        );\n        self::assertEquals(\n            4,\n            $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:hpsRaise', 'w:val')\n        );\n        self::assertEquals(\n            18,\n            $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:hpsBaseText', 'w:val')\n        );\n        self::assertEquals(\n            'ja-JP',\n            $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:lid', 'w:val')\n        );\n        // check ruby text\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rt/w:r/w:t'));\n        self::assertEquals(\n            'わたし',\n            $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rt/w:r/w:t')->nodeValue\n        );\n        // check base text\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rubyBase/w:r/w:t'));\n        self::assertEquals(\n            '私',\n            $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rubyBase/w:r/w:t')->nodeValue\n        );\n    }\n\n    /**\n     * Test Ruby title writing.\n     */\n    public function testRubyTitleWriting(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->addTitleStyle(1, ['name' => 'Arial', 'size' => 24, 'bold' => true, 'color' => '990000']);\n\n        $section = $phpWord->addSection();\n        $properties = new RubyProperties();\n        $properties->setAlignment(RubyProperties::ALIGNMENT_RIGHT_VERTICAL);\n        $properties->setFontFaceSize(10);\n        $properties->setFontPointsAboveBaseText(4);\n        $properties->setFontSizeForBaseText(18);\n        $properties->setLanguageId('ja-JP');\n\n        $baseTextRun = new TextRun(null);\n        $baseTextRun->addText('私');\n        $rubyTextRun = new TextRun(null);\n        $rubyTextRun->addText('わたし');\n\n        $textRun = new TextRun();\n        $textRun->addRuby($baseTextRun, $rubyTextRun, $properties);\n        $section->addTitle($textRun, 1);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n        // make sure style made it in\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:pStyle'));\n        self::assertEquals(\n            'Heading1',\n            $doc->getElement('/w:document/w:body/w:p/w:pPr/w:pStyle')->getAttribute('w:val')\n        );\n        // check ruby props\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr'));\n        self::assertEquals(\n            RubyProperties::ALIGNMENT_RIGHT_VERTICAL,\n            $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:rubyAlign')->getAttribute('w:val')\n        );\n        self::assertEquals(\n            10,\n            $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:hps')->getAttribute('w:val')\n        );\n        self::assertEquals(\n            4,\n            $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:hpsRaise')->getAttribute('w:val')\n        );\n        self::assertEquals(\n            18,\n            $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:hpsBaseText')->getAttribute('w:val')\n        );\n        self::assertEquals(\n            'ja-JP',\n            $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:lid')->getAttribute('w:val')\n        );\n        // check ruby text\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rt/w:r/w:t'));\n        self::assertEquals(\n            'わたし',\n            $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rt/w:r/w:t')->nodeValue\n        );\n        // check base text\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rubyBase/w:r/w:t'));\n        self::assertEquals(\n            '私',\n            $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rubyBase/w:r/w:t')->nodeValue\n        );\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/Word2007/Part/AbstractPartTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\Word2007\\Part;\n\nuse Exception;\nuse PhpOffice\\PhpWord\\Writer\\Word2007;\n\n/**\n * @runTestsInSeparateProcesses\n */\nclass AbstractPartTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * covers   ::setParentWriter\n     * covers   ::getParentWriter.\n     */\n    public function testSetGetParentWriter(): void\n    {\n        // @phpstan-ignore-next-line\n        if (method_exists($this, 'getMockForAbstractClass')) {\n            $stub = $this->getMockForAbstractClass(Word2007\\Part\\AbstractPart::class);\n        } else {\n            /** @var Word2007\\Part\\AbstractPart $stub */\n            $stub = new class() extends Word2007\\Part\\AbstractPart {\n                public function write(): string\n                {\n                    return '';\n                }\n            };\n        }\n        $stub->setParentWriter(new Word2007());\n        self::assertEquals(new Word2007(), $stub->getParentWriter());\n    }\n\n    /**\n     * covers   ::getParentWriter.\n     */\n    public function testSetGetParentWriterNull(): void\n    {\n        $this->expectException(Exception::class);\n        $this->expectExceptionMessage('No parent WriterInterface assigned.');\n        // @phpstan-ignore-next-line\n        if (method_exists($this, 'getMockForAbstractClass')) {\n            $stub = $this->getMockForAbstractClass(Word2007\\Part\\AbstractPart::class);\n        } else {\n            /** @var Word2007\\Part\\AbstractPart $stub */\n            $stub = new class() extends Word2007\\Part\\AbstractPart {\n                public function write(): string\n                {\n                    return '';\n                }\n            };\n        }\n        $stub->getParentWriter();\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/Word2007/Part/CommentsTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\Word2007\\Part;\n\nuse DateTime;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\Word2007\\Part\\Comment.\n *\n * @runTestsInSeparateProcesses\n */\nclass CommentsTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Executed before each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    /**\n     * Write comments.\n     */\n    public function testWriteComments(): void\n    {\n        $comment = new \\PhpOffice\\PhpWord\\Element\\Comment('Authors name', new DateTime(), 'my_initials');\n        $comment->addText('Test');\n\n        $phpWord = new PhpWord();\n        $phpWord->addComment($comment);\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $path = '/w:comments/w:comment';\n        $file = 'word/comments.xml';\n\n        self::assertTrue($doc->elementExists($path, $file));\n\n        $element = $doc->getElement($path, $file);\n        self::assertNotNull($element->getAttribute('w:id'));\n        self::assertEquals('Authors name', $element->getAttribute('w:author'));\n        self::assertEquals('my_initials', $element->getAttribute('w:initials'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/Word2007/Part/DocumentTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\Word2007\\Part;\n\nuse DateTime;\nuse PhpOffice\\PhpWord\\ComplexType\\FootnoteProperties;\nuse PhpOffice\\PhpWord\\Metadata\\DocInfo;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\nuse PhpOffice\\PhpWord\\SimpleType\\NumberFormat;\nuse PhpOffice\\PhpWord\\Style\\Cell;\nuse PhpOffice\\PhpWord\\Style\\Font;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\Word2007\\Part\\Document.\n *\n * @runTestsInSeparateProcesses\n */\nclass DocumentTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Executed before each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    /**\n     * Write custom properties.\n     */\n    public function testWriteCustomProps(): void\n    {\n        $phpWord = new PhpWord();\n        $docInfo = $phpWord->getDocInfo();\n\n        $docInfo->setCustomProperty('key1', null);\n        $docInfo->setCustomProperty('key2', true);\n        $docInfo->setCustomProperty('key3', 3);\n        $docInfo->setCustomProperty('key4', 4.4);\n        $docInfo->setCustomProperty('key5', 'value5');\n        $docInfo->setCustomProperty('key6', new DateTime());\n        $docInfo->setCustomProperty('key7', time(), DocInfo::PROPERTY_TYPE_DATE);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n        self::assertNotNull($doc);\n\n        //         $this->assertTrue($doc->elementExists('/Properties/property[name=\"key1\"]/vt:lpwstr'));\n        //         $this->assertTrue($doc->elementExists('/Properties/property[name=\"key2\"]/vt:bool'));\n        //         $this->assertTrue($doc->elementExists('/Properties/property[name=\"key3\"]/vt:i4'));\n        //         $this->assertTrue($doc->elementExists('/Properties/property[name=\"key4\"]/vt:r8'));\n        //         $this->assertTrue($doc->elementExists('/Properties/property[name=\"key5\"]/vt:lpwstr'));\n    }\n\n    /**\n     * Write end section page numbering.\n     */\n    public function testWriteEndSectionPageNumbering(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $section->addHeader();\n        $section->addHeader('first');\n        $style = $section->getStyle();\n        $style->setLandscape();\n        $style->setPageNumberingStart(2);\n        $style->setBorderSize(240);\n        $style->setBreakType('nextPage');\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n        $element = $doc->getElement('/w:document/w:body/w:sectPr/w:pgNumType');\n\n        self::assertEquals(2, $element->getAttribute('w:start'));\n    }\n\n    /**\n     * Write section footnote properties.\n     */\n    public function testSectionFootnoteProperties(): void\n    {\n        $properties = new FootnoteProperties();\n        $properties->setPos(FootnoteProperties::POSITION_DOC_END);\n        $properties->setNumFmt(NumberFormat::LOWER_ROMAN);\n        $properties->setNumStart(1);\n        $properties->setNumRestart(FootnoteProperties::RESTART_NUMBER_EACH_PAGE);\n\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $section->setFootnoteProperties($properties);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $element = $doc->getElement('/w:document/w:body/w:sectPr/w:footnotePr/w:pos');\n        self::assertEquals(FootnoteProperties::POSITION_DOC_END, $element->getAttribute('w:val'));\n\n        $element = $doc->getElement('/w:document/w:body/w:sectPr/w:footnotePr/w:numFmt');\n        self::assertEquals(NumberFormat::LOWER_ROMAN, $element->getAttribute('w:val'));\n\n        $element = $doc->getElement('/w:document/w:body/w:sectPr/w:footnotePr/w:numStart');\n        self::assertEquals(1, $element->getAttribute('w:val'));\n\n        $element = $doc->getElement('/w:document/w:body/w:sectPr/w:footnotePr/w:numRestart');\n        self::assertEquals(FootnoteProperties::RESTART_NUMBER_EACH_PAGE, $element->getAttribute('w:val'));\n    }\n\n    /**\n     * Write elements.\n     */\n    public function testElements(): void\n    {\n        $objectSrc = __DIR__ . '/../../../_files/documents/sheet.xls';\n\n        $phpWord = new PhpWord();\n        $phpWord->addTitleStyle(1, ['color' => '333333', 'bold' => true]);\n        $phpWord->addTitleStyle(2, ['color' => '666666']);\n        $section = $phpWord->addSection();\n        $section->addTOC();\n        $section->addPageBreak();\n        $section->addText('After page break.');\n        $section->addTitle('Title 1', 1);\n        $section->addListItem('List Item 1', 0);\n        $section->addListItem('List Item 2', 0);\n        $section->addListItem('List Item 3', 0);\n\n        $section = $phpWord->addSection();\n        $section->addTitle('Title 2', 2);\n        $section->addObject($objectSrc);\n        $section->addTextBox([]);\n        $section->addTextBox(\n            [\n                'wrappingStyle' => 'square',\n                'positioning' => 'relative',\n                'posHorizontalRel' => 'margin',\n                'posVerticalRel' => 'margin',\n                'innerMargin' => 10,\n                'borderSize' => 1,\n                'borderColor' => '#FF0',\n            ]\n        );\n        $section->addTextBox(['wrappingStyle' => 'tight', 'positioning' => 'absolute', 'alignment' => Jc::CENTER]);\n        $section->addListItemRun()->addText('List item run 1');\n        $section->addField(\n            'DATE',\n            ['dateformat' => 'dddd d MMMM yyyy H:mm:ss'],\n            ['PreserveFormat', 'LunarCalendar']\n        );\n        $section->addField(\n            'DATE',\n            ['dateformat' => 'dddd d MMMM yyyy H:mm:ss'],\n            ['PreserveFormat', 'SakaEraCalendar']\n        );\n        $section->addField(\n            'DATE',\n            ['dateformat' => 'dddd d MMMM yyyy H:mm:ss'],\n            ['PreserveFormat', 'LastUsedFormat']\n        );\n        $section->addField('PAGE', ['format' => 'ArabicDash']);\n        $section->addLine(\n            [\n                'width' => 10,\n                'height' => 10,\n                'positioning' => 'absolute',\n                'beginArrow' => 'block',\n                'endArrow' => 'open',\n                'dash' => 'rounddot',\n                'weight' => 10,\n            ]\n        );\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        // TOC\n        $element = $doc->getElement('/w:document/w:body/w:p[1]/w:pPr/w:tabs/w:tab');\n        self::assertEquals('right', $element->getAttribute('w:val'));\n        self::assertEquals('dot', $element->getAttribute('w:leader'));\n        self::assertEquals(9062, $element->getAttribute('w:pos'));\n\n        // Page break\n        $element = $doc->getElement('/w:document/w:body/w:p[4]/w:r/w:br');\n        self::assertEquals('page', $element->getAttribute('w:type'));\n\n        // Title\n        $element = $doc->getElement('/w:document/w:body/w:p[6]/w:pPr/w:pStyle');\n        self::assertEquals('Heading1', $element->getAttribute('w:val'));\n\n        // List item\n        $element = $doc->getElement('/w:document/w:body/w:p[7]/w:pPr/w:numPr/w:numId');\n        self::assertEquals(3, $element->getAttribute('w:val'));\n\n        // Object\n        $element = $doc->getElement('/w:document/w:body/w:p[12]/w:r/w:object/o:OLEObject');\n        self::assertEquals('Embed', $element->getAttribute('Type'));\n    }\n\n    /**\n     * Write element with some styles.\n     */\n    public function testElementStyles(): void\n    {\n        $objectSrc = __DIR__ . '/../../../_files/documents/sheet.xls';\n\n        $tabs = [new \\PhpOffice\\PhpWord\\Style\\Tab('right', 9090)];\n        $phpWord = new PhpWord();\n        $phpWord->addParagraphStyle(\n            'pStyle',\n            [\n                'alignment' => Jc::CENTER,\n                'tabs' => $tabs,\n                'shading' => ['fill' => 'FFFF99'],\n                'borderSize' => 4,\n            ]\n        ); // Style #1\n        $phpWord->addFontStyle(\n            'fStyle',\n            [\n                'size' => '20',\n                'bold' => true,\n                'allCaps' => true,\n                'scale' => 200,\n                'spacing' => 240,\n                'kerning' => 10,\n            ]\n        ); // Style #2\n        $phpWord->addTitleStyle(1, ['color' => '333333', 'doubleStrikethrough' => true]); // Style #3\n        $phpWord->addTableStyle('tStyle', ['borderSize' => 1]);\n        $fontStyle = new Font('text', ['alignment' => Jc::CENTER]);\n\n        $section = $phpWord->addSection();\n        $section->addListItem('List Item', 0, null, null, 'pStyle'); // Style #5\n        $section->addObject($objectSrc, ['alignment' => Jc::CENTER]);\n        $section->addTOC($fontStyle);\n        $section->addTitle('Title 1', 1);\n        $section->addTOC('fStyle');\n        $table = $section->addTable('tStyle');\n        $table->setWidth(100);\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        // List item\n        $element = $doc->getElement('/w:document/w:body/w:p[1]/w:pPr/w:numPr/w:numId');\n        self::assertEquals(5, $element->getAttribute('w:val'));\n\n        // Object\n        $element = $doc->getElement('/w:document/w:body/w:p[2]/w:r/w:object/o:OLEObject');\n        self::assertEquals('Embed', $element->getAttribute('Type'));\n\n        // TOC\n        $element = $doc->getElement('/w:document/w:body/w:p[3]/w:pPr/w:tabs/w:tab');\n        self::assertEquals('right', $element->getAttribute('w:val'));\n        self::assertEquals('dot', $element->getAttribute('w:leader'));\n        self::assertEquals(9062, $element->getAttribute('w:pos'));\n    }\n\n    /**\n     * Test write text element.\n     */\n    public function testWriteText(): void\n    {\n        $rStyle = 'rStyle';\n        $pStyle = 'pStyle';\n\n        $phpWord = new PhpWord();\n        $phpWord->addFontStyle($rStyle, ['bold' => true]);\n        $phpWord->addParagraphStyle($pStyle, ['hanging' => 120, 'indent' => 120]);\n        $section = $phpWord->addSection();\n        $section->addText('Test', $rStyle, $pStyle);\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $element = '/w:document/w:body/w:p/w:r/w:rPr/w:rStyle';\n        self::assertEquals($rStyle, $doc->getElementAttribute($element, 'w:val'));\n        $element = '/w:document/w:body/w:p/w:pPr/w:pStyle';\n        self::assertEquals($pStyle, $doc->getElementAttribute($element, 'w:val'));\n    }\n\n    /**\n     * Test write textrun element.\n     */\n    public function testWriteTextRun(): void\n    {\n        $pStyle = 'pStyle';\n        $aStyle = ['alignment' => Jc::BOTH, 'spaceBefore' => 120, 'spaceAfter' => 120];\n        $imageSrc = __DIR__ . '/../../../_files/images/earth.jpg';\n\n        $phpWord = new PhpWord();\n        $phpWord->addParagraphStyle($pStyle, $aStyle);\n        $section = $phpWord->addSection('Test');\n        $textrun = $section->addTextRun($pStyle);\n        $textrun->addText('Test');\n        $textrun->addTextBreak();\n        $textrun = $section->addTextRun($aStyle);\n        $textrun->addLink('https://github.com/PHPOffice/PHPWord');\n        $textrun->addImage($imageSrc, ['alignment' => Jc::CENTER]);\n        $textrun->addFootnote();\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $parent = '/w:document/w:body/w:p';\n        self::assertTrue($doc->elementExists(\"{$parent}/w:pPr/w:pStyle[@w:val='{$pStyle}']\"));\n    }\n\n    /**\n     * Test write link element.\n     */\n    public function testWriteLink(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $fontStyleArray = ['bold' => true];\n        $fontStyleName = 'Font Style';\n        $paragraphStyleArray = ['alignment' => Jc::CENTER];\n        $paragraphStyleName = 'Paragraph Style';\n\n        $expected = 'PHPWord on GitHub';\n        $section->addLink('https://github.com/PHPOffice/PHPWord', $expected);\n        $section->addLink('https://github.com/PHPOffice/PHPWord', 'Test', $fontStyleArray, $paragraphStyleArray);\n        $section->addLink('https://github.com/PHPOffice/PHPWord', 'Test', $fontStyleName, $paragraphStyleName);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n        $element = $doc->getElement('/w:document/w:body/w:p/w:hyperlink/w:r/w:t');\n\n        self::assertEquals($expected, $element->nodeValue);\n    }\n\n    /**\n     * Test write preserve text element.\n     */\n    public function testWritePreserveText(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $footer = $section->addFooter();\n        $fontStyleArray = ['bold' => true];\n        $fontStyleName = 'Font';\n        $paragraphStyleArray = ['alignment' => Jc::END];\n        $paragraphStyleName = 'Paragraph';\n\n        $footer->addPreserveText('Page {PAGE}');\n        $footer->addPreserveText('{PAGE}', $fontStyleArray, $paragraphStyleArray);\n        $footer->addPreserveText('{PAGE}', $fontStyleName, $paragraphStyleName);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n        $preserve = $doc->getElement('w:p/w:r[2]/w:instrText', 'word/footer1.xml');\n\n        self::assertEquals('PAGE', $preserve->nodeValue);\n        self::assertEquals('preserve', $preserve->getAttribute('xml:space'));\n    }\n\n    /**\n     * Test write text break.\n     */\n    public function testWriteTextBreak(): void\n    {\n        $fArray = ['size' => 12];\n        $pArray = ['spacing' => 240];\n        $fName = 'fStyle';\n        $pName = 'pStyle';\n\n        $phpWord = new PhpWord();\n        $phpWord->addFontStyle($fName, $fArray);\n        $phpWord->addParagraphStyle($pName, $pArray);\n        $section = $phpWord->addSection();\n        $section->addTextBreak();\n        $section->addTextBreak(1, $fArray, $pArray);\n        $section->addTextBreak(1, $fName, $pName);\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $element = $doc->getElement('/w:document/w:body/w:p/w:pPr/w:rPr/w:rStyle');\n        self::assertEquals($fName, $element->getAttribute('w:val'));\n        $element = $doc->getElement('/w:document/w:body/w:p/w:pPr/w:pStyle');\n        self::assertEquals($pName, $element->getAttribute('w:val'));\n    }\n\n    /**\n     * covers ::_writeImage.\n     */\n    public function testWriteImage(): void\n    {\n        $phpWord = new PhpWord();\n        $styles = ['alignment' => Jc::START, 'width' => 40, 'height' => 40, 'marginTop' => -1, 'marginLeft' => -1];\n        $wraps = ['inline', 'behind', 'infront', 'square', 'tight'];\n        $section = $phpWord->addSection();\n        foreach ($wraps as $wrap) {\n            $styles['wrappingStyle'] = $wrap;\n            $section->addImage(__DIR__ . '/../../../_files/images/earth.jpg', $styles);\n        }\n\n        $archiveFile = realpath(__DIR__ . '/../../../_files/documents/reader.docx');\n        $imageFile = 'word/media/image1.jpeg';\n        $source = 'zip://' . $archiveFile . '#' . $imageFile;\n        $section->addImage($source);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        // behind\n        $element = $doc->getElement('/w:document/w:body/w:p[2]/w:r/w:pict/v:shape');\n        $style = $element->getAttribute('style');\n        // @phpstan-ignore-next-line\n        if (method_exists(self::class, 'assertMatchesRegularExpression')) {\n            self::assertMatchesRegularExpression('/z\\-index:\\-[0-9]*/', $style);\n        } elseif (method_exists(self::class, 'assertRegExp')) { // @phpstan-ignore-line\n            self::assertRegExp('/z\\-index:\\-[0-9]*/', $style);\n        } else {\n            self::fail('Unsure how to test regexp');\n        }\n\n        // square\n        $element = $doc->getElement('/w:document/w:body/w:p[4]/w:r/w:pict/v:shape/w10:wrap');\n        self::assertEquals('square', $element->getAttribute('type'));\n    }\n\n    /**\n     * covers ::_writeWatermark.\n     */\n    public function testWriteWatermark(): void\n    {\n        $imageSrc = __DIR__ . '/../../../_files/images/earth.jpg';\n\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $header = $section->addHeader();\n        $header->addWatermark($imageSrc);\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $element = $doc->getElement('/w:document/w:body/w:sectPr/w:headerReference');\n        self::assertStringStartsWith('rId', $element->getAttribute('r:id'));\n    }\n\n    /**\n     * covers ::_writeTitle.\n     */\n    public function testWriteTitle(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->addTitleStyle(1, ['bold' => true], ['spaceAfter' => 240]);\n        $phpWord->addSection()->addTitle('Test', 1);\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $element = '/w:document/w:body/w:p/w:pPr/w:pStyle';\n        self::assertEquals('Heading1', $doc->getElementAttribute($element, 'w:val'));\n    }\n\n    /**\n     * covers ::_writeCheckbox.\n     */\n    public function testWriteCheckbox(): void\n    {\n        $rStyle = 'rStyle';\n        $pStyle = 'pStyle';\n\n        $phpWord = new PhpWord();\n        // $phpWord->addFontStyle($rStyle, array('bold' => true));\n        // $phpWord->addParagraphStyle($pStyle, array('hanging' => 120, 'indent' => 120));\n        $section = $phpWord->addSection();\n        $section->addCheckBox('Check1', 'Test', $rStyle, $pStyle);\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $element = '/w:document/w:body/w:p/w:r/w:fldChar/w:ffData/w:name';\n        self::assertEquals('Check1', $doc->getElementAttribute($element, 'w:val'));\n    }\n\n    /**\n     * covers ::_writeParagraphStyle.\n     */\n    public function testWriteParagraphStyle(): void\n    {\n        // Create the doc\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $attributes = [\n            'alignment' => Jc::END,\n            'widowControl' => false,\n            'keepNext' => true,\n            'keepLines' => true,\n            'pageBreakBefore' => true,\n        ];\n        foreach ($attributes as $attribute => $value) {\n            $section->addText('Test', null, [$attribute => $value]);\n        }\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        // Test the attributes\n        $attributeCount = 0;\n        foreach ($attributes as $key => $value) {\n            ++$attributeCount;\n            $nodeName = ($key == 'alignment') ? 'jc' : $key;\n            $path = \"/w:document/w:body/w:p[{$attributeCount}]/w:pPr/w:{$nodeName}\";\n            if ('alignment' != $key) {\n                $value = $value ? 1 : 0;\n            }\n            $element = $doc->getElement($path);\n            self::assertEquals($value, $element->getAttribute('w:val'));\n        }\n    }\n\n    /**\n     * covers ::_writeTextStyle.\n     */\n    public function testWriteFontStyle(): void\n    {\n        $phpWord = new PhpWord();\n        $styles['name'] = 'Verdana';\n        $styles['size'] = 14;\n        $styles['bold'] = true;\n        $styles['italic'] = true;\n        $styles['underline'] = 'dash';\n        $styles['strikethrough'] = true;\n        $styles['superScript'] = true;\n        $styles['color'] = 'FF0000';\n        $styles['fgColor'] = 'yellow';\n        $styles['bgColor'] = 'FFFF00';\n        $styles['hint'] = 'eastAsia';\n        $styles['smallCaps'] = true;\n\n        $section = $phpWord->addSection();\n        $section->addText('Test', $styles);\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $parent = '/w:document/w:body/w:p/w:r/w:rPr';\n        self::assertEquals($styles['name'], $doc->getElementAttribute(\"{$parent}/w:rFonts\", 'w:ascii'));\n        self::assertEquals($styles['size'] * 2, $doc->getElementAttribute(\"{$parent}/w:sz\", 'w:val'));\n        self::assertTrue($doc->elementExists(\"{$parent}/w:b\"));\n        self::assertTrue($doc->elementExists(\"{$parent}/w:i\"));\n        self::assertEquals($styles['underline'], $doc->getElementAttribute(\"{$parent}/w:u\", 'w:val'));\n        self::assertTrue($doc->elementExists(\"{$parent}/w:strike\"));\n        self::assertFalse($doc->elementExists(\"{$parent}/w:dstrike\"));\n        self::assertEquals('superscript', $doc->getElementAttribute(\"{$parent}/w:vertAlign\", 'w:val'));\n        self::assertEquals($styles['color'], $doc->getElementAttribute(\"{$parent}/w:color\", 'w:val'));\n        self::assertEquals($styles['fgColor'], $doc->getElementAttribute(\"{$parent}/w:highlight\", 'w:val'));\n        self::assertTrue($doc->elementExists(\"{$parent}/w:smallCaps\"));\n    }\n\n    /**\n     * covers ::_writeTextStyle.\n     *\n     * @dataProvider providerFontStyleStrikethrough\n     */\n    public function testWriteFontStyleStrikethrough(\n        bool $isStrikethrough,\n        bool $isDoubleStrikethrough,\n        bool $expectedStrikethrough,\n        bool $expectedDoubleStrikethrough\n    ): void {\n        $phpWord = new PhpWord();\n        $styles['strikethrough'] = $isStrikethrough;\n        $styles['doublestrikethrough'] = $isDoubleStrikethrough;\n\n        $section = $phpWord->addSection();\n        $section->addText('Test', $styles);\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $parent = '/w:document/w:body/w:p/w:r/w:rPr';\n        self::assertSame($expectedStrikethrough, $doc->elementExists(\"{$parent}/w:strike\"));\n        self::assertSame($expectedDoubleStrikethrough, $doc->elementExists(\"{$parent}/w:dstrike\"));\n    }\n\n    public static function providerFontStyleStrikethrough(): iterable\n    {\n        return [\n            [true, true, false, true],\n            [true, false, true, false],\n            [false, true, false, true],\n            [false, false, false, false],\n        ];\n    }\n\n    /**\n     * Tests that if no color is set on a cell a border gets writen with the default color.\n     */\n    public function testWriteDefaultColor(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        $cStyles['borderTopSize'] = 120;\n\n        $table = $section->addTable();\n        $table->addRow();\n        $cell = $table->addCell(null, $cStyles);\n        $cell->addText('Test');\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n        self::assertEquals(\n            Cell::DEFAULT_BORDER_COLOR,\n            $doc->getElementAttribute(\n                '/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr/w:tcBorders/w:top',\n                'w:color'\n            )\n        );\n    }\n\n    /**\n     * covers ::_writeTableStyle.\n     */\n    public function testWriteTableStyle(): void\n    {\n        $phpWord = new PhpWord();\n        $rHeight = 120;\n        $cWidth = 120;\n        $imageSrc = __DIR__ . '/../../../_files/images/earth.jpg';\n        $objectSrc = __DIR__ . '/../../../_files/documents/sheet.xls';\n\n        $tStyles['width'] = 50;\n        $tStyles['cellMarginTop'] = 120;\n        $tStyles['cellMarginRight'] = 120;\n        $tStyles['cellMarginBottom'] = 120;\n        $tStyles['cellMarginLeft'] = 120;\n        $rStyles['tblHeader'] = true;\n        $rStyles['cantSplit'] = true;\n        $cStyles['valign'] = 'top';\n        $cStyles['textDirection'] = 'btLr';\n        $cStyles['bgColor'] = 'FF0000';\n        $cStyles['borderTopSize'] = 120;\n        $cStyles['borderBottomSize'] = 120;\n        $cStyles['borderLeftSize'] = 120;\n        $cStyles['borderRightSize'] = 120;\n        $cStyles['borderTopColor'] = 'FF0000';\n        $cStyles['borderBottomColor'] = 'FF0000';\n        $cStyles['borderLeftColor'] = 'FF0000';\n        $cStyles['borderRightColor'] = 'FF0000';\n        $cStyles['vMerge'] = 'restart';\n\n        $section = $phpWord->addSection();\n        $table = $section->addTable($tStyles);\n        $table->setWidth(100);\n        $table->addRow($rHeight, $rStyles);\n        $cell = $table->addCell($cWidth, $cStyles);\n        $cell->addText('Test');\n        $cell->addTextBreak();\n        $cell->addLink('https://github.com/PHPOffice/PHPWord');\n        $cell->addListItem('Test');\n        $cell->addImage($imageSrc);\n        $cell->addObject($objectSrc);\n        $textrun = $cell->addTextRun();\n        $textrun->addText('Test');\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $parent = '/w:document/w:body/w:tbl/w:tblPr/w:tblCellMar';\n\n        $parent = '/w:document/w:body/w:tbl/w:tr/w:trPr';\n        self::assertEquals($rHeight, $doc->getElementAttribute(\"{$parent}/w:trHeight\", 'w:val'));\n        self::assertEquals($rStyles['tblHeader'], $doc->getElementAttribute(\"{$parent}/w:tblHeader\", 'w:val'));\n        self::assertEquals($rStyles['cantSplit'], $doc->getElementAttribute(\"{$parent}/w:cantSplit\", 'w:val'));\n\n        $parent = '/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr';\n        self::assertEquals($cWidth, $doc->getElementAttribute(\"{$parent}/w:tcW\", 'w:w'));\n        self::assertEquals($cStyles['valign'], $doc->getElementAttribute(\"{$parent}/w:vAlign\", 'w:val'));\n        self::assertEquals($cStyles['textDirection'], $doc->getElementAttribute(\"{$parent}/w:textDirection\", 'w:val'));\n    }\n\n    /**\n     * covers ::_writeCellStyle.\n     */\n    public function testWriteCellStyleCellGridSpan(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n\n        $table = $section->addTable();\n\n        $table->addRow();\n        $cell = $table->addCell(200);\n        $cell->getStyle()->setGridSpan(5);\n\n        $table->addRow();\n        $table->addCell(40);\n        $table->addCell(40);\n        $table->addCell(40);\n        $table->addCell(40);\n        $table->addCell(40);\n\n        $table->addRow();\n        $cell = $table->addCell(200, ['borderRightColor' => 'FF0000']);\n        $cell->getStyle()->setGridSpan(5);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n        $element = $doc->getElement('/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr/w:gridSpan');\n\n        self::assertEquals(5, $element->getAttribute('w:val'));\n    }\n\n    /**\n     * Test write gutter and line numbering.\n     */\n    public function testWriteGutterAndLineNumbering(): void\n    {\n        $pageMarginPath = '/w:document/w:body/w:sectPr/w:pgMar';\n        $lineNumberingPath = '/w:document/w:body/w:sectPr/w:lnNumType';\n\n        $phpWord = new PhpWord();\n        $phpWord->addSection(['gutter' => 240, 'lineNumbering' => []]);\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        self::assertEquals(240, $doc->getElement($pageMarginPath)->getAttribute('w:gutter'));\n        self::assertTrue($doc->elementExists($lineNumberingPath));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/Word2007/Part/FooterTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\Word2007\\Part;\n\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Writer\\Word2007;\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Part\\Footer;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\Word2007\\Part\\Footer.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Writer\\Word2007\\Part\\Footer\n *\n * @runTestsInSeparateProcesses\n */\nclass FooterTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Write footer.\n     */\n    public function testWriteFooter(): void\n    {\n        $imageSrc = __DIR__ . '/../../../_files/images/PhpWord.png';\n        $container = new \\PhpOffice\\PhpWord\\Element\\Footer(1);\n        $container->addText('');\n        $container->addPreserveText('');\n        $container->addTextBreak();\n        $container->addTextRun();\n        $container->addTable()->addRow()->addCell()->addText('');\n        $container->addImage($imageSrc);\n\n        $writer = new Word2007();\n        $dir = Settings::getTempDir() . DIRECTORY_SEPARATOR . 'phpwordcachefooter';\n        if (!is_dir($dir) && !mkdir($dir)) {\n            self::fail('Unable to create temp directory');\n        }\n        $writer->setUseDiskCaching(true, $dir);\n        $object = new Footer();\n        $object->setParentWriter($writer);\n        $object->setElement($container);\n        $xml = simplexml_load_string($object->write());\n\n        self::assertInstanceOf('SimpleXMLElement', $xml);\n        TestHelperDOCX::deleteDir($dir);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/Word2007/Part/FootnotesTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\Word2007\\Part;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * @coversNothing\n *\n * @runTestsInSeparateProcesses\n */\nclass FootnotesTest extends \\PHPUnit\\Framework\\TestCase\n{\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    public function testWriteFootnotes(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->addParagraphStyle('pStyle', ['alignment' => Jc::START]);\n        $section = $phpWord->addSection();\n        $section->addText('Text');\n        $footnote1 = $section->addFootnote('pStyle');\n        $footnote1->addText('Footnote');\n        $footnote1->addTextBreak();\n        $footnote1->addLink('https://github.com/PHPOffice/PHPWord');\n        $footnote2 = $section->addEndnote(['alignment' => Jc::START]);\n        $footnote2->addText('Endnote');\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:footnoteReference'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:endnoteReference'));\n\n        self::assertFalse($doc->elementExists('/w:document/w:body/w:p/w:r/w:footnoteReference[@w:id=\"0\"]'));\n        self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:footnoteReference[@w:id=\"1\"]'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/Word2007/Part/HeaderTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\Word2007\\Part;\n\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Writer\\Word2007;\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Part\\Header;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\Word2007\\Part\\Header.\n *\n * @runTestsInSeparateProcesses\n */\nclass HeaderTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Write header.\n     */\n    public function testWriteHeader(): void\n    {\n        $imageSrc = __DIR__ . '/../../../_files/images/PhpWord.png';\n\n        $container = new \\PhpOffice\\PhpWord\\Element\\Header(1);\n        $container->addText('Test');\n        $container->addPreserveText('');\n        $container->addTextBreak();\n        $container->addTextRun();\n        $container->addTable()->addRow()->addCell()->addText('');\n        $container->addImage($imageSrc);\n        $container->addWatermark($imageSrc);\n\n        $writer = new Word2007();\n        $dir = Settings::getTempDir() . DIRECTORY_SEPARATOR . 'phpwordcachefooter';\n        if (!is_dir($dir) && !mkdir($dir)) {\n            self::fail('Unable to create temp directory');\n        }\n        $writer->setUseDiskCaching(true, $dir);\n        $object = new Header();\n        $object->setParentWriter($writer);\n        $object->setElement($container);\n        $xml = simplexml_load_string($object->write());\n\n        self::assertInstanceOf('SimpleXMLElement', $xml);\n        TestHelperDOCX::deleteDir($dir);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/Word2007/Part/NumberingTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\Word2007\\Part;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\nuse PhpOffice\\PhpWord\\SimpleType\\NumberFormat;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\Word2007\\Part\\Numbering.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Writer\\Word2007\\Part\\Numbering\n *\n * @runTestsInSeparateProcesses\n *\n * @since 0.10.0\n */\nclass NumberingTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Executed before each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    /**\n     * Write footnotes.\n     */\n    public function testWriteNumbering(): void\n    {\n        $xmlFile = 'word/numbering.xml';\n\n        $phpWord = new PhpWord();\n        $phpWord->addNumberingStyle(\n            'numStyle',\n            [\n                'type' => 'multilevel',\n                'levels' => [\n                    [\n                        'start' => 1,\n                        'format' => NumberFormat::DECIMAL,\n                        'restart' => 1,\n                        'suffix' => 'space',\n                        'text' => '%1.',\n                        'alignment' => Jc::START,\n                        'left' => 360,\n                        'hanging' => 360,\n                        'tabPos' => 360,\n                        'font' => 'Arial',\n                        'hint' => 'default',\n                    ],\n                ],\n            ]\n        );\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        self::assertTrue($doc->elementExists('/w:numbering/w:abstractNum', $xmlFile));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/Word2007/Part/SettingsTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\Word2007\\Part;\n\nuse PhpOffice\\PhpWord\\ComplexType\\ProofState;\nuse PhpOffice\\PhpWord\\ComplexType\\TrackChangesView;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Shared\\Microsoft\\PasswordEncoder;\nuse PhpOffice\\PhpWord\\SimpleType\\Zoom;\nuse PhpOffice\\PhpWord\\Style\\Language;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\Word2007\\Part\\Settings.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Writer\\Word2007\\Part\\Settings\n */\nclass SettingsTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Executed before each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    /**\n     * Test document protection.\n     */\n    public function testDocumentProtection(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->getSettings()->getDocumentProtection()->setEditing('forms');\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $file = 'word/settings.xml';\n\n        $path = '/w:settings/w:documentProtection';\n        self::assertTrue($doc->elementExists($path, $file));\n    }\n\n    /**\n     * Test document protection with password.\n     */\n    public function testDocumentProtectionWithPassword(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->getSettings()->getDocumentProtection()->setEditing('readOnly');\n        $phpWord->getSettings()->getDocumentProtection()->setPassword('testÄö@€!$&');\n        $phpWord->getSettings()->getDocumentProtection()->setSalt(base64_decode('uq81pJRRGFIY5U+E9gt8tA=='));\n        $phpWord->getSettings()->getDocumentProtection()->setAlgorithm(PasswordEncoder::ALGORITHM_MD2);\n        $phpWord->getSettings()->getDocumentProtection()->setSpinCount(10);\n        $sect = $phpWord->addSection();\n        $sect->addText('This is a protected document');\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $file = 'word/settings.xml';\n\n        $path = '/w:settings/w:documentProtection';\n        self::assertTrue($doc->elementExists($path, $file));\n        self::assertEquals('rUuJbk6LuN2/qFyp7IUPQA==', $doc->getElement($path, $file)->getAttribute('w:hash'));\n        self::assertEquals('1', $doc->getElement($path, $file)->getAttribute('w:cryptAlgorithmSid'));\n        self::assertEquals('10', $doc->getElement($path, $file)->getAttribute('w:cryptSpinCount'));\n    }\n\n    /**\n     * Test document protection with password without setting salt.\n     */\n    public function testDocumentProtectionWithPasswordNoSalt(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->getSettings()->getDocumentProtection()->setEditing('readOnly');\n        $phpWord->getSettings()->getDocumentProtection()->setPassword('testÄö@€!$&');\n        //$phpWord->getSettings()->getDocumentProtection()->setSalt(base64_decode('uq81pJRRGFIY5U+E9gt8tA=='));\n        $phpWord->getSettings()->getDocumentProtection()->setAlgorithm(PasswordEncoder::ALGORITHM_MD2);\n        $phpWord->getSettings()->getDocumentProtection()->setSpinCount(10);\n        $sect = $phpWord->addSection();\n        $sect->addText('This is a protected document');\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $file = 'word/settings.xml';\n\n        $path = '/w:settings/w:documentProtection';\n        self::assertTrue($doc->elementExists($path, $file));\n        //$this->assertEquals('rUuJbk6LuN2/qFyp7IUPQA==', $doc->getElement($path, $file)->getAttribute('w:hash'));\n        self::assertEquals('1', $doc->getElement($path, $file)->getAttribute('w:cryptAlgorithmSid'));\n        self::assertEquals('10', $doc->getElement($path, $file)->getAttribute('w:cryptSpinCount'));\n    }\n\n    /**\n     * Test compatibility.\n     */\n    public function testCompatibility(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->getCompatibility()->setOoxmlVersion(15);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $file = 'word/settings.xml';\n\n        $path = '/w:settings/w:compat/w:compatSetting';\n        self::assertTrue($doc->elementExists($path, $file));\n        self::assertEquals($phpWord->getCompatibility()->getOoxmlVersion(), 15);\n    }\n\n    /**\n     * Test language.\n     */\n    public function testDefaultLanguage(): void\n    {\n        $phpWord = new PhpWord();\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $file = 'word/settings.xml';\n\n        $path = '/w:settings/w:themeFontLang';\n        self::assertTrue($doc->elementExists($path, $file));\n        $element = $doc->getElement($path, $file);\n\n        self::assertEquals('en-US', $element->getAttribute('w:val'));\n    }\n\n    /**\n     * Test language.\n     */\n    public function testLanguage(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->getSettings()->setThemeFontLang(new Language(Language::DE_DE, Language::KO_KR, Language::HE_IL));\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $file = 'word/settings.xml';\n\n        $path = '/w:settings/w:themeFontLang';\n        self::assertTrue($doc->elementExists($path, $file));\n        $element = $doc->getElement($path, $file);\n\n        self::assertEquals(Language::DE_DE, $element->getAttribute('w:val'));\n        self::assertEquals(Language::KO_KR, $element->getAttribute('w:eastAsia'));\n        self::assertEquals(Language::HE_IL, $element->getAttribute('w:bidi'));\n    }\n\n    /**\n     * Test proofState.\n     */\n    public function testProofState(): void\n    {\n        $proofState = new ProofState();\n        $proofState->setSpelling(ProofState::DIRTY);\n        $proofState->setGrammar(ProofState::DIRTY);\n        $phpWord = new PhpWord();\n        $phpWord->getSettings()->setProofState($proofState);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $file = 'word/settings.xml';\n\n        $path = '/w:settings/w:proofState';\n        self::assertTrue($doc->elementExists($path, $file));\n        $element = $doc->getElement($path, $file);\n\n        self::assertEquals('dirty', $element->getAttribute('w:spelling'));\n        self::assertEquals('dirty', $element->getAttribute('w:grammar'));\n    }\n\n    /**\n     * Test spelling.\n     */\n    public function testSpelling(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->getSettings()->setHideSpellingErrors(true);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $file = 'word/settings.xml';\n\n        $path = '/w:settings/w:hideSpellingErrors';\n        self::assertTrue($doc->elementExists($path, $file));\n        $element = $doc->getElement($path, $file);\n\n        self::assertSame('true', $element->getAttribute('w:val'));\n    }\n\n    /**\n     * Test even and odd headers.\n     */\n    public function testEvenAndOddHeaders(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->getSettings()->setEvenAndOddHeaders(true);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $file = 'word/settings.xml';\n\n        $path = '/w:settings/w:evenAndOddHeaders';\n        self::assertTrue($doc->elementExists($path, $file));\n\n        $element = $doc->getElement($path, $file);\n        self::assertSame('true', $element->getAttribute('w:val'));\n    }\n\n    public function testUpdateFields(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->getSettings()->setUpdateFields(true);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $file = 'word/settings.xml';\n\n        $path = '/w:settings/w:updateFields';\n        self::assertTrue($doc->elementExists($path, $file));\n\n        $element = $doc->getElement($path, $file);\n        self::assertSame('true', $element->getAttribute('w:val'));\n    }\n\n    /**\n     * Test zoom percentage.\n     */\n    public function testZoomPercentage(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->getSettings()->setZoom(75);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $file = 'word/settings.xml';\n\n        $path = '/w:settings/w:zoom';\n        self::assertTrue($doc->elementExists($path, $file));\n\n        $element = $doc->getElement($path, $file);\n        self::assertEquals('75', $element->getAttribute('w:percent'));\n    }\n\n    /**\n     * Test zoom value.\n     */\n    public function testZoomValue(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->getSettings()->setZoom(Zoom::FULL_PAGE);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $file = 'word/settings.xml';\n\n        $path = '/w:settings/w:zoom';\n        self::assertTrue($doc->elementExists($path, $file));\n\n        $element = $doc->getElement($path, $file);\n        self::assertEquals('fullPage', $element->getAttribute('w:val'));\n    }\n\n    public function testMirrorMargins(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->getSettings()->setMirrorMargins(true);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $file = 'word/settings.xml';\n\n        $path = '/w:settings/w:mirrorMargins';\n        self::assertTrue($doc->elementExists($path, $file));\n\n        $element = $doc->getElement($path, $file);\n        self::assertSame('true', $element->getAttribute('w:val'));\n    }\n\n    /**\n     * Test Revision View.\n     */\n    public function testRevisionView(): void\n    {\n        $trackChangesView = new TrackChangesView();\n        $trackChangesView->setFormatting(false);\n        $trackChangesView->setComments(true);\n\n        $phpWord = new PhpWord();\n        $phpWord->getSettings()->setRevisionView($trackChangesView);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $file = 'word/settings.xml';\n\n        $path = '/w:settings/w:revisionView';\n        self::assertTrue($doc->elementExists($path, $file));\n\n        $element = $doc->getElement($path, $file);\n        self::assertEquals('false', $element->getAttribute('w:formatting'));\n        self::assertEquals('true', $element->getAttribute('w:comments'));\n    }\n\n    public function testHideSpellingErrors(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->getSettings()->setHideSpellingErrors(true);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $file = 'word/settings.xml';\n\n        $path = '/w:settings/w:hideSpellingErrors';\n        self::assertTrue($doc->elementExists($path, $file));\n\n        $element = $doc->getElement($path, $file);\n        self::assertSame('true', $element->getAttribute('w:val'));\n    }\n\n    public function testHideGrammaticalErrors(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->getSettings()->setHideGrammaticalErrors(true);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $file = 'word/settings.xml';\n\n        $path = '/w:settings/w:hideGrammaticalErrors';\n        self::assertTrue($doc->elementExists($path, $file));\n\n        $element = $doc->getElement($path, $file);\n        self::assertSame('true', $element->getAttribute('w:val'));\n    }\n\n    /**\n     * Test track Revisions.\n     */\n    public function testTrackRevisions(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->getSettings()->setTrackRevisions(true);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $file = 'word/settings.xml';\n\n        $path = '/w:settings/w:trackRevisions';\n        self::assertTrue($doc->elementExists($path, $file));\n\n        $element = $doc->getElement($path, $file);\n        self::assertSame('true', $element->getAttribute('w:val'));\n    }\n\n    /**\n     * Test doNotTrackMoves.\n     */\n    public function testDoNotTrackMoves(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->getSettings()->setDoNotTrackMoves(true);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $file = 'word/settings.xml';\n\n        $path = '/w:settings/w:doNotTrackMoves';\n        self::assertTrue($doc->elementExists($path, $file));\n\n        $element = $doc->getElement($path, $file);\n        self::assertSame('true', $element->getAttribute('w:val'));\n    }\n\n    /**\n     * Test DoNotTrackFormatting.\n     */\n    public function testDoNotTrackFormatting(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->getSettings()->setDoNotTrackFormatting(true);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $file = 'word/settings.xml';\n\n        $path = '/w:settings/w:doNotTrackFormatting';\n        self::assertTrue($doc->elementExists($path, $file));\n\n        $element = $doc->getElement($path, $file);\n        self::assertSame('true', $element->getAttribute('w:val'));\n    }\n\n    public function testAutoHyphenation(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->getSettings()->setAutoHyphenation(true);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $file = 'word/settings.xml';\n\n        $path = '/w:settings/w:autoHyphenation';\n        self::assertTrue($doc->elementExists($path, $file));\n\n        $element = $doc->getElement($path, $file);\n        self::assertSame('true', $element->getAttribute('w:val'));\n    }\n\n    public function testConsecutiveHyphenLimit(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->getSettings()->setConsecutiveHyphenLimit(2);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $file = 'word/settings.xml';\n\n        $path = '/w:settings/w:consecutiveHyphenLimit';\n        self::assertTrue($doc->elementExists($path, $file));\n\n        $element = $doc->getElement($path, $file);\n        self::assertSame('2', $element->getAttribute('w:val'));\n    }\n\n    public function testHyphenationZone(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->getSettings()->setHyphenationZone(100);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $file = 'word/settings.xml';\n\n        $path = '/w:settings/w:hyphenationZone';\n        self::assertTrue($doc->elementExists($path, $file));\n\n        $element = $doc->getElement($path, $file);\n        self::assertSame('100', $element->getAttribute('w:val'));\n    }\n\n    public function testDoNotHyphenateCaps(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->getSettings()->setDoNotHyphenateCaps(true);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $file = 'word/settings.xml';\n\n        $path = '/w:settings/w:doNotHyphenateCaps';\n        self::assertTrue($doc->elementExists($path, $file));\n\n        $element = $doc->getElement($path, $file);\n        self::assertSame('true', $element->getAttribute('w:val'));\n    }\n\n    public function testBookFoldPrinting(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->getSettings()->setBookFoldPrinting(true);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $file = 'word/settings.xml';\n\n        $path = '/w:settings/w:bookFoldPrinting';\n        self::assertTrue($doc->elementExists($path, $file));\n\n        $element = $doc->getElement($path, $file);\n        self::assertSame('true', $element->getAttribute('w:val'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/Word2007/Part/StylesTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\Word2007\\Part;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\nuse PhpOffice\\PhpWord\\Style\\Font;\nuse PhpOffice\\PhpWord\\Style\\Paragraph;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\Word2007\\Part\\Styles.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Writer\\Word2007\\Part\\Styles\n *\n * @runTestsInSeparateProcesses\n */\nclass StylesTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Executed before each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    /**\n     * Test write styles.\n     */\n    public function testWriteStyles(): void\n    {\n        $phpWord = new PhpWord();\n\n        $pStyle = ['alignment' => Jc::BOTH];\n        $pBase = ['basedOn' => 'Normal'];\n        $pNew = ['basedOn' => 'Base Style', 'next' => 'Normal'];\n        $rStyle = ['size' => 20];\n        $tStyle = ['bgColor' => 'FF0000', 'cellMargin' => 120, 'borderSize' => 120];\n        $firstRowStyle = ['bgColor' => '0000FF', 'borderSize' => 120, 'borderColor' => '00FF00'];\n        $phpWord->setDefaultParagraphStyle($pStyle);\n        $phpWord->addParagraphStyle('Base Style', $pBase);\n        $phpWord->addParagraphStyle('New Style', $pNew);\n        $phpWord->addFontStyle('New Style', $rStyle, $pStyle);\n        $phpWord->addTableStyle('Table Style', $tStyle, $firstRowStyle);\n        $phpWord->addTitleStyle(1, $rStyle, $pStyle);\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $file = 'word/styles.xml';\n\n        // Normal style generated?\n        $path = '/w:styles/w:style[@w:styleId=\"Normal\"]/w:name';\n        $element = $doc->getElement($path, $file);\n        self::assertEquals('Normal', $element->getAttribute('w:val'));\n\n        // Parent style referenced?\n        $path = '/w:styles/w:style[@w:styleId=\"New Style\"]/w:basedOn';\n        $element = $doc->getElement($path, $file);\n        self::assertEquals('Base Style', $element->getAttribute('w:val'));\n\n        // Next paragraph style correct?\n        $path = '/w:styles/w:style[@w:styleId=\"New Style\"]/w:next';\n        $element = $doc->getElement($path, $file);\n        self::assertEquals('Normal', $element->getAttribute('w:val'));\n    }\n\n    public function testFontStyleBasedOn(): void\n    {\n        $phpWord = new PhpWord();\n\n        $baseParagraphStyle = new Paragraph();\n        $baseParagraphStyle->setAlignment(Jc::CENTER);\n        $baseParagraphStyle = $phpWord->addParagraphStyle('BaseStyle', $baseParagraphStyle);\n\n        $childFont = new Font();\n        $childFont->setParagraph($baseParagraphStyle);\n        $childFont->setSize(16);\n        $childFont = $phpWord->addFontStyle('ChildFontStyle', $childFont);\n\n        $otherFont = new Font();\n        $otherFont->setSize(20);\n        $otherFont = $phpWord->addFontStyle('OtherFontStyle', $otherFont);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $file = 'word/styles.xml';\n\n        // Normal style generated?\n        $path = '/w:styles/w:style[@w:styleId=\"BaseStyle\"]/w:name';\n        $element = $doc->getElement($path, $file);\n        self::assertEquals('BaseStyle', $element->getAttribute('w:val'));\n\n        // Font style with paragraph should have it's base style set to that paragraphs style name\n        $path = '/w:styles/w:style[w:name/@w:val=\"ChildFontStyle\"]/w:basedOn';\n        $element = $doc->getElement($path, $file);\n        self::assertEquals('BaseStyle', $element->getAttribute('w:val'));\n\n        // Font style without paragraph should not have a base style set\n        $path = '/w:styles/w:style[w:name/@w:val=\"OtherFontStyle\"]/w:basedOn';\n        $element = $doc->getElement($path, $file);\n        self::assertNull($element);\n    }\n\n    public function testFontStyleBasedOnOtherFontStyle(): void\n    {\n        $phpWord = new PhpWord();\n\n        $styleGenerationP = new Paragraph();\n        $styleGenerationP->setAlignment(Jc::BOTH);\n\n        $styleGeneration = new Font();\n        $styleGeneration->setParagraph($styleGenerationP);\n        $styleGeneration->setSize(9.5);\n        $phpWord->addFontStyle('Generation', $styleGeneration);\n\n        $styleGenerationEteinteP = new Paragraph();\n        $styleGenerationEteinteP->setBasedOn('Generation');\n\n        $styleGenerationEteinte = new Font();\n        $styleGenerationEteinte->setParagraph($styleGenerationEteinteP);\n        $styleGenerationEteinte->setSize(8.5);\n        $phpWord->addFontStyle('GeneratEteinte', $styleGenerationEteinte);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $file = 'word/styles.xml';\n\n        $path = '/w:styles/w:style[@w:styleId=\"GeneratEteinte\"]/w:basedOn';\n        $element = $doc->getElement($path, $file);\n        self::assertEquals('Generation', $element->getAttribute('w:val'));\n    }\n\n    /**\n     * Test default font color.\n     */\n    public function testDefaultDefaultFontColor(): void\n    {\n        $phpWord = new PhpWord();\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $file = 'word/styles.xml';\n\n        $path = '/w:styles/w:docDefaults/w:rPrDefault/w:rPr/w:color';\n        self::assertTrue($doc->elementExists($path, $file));\n        $element = $doc->getElement($path, $file);\n\n        self::assertEquals('000000', $element->getAttribute('w:val'));\n    }\n\n    /**\n     * Test default font color.\n     */\n    public function testDefaultFontColor(): void\n    {\n        $phpWord = new PhpWord();\n        $defaultFontColor = '00FF00';\n        $phpWord->setDefaultFontColor($defaultFontColor);\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n\n        $file = 'word/styles.xml';\n\n        $path = '/w:styles/w:docDefaults/w:rPrDefault/w:rPr/w:color';\n        self::assertTrue($doc->elementExists($path, $file));\n        $element = $doc->getElement($path, $file);\n\n        self::assertEquals($defaultFontColor, $element->getAttribute('w:val'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/Word2007/PartTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\Word2007;\n\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Part\\RelsPart;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\Word2007\\Part subnamespace.\n *\n * Covers miscellaneous tests\n */\nclass PartTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test exception when no type or target assigned to a relation.\n     *\n     * @covers \\PhpOffice\\PhpWord\\Writer\\Word2007\\Part\\Rels::writeRel\n     */\n    public function testRelsWriteRelException(): void\n    {\n        $this->expectException(\\PhpOffice\\PhpWord\\Exception\\Exception::class);\n        $this->expectExceptionMessage('Invalid parameters passed.');\n        $object = new RelsPart();\n        $object->setMedia([['type' => '', 'target' => '']]);\n        $object->write();\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/Word2007/Style/DirectionTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\Word2007\\Style;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Shared\\Html as SharedHtml;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\nclass DirectionTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Executed before each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        Settings::setDefaultRtl(null);\n        TestHelperDOCX::clear();\n    }\n\n    /**\n     * Test write styles.\n     */\n    public function testDirection(): void\n    {\n        $word = new PhpWord();\n        Settings::setDefaultRtl(true);\n        $section = $word->addSection();\n        $html = '<p>  الألم الذي ربما تنجم عنه بعض ا.</p>';\n        SharedHtml::addHtml($section, $html, false, false);\n        $english = '<p style=\"text-align: left; direction: ltr;\">LTR in RTL document.</p>';\n        SharedHtml::addHtml($section, $english, false, false);\n        $doc = TestHelperDOCX::getDocument($word, 'Word2007');\n\n        $path = '/w:document/w:body/w:p[1]/w:pPr/w:bidi';\n        self::assertTrue($doc->elementExists($path));\n        $path = '/w:document/w:body/w:p[2]/w:pPr/w:bidi';\n        self::assertFalse($doc->elementExists($path));\n\n        $path = '/w:document/w:body/w:p[1]/w:pPr/w:jc';\n        self::assertFalse($doc->elementExists($path));\n        $path = '/w:document/w:body/w:p[2]/w:pPr/w:jc';\n        self::assertTrue($doc->elementExists($path));\n        self::assertSame('start', $doc->getElementAttribute($path, 'w:val'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/Word2007/Style/FontTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\Word2007\\Style;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Shared\\Html;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Font.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Font\n *\n * @runTestsInSeparateProcesses\n */\nclass FontTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Executed before each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    /**\n     * Test write styles.\n     */\n    public function testFontRTL(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $textrun = $section->addTextRun();\n        $textrun->addText('سلام این یک پاراگراف راست به چپ است', ['rtl' => true, 'lang' => 'ar-DZ']);\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $file = 'word/document.xml';\n        $path = '/w:document/w:body/w:p/w:r/w:rPr/w:rtl';\n        self::assertTrue($doc->elementExists($path, $file));\n    }\n\n    public function testFontRTLNamed(): void\n    {\n        $phpWord = new PhpWord();\n        $stnam = 'fstyle';\n        $phpWord->addFontStyle($stnam, [\n            'rtl' => true,\n            'name' => 'Courier New',\n            'size' => 8,\n        ]);\n        $section = $phpWord->addSection();\n        $txt = 'היום יום שני';  // Translation = Today is Monday\n        $section->addText($txt, $stnam);\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $element = '/w:document/w:body/w:p/w:r';\n        $txtelem = $element . '/w:t';\n        $styelem = $element . '/w:rPr';\n        self::assertTrue($doc->elementExists($txtelem));\n        self::assertEquals($txt, $doc->getElement($txtelem)->textContent);\n        self::assertTrue($doc->elementExists($styelem));\n        self::assertTrue($doc->elementExists($styelem . '/w:rStyle'));\n        self::assertEquals($stnam, $doc->getElementAttribute($styelem . '/w:rStyle', 'w:val'));\n        self::assertTrue($doc->elementExists($styelem . '/w:rtl'));\n    }\n\n    public function testFontNotRTLNamed(): void\n    {\n        $phpWord = new PhpWord();\n        $stnam = 'fstyle';\n        $phpWord->addFontStyle($stnam, [\n            //'rtl'  => true,\n            'name' => 'Courier New',\n            'size' => 8,\n        ]);\n        $section = $phpWord->addSection();\n        $txt = 'היום יום שני';  // Translation = Today is Monday\n        $section->addText($txt, $stnam);\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $element = '/w:document/w:body/w:p/w:r';\n        $txtelem = $element . '/w:t';\n        $styelem = $element . '/w:rPr';\n        self::assertTrue($doc->elementExists($txtelem));\n        self::assertEquals($txt, $doc->getElement($txtelem)->textContent);\n        self::assertTrue($doc->elementExists($styelem));\n        self::assertTrue($doc->elementExists($styelem . '/w:rStyle'));\n        self::assertEquals($stnam, $doc->getElementAttribute($styelem . '/w:rStyle', 'w:val'));\n        self::assertFalse($doc->elementExists($styelem . '/w:rtl'));\n    }\n\n    public function testNoProof(): void\n    {\n        $phpWord = new PhpWord();\n        $fontStyle = [\n            'noProof' => true,\n            'name' => 'Courier New',\n            'size' => 8,\n        ];\n        $section = $phpWord->addSection();\n        $txt = 'spellung error';\n        $section->addText($txt, $fontStyle);\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $element = '/w:document/w:body/w:p/w:r';\n        $txtelem = $element . '/w:t';\n        $styelem = $element . '/w:rPr';\n        $noproofelem = $styelem . '/w:noProof';\n        self::assertTrue($doc->elementExists($txtelem));\n        self::assertEquals($txt, $doc->getElement($txtelem)->textContent);\n        self::assertTrue($doc->elementExists($styelem));\n        self::assertTrue($doc->elementExists($noproofelem));\n        self::assertEquals('1', $doc->getElementAttribute($noproofelem, 'w:val'));\n    }\n\n    /**\n     * Test writing font with language.\n     */\n    public function testFontWithLang(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $section->addText('Ce texte-ci est en français.', ['lang' => \\PhpOffice\\PhpWord\\Style\\Language::FR_BE]);\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $file = 'word/document.xml';\n        $path = '/w:document/w:body/w:p/w:r/w:rPr/w:lang';\n        self::assertTrue($doc->elementExists($path, $file));\n    }\n\n    /**\n     * Test writing position.\n     */\n    public function testPosition(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $section->addText('This text is lowered', ['position' => -20]);\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $path = '/w:document/w:body/w:p/w:r/w:rPr/w:position';\n        self::assertTrue($doc->elementExists($path));\n        self::assertEquals(-20, $doc->getElementAttribute($path, 'w:val'));\n    }\n\n    public static function testRgb(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection(['pageNumberingStart' => 1]);\n        $html = implode(\n            \"\\n\",\n            [\n                '<table>',\n                '<tbody>',\n                '<tr>',\n                '<td style=\"color: #A7D9C1;\">This one is in color.</td>',\n                '<td style=\"color: rgb(167, 217, 193);\">This one too.</td>',\n                '</tr>',\n                '</tbody>',\n                '</table>',\n            ]\n        );\n\n        Html::addHtml($section, $html, false, false);\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $element = '/w:document/w:body/w:tbl/w:tr/w:tc/w:p/w:r';\n        $txtelem = $element . '/w:t';\n        $styelem = $element . '/w:rPr';\n        self::assertTrue($doc->elementExists($txtelem));\n        self::assertSame('This one is in color.', $doc->getElement($txtelem)->textContent);\n        self::assertTrue($doc->elementExists($styelem));\n        self::assertTrue($doc->elementExists($styelem . '/w:color'));\n        self::assertSame('A7D9C1', $doc->getElementAttribute($styelem . '/w:color', 'w:val'));\n\n        $element = '/w:document/w:body/w:tbl/w:tr/w:tc[2]/w:p/w:r';\n        $txtelem = $element . '/w:t';\n        $styelem = $element . '/w:rPr';\n        self::assertTrue($doc->elementExists($txtelem));\n        self::assertSame('This one too.', $doc->getElement($txtelem)->textContent);\n        self::assertTrue($doc->elementExists($styelem));\n        self::assertTrue($doc->elementExists($styelem . '/w:color'));\n        self::assertSame('A7D9C1', $doc->getElementAttribute($styelem . '/w:color', 'w:val'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/Word2007/Style/ImageTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\Word2007\\Style;\n\nuse PhpOffice\\PhpWord\\Style\\Image;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Font.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Frame\n *\n * @runTestsInSeparateProcesses\n */\nclass ImageTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Executed before each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    /**\n     * Test writing image wrapping.\n     */\n    public function testWrapping(): void\n    {\n        $styles = [\n            'wrap' => Image::WRAP_INLINE,\n            'wrapDistanceLeft' => 10,\n            'wrapDistanceRight' => 20,\n            'wrapDistanceTop' => 30,\n            'wrapDistanceBottom' => 40,\n        ];\n\n        $phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n        $section = $phpWord->addSection();\n        $section->addImage(__DIR__ . '/../../../_files/images/earth.jpg', $styles);\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $path = '/w:document/w:body/w:p[1]/w:r/w:rPr/w:position';\n        self::assertFalse($doc->elementExists($path));\n        $path = '/w:document/w:body/w:p[1]/w:r/w:pict/v:shape';\n        self::assertTrue($doc->elementExists($path . '/w10:wrap'));\n        self::assertEquals('inline', $doc->getElementAttribute($path . '/w10:wrap', 'type'));\n\n        self::assertTrue($doc->elementExists($path));\n        $style = $doc->getElement($path)->getAttribute('style');\n        self::assertNotNull($style);\n        self::assertStringContainsString('mso-wrap-distance-left:10pt;', $style);\n        self::assertStringContainsString('mso-wrap-distance-right:20pt;', $style);\n        self::assertStringContainsString('mso-wrap-distance-top:30pt;', $style);\n        self::assertStringContainsString('mso-wrap-distance-bottom:40pt;', $style);\n    }\n\n    /**\n     * Test writing image wrapping.\n     */\n    public function testWrappingWithPosition(): void\n    {\n        $styles = [\n            'wrap' => Image::WRAP_INLINE,\n            'wrapDistanceLeft' => 10,\n            'wrapDistanceRight' => 20,\n            'wrapDistanceTop' => 30,\n            'wrapDistanceBottom' => 40,\n            'position' => 10,\n        ];\n\n        $phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n        $section = $phpWord->addSection();\n        $section->addImage(__DIR__ . '/../../../_files/images/earth.jpg', $styles);\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $path = '/w:document/w:body/w:p[1]/w:r/w:rPr/w:position';\n        self::assertEquals('10', $doc->getElement($path)->getAttribute('w:val'));\n        $path = '/w:document/w:body/w:p[1]/w:r/w:pict/v:shape';\n        self::assertTrue($doc->elementExists($path . '/w10:wrap'));\n        self::assertEquals('inline', $doc->getElementAttribute($path . '/w10:wrap', 'type'));\n\n        self::assertTrue($doc->elementExists($path));\n        $style = $doc->getElement($path)->getAttribute('style');\n        self::assertNotNull($style);\n        self::assertStringContainsString('mso-wrap-distance-left:10pt;', $style);\n        self::assertStringContainsString('mso-wrap-distance-right:20pt;', $style);\n        self::assertStringContainsString('mso-wrap-distance-top:30pt;', $style);\n        self::assertStringContainsString('mso-wrap-distance-bottom:40pt;', $style);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/Word2007/Style/IndentationTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\Word2007\\Style;\n\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\Style\\Paragraph;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\nclass IndentationTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Executed before each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        Settings::setDefaultRtl(null);\n        TestHelperDOCX::clear();\n    }\n\n    public function testDefault(): void\n    {\n        $word = new PhpWord();\n        Settings::setDefaultRtl(true);\n        $section = $word->addSection();\n        $text = $section->addText('AA');\n        $paragraphStyle = $text->getParagraphStyle();\n        self::assertInstanceOf(Paragraph::class, $paragraphStyle);\n        $paragraphStyle->setIndentation([]);\n        $doc = TestHelperDOCX::getDocument($word, 'Word2007');\n\n        $path = '/w:document/w:body/w:p[1]/w:pPr/w:ind';\n        self::assertTrue($doc->elementExists($path));\n        self::assertFalse($doc->hasElementAttribute($path, 'w:firstLineChars'));\n    }\n\n    public function testFirstLineChars(): void\n    {\n        $word = new PhpWord();\n        Settings::setDefaultRtl(true);\n        $section = $word->addSection();\n        $text = $section->addText('AA');\n        $paragraphStyle = $text->getParagraphStyle();\n        self::assertInstanceOf(Paragraph::class, $paragraphStyle);\n        $paragraphStyle->setIndentation([\n            'firstLineChars' => 1440,\n        ]);\n        $doc = TestHelperDOCX::getDocument($word, 'Word2007');\n\n        $path = '/w:document/w:body/w:p[1]/w:pPr/w:ind';\n        self::assertTrue($doc->elementExists($path));\n        self::assertTrue($doc->hasElementAttribute($path, 'w:firstLineChars'));\n        self::assertSame('1440', $doc->getElementAttribute($path, 'w:firstLineChars'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/Word2007/Style/ParagraphTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\Word2007\\Style;\n\nuse PhpOffice\\PhpWord\\Style\\Paragraph as ParagraphStyle;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Paragraph.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Paragraph\n *\n * @runTestsInSeparateProcesses\n */\nclass ParagraphTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Executed before each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    /**\n     * Test write styles.\n     */\n    public function testParagraphNumbering(): void\n    {\n        $phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n        $phpWord->addParagraphStyle('testStyle', ['indent' => '10']);\n        $section = $phpWord->addSection();\n        $section->addText('test', null, ['numStyle' => 'testStyle', 'numLevel' => '1']);\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $path = '/w:document/w:body/w:p/w:pPr/w:numPr/w:ilvl';\n        self::assertTrue($doc->elementExists($path));\n    }\n\n    public function testLineSpacingExact(): void\n    {\n        $phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n        $section = $phpWord->addSection();\n        $section->addText('test', null, ['spacing' => 240, 'spacingLineRule' => 'exact']);\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $path = '/w:document/w:body/w:p/w:pPr/w:spacing';\n        self::assertTrue($doc->elementExists($path));\n        self::assertEquals('exact', $doc->getElementAttribute($path, 'w:lineRule'));\n        self::assertEquals('240', $doc->getElementAttribute($path, 'w:line'));\n    }\n\n    public function testLineSpacingAuto(): void\n    {\n        $phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n        $section = $phpWord->addSection();\n        $section->addText('test', null, ['spacing' => 240, 'spacingLineRule' => 'auto']);\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $path = '/w:document/w:body/w:p/w:pPr/w:spacing';\n        self::assertTrue($doc->elementExists($path));\n        self::assertEquals('auto', $doc->getElementAttribute($path, 'w:lineRule'));\n        self::assertEquals('480', $doc->getElementAttribute($path, 'w:line'));\n    }\n\n    public function testSuppressAutoHyphens(): void\n    {\n        $paragraphStyle = new ParagraphStyle();\n        $paragraphStyle->setSuppressAutoHyphens(true);\n\n        $phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n        $section = $phpWord->addSection();\n        $section->addText('test', null, $paragraphStyle);\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $path = '/w:document/w:body/w:p/w:pPr/w:suppressAutoHyphens';\n        self::assertTrue($doc->elementExists($path));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/Word2007/Style/SectionTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\Word2007\\Style;\n\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Section.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Section\n *\n * @runTestsInSeparateProcesses\n */\nclass SectionTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Executed before each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    public function testMarginInInches(): void\n    {\n        $unit = Settings::getMeasurementUnit();\n        Settings::setMeasurementUnit(Settings::UNIT_INCH);\n\n        $phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n        $section = $phpWord->addSection();\n        $section->getStyle()->setMarginTop(0.1)->setMarginBottom(0.4)->setMarginLeft(0.2)->setMarginRight(0.3);\n        $section->addText('test');\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n        Settings::setMeasurementUnit($unit);\n\n        $path = '/w:document/w:body/w:sectPr/w:pgMar';\n        self::assertEquals('144', $doc->getElementAttribute($path, 'w:top'));\n        self::assertEquals('432', $doc->getElementAttribute($path, 'w:right'));\n        self::assertEquals('576', $doc->getElementAttribute($path, 'w:bottom'));\n        self::assertEquals('288', $doc->getElementAttribute($path, 'w:left'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/Word2007/Style/TableCellTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\Word2007\\Style;\n\nuse PhpOffice\\PhpWord\\Shared\\Converter;\nuse PhpOffice\\PhpWord\\SimpleType\\TblWidth;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Table.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Table\n *\n * @runTestsInSeparateProcesses\n */\nclass TableCellTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Executed before each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    /**\n     * Test write styles.\n     */\n    public function testCellPadding(): void\n    {\n        $phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n        $section = $phpWord->addSection();\n        $table = $section->addTable();\n        $table->addRow();\n\n        $testValTop = Converter::pixelToTwip(10);\n        $testValRight = Converter::pixelToTwip(11);\n        $testValBottom = Converter::pixelToTwip(12);\n        $testValLeft = Converter::pixelToTwip(13);\n\n        $cellStyle = [\n            'paddingTop' => $testValTop,\n            'paddingRight' => $testValRight,\n            'paddingBottom' => $testValBottom,\n            'paddingLeft' => $testValLeft,\n        ];\n        $table->addCell(null, $cellStyle)->addText('Some text');\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $path = '/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr/w:tcMar/w:top';\n        self::assertTrue($doc->elementExists($path));\n        self::assertEquals($testValTop, $doc->getElementAttribute($path, 'w:w'));\n        self::assertEquals(TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type'));\n\n        $path = '/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr/w:tcMar/w:start';\n        self::assertTrue($doc->elementExists($path));\n        self::assertEquals($testValLeft, $doc->getElementAttribute($path, 'w:w'));\n        self::assertEquals(TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type'));\n\n        $path = '/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr/w:tcMar/w:bottom';\n        self::assertTrue($doc->elementExists($path));\n        self::assertEquals($testValBottom, $doc->getElementAttribute($path, 'w:w'));\n        self::assertEquals(TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type'));\n\n        $path = '/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr/w:tcMar/w:end';\n        self::assertTrue($doc->elementExists($path));\n        self::assertEquals($testValRight, $doc->getElementAttribute($path, 'w:w'));\n        self::assertEquals(TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/Word2007/Style/TableTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\Word2007\\Style;\n\nuse PhpOffice\\PhpWord\\ComplexType\\TblWidth as TblWidthComplexType;\nuse PhpOffice\\PhpWord\\SimpleType\\TblWidth;\nuse PhpOffice\\PhpWord\\Style\\Table;\nuse PhpOffice\\PhpWord\\Style\\TablePosition;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Table.\n *\n * @coversDefaultClass \\PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Table\n *\n * @runTestsInSeparateProcesses\n */\nclass TableTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Executed before each method of the class.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    /**\n     * Test write styles.\n     */\n    public function testTableLayout(): void\n    {\n        $tableStyle = new Table();\n        $tableStyle->setLayout(Table::LAYOUT_FIXED);\n\n        $phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n        $section = $phpWord->addSection();\n        $table = $section->addTable($tableStyle);\n        $table->addRow();\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $path = '/w:document/w:body/w:tbl/w:tblPr/w:tblLayout';\n        self::assertTrue($doc->elementExists($path));\n        self::assertEquals(Table::LAYOUT_FIXED, $doc->getElementAttribute($path, 'w:type'));\n    }\n\n    /**\n     * Test write styles.\n     */\n    public function testCellSpacing(): void\n    {\n        $tableStyle = new Table();\n        $tableStyle->setCellSpacing(10.3);\n\n        $phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n        $section = $phpWord->addSection();\n        $table = $section->addTable($tableStyle);\n        $table->addRow();\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $path = '/w:document/w:body/w:tbl/w:tblPr/w:tblCellSpacing';\n        self::assertTrue($doc->elementExists($path));\n        self::assertEquals(10.3, $doc->getElementAttribute($path, 'w:w'));\n        self::assertEquals(TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type'));\n    }\n\n    /**\n     * Test write table position.\n     */\n    public function testTablePosition(): void\n    {\n        $tablePosition = [\n            'leftFromText' => 10,\n            'rightFromText' => 20,\n            'topFromText' => 30,\n            'bottomFromText' => 40,\n            'vertAnchor' => TablePosition::VANCHOR_PAGE,\n            'horzAnchor' => TablePosition::HANCHOR_MARGIN,\n            'tblpXSpec' => TablePosition::XALIGN_CENTER,\n            'tblpX' => 50,\n            'tblpYSpec' => TablePosition::YALIGN_TOP,\n            'tblpY' => 60,\n        ];\n        $tableStyle = new Table();\n        $tableStyle->setPosition($tablePosition);\n\n        $phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n        $section = $phpWord->addSection();\n        $table = $section->addTable($tableStyle);\n        $table->addRow();\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $path = '/w:document/w:body/w:tbl/w:tblPr/w:tblpPr';\n        self::assertTrue($doc->elementExists($path));\n        self::assertEquals(10, $doc->getElementAttribute($path, 'w:leftFromText'));\n        self::assertEquals(20, $doc->getElementAttribute($path, 'w:rightFromText'));\n        self::assertEquals(30, $doc->getElementAttribute($path, 'w:topFromText'));\n        self::assertEquals(40, $doc->getElementAttribute($path, 'w:bottomFromText'));\n        self::assertEquals(TablePosition::VANCHOR_PAGE, $doc->getElementAttribute($path, 'w:vertAnchor'));\n        self::assertEquals(TablePosition::HANCHOR_MARGIN, $doc->getElementAttribute($path, 'w:horzAnchor'));\n        self::assertEquals(TablePosition::XALIGN_CENTER, $doc->getElementAttribute($path, 'w:tblpXSpec'));\n        self::assertEquals(50, $doc->getElementAttribute($path, 'w:tblpX'));\n        self::assertEquals(TablePosition::YALIGN_TOP, $doc->getElementAttribute($path, 'w:tblpYSpec'));\n        self::assertEquals(60, $doc->getElementAttribute($path, 'w:tblpY'));\n    }\n\n    public function testIndent(): void\n    {\n        $value = 100;\n        $type = TblWidth::TWIP;\n\n        $tableStyle = new Table();\n        $tableStyle->setIndent(new TblWidthComplexType($value, $type));\n\n        $phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n        $section = $phpWord->addSection();\n        $table = $section->addTable($tableStyle);\n        $table->addRow();\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $path = '/w:document/w:body/w:tbl/w:tblPr/w:tblInd';\n        self::assertTrue($doc->elementExists($path));\n        self::assertSame($value, (int) $doc->getElementAttribute($path, 'w:w'));\n        self::assertSame($type, $doc->getElementAttribute($path, 'w:type'));\n    }\n\n    public function testRigthToLeft(): void\n    {\n        $tableStyle = new Table();\n        $tableStyle->setBidiVisual(true);\n\n        $phpWord = new \\PhpOffice\\PhpWord\\PhpWord();\n        $section = $phpWord->addSection();\n        $table = $section->addTable($tableStyle);\n        $table->addRow();\n\n        $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');\n\n        $path = '/w:document/w:body/w:tbl/w:tblPr/w:bidiVisual';\n        self::assertTrue($doc->elementExists($path));\n        self::assertEquals('1', $doc->getElementAttribute($path, 'w:val'));\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/Word2007/StyleTest.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer\\Word2007;\n\nuse PhpOffice\\PhpWord\\Shared\\XMLWriter;\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Frame;\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\Line;\nuse PhpOffice\\PhpWord\\Writer\\Word2007\\Style\\TextBox;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\Word2007\\Style subnamespace.\n */\nclass StyleTest extends \\PHPUnit\\Framework\\TestCase\n{\n    /**\n     * Test empty styles.\n     */\n    public function testEmptyStyles(): void\n    {\n        $styles = [\n            'Cell', 'Font', 'Image', 'Indentation', 'LineNumbering',\n            'Paragraph', 'Row', 'Section', 'Shading', 'Spacing', 'Tab', 'Table',\n            'TextBox', 'Line', 'Shape', 'Frame', 'Outline', 'Fill', 'Shadow', 'Extrusion',\n        ];\n        foreach ($styles as $style) {\n            $objectClass = 'PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007\\\\Style\\\\' . $style;\n            $xmlWriter = new XMLWriter();\n            $object = new $objectClass($xmlWriter);\n            $object->write();\n\n            self::assertEquals('', $xmlWriter->getData());\n        }\n    }\n\n    /**\n     * Test method exceptions.\n     */\n    public function testMethodExceptionsFrame(): void\n    {\n        $xmlWriter = new XMLWriter();\n        $object = new Frame($xmlWriter);\n        $object->writeAlignment();\n\n        self::assertEquals('', $xmlWriter->getData());\n    }\n\n    /**\n     * Test method exceptions.\n     */\n    public function testMethodExceptionsLine(): void\n    {\n        $xmlWriter = new XMLWriter();\n        $object = new Line($xmlWriter);\n        $object->writeStroke();\n\n        self::assertEquals('', $xmlWriter->getData());\n    }\n\n    /**\n     * Test method exceptions.\n     */\n    public function testMethodExceptionsTextBox(): void\n    {\n        $xmlWriter = new XMLWriter();\n        $object = new TextBox($xmlWriter);\n        $object->writeBorder();\n\n        self::assertEquals('', $xmlWriter->getData());\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/Writer/Word2007Test.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests\\Writer;\n\nuse finfo;\nuse PhpOffice\\PhpWord\\PhpWord;\nuse PhpOffice\\PhpWord\\Settings;\nuse PhpOffice\\PhpWord\\SimpleType\\Jc;\nuse PhpOffice\\PhpWord\\Writer\\Word2007;\nuse PhpOffice\\PhpWordTests\\AbstractWebServerEmbedded;\nuse PhpOffice\\PhpWordTests\\TestHelperDOCX;\n\n/**\n * Test class for PhpOffice\\PhpWord\\Writer\\Word2007.\n *\n * @runTestsInSeparateProcesses\n */\nclass Word2007Test extends AbstractWebServerEmbedded\n{\n    /**\n     * Tear down after each test.\n     */\n    protected function tearDown(): void\n    {\n        TestHelperDOCX::clear();\n    }\n\n    /**\n     * Construct.\n     */\n    public function testConstruct(): void\n    {\n        $object = new Word2007(new PhpWord());\n\n        $writerParts = [\n            'ContentTypes' => 'ContentTypes',\n            'Rels' => 'Rels',\n            'DocPropsApp' => 'DocPropsApp',\n            'Document' => 'Document',\n            'Styles' => 'Styles',\n            'Numbering' => 'Numbering',\n            'Settings' => 'Settings',\n            'WebSettings' => 'WebSettings',\n            'Header' => 'Header',\n            'Footer' => 'Footer',\n            'Footnotes' => 'Footnotes',\n            'Endnotes' => 'Footnotes',\n        ];\n        foreach ($writerParts as $part => $type) {\n            self::assertInstanceOf(\n                \"PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007\\\\Part\\\\{$type}\",\n                $object->getWriterPart($part)\n            );\n            self::assertInstanceOf(\n                'PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007',\n                $object->getWriterPart($part)->getParentWriter()\n            );\n        }\n    }\n\n    /**\n     * Save.\n     */\n    public function testSave(): void\n    {\n        $localImage = __DIR__ . '/../_files/images/earth.jpg';\n        $remoteImage = self::getRemoteGifImageUrl();\n        $phpWord = new PhpWord();\n        $phpWord->addFontStyle('Font', ['size' => 11]);\n        $phpWord->addParagraphStyle('Paragraph', ['alignment' => Jc::CENTER]);\n        $section = $phpWord->addSection();\n        $section->addText('Test 1', 'Font', 'Paragraph');\n        $section->addTextBreak();\n        $section->addText('Test 2');\n        $section = $phpWord->addSection();\n        $textrun = $section->addTextRun();\n        $textrun->addText('Test 3');\n        $footnote = $textrun->addFootnote();\n        $footnote->addLink('https://github.com/PHPOffice/PHPWord');\n        $header = $section->addHeader();\n        $header->addImage($localImage);\n        $footer = $section->addFooter();\n        $footer->addImage($remoteImage);\n\n        $writer = new Word2007($phpWord);\n        $file = __DIR__ . '/../_files/temp.docx';\n        $writer->save($file);\n\n        self::assertFileExists($file);\n\n        unlink($file);\n    }\n\n    /**\n     * Save using disk caching.\n     */\n    public function testSaveUseDiskCaching(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $section->addText('Test');\n        $footnote = $section->addFootnote();\n        $footnote->addText('Test');\n\n        $writer = new Word2007($phpWord);\n        $dir = Settings::getTempDir() . DIRECTORY_SEPARATOR . 'phpwordcachefooter';\n        if (!is_dir($dir) && !mkdir($dir)) {\n            self::fail('Unable to create temp directory');\n        }\n        $writer->setUseDiskCaching(true, $dir);\n        $file = __DIR__ . '/../_files/temp.docx';\n        $writer->save($file);\n\n        self::assertFileExists($file);\n\n        unlink($file);\n        TestHelperDOCX::deleteDir($dir);\n    }\n\n    /**\n     * Check content types.\n     */\n    public function testCheckContentTypes(): void\n    {\n        $images = [\n            'mars_noext_jpg' => '1.jpg',\n            'mars.jpg' => '2.jpg',\n            'mario.gif' => '3.gif',\n            'firefox.png' => '4.png',\n            'duke_nukem.bmp' => '5.bmp',\n            'angela_merkel.tif' => '6.tif',\n        ];\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        foreach ($images as $source => $target) {\n            $section->addImage(__DIR__ . \"/../_files/images/{$source}\");\n        }\n\n        $doc = TestHelperDOCX::getDocument($phpWord);\n        $mediaPath = $doc->getPath() . '/word/media';\n\n        foreach ($images as $source => $target) {\n            self::assertFileEquals(\n                __DIR__ . \"/../_files/images/{$source}\",\n                $mediaPath . \"/section_image{$target}\"\n            );\n        }\n    }\n\n    /**\n     * Get writer part return null value.\n     */\n    public function testGetWriterPartNull(): void\n    {\n        $object = new Word2007();\n        self::assertNull($object->getWriterPart());\n    }\n\n    /**\n     * Set/get use disk caching.\n     */\n    public function testSetGetUseDiskCaching(): void\n    {\n        $phpWord = new PhpWord();\n        $phpWord->addSection();\n        $object = new Word2007($phpWord);\n        $object->setUseDiskCaching(true, PHPWORD_TESTS_BASE_DIR);\n        $writer = new Word2007($phpWord);\n        ob_start();\n        $writer->save('php://output');\n        $contents = ob_get_contents();\n        self::assertTrue(ob_end_clean());\n        self::assertTrue($object->isUseDiskCaching());\n        self::assertNotEmpty($contents);\n    }\n\n    /**\n     * Use disk caching exception.\n     */\n    public function testSetUseDiskCachingException(): void\n    {\n        $this->expectException(\\PhpOffice\\PhpWord\\Exception\\Exception::class);\n        $dir = implode(DIRECTORY_SEPARATOR, [PHPWORD_TESTS_BASE_DIR, 'foo']);\n\n        $object = new Word2007();\n        $object->setUseDiskCaching(true, $dir);\n    }\n\n    /**\n     * File is detected as Word 2007.\n     */\n    public function testMime(): void\n    {\n        $phpWord = new PhpWord();\n        $section = $phpWord->addSection();\n        $section->addText('Test 1');\n\n        $writer = new Word2007($phpWord);\n        $file = __DIR__ . '/../_files/temp.docx';\n        $writer->save($file);\n\n        $finfo = new finfo(FILEINFO_MIME_TYPE);\n        $mime = $finfo->file($file);\n\n        self::assertEquals('application/vnd.openxmlformats-officedocument.wordprocessingml.document', $mime);\n\n        unlink($file);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/XmlDocument.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nnamespace PhpOffice\\PhpWordTests;\n\nuse DOMDocument;\nuse DOMElement;\nuse DOMNode;\nuse DOMNodeList;\nuse DOMXPath;\n\n/**\n * DOM wrapper class.\n */\nclass XmlDocument\n{\n    /**\n     * Path.\n     *\n     * @var string\n     */\n    private $path;\n\n    /**\n     * DOMDocument object.\n     *\n     * @var DOMDocument\n     */\n    private $dom;\n\n    /**\n     * DOMXPath object.\n     *\n     * @var DOMXPath\n     */\n    private $xpath;\n\n    /**\n     * File name.\n     *\n     * @var string\n     */\n    private $file;\n\n    /**\n     * Default file name.\n     *\n     * @var string\n     */\n    private $defaultFile = 'word/document.xml';\n\n    /**\n     * Create new instance.\n     *\n     * @param string $path\n     */\n    public function __construct($path)\n    {\n        $this->path = realpath($path);\n    }\n\n    /**\n     * Get default file.\n     */\n    public function getDefaultFile(): string\n    {\n        return $this->defaultFile;\n    }\n\n    /**\n     * Set default file.\n     */\n    public function setDefaultFile(string $file): string\n    {\n        $temp = $this->defaultFile;\n\n        $this->defaultFile = $file;\n\n        return $temp;\n    }\n\n    /**\n     * Get file name.\n     */\n    public function getFile(): string\n    {\n        return $this->file;\n    }\n\n    /**\n     * Get path.\n     */\n    public function getPath(): string\n    {\n        return $this->path;\n    }\n\n    /**\n     * Get DOM from file.\n     */\n    public function getFileDom(string $file = ''): DOMDocument\n    {\n        if (!$file) {\n            $file = $this->defaultFile;\n        }\n        if (null !== $this->dom && $file === $this->file) {\n            return $this->dom;\n        }\n\n        $this->xpath = null;\n        $this->file = $file;\n\n        $file = $this->path . '/' . $file;\n        if (\\PHP_VERSION_ID < 80000) {\n            $orignalLibEntityLoader = libxml_disable_entity_loader(false);\n        }\n        $this->dom = new DOMDocument();\n        $this->dom->load($file);\n        if (\\PHP_VERSION_ID < 80000) {\n            libxml_disable_entity_loader($orignalLibEntityLoader);\n        }\n\n        return $this->dom;\n    }\n\n    /**\n     * Get node list.\n     *\n     * @return DOMNodeList<DOMNode>\n     */\n    public function getNodeList(string $path, string $file = ''): DOMNodeList\n    {\n        if (!$file) {\n            $file = $this->defaultFile;\n        }\n        if (null === $this->dom || $file !== $this->file) {\n            $this->getFileDom($file);\n        }\n\n        if (null === $this->xpath) {\n            $this->xpath = new DOMXPath($this->dom);\n            $this->xpath->registerNamespace('w14', 'http://schemas.microsoft.com/office/word/2010/wordml');\n        }\n\n        return $this->xpath->query($path);\n    }\n\n    /**\n     * Get element.\n     */\n    public function getElement(string $path, string $file = ''): ?DOMElement\n    {\n        return $this->getNodeList($path, $file)->item(0);\n    }\n\n    /**\n     * Get element attribute.\n     */\n    public function getElementAttribute(string $path, string $attribute, string $file = ''): string\n    {\n        return $this->getElement($path, $file)->getAttribute($attribute);\n    }\n\n    /**\n     * Return if element attribute exists.\n     */\n    public function hasElementAttribute(string $path, string $attribute, string $file = ''): bool\n    {\n        return $this->getElement($path, $file)->hasAttribute($attribute);\n    }\n\n    /**\n     * Check if element exists.\n     */\n    public function elementExists(string $path, string $file = ''): bool\n    {\n        $nodeList = $this->getNodeList($path, $file);\n\n        return $nodeList->length != 0;\n    }\n\n    /**\n     * Returns the xml, or part of it as a formatted string.\n     *\n     * @return false|string\n     */\n    public function printXml(string $path = '/', string $file = '')\n    {\n        $element = $this->getElement($path, $file);\n\n        $newdoc = new DOMDocument();\n        $newdoc->formatOutput = true;\n        $newdoc->preserveWhiteSpace = false;\n        $node = $newdoc->importNode($element, true);\n        $newdoc->appendChild($node);\n\n        return $newdoc->saveXML($node);\n    }\n}\n"
  },
  {
    "path": "tests/PhpWordTests/_files/documents/reader.html",
    "content": "<html>\n<head>\n<meta charset=\"UTF-8\" />\n<title>PHPWord</title>\n</head>\n<body>\n<h1>Adding element via HTML</h1>\n<p>Some well formed HTML snippet needs to be used</p>\n<p>With for example <strong>some<sup>1</sup> <em>inline</em> formatting</strong><sub>1</sub></p>\n<p>Unordered (bulleted) list:</p>\n<ul><li>Item 1</li><li>Item 2</li><ul><li>Item 2.1</li><li>Item 2.1</li></ul></ul>\n<p>Ordered (numbered) list:</p>\n<ol><li>Item 1</li><li>Item 2</li></ol>\n</body>\n</html>\n"
  },
  {
    "path": "tests/PhpWordTests/_files/documents/reader.rtf",
    "content": "{\\rtf1\n\\ansi\\ansicpg1252\n\\deff0\n{\\fonttbl{\\f0\\fnil\\fcharset0 Arial;}{\\f1\\fnil\\fcharset0 Times New Roman;}}\n{\\colortbl;\\red255\\green0\\blue0;\\red14\\green0\\blue0}\n{\\*\\generator PhpWord;}\n\n{\\info{\\title }{\\subject }{\\category }{\\keywords }{\\comment }{\\author }{\\operator }{\\creatim \\yr2014\\mo05\\dy27\\hr23\\min36\\sec45}{\\revtim \\yr2014\\mo05\\dy27\\hr23\\min36\\sec45}{\\company }{\\manager }}\n\\deftab720\\viewkind1\\uc1\\pard\\nowidctlpar\\lang1036\\kerning1\\fs20\n{Welcome to PhpWord}\\par\n\\pard\\nowidctlpar{\\cf0\\f0 Hello World!}\\par\n\\par\n\\par\n\\pard\\nowidctlpar{\\cf0\\f0\\fs32\\b\\i I am styled by a <font style> definition.}\\par\n\\pard\\nowidctlpar{\\cf0\\f0 I am styled by a paragraph style definition.}\\par\n\\pard\\nowidctlpar\\qc\\sa100{\\cf0\\f0\\fs32\\b\\i I am styled by both font and paragraph style.}\\par\n\\pard\\nowidctlpar{\\cf1\\f1\\fs40\\b\\i\\ul\\strike\\super I am inline styled.}\\par\n\\par\n{\\field {\\*\\fldinst {HYPERLINK \"https://github.com/PHPOffice/PHPWord\"}}{\\fldrslt {PHPWord on GitHub}}}\\par\n\\par\n}"
  },
  {
    "path": "tests/PhpWordTests/_files/xsl/passthrough.xsl",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"\n>\n\n    <xsl:template match='@*|node()'>\n        <xsl:copy>\n            <xsl:apply-templates select='@*|node()'/>\n        </xsl:copy>\n    </xsl:template>\n\n</xsl:stylesheet>"
  },
  {
    "path": "tests/PhpWordTests/_files/xsl/remove_tables_by_needle.xsl",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<xsl:stylesheet\n    version=\"1.0\"\n    xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"\n    xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\">\n\n  <xsl:template match='@*|node()'>\n    <xsl:copy>\n      <xsl:apply-templates select='@*|node()'/>\n    </xsl:copy>\n  </xsl:template>\n\n  <xsl:template match=\"//w:tbl\">\n    <xsl:choose>\n      <xsl:when test=\"w:tr/w:tc/w:p/w:r/w:t[contains(., $needle)]\"/>\n      <xsl:otherwise>\n        <xsl:copy>\n          <xsl:apply-templates select='@*|node()'/>\n        </xsl:copy>\n      </xsl:otherwise>\n    </xsl:choose>\n  </xsl:template>\n\n</xsl:stylesheet>\n"
  },
  {
    "path": "tests/bootstrap.php",
    "content": "<?php\n\n/**\n * This file is part of PHPWord - A pure PHP library for reading and writing\n * word processing documents.\n *\n * PHPWord is free software distributed under the terms of the GNU Lesser\n * General Public License version 3 as published by the Free Software Foundation.\n *\n * For the full copyright and license information, please read the LICENSE\n * file that was distributed with this source code. For the full list of\n * contributors, visit https://github.com/PHPOffice/PHPWord/contributors. test bootstrap\n *\n * @see         https://github.com/PHPOffice/PHPWord\n *\n * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3\n */\n\nrequire dirname(__DIR__) . '/vendor/autoload.php';\n\ndate_default_timezone_set('UTC');\n\n// defining base dir for tests\nif (!defined('PHPWORD_TESTS_BASE_DIR')) {\n    define('PHPWORD_TESTS_BASE_DIR', realpath(__DIR__));\n}\n\nfunction phpunit10ErrorHandler(int $errno, string $errstr, string $filename, int $lineno): bool\n{\n    $x = error_reporting() & $errno;\n    if (\n        in_array(\n            $errno,\n            [\n                E_DEPRECATED,\n                E_WARNING,\n                E_NOTICE,\n                E_USER_DEPRECATED,\n                E_USER_NOTICE,\n                E_USER_WARNING,\n            ],\n            true\n        )\n    ) {\n        if (0 === $x) {\n            return true; // message suppressed - stop error handling\n        }\n\n        throw new Exception(\"$errstr $filename $lineno\");\n    }\n\n    return false; // continue error handling\n}\n\nfunction utf8decode(string $value, string $toEncoding = 'ISO-8859-1'): string\n{\n    $result = function_exists('mb_convert_encoding') ? mb_convert_encoding($value, $toEncoding, 'UTF-8') : utf8_decode($value);\n\n    return $result === false ? '' : $result;\n}\n\n// @phpstan-ignore-next-line\nif (!method_exists(PHPUnit\\Framework\\TestCase::class, 'setOutputCallback')) {\n    ini_set('error_reporting', (string) E_ALL);\n    set_error_handler('phpunit10ErrorHandler');\n}\n"
  }
]