pax_global_header00006660000000000000000000000064142551157270014523gustar00rootroot0000000000000052 comment=00e0b7c02bfbfbb487f5f1480493d3f53afba759 sejda-io-2.1.4/000077500000000000000000000000001425511572700132225ustar00rootroot00000000000000sejda-io-2.1.4/.github/000077500000000000000000000000001425511572700145625ustar00rootroot00000000000000sejda-io-2.1.4/.github/workflows/000077500000000000000000000000001425511572700166175ustar00rootroot00000000000000sejda-io-2.1.4/.github/workflows/build.yml000066400000000000000000000007031425511572700204410ustar00rootroot00000000000000name: build on: [push] jobs: build: runs-on: ubuntu-latest strategy: matrix: java: ['8', '11', '17'] name: JDK ${{ matrix.java }} steps: - uses: actions/checkout@v2 - name: Set up JDK uses: actions/setup-java@v2 with: java-version: ${{ matrix.java }} distribution: 'temurin' cache: 'maven' - name: Build with Maven run: mvn --batch-mode --update-snapshots verifysejda-io-2.1.4/.gitignore000066400000000000000000000002001425511572700152020ustar00rootroot00000000000000*.class .classpath .project .launch .settings/ target/ .externalToolBuilders/ .idea *.iml # Package Files # *.jar *.war *.ear sejda-io-2.1.4/LICENSE000066400000000000000000000240411425511572700142300ustar00rootroot00000000000000Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: You must give any other recipients of the Work or Derivative Works a copy of this License; and You must cause any modified files to carry prominent notices stating that You changed the files; and You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. sejda-io-2.1.4/README.md000066400000000000000000000004671425511572700145100ustar00rootroot00000000000000Sejda-io (http://www.sejda.org) ===== ![Build Status](https://github.com/torakiki/sejda-io/actions/workflows/build.yml/badge.svg) [![License](http://img.shields.io/badge/license-APLv2-blue.svg)](http://www.apache.org/licenses/LICENSE-2.0.html) A layer of Input/Output classes built on top of java io and nio. sejda-io-2.1.4/development/000077500000000000000000000000001425511572700155445ustar00rootroot00000000000000sejda-io-2.1.4/development/eclipse/000077500000000000000000000000001425511572700171705ustar00rootroot00000000000000sejda-io-2.1.4/development/eclipse/checkstyle plugin/000077500000000000000000000000001425511572700226055ustar00rootroot00000000000000sejda-io-2.1.4/development/eclipse/checkstyle plugin/checkstyle.xml000066400000000000000000000105061425511572700254670ustar00rootroot00000000000000 sejda-io-2.1.4/development/eclipse/checkstyle plugin/suppression.xml000066400000000000000000000003611425511572700257210ustar00rootroot00000000000000 sejda-io-2.1.4/development/eclipse/code_format.xml000066400000000000000000000716461425511572700222120ustar00rootroot00000000000000 sejda-io-2.1.4/development/eclipse/codetemplates.xml000066400000000000000000000016231425511572700225450ustar00rootroot00000000000000sejda-io-2.1.4/development/eclipse/eclipse_compiler_and_style_settings.epf000066400000000000000000002207031425511572700271700ustar00rootroot00000000000000#Thu Sep 13 17:30:06 CEST 2018 \!/= /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.codegen.targetPlatform=10 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.compliance=10 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.assertIdentifier=error /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.emptyStatement=warning /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.enumIdentifier=error /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.fieldHiding=warning /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=error /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=error /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.noEffectAssignment=error /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=info /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=error /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=error /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=disabled /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unusedImport=error /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=error /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.source=10 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.align_type_members_on_columns=false /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=0 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_assignment=0 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_enum_constants=49 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_module_statements=16 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=82 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.blank_lines_after_package=1 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.blank_lines_before_field=0 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.blank_lines_before_method=1 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.blank_lines_before_package=0 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped=false /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions=false /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=false /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.format_block_comments=true /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.format_header=false /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.format_html=true /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.format_line_comments=true /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.format_source_code=true /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.indent_root_tags=true /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.line_length=180 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.compact_else_if=true /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.continuation_indentation=2 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.indent_empty_lines=false /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.indentation.size=8 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.join_lines_in_comments=true /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.join_wrapped_lines=true /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.lineSplit=120 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.tabulation.char=space /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.tabulation.size=4 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.use_on_off_tags=false /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true /instance/org.eclipse.jdt.ui/formatter_profile=_pdfsam /instance/org.eclipse.jdt.ui/formatter_settings_version=14 /instance/org.eclipse.jdt.ui/org.eclipse.jdt.ui.exception.name=e /instance/org.eclipse.jdt.ui/org.eclipse.jdt.ui.formatterprofiles=\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n /instance/org.eclipse.jdt.ui/org.eclipse.jdt.ui.formatterprofiles.version=14 /instance/org.eclipse.jdt.ui/org.eclipse.jdt.ui.gettersetter.use.is=true /instance/org.eclipse.jdt.ui/org.eclipse.jdt.ui.javadoc=true /instance/org.eclipse.jdt.ui/org.eclipse.jdt.ui.overrideannotation=true /instance/org.eclipse.jdt.ui/org.eclipse.jdt.ui.text.custom_code_templates= @org.eclipse.jdt.core=3.14.0.v20180528-0519 @org.eclipse.jdt.ui=3.14.0.v20180529-1023 file_export_version=3.0 sejda-io-2.1.4/pom.xml000066400000000000000000000146151425511572700145460ustar00rootroot00000000000000 4.0.0 org.sejda sejda-io jar sejda-io 2.1.4 An Input/Output layer built on top of Java standard io and nio packages http://www.sejda.org GitHub https://github.com/torakiki/sejda-io/ sejda http://www.sejda.org Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0 repo ASLv2 UTF-8 scm:git:git@github.com:torakiki/sejda-io.git scm:git:git@github.com:torakiki/sejda-io.git scm:git:git@github.com:torakiki/sejda-io.git v2.1.4 torakiki Andrea Vacondio andrea.vacondio@gmail.com ediweissmann Eduard Weissmann edi.weissmann@gmail.com sonatype-nexus-snapshots https://oss.sonatype.org/content/repositories/snapshots sonatype-nexus-staging https://oss.sonatype.org/service/local/staging/deploy/maven2/ toolchain env.CI !true org.apache.maven.plugins maven-toolchains-plugin 3.0.0 toolchain 8 release org.apache.maven.plugins maven-javadoc-plugin 3.3.1 attach-javadocs jar -Xdoclint:none org.apache.maven.plugins maven-release-plugin 3.0.0-M4 v@{project.version} clean install org.apache.maven.plugins maven-gpg-plugin 3.0.1 sign-artifacts verify sign org.sonatype.plugins nexus-staging-maven-plugin 1.6.8 true ossrh https://oss.sonatype.org/ true org.apache.maven.plugins maven-compiler-plugin 3.8.1 1.8 1.8 org.apache.maven.plugins maven-jar-plugin 3.2.0 org.sejda.io org.apache.maven.plugins maven-source-plugin 3.2.0 attach-sources jar-no-fork org.apache.maven.plugins maven-surefire-plugin 3.0.0-M5 org.slf4j slf4j-api 1.7.36 org.sejda sejda-commons 1.1.7 ch.qos.logback logback-classic 1.2.11 test ch.qos.logback logback-core 1.2.11 test org.mockito mockito-core 4.6.1 test org.junit.jupiter junit-jupiter-engine 5.8.2 test org.hamcrest hamcrest-library 2.2 test sejda-io-2.1.4/src/000077500000000000000000000000001425511572700140115ustar00rootroot00000000000000sejda-io-2.1.4/src/main/000077500000000000000000000000001425511572700147355ustar00rootroot00000000000000sejda-io-2.1.4/src/main/java/000077500000000000000000000000001425511572700156565ustar00rootroot00000000000000sejda-io-2.1.4/src/main/java/org/000077500000000000000000000000001425511572700164455ustar00rootroot00000000000000sejda-io-2.1.4/src/main/java/org/sejda/000077500000000000000000000000001425511572700175335ustar00rootroot00000000000000sejda-io-2.1.4/src/main/java/org/sejda/io/000077500000000000000000000000001425511572700201425ustar00rootroot00000000000000sejda-io-2.1.4/src/main/java/org/sejda/io/BaseSeekableSource.java000066400000000000000000000031661425511572700245020ustar00rootroot00000000000000/* * Copyright 2018 Sober Lemur S.a.s. di Vacondio Andrea * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.io; import static org.sejda.commons.util.RequireUtils.requireNotBlank; import static org.sejda.commons.util.RequireUtils.requireState; import java.io.IOException; /** * Abstract {@link SeekableSource} that provides base functionalities common to all the {@link SeekableSource}s. * * @author Andrea Vacondio */ public abstract class BaseSeekableSource implements SeekableSource { private boolean open = true; private String id; public BaseSeekableSource(String id) { requireNotBlank(id, "SeekableSource id cannot be blank"); this.id = id; } @Override public boolean isOpen() { return open; } @Override public void close() throws IOException { this.open = false; } @Override public void requireOpen() throws IOException { requireState(isOpen(), "The SeekableSource has been closed"); } /** * @return the unique id for this source */ @Override public String id() { return id; } } sejda-io-2.1.4/src/main/java/org/sejda/io/BufferedCountingChannelWriter.java000066400000000000000000000074671425511572700267420ustar00rootroot00000000000000/* * Copyright 2018 Sober Lemur S.a.s. di Vacondio Andrea * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.io; import static org.sejda.commons.util.RequireUtils.requireNotNullArg; import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.nio.charset.StandardCharsets; import org.sejda.commons.util.IOUtils; /** * Component providing methods to write to a {@link CountingWritableByteChannel}. This implementation is buffered and bytes are flushed to the {@link CountingWritableByteChannel} * only when the buffer is full. The buffer size is configurable using the OUTPUT_BUFFER_SIZE_PROPERTY property. * * @author Andrea Vacondio */ public class BufferedCountingChannelWriter implements Closeable { public static final String OUTPUT_BUFFER_SIZE_PROPERTY = "org.sejda.io.buffered.output.size"; private static final byte EOL = '\n'; private CountingWritableByteChannel channel; private ByteBuffer buffer = ByteBuffer.allocate(Integer.getInteger(OUTPUT_BUFFER_SIZE_PROPERTY, 4096)); private boolean onNewLine = false; public BufferedCountingChannelWriter(CountingWritableByteChannel channel) { requireNotNullArg(channel, "Cannot write to a null channell"); this.channel = channel; } @Override public void close() throws IOException { if (channel.isOpen() && buffer.position() != 0) { flush(); } IOUtils.close(channel); } public void writeEOL() throws IOException { if (!onNewLine) { write(EOL); onNewLine = true; } } /** * Writes the given string in {@link StandardCharsets#ISO_8859_1} * * @param value * @throws IOException */ public void write(String value) throws IOException { write(value.getBytes(StandardCharsets.ISO_8859_1)); } /** * Writes the given bytes to the destination * * @param bytes * @throws IOException */ public void write(byte[] bytes) throws IOException { for (int i = 0; i < bytes.length; i++) { write(bytes[i]); } } /** * Writes the single byte to the destination * * @param myByte * @throws IOException */ public void write(byte myByte) throws IOException { onNewLine = false; buffer.put(myByte); if (!buffer.hasRemaining()) { flush(); } } /** * Writes everything that is read from the {@link InputStream} to the destination * * @param stream * @throws IOException */ public void write(InputStream stream) throws IOException { onNewLine = false; try (ReadableByteChannel readable = Channels.newChannel(stream)) { flush(); while (readable.read(buffer) != -1) { flush(); } } } /** * @return the current offset in the output */ public long offset() { return channel.count() + buffer.position(); } /** * Flush the buffer * * @throws IOException */ public void flush() throws IOException { buffer.flip(); channel.write(buffer); buffer.clear(); } } sejda-io-2.1.4/src/main/java/org/sejda/io/BufferedSeekableSource.java000066400000000000000000000103121425511572700253410ustar00rootroot00000000000000/* * Copyright 2018 Sober Lemur S.a.s. di Vacondio Andrea * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.io; import static java.util.Optional.ofNullable; import static org.sejda.commons.util.RequireUtils.requireArg; import static org.sejda.commons.util.RequireUtils.requireNotBlank; import static org.sejda.commons.util.RequireUtils.requireNotNullArg; import static org.sejda.commons.util.RequireUtils.requireState; import java.io.IOException; import java.nio.ByteBuffer; import org.sejda.commons.util.IOUtils; /** * {@link SeekableSource} wrapping an existing one and providing buffered read. When a read method is called, a {@link SeekableSources#INPUT_BUFFER_SIZE_PROPERTY} long chunk of * bytes is read from the underlying source and stored in memory. Subsequent reads are served from the in memory buffer until they fall outside its range, at that point a new * buffer is read from the wrapped source. * * @author Andrea Vacondio */ public class BufferedSeekableSource implements SeekableSource { private ByteBuffer buffer = ByteBuffer.allocate( Integer.getInteger(SeekableSources.INPUT_BUFFER_SIZE_PROPERTY, 8192)); private SeekableSource wrapped; private long position; private long size; public BufferedSeekableSource(SeekableSource wrapped) { requireNotNullArg(wrapped, "Input decorated SeekableSource cannot be null"); this.wrapped = wrapped; this.size = wrapped.size(); this.buffer.limit(0); } @Override public boolean isOpen() { return this.wrapped.isOpen(); } @Override public void requireOpen() throws IOException { this.wrapped.requireOpen(); } /** * @return the unique id for this source */ @Override public String id() { return this.wrapped.id(); } @Override public long position() { return this.position; } @Override public SeekableSource position(long newPosition) throws IOException { requireArg(newPosition >= 0, "Cannot set position to a negative value"); if (newPosition != this.position) { long newBufPosition = newPosition - position + buffer.position(); if (newBufPosition >= 0 && newBufPosition < buffer.limit()) { buffer.position((int) newBufPosition); } else { buffer.limit(0); wrapped.position(newPosition); } this.position = Math.min(newPosition, size); } return this; } @Override public long size() { return size; } @Override public void close() throws IOException { IOUtils.close(wrapped); buffer.clear(); buffer.limit(0); } @Override public int read(ByteBuffer dst) throws IOException { requireOpen(); buffer.limit(0); wrapped.position(position); int read = wrapped.read(dst); if (read > 0) { position += read; } return read; } @Override public int read() throws IOException { requireOpen(); if (ensureBuffer() > 0) { position++; return buffer.get() & 0xff; } return -1; } private int ensureBuffer() throws IOException { if (!buffer.hasRemaining()) { buffer.clear(); wrapped.read(buffer); buffer.flip(); } return buffer.remaining(); } protected SeekableSource wrapped() { return wrapped; } @Override public SeekableSource view(long startingPosition, long length) throws IOException { requireOpen(); return new BufferedSeekableSource(wrapped.view(startingPosition, length)); } } sejda-io-2.1.4/src/main/java/org/sejda/io/ByteArraySeekableSource.java000066400000000000000000000051151425511572700255260ustar00rootroot00000000000000/* * Copyright 2018 Sober Lemur S.a.s. di Vacondio Andrea * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.io; import static java.util.Optional.ofNullable; import static org.sejda.commons.util.RequireUtils.requireArg; import java.io.IOException; import java.nio.ByteBuffer; import java.util.UUID; /** * A byte array based {@link SeekableSource} with a max size of 2GB. * * @author Andrea Vacondio */ public class ByteArraySeekableSource extends BaseSeekableSource { private byte[] bytes; private long position; public ByteArraySeekableSource(byte[] bytes) { super(ofNullable(bytes).map(UUID::nameUUIDFromBytes).map(UUID::toString).orElseThrow(() -> { return new IllegalArgumentException("Input byte array cannot be null"); })); this.bytes = bytes; } @Override public long position() { return position; } @Override public SeekableSource position(long position) { requireArg(position >= 0, "Cannot set position to a negative value"); this.position = Math.min(position, size()); return this; } @Override public long size() { return bytes.length; } @Override public int read(ByteBuffer dst) throws IOException { requireOpen(); if (position < size()) { int toCopy = (int) Math.min(dst.remaining(), size() - position); dst.put(bytes, (int) position, toCopy); position += toCopy; return toCopy; } return -1; } @Override public int read() throws IOException { requireOpen(); if (position < size()) { return bytes[(int) position++] & 0xff; } return -1; } @Override public void close() throws IOException { super.close(); this.bytes = new byte[0]; } @Override public SeekableSource view(long startingPosition, long length) throws IOException { requireOpen(); return new SeekableSourceView(() -> new ByteArraySeekableSource(bytes), id(), startingPosition, length); } } sejda-io-2.1.4/src/main/java/org/sejda/io/CountingWritableByteChannel.java000066400000000000000000000076371425511572700264170ustar00rootroot00000000000000/* * Copyright 2018 Sober Lemur S.a.s. di Vacondio Andrea * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.io; import static org.sejda.commons.util.RequireUtils.requireNotNullArg; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.Channels; import java.nio.channels.ClosedChannelException; import java.nio.channels.WritableByteChannel; import org.sejda.commons.util.IOUtils; /** * A {@link WritableByteChannel} that keeps track of the number of written bytes * * @author Andrea Vacondio */ public class CountingWritableByteChannel implements WritableByteChannel { private long written = 0; private WritableByteChannel wrapped; public CountingWritableByteChannel(WritableByteChannel wrapped) { requireNotNullArg(wrapped, "Cannot decorate a null instance"); this.wrapped = wrapped; } /** * @return the number of written bytes */ public long count() { return written; } @Override public int write(ByteBuffer src) throws IOException { if (!isOpen()) { throw new ClosedChannelException(); } int count = wrapped.write(src); written += count; return count; } @Override public boolean isOpen() { return wrapped.isOpen(); } @Override public void close() throws IOException { IOUtils.close(wrapped); } /** * Static factory method to create a {@link CountingWritableByteChannel} from an existing {@link WritableByteChannel}. * * @param channel * @return the newly created {@link CountingWritableByteChannel} */ public static CountingWritableByteChannel from(WritableByteChannel channel) { return new CountingWritableByteChannel(channel); } /** * Static factory method to create a {@link CountingWritableByteChannel} from an existing {@link OutputStream}. * * @param stream * @return the newly created {@link CountingWritableByteChannel} */ public static CountingWritableByteChannel from(OutputStream stream) { return new CountingWritableByteChannel(Channels.newChannel(stream)); } /** * Static factory method to create a {@link CountingWritableByteChannel} from an existing {@link File}. If the file already exists its content is purged. * * @param file * @return the newly created {@link CountingWritableByteChannel} * @throws IOException * @see RandomAccessFile#RandomAccessFile(File, String) */ public static CountingWritableByteChannel from(File file) throws IOException { RandomAccessFile raf = new RandomAccessFile(file, "rw"); raf.setLength(0); return new CountingWritableByteChannel(raf.getChannel()); } /** * Static factory method to create a {@link CountingWritableByteChannel} from an existing file path. If the file already exists its content is purged. * * @param file * @return the newly created {@link CountingWritableByteChannel} * @throws IOException * @see RandomAccessFile#RandomAccessFile(String, String) */ public static CountingWritableByteChannel from(String file) throws IOException { RandomAccessFile raf = new RandomAccessFile(file, "rw"); raf.setLength(0); return new CountingWritableByteChannel(raf.getChannel()); } } sejda-io-2.1.4/src/main/java/org/sejda/io/DevNullWritableByteChannel.java000066400000000000000000000022061425511572700261650ustar00rootroot00000000000000/* * Copyright 2018 Sober Lemur S.a.s. di Vacondio Andrea * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.io; import java.nio.ByteBuffer; import java.nio.channels.WritableByteChannel; /** * {@link WritableByteChannel} that does nothing . * * @author Andrea Vacondio * */ public class DevNullWritableByteChannel implements WritableByteChannel { private boolean open = true; @Override public boolean isOpen() { return open; } @Override public void close() { this.open = false; } @Override public int write(ByteBuffer src) { return src.remaining(); } } sejda-io-2.1.4/src/main/java/org/sejda/io/FileChannelSeekableSource.java000066400000000000000000000056161425511572700260020ustar00rootroot00000000000000/* * Copyright 2018 Sober Lemur S.a.s. di Vacondio Andrea * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.io; import static java.util.Optional.ofNullable; import static org.sejda.commons.util.RequireUtils.requireArg; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import org.sejda.commons.util.IOUtils; /** * A {@link SeekableSource} implementation based on {@link FileChannel}. * * @author Andrea Vacondio */ public class FileChannelSeekableSource extends BaseSeekableSource { private FileChannel channel; private File file; private long size; private ThreadBoundCopiesSupplier localCopiesSupplier = new ThreadBoundCopiesSupplier<>( () -> new FileChannelSeekableSource(file)); public FileChannelSeekableSource(File file) throws IOException { super(ofNullable(file).map(File::getAbsolutePath).orElseThrow(() -> { return new IllegalArgumentException("Input file cannot be null"); })); this.channel = new RandomAccessFile(file, "r").getChannel(); this.size = channel.size(); this.file = file; } @Override public long position() throws IOException { return channel.position(); } @Override public SeekableSource position(long newPosition) throws IOException { requireArg(newPosition >= 0, "Cannot set position to a negative value"); channel.position(newPosition); return this; } @Override public long size() { return size; } @Override public void close() throws IOException { super.close(); IOUtils.close(localCopiesSupplier); IOUtils.close(channel); } @Override public int read(ByteBuffer dst) throws IOException { requireOpen(); return channel.read(dst); } @Override public int read() throws IOException { requireOpen(); ByteBuffer buffer = ByteBuffer.allocate(1); if (channel.read(buffer) > 0) { buffer.flip(); return buffer.get() & 0xff; } return -1; } @Override public SeekableSource view(long startingPosition, long length) throws IOException { requireOpen(); return new SeekableSourceView(localCopiesSupplier, id(), startingPosition, length); } } sejda-io-2.1.4/src/main/java/org/sejda/io/MemoryMappedSeekableSource.java000066400000000000000000000136601425511572700262270ustar00rootroot00000000000000/* * Copyright 2018 Sober Lemur S.a.s. di Vacondio Andrea * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.io; import static java.util.Optional.ofNullable; import static org.sejda.commons.util.RequireUtils.requireArg; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileChannel.MapMode; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.function.Consumer; import org.sejda.io.util.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A {@link SeekableSource} implementation based on MappedByteBuffer. To overcome the int limit of the MappedByteBuffer, this source implement a pagination algorithm allowing to * open files of any size. The size of the pages can be configured using the {@link SeekableSources#MEMORY_MAPPED_PAGE_SIZE_PROPERTY} system property. * * @author Andrea Vacondio * */ public class MemoryMappedSeekableSource extends BaseSeekableSource { private static final Logger LOG = LoggerFactory.getLogger(MemoryMappedSeekableSource.class); private static final long MB_256 = 1 << 28; private final long pageSize = Long.getLong(SeekableSources.MEMORY_MAPPED_PAGE_SIZE_PROPERTY, MB_256); private List pages = new ArrayList<>(); private long position; private long size; private ThreadBoundCopiesSupplier localCopiesSupplier = new ThreadBoundCopiesSupplier<>( () -> new MemoryMappedSeekableSource(this)); private Consumer unmapper = IOUtils::unmap; public MemoryMappedSeekableSource(File file) throws IOException { super(ofNullable(file).map(File::getAbsolutePath).orElseThrow(() -> { return new IllegalArgumentException("Input file cannot be null"); })); try (FileChannel channel = new RandomAccessFile(file, "r").getChannel()) { this.size = channel.size(); int zeroBasedPagesNumber = (int) (channel.size() / pageSize); for (int i = 0; i <= zeroBasedPagesNumber; i++) { if (i == zeroBasedPagesNumber) { pages.add(i, channel.map(MapMode.READ_ONLY, i * pageSize, channel.size() - (i * pageSize))); } else { pages.add(i, channel.map(MapMode.READ_ONLY, i * pageSize, pageSize)); } } LOG.debug("Created MemoryMappedSeekableSource with " + pages.size() + " pages"); } } private MemoryMappedSeekableSource(MemoryMappedSeekableSource parent) { super(parent.id()); this.size = parent.size; for (ByteBuffer page : parent.pages) { this.pages.add(page.duplicate()); } // unmap doesn't work on duplicate, see Unsafe#invokeCleaner this.unmapper = null; } @Override public long position() { return position; } @Override public long size() { return size; } @Override public SeekableSource position(long position) { requireArg(position >= 0, "Cannot set position to a negative value"); this.position = Math.min(position, this.size); return this; } @Override public int read(ByteBuffer dst) throws IOException { requireOpen(); int zeroBasedPagesNumber = (int) (position() / pageSize); ByteBuffer page = pages.get(zeroBasedPagesNumber); int relativePosition = (int) (position() - (zeroBasedPagesNumber * pageSize)); if (relativePosition < page.limit()) { int read = readPage(dst, zeroBasedPagesNumber, relativePosition); while (dst.hasRemaining()) { int readBytes = readPage(dst, ++zeroBasedPagesNumber, 0); if (readBytes == 0) { break; } read += readBytes; } position += read; return read; } return -1; } private int readPage(ByteBuffer dst, int pageNumber, int bufferPosition) { if (pageNumber < pages.size()) { ByteBuffer page = pages.get(pageNumber); page.position(bufferPosition); if (page.hasRemaining()) { int toRead = Math.min(dst.remaining(), page.remaining()); byte[] bufToRead = new byte[toRead]; page.get(bufToRead); dst.put(bufToRead); return toRead; } } return 0; } @Override public int read() throws IOException { requireOpen(); int zeroBasedPagesNumber = (int) (position() / pageSize); ByteBuffer page = pages.get(zeroBasedPagesNumber); int relativePosition = (int) (position() - (zeroBasedPagesNumber * pageSize)); if (relativePosition < page.limit()) { position++; return page.get(relativePosition); } return -1; } @Override public void close() throws IOException { super.close(); org.sejda.commons.util.IOUtils.close(localCopiesSupplier); Optional.ofNullable(unmapper).ifPresent(m -> pages.stream().forEach(m)); pages.clear(); } @Override public SeekableSource view(long startingPosition, long length) throws IOException { requireOpen(); return new SeekableSourceView(localCopiesSupplier, id(), startingPosition, length); } } sejda-io-2.1.4/src/main/java/org/sejda/io/OffsettableSeekableSource.java000066400000000000000000000021231425511572700260560ustar00rootroot00000000000000package org.sejda.io; /* * Copyright 2022 Sober Lemur S.a.s. di Vacondio Andrea and Sejda BV * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import java.io.IOException; /** * A {@link SeekableSource} that can be offsetted by a given number of bytes * * @author Andrea Vacondio */ public interface OffsettableSeekableSource extends SeekableSource { /** * Sets the offset for this source * * @param offset * @throws IllegalArgumentException if the offset is negative or if it would lead to a negative size */ void offset(long offset) throws IOException; } sejda-io-2.1.4/src/main/java/org/sejda/io/OffsettableSeekableSourceImpl.java000066400000000000000000000053601425511572700267060ustar00rootroot00000000000000package org.sejda.io; /* * Copyright 2022 Sober Lemur S.a.s. di Vacondio Andrea and Sejda BV * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import org.sejda.commons.util.IOUtils; import java.io.IOException; import java.nio.ByteBuffer; import static org.sejda.commons.util.RequireUtils.requireArg; import static org.sejda.commons.util.RequireUtils.requireNotNullArg; /** * A decorator for a {@link SeekableSource} that adds the concept of offset. * * @author Andrea Vacondio */ class OffsettableSeekableSourceImpl implements OffsettableSeekableSource { private SeekableSource wrapped; private long offset = 0; public OffsettableSeekableSourceImpl(SeekableSource wrapped) { requireNotNullArg(wrapped, "Input decorated SeekableSource cannot be null"); this.wrapped = wrapped; } @Override public String id() { return this.wrapped.id(); } @Override public boolean isOpen() { return this.wrapped.isOpen(); } @Override public void requireOpen() throws IOException { this.wrapped.requireOpen(); } @Override public long size() { return wrapped.size() - offset; } @Override public void offset(long offset) throws IOException{ requireArg(offset >= 0, "Cannot set a negative offset"); requireArg((wrapped.size() - offset) >= 0, "Invalid offset bigger then the wrapped source size"); this.offset = offset; this.wrapped.position(this.wrapped.position() + offset); } @Override public long position() throws IOException { return this.wrapped.position() - offset; } @Override public SeekableSource position(long position) throws IOException { return this.wrapped.position(position + offset); } @Override public int read() throws IOException { return this.wrapped.read(); } @Override public SeekableSource view(long startingPosition, long length) throws IOException { return this.wrapped.view(startingPosition + offset, length); } @Override public int read(ByteBuffer dst) throws IOException { return this.wrapped.read(dst); } @Override public void close() throws IOException { IOUtils.close(wrapped); } } sejda-io-2.1.4/src/main/java/org/sejda/io/SeekableSource.java000066400000000000000000000130651425511572700237060ustar00rootroot00000000000000/* * Copyright 2018 Sober Lemur S.a.s. di Vacondio Andrea * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.io; import java.io.IOException; import java.io.InputStream; import java.nio.channels.ReadableByteChannel; /** * Readable source that provides random access capabilities. * * @author Andrea Vacondio */ public interface SeekableSource extends ReadableByteChannel { /** * @return the unique id for the source. */ String id(); /** * @return the current source position as a positive long * @throws IOException */ long position() throws IOException; /** * Sets the source position. Setting the position to a value that is greater than the source's size is legal but does not change the size of the source. A later attempt to read * bytes at such a position will immediately return an end-of-file indication. * * @param position * a non-negative long for the new position * @return this source * @throws IOException */ SeekableSource position(long position) throws IOException; /** * @return The source size, measured in bytes */ long size(); /** * Reads a byte of data from this source. The byte is returned as an integer in the range 0 to 255 ( {@code 0x00-0xff} ). * * @return the next byte of data, or {@code -1} if there is no more data. * @throws IOException */ int read() throws IOException; /** * @param startingPosition * @param length * @return a readable view of a portion of this {@link SeekableSource}. Reading from the view doesn't affect the {@link SeekableSource} position. Closing the * {@link SeekableSource} makes all the views unreadable but closing the view has no effect on the {@link SeekableSource}. A view may or may not work on a thread bound * copy of the {@link SeekableSource} so as a general rule it should not be created and handed to other threads.. * @throws IOException * if something goes wrong while creating the view */ SeekableSource view(long startingPosition, long length) throws IOException; /** * Skips backward the given number of bytes moving back the source position * * @param offset * the number of bytes to skip back. * @return this source * @throws IOException */ default SeekableSource back(long offset) throws IOException { long newPosition = position() - offset; if (newPosition < 0 || newPosition > size()) { throw new IllegalArgumentException( "Going back would move to " + newPosition + ", outside of source boundaries"); } position(newPosition); return this; } /** * Skips backward moving back the source position of one byte * * @return this source * @throws IOException * @see SeekableSource#back(long) */ default SeekableSource back() throws IOException { return back(1); } /** * Skips the given number of bytes moving forward the source position * * @param offset * the number of bytes to skip . * @return this source * @throws IOException */ default SeekableSource forward(long offset) throws IOException { return back(-offset); } /** * Reads the next byte and sets the position back by one. * * @return the next byte or {@code -1} if there is no more data. * @throws IOException * @see #read() */ default int peek() throws IOException { int val = read(); if (val != -1) { back(1); } return val; } /** * Reads the previous byte and sets the position back where it was. * * @return the previous byte or {@code -1} if we are at the beginning of the source. * @throws IOException * @see #read() */ default int peekBack() throws IOException { if (position() > 0) { back(1); return read(); } return -1; } /** * Creates an {@link InputStream} from this {@link SeekableSource}. * * @return the input stream wrapping the given {@link SeekableSource} */ default InputStream asInputStream() { return new SeekableSourceInputStream(this); } /** * Resets stream back to beginning */ default void reset() { try { requireOpen(); this.back(this.position()); } catch (IOException e) { throw new RuntimeException("Failed to reset stream"); } } /** * @throws IllegalStateException if the source is closed * @throws IOException */ void requireOpen() throws IOException; /** * Creates an {@link InputStream} from this {@link SeekableSource} resetting the stream to the beginning. * * @return the input stream wrapping the given {@link SeekableSource} */ default InputStream asNewInputStream() { reset(); return new SeekableSourceInputStream(this); } } sejda-io-2.1.4/src/main/java/org/sejda/io/SeekableSourceInputStream.java000066400000000000000000000046151425511572700261030ustar00rootroot00000000000000/* * Copyright 2018 Sober Lemur S.a.s. di Vacondio Andrea * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.io; import static org.sejda.commons.util.RequireUtils.requireNotNullArg; import static org.sejda.commons.util.RequireUtils.requireState; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; /** * Bridge between {@link SeekableSource} and {@link InputStream} * * @author Andrea Vacondio */ class SeekableSourceInputStream extends InputStream { private SeekableSource wrapped; SeekableSourceInputStream(SeekableSource wrapped) { requireNotNullArg(wrapped, "Cannot decorate a null instance"); this.wrapped = wrapped; } @Override public int read() throws IOException { return getSource().read(); } @Override public int read(byte[] b) throws IOException { if (available() > 0) { return getSource().read(ByteBuffer.wrap(b, 0, Math.min(b.length, available()))); } return -1; } @Override public int read(byte[] b, int offset, int length) throws IOException { if (available() > 0) { return getSource().read(ByteBuffer.wrap(b, Math.min(b.length, offset), Math.min(length, Math.min(b.length - offset, available())))); } return -1; } @Override public int available() throws IOException { SeekableSource source = getSource(); return (int) Math.max(0, (source.size() - source.position())); } @Override public long skip(long offset) throws IOException { SeekableSource source = getSource(); long start = source.position(); return source.forward(Math.min(offset, available())).position() - start; } private SeekableSource getSource() { requireState(wrapped.isOpen(), "The SeekableSource has been closed"); return wrapped; } } sejda-io-2.1.4/src/main/java/org/sejda/io/SeekableSourceSupplier.java000066400000000000000000000014751425511572700254340ustar00rootroot00000000000000/* * Copyright 2018 Sober Lemur S.a.s. di Vacondio Andrea * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.io; import java.io.IOException; /** * @author Andrea Vacondio */ @FunctionalInterface public interface SeekableSourceSupplier { T get() throws IOException; } sejda-io-2.1.4/src/main/java/org/sejda/io/SeekableSourceView.java000066400000000000000000000105711425511572700245400ustar00rootroot00000000000000/* * Copyright 2018 Sober Lemur S.a.s. di Vacondio Andrea * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.io; import static org.sejda.commons.util.RequireUtils.requireArg; import static org.sejda.commons.util.RequireUtils.requireNotNullArg; import static org.sejda.commons.util.RequireUtils.requireState; import java.io.IOException; import java.nio.ByteBuffer; /** * {@link SeekableSource} representing a view over a portion of a parent {@link SeekableSource}. A view becomes invalid if the parent {@link SeekableSource} is closed. The view * works on a thread local copy of the parent source so the parent position is not modified when a read method is called on the view. * * @author Andrea Vacondio */ class SeekableSourceView extends BaseSeekableSource { private long startingPosition; private long length; private long currentPosition; private SeekableSourceSupplier supplier; public SeekableSourceView(SeekableSourceSupplier supplier, String id, long startingPosition, long length) throws IOException { super(id); requireArg(startingPosition >= 0, "Starting position cannot be negative"); requireArg(length > 0, "View length must be positive"); requireNotNullArg(supplier, "Input decorated SeekableSource cannot be null"); this.startingPosition = startingPosition; this.currentPosition = 0; SeekableSource wrapped = supplier.get(); requireArg(startingPosition < wrapped.size(), "Starting position cannot be higher then wrapped source size"); this.length = Math.min(length, wrapped.size() - startingPosition); this.supplier = supplier; } @Override public long position() { return currentPosition; } @Override public SeekableSource position(long newPosition) throws IOException { SeekableSource wrapped = supplier.get(); requireArg(newPosition >= 0, "Cannot set position to a negative value"); this.currentPosition = Math.min(length, newPosition); wrapped.position(startingPosition + currentPosition); return this; } @Override public long size() { return length; } @Override public int read(ByteBuffer dst) throws IOException { SeekableSource wrapped = supplier.get(); requireOpen(); if (hasAvailable()) { wrapped.position(startingPosition + currentPosition); if (dst.remaining() > available()) { dst.limit(dst.position() + (int) available()); } int read = wrapped.read(dst); if (read > 0) { currentPosition += read; return read; } } return -1; } @Override public int read() throws IOException { requireOpen(); SeekableSource wrapped = supplier.get(); if (hasAvailable()) { wrapped.position(startingPosition + currentPosition); currentPosition++; return wrapped.read(); } return -1; } private boolean hasAvailable() { return available() > 0; } private long available() { return length - currentPosition; } @Override public void close() throws IOException { super.close(); this.currentPosition = 0; } @Override public void requireOpen() throws IOException { super.requireOpen(); SeekableSource wrapped = supplier.get(); requireState(wrapped.isOpen(), "The original SeekableSource has been closed"); } /** * Cannot create a view of a view. This method throws {@link RuntimeException}. * * @throws RuntimeException */ @Override public SeekableSource view(long startingPosition, long length) { throw new RuntimeException("Cannot create a view of a view"); } } sejda-io-2.1.4/src/main/java/org/sejda/io/SeekableSources.java000066400000000000000000000132461425511572700240720ustar00rootroot00000000000000/* * Copyright 2018 Sober Lemur S.a.s. di Vacondio Andrea * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.io; import static java.util.Objects.requireNonNull; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.StandardCopyOption; import org.sejda.commons.util.IOUtils; /** * This class consists of solely static methods to create the most appropriate {@link SeekableSource} based on the given input or to bridge {@link SeekableSource}s to the more * traditional {@link InputStream} or other standard I/O classes. * * @author Andrea Vacondio * */ public final class SeekableSources { /** * Threshold size in bytes where the SeekableSources method will switch to {@link MemoryMappedSeekableSource#MemoryMappedSeekableSource(File)} */ public static final String MAPPED_SIZE_THRESHOLD_PROPERTY = "org.sejda.io.mapped.size.threshold"; /** * Threshold size in bytes where the SeekableSources method will switch to {@link MemoryMappedSeekableSource#MemoryMappedSeekableSource(File)} */ public static final String DISABLE_MEMORY_MAPPED_PROPERTY = "org.sejda.io.mapped.disabled"; /** * Buffer size for {@link BufferedSeekableSource} */ public static final String INPUT_BUFFER_SIZE_PROPERTY = "org.sejda.io.buffered.input.size"; /** * Size of the pages used by {@link MemoryMappedSeekableSource} */ public static final String MEMORY_MAPPED_PAGE_SIZE_PROPERTY = "org.sejda.io.memory.mapped.page.size"; private static final long MB_16 = 1 << 24; private SeekableSources() { // utility } /** * Factory method to create a {@link SeekableSource} from a {@link File}. An attempt is made to return the best {@link SeekableSource} implementation based on the size of the * file and bitness of the JVM. * * @param file * @return a {@link SeekableSource} from the given file. * @throws IOException */ public static SeekableSource seekableSourceFrom(File file) throws IOException { requireNonNull(file); if (!"32".equals(System.getProperty("sun.arch.data.model")) && !Boolean.getBoolean(DISABLE_MEMORY_MAPPED_PROPERTY) && file.length() > Long.getLong(MAPPED_SIZE_THRESHOLD_PROPERTY, MB_16)) { return new BufferedSeekableSource(new MemoryMappedSeekableSource(file)); } return new BufferedSeekableSource(new FileChannelSeekableSource(file)); } /** * Factory method to create a {@link SeekableSource} from a {@link InputStream}. The whole stream is read an stored in a byte array with a max size of 2GB. * * @param stream * @return a {@link SeekableSource} from the given stream. * @throws IOException */ public static SeekableSource inMemorySeekableSourceFrom(InputStream stream) throws IOException { requireNonNull(stream); return new ByteArraySeekableSource(IOUtils.toByteArray(stream)); } /** * Factory method to create a {@link SeekableSource} from a byte array. * * @param bytes * @return a {@link SeekableSource} wrapping the given byte array. */ public static SeekableSource inMemorySeekableSourceFrom(byte[] bytes) { requireNonNull(bytes); return new ByteArraySeekableSource(bytes); } /** * Factory method to create a {@link SeekableSource} from a {@link InputStream}. The whole stream is copied to a temporary file. * * @param stream * @return a {@link SeekableSource} from the given stream. * @throws IOException */ public static SeekableSource onTempFileSeekableSourceFrom(InputStream stream) throws IOException { return onTempFileSeekableSourceFrom(stream, "SejdaIO"); } /** * Factory method to create a {@link SeekableSource} from a {@link InputStream}. The whole stream is copied to a temporary file. * * @param stream * @param filenameHint name to use for the temp file that will be created * @return a {@link SeekableSource} from the given stream. * @throws IOException */ public static SeekableSource onTempFileSeekableSourceFrom(InputStream stream, String filenameHint) throws IOException { requireNonNull(stream); File tempDir = Files.createTempDirectory("SejdaIODir").toFile(); File temp = new File(tempDir, filenameHint); if(temp.exists()) { throw new RuntimeException("Temp file collision: "+ temp.getAbsolutePath()); } Files.copy(stream, temp.toPath(), StandardCopyOption.REPLACE_EXISTING); return new BufferedSeekableSource(new FileChannelSeekableSource(temp) { @Override public void close() throws IOException { super.close(); Files.deleteIfExists(temp.toPath()); } }); } /** * Factory method to create an {@link OffsettableSeekableSource} from a {@link SeekableSource} * @param source * @return */ public static OffsettableSeekableSource asOffsettable(SeekableSource source) { requireNonNull(source); return new OffsettableSeekableSourceImpl(source); } } sejda-io-2.1.4/src/main/java/org/sejda/io/ThreadBoundCopiesSupplier.java000066400000000000000000000040111425511572700260670ustar00rootroot00000000000000/* * Copyright 2018 Sober Lemur S.a.s. di Vacondio Andrea * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.io; import static java.util.Objects.isNull; import static java.util.Objects.requireNonNull; import java.io.Closeable; import java.io.IOException; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.sejda.commons.util.IOUtils; /** * Component suppling per-thread copies of a {@link SeekableSource} using the provided supplier. When closed, all the generated copies are closed as well. * * @author Andrea Vacondio */ public class ThreadBoundCopiesSupplier implements Closeable, SeekableSourceSupplier { private ConcurrentMap copies = new ConcurrentHashMap<>(); private final SeekableSourceSupplier supplier; public ThreadBoundCopiesSupplier(SeekableSourceSupplier supplier) { requireNonNull(supplier); this.supplier = supplier; } @Override public T get() throws IOException { long id = Thread.currentThread().getId(); T copy = copies.get(id); if (isNull(copy)) { T newCopy = supplier.get(); copy = copies.putIfAbsent(id, newCopy); if (isNull(copy)) { copy = newCopy; } else { IOUtils.closeQuietly(newCopy); } } return copy; } @Override public void close() { copies.values().stream().forEach(IOUtils::closeQuietly); } } sejda-io-2.1.4/src/main/java/org/sejda/io/util/000077500000000000000000000000001425511572700211175ustar00rootroot00000000000000sejda-io-2.1.4/src/main/java/org/sejda/io/util/IOUtils.java000066400000000000000000000206551425511572700233220ustar00rootroot00000000000000/* * Copyright 2018 Sober Lemur S.a.s. di Vacondio Andrea * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.io.util; import static java.lang.invoke.MethodHandles.constant; import static java.lang.invoke.MethodHandles.dropArguments; import static java.lang.invoke.MethodHandles.filterReturnValue; import static java.lang.invoke.MethodHandles.guardWithTest; import static java.lang.invoke.MethodHandles.lookup; import static java.lang.invoke.MethodType.methodType; import static java.util.Objects.nonNull; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles.Lookup; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.nio.ByteBuffer; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Objects; import java.util.Optional; import java.util.function.Consumer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Utility class with I/O related static methods */ public final class IOUtils { private static final Logger LOG = LoggerFactory.getLogger(IOUtils.class); private static final Optional> UNMAPPER; static { UNMAPPER = Optional .ofNullable(AccessController.doPrivileged((PrivilegedAction>) IOUtils::unmapper)); } private IOUtils() { // hide } /** * Unmap memory mapped byte buffers. This is a hack waiting for a proper JVM provided solution expected in java 10 https://bugs.openjdk.java.net/browse/JDK-4724038 The issue * here is that even when closed, memory mapped byte buffers hold a lock on the underlying file until GC is executed and this in turns result in an error if the user tries to * move or delete the file. * * @param buf */ public static void unmap(ByteBuffer buf) { try { UNMAPPER.ifPresent(u -> u.accept(buf)); } catch (Exception e) { LOG.error("Unable to unmap ByteBuffer.", e); } } /** * This is adapted from org.apache.lucene.store.MMapDirectory * * @return */ //java 9 or above // private static Consumer unmapper() { // final Lookup lookup = lookup(); // try { // // *** sun.misc.Unsafe unmapping (Java 9+) *** // final Class unsafeClass = Class.forName("sun.misc.Unsafe"); // // first check if Unsafe has the right method, otherwise we can give up // // without doing any security critical stuff: // final MethodHandle unmapper = lookup.findVirtual(unsafeClass, "invokeCleaner", // methodType(void.class, ByteBuffer.class)); // // fetch the unsafe instance and bind it to the virtual MH: // final Field f = unsafeClass.getDeclaredField("theUnsafe"); // f.setAccessible(true); // final Object theUnsafe = f.get(null); // return newBufferCleaner(ByteBuffer.class, unmapper.bindTo(theUnsafe)); // } catch (SecurityException se) { // LOG.error( // "Unmapping is not supported because of missing permissions. Please grant at least the following permissions: RuntimePermission(\"accessClassInPackage.sun.misc\") " // + " and ReflectPermission(\"suppressAccessChecks\")", // se); // // } catch (ReflectiveOperationException | RuntimeException e) { // LOG.error("Unmapping is not supported.", e); // } // return null; // } /** * This is adapted from org.apache.lucene.store.MMapDirectory * * @return */ private static Consumer unmapper() { final Lookup lookup = lookup(); try { try { // *** sun.misc.Unsafe unmapping (Java 9+) *** final Class unsafeClass = Class.forName("sun.misc.Unsafe"); // first check if Unsafe has the right method, otherwise we can give up // without doing any security critical stuff: final MethodHandle unmapper = lookup.findVirtual(unsafeClass, "invokeCleaner", methodType(void.class, ByteBuffer.class)); // fetch the unsafe instance and bind it to the virtual MH: final Field f = unsafeClass.getDeclaredField("theUnsafe"); f.setAccessible(true); final Object theUnsafe = f.get(null); return newBufferCleaner(ByteBuffer.class, unmapper.bindTo(theUnsafe)); } catch (SecurityException se) { // rethrow to report errors correctly (we need to catch it here, as we also catch RuntimeException below!): throw se; } catch (ReflectiveOperationException | RuntimeException e) { // *** sun.misc.Cleaner unmapping (Java 8) *** final Class directBufferClass = Class.forName("java.nio.DirectByteBuffer"); final Method m = directBufferClass.getMethod("cleaner"); m.setAccessible(true); final MethodHandle directBufferCleanerMethod = lookup.unreflect(m); final Class cleanerClass = directBufferCleanerMethod.type().returnType(); /* * "Compile" a MH that basically is equivalent to the following code: void unmapper(ByteBuffer byteBuffer) { sun.misc.Cleaner cleaner = ((java.nio.DirectByteBuffer) * byteBuffer).cleaner(); if (Objects.nonNull(cleaner)) { cleaner.clean(); } else { noop(cleaner); // the noop is needed because MethodHandles#guardWithTest always * needs ELSE } } */ final MethodHandle cleanMethod = lookup.findVirtual(cleanerClass, "clean", methodType(void.class)); final MethodHandle nonNullTest = lookup .findStatic(Objects.class, "nonNull", methodType(boolean.class, Object.class)) .asType(methodType(boolean.class, cleanerClass)); final MethodHandle noop = dropArguments(constant(Void.class, null).asType(methodType(void.class)), 0, cleanerClass); final MethodHandle unmapper = filterReturnValue(directBufferCleanerMethod, guardWithTest(nonNullTest, cleanMethod, noop)).asType(methodType(void.class, ByteBuffer.class)); return newBufferCleaner(directBufferClass, unmapper); } } catch (SecurityException se) { LOG.error( "Unmapping is not supported because of missing permissions. Please grant at least the following permissions: RuntimePermission(\"accessClassInPackage.sun.misc\") " + " and ReflectPermission(\"suppressAccessChecks\")", se); } catch (ReflectiveOperationException | RuntimeException e) { LOG.error("Unmapping is not supported.", e); } return null; } private static Consumer newBufferCleaner(final Class unmappableBufferClass, final MethodHandle unmapper) { assert Objects.equals(methodType(void.class, ByteBuffer.class), unmapper.type()); return (ByteBuffer buffer) -> { if (!buffer.isDirect()) { throw new IllegalArgumentException("unmapping only works with direct buffers"); } if (!unmappableBufferClass.isInstance(buffer)) { throw new IllegalArgumentException("buffer is not an instance of " + unmappableBufferClass.getName()); } final Throwable e = AccessController.doPrivileged((PrivilegedAction) () -> { try { unmapper.invokeExact(buffer); return null; } catch (Throwable t) { return t; } }); if (nonNull(e)) { LOG.error("Unable to unmap the mapped buffer", e); } }; } } sejda-io-2.1.4/src/test/000077500000000000000000000000001425511572700147705ustar00rootroot00000000000000sejda-io-2.1.4/src/test/java/000077500000000000000000000000001425511572700157115ustar00rootroot00000000000000sejda-io-2.1.4/src/test/java/org/000077500000000000000000000000001425511572700165005ustar00rootroot00000000000000sejda-io-2.1.4/src/test/java/org/sejda/000077500000000000000000000000001425511572700175665ustar00rootroot00000000000000sejda-io-2.1.4/src/test/java/org/sejda/io/000077500000000000000000000000001425511572700201755ustar00rootroot00000000000000sejda-io-2.1.4/src/test/java/org/sejda/io/BaseSeekableSourceTest.java000066400000000000000000000052051425511572700253710ustar00rootroot00000000000000/* * Copyright 2018 Sober Lemur S.a.s. di Vacondio Andrea * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.io; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.nio.ByteBuffer; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * @author Andrea Vacondio * */ public class BaseSeekableSourceTest { private BaseSeekableSource victim; @BeforeEach public void setUp() { victim = new BaseSeekableSource("id") { @Override public int read(ByteBuffer dst) { return 0; } @Override public SeekableSource view(long startingPosition, long length) { return null; } @Override public long size() { return 0; } @Override public int read() { return 0; } @Override public SeekableSource position(long position) { return null; } @Override public long position() { return 0; } }; } @Test public void isOpen() throws IOException { assertTrue(victim.isOpen()); victim.close(); assertFalse(victim.isOpen()); } @Test public void requireOpen() throws IOException { assertTrue(victim.isOpen()); victim.requireOpen(); } @Test public void failingRequireOpen() throws IOException { assertTrue(victim.isOpen()); victim.close(); assertThrows(IllegalStateException.class, () -> { victim.requireOpen(); }); } @Test public void id() { assertEquals("id", victim.id()); } @Test public void inputStreamFrom() { assertNotNull(victim.asInputStream()); } } sejda-io-2.1.4/src/test/java/org/sejda/io/BaseTestSeekableSource.java000066400000000000000000000104541425511572700253730ustar00rootroot00000000000000/* * Copyright 2018 Sober Lemur S.a.s. di Vacondio Andrea * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.io; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.nio.ByteBuffer; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.sejda.commons.util.IOUtils; /** * @author Andrea Vacondio * */ public abstract class BaseTestSeekableSource { abstract SeekableSource victim(); @AfterEach public void tearDown() throws IOException { IOUtils.close(victim()); } @Test public void illegalPosition() { assertThrows(IllegalArgumentException.class, () -> { victim().position(-10); }); } @Test public void viewClosed() throws IOException { victim().close(); assertThrows(IllegalStateException.class, () -> { victim().view(0, 2); }); } @Test public void view() throws IOException { assertNotNull(victim().view(0, 2)); } @Test public void close() throws IOException { victim().read(); assertTrue(victim().isOpen()); victim().close(); assertFalse(victim().isOpen()); } @Test public void readClosed() throws IOException { victim().close(); assertThrows(IllegalStateException.class, () -> { victim().read(); }); } @Test public void readByteBuffClosed() throws IOException { victim().close(); assertThrows(IllegalStateException.class, () -> { victim().read(ByteBuffer.allocate(5)); }); } @Test public void forward() throws IOException { assertEquals(0, victim().position()); assertEquals(1, victim().forward(1).position()); } @Test public void invalidForward() throws IOException { assertEquals(0, victim().position()); assertThrows(IllegalArgumentException.class, () -> { victim().forward(victim().size() + 1); }); } @Test public void back() throws IOException { assertEquals(1, victim().forward(1).position()); assertEquals(0, victim().back().position()); } @Test public void invalidBack() throws IOException { assertEquals(0, victim().position()); assertThrows(IllegalArgumentException.class, () -> { victim().back(); }); } @Test public void peek() throws IOException { assertEquals(0, victim().position()); assertNotEquals(-1, victim().peek()); assertEquals(0, victim().position()); } @Test public void peekEOF() throws IOException { victim().position(victim().size()); assertEquals(-1, victim().peek()); } @Test public void peekBack() throws IOException { victim().position(victim().size()); assertNotEquals(-1, victim().peekBack()); assertEquals(victim().size(), victim().position()); } @Test public void peekBackBeginning() throws IOException { assertEquals(0, victim().position()); assertEquals(-1, victim().peekBack()); } @Test public void requireOpen() throws IOException { assertTrue(victim().isOpen()); victim().requireOpen(); } @Test public void failingRequireOpen() throws IOException { assertTrue(victim().isOpen()); victim().close(); assertThrows(IllegalStateException.class, () -> { victim().requireOpen(); }); } } sejda-io-2.1.4/src/test/java/org/sejda/io/BufferedCountingChannelWriterTest.java000066400000000000000000000114671425511572700276300ustar00rootroot00000000000000/* * Copyright 2018 Sober Lemur S.a.s. di Vacondio Andrea * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.io; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Arrays; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * @author Andrea Vacondio * */ public class BufferedCountingChannelWriterTest { private ByteArrayOutputStream out; private CountingWritableByteChannel channel; private BufferedCountingChannelWriter victim; @BeforeEach public void setUp() { out = new ByteArrayOutputStream(); channel = CountingWritableByteChannel.from(out); victim = new BufferedCountingChannelWriter(channel); } @AfterEach public void after() { System.getProperties().remove(BufferedCountingChannelWriter.OUTPUT_BUFFER_SIZE_PROPERTY); } @Test public void nullConstructor() { assertThrows(IllegalArgumentException.class, () -> { new BufferedCountingChannelWriter(null); }, "Cannot write to a null channell"); } @Test public void close() throws IOException { victim.close(); assertFalse(channel.isOpen()); } @Test public void flush() throws IOException { channel = mock(CountingWritableByteChannel.class); victim = new BufferedCountingChannelWriter(channel); victim.writeEOL(); verify(channel, times(0)).write(any()); victim.flush(); verify(channel).write(any()); } @Test public void closeFlushes() throws IOException { channel = mock(CountingWritableByteChannel.class); when(channel.isOpen()).thenReturn(true); victim = new BufferedCountingChannelWriter(channel); victim.writeEOL(); verify(channel, times(0)).write(any()); victim.close(); verify(channel).write(any()); } @Test public void writeEOL() throws IOException { victim.writeEOL(); victim.close(); assertTrue(Arrays.equals(new byte[] { '\n' }, out.toByteArray())); } @Test public void prettyPrintJustOneEOL() throws IOException { victim.writeEOL(); victim.writeEOL(); victim.write((byte) -1); victim.writeEOL(); victim.writeEOL(); victim.close(); assertTrue(Arrays.equals(new byte[] { '\n', -1, '\n' }, out.toByteArray())); } @Test public void multipleCloseDontThrowException() throws IOException { victim.close(); victim.writeEOL(); victim.close(); } @Test public void writeString() throws IOException { victim.write("ChuckNorris"); victim.close(); assertTrue(Arrays.equals("ChuckNorris".getBytes("ISO-8859-1"), out.toByteArray())); } @Test public void writeBytesExceedingBuffer() throws IOException { System.getProperties().setProperty(BufferedCountingChannelWriter.OUTPUT_BUFFER_SIZE_PROPERTY, "4"); victim = new BufferedCountingChannelWriter(channel); byte[] bytes = new byte[] { '1', '1', '2', '1', '1' }; victim.write(bytes); assertEquals(5, victim.offset()); victim.close(); assertTrue(Arrays.equals(bytes, out.toByteArray())); } @Test public void writeInputStream() throws IOException { byte[] bytes = new byte[] { '1', '1', '2', '1', '1' }; victim.write(bytes); byte[] streamBytes = "ChuckNorris".getBytes("ISO-8859-1"); ByteArrayInputStream is = new ByteArrayInputStream(streamBytes); victim.write(is); victim.close(); byte[] expected = Arrays.copyOf(bytes, bytes.length + streamBytes.length); System.arraycopy(streamBytes, 0, expected, bytes.length, streamBytes.length); assertTrue(Arrays.equals(expected, out.toByteArray())); } } sejda-io-2.1.4/src/test/java/org/sejda/io/BufferedSeekableSourceTest.java000066400000000000000000000072711425511572700262460ustar00rootroot00000000000000/* * Copyright 2018 Sober Lemur S.a.s. di Vacondio Andrea * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.io; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.nio.ByteBuffer; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * @author Andrea Vacondio */ public class BufferedSeekableSourceTest extends BaseTestSeekableSource { private ByteArraySeekableSource wrapped; private BufferedSeekableSource victim; @BeforeEach public void setUp() { wrapped = new ByteArraySeekableSource(new byte[] { 'a', 'b', 'c' }); victim = new BufferedSeekableSource(wrapped); } @Test public void failingConstructor() { assertThrows(IllegalArgumentException.class, () -> { new BufferedSeekableSource(null); }, "Input decorated SeekableSource cannot be null"); } @Test public void constructor() { assertEquals(wrapped.id(), victim.id()); assertEquals(wrapped.size(), victim.size()); } @Override @Test public void close() throws IOException { victim.read(); assertTrue(victim.isOpen()); assertTrue(wrapped.isOpen()); victim.close(); assertFalse(victim.isOpen()); assertFalse(wrapped.isOpen()); } @Test public void read() throws IOException { assertEquals(97, victim.read()); assertEquals(1, victim.position()); assertEquals(98, victim.read()); assertEquals(2, victim.position()); assertEquals(99, victim.read()); assertEquals(3, victim.position()); assertEquals(-1, victim.read()); assertEquals(3, victim.position()); } @Test public void readBuff() throws IOException { victim.position(1); ByteBuffer dst = ByteBuffer.allocate(10); victim.read(dst); dst.flip(); assertEquals(2, dst.remaining()); assertEquals(98, dst.get()); assertEquals(99, dst.get()); ByteBuffer empty = ByteBuffer.allocate(10); victim.read(empty); empty.flip(); assertFalse(empty.hasRemaining()); } @Test public void position() throws IOException { assertEquals(0, victim.position()); assertEquals(97, victim.read()); victim.position(0); assertEquals(0, victim.position()); victim.position(0); assertEquals(0, victim.position()); victim.position(2); assertEquals(2, victim.position()); victim.read(); assertEquals(3, victim.position()); assertEquals(-1, victim.read()); victim.position(2); assertEquals(2, victim.position()); victim.position(20); assertEquals(3, victim.position()); assertEquals(-1, victim.read()); } @Test public void closedWrapped() throws IOException { this.wrapped.close(); assertFalse(victim.isOpen()); } @Override SeekableSource victim() { return victim; } } sejda-io-2.1.4/src/test/java/org/sejda/io/ByteArraySeekableSourceTest.java000066400000000000000000000057401425511572700264250ustar00rootroot00000000000000/* * Copyright 2018 Sober Lemur S.a.s. di Vacondio Andrea * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.io; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import java.io.IOException; import java.nio.ByteBuffer; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * @author Andrea Vacondio * */ public class ByteArraySeekableSourceTest extends BaseTestSeekableSource { private ByteArraySeekableSource victim; @BeforeEach public void setUp() { victim = new ByteArraySeekableSource(new byte[] { 'a', 'b', 'c' }); } @Test public void failingConstructor() { assertThrows(IllegalArgumentException.class, () -> { new ByteArraySeekableSource(null); }, "Input byte array cannot be null"); } @Test public void read() throws IOException { assertEquals(97, victim.read()); assertEquals(1, victim.position()); assertEquals(98, victim.read()); assertEquals(2, victim.position()); assertEquals(99, victim.read()); assertEquals(3, victim.position()); assertEquals(-1, victim.read()); assertEquals(3, victim.position()); } @Test public void readBuff() throws IOException { victim.position(1); ByteBuffer dst = ByteBuffer.allocate(10); victim.read(dst); dst.flip(); assertEquals(2, dst.remaining()); assertEquals(98, dst.get()); assertEquals(99, dst.get()); ByteBuffer empty = ByteBuffer.allocate(10); victim.read(empty); empty.flip(); assertFalse(empty.hasRemaining()); } @Test public void position() throws IOException { assertEquals(0, victim.position()); assertEquals(97, victim.read()); victim.position(0); assertEquals(0, victim.position()); victim.position(0); assertEquals(0, victim.position()); victim.position(2); assertEquals(2, victim.position()); victim.read(); assertEquals(3, victim.position()); assertEquals(-1, victim.read()); victim.position(2); assertEquals(2, victim.position()); victim.position(20); assertEquals(3, victim.position()); assertEquals(-1, victim.read()); } @Override SeekableSource victim() { return victim; } } sejda-io-2.1.4/src/test/java/org/sejda/io/CountingWritableByteChannelTest.java000066400000000000000000000101201425511572700272670ustar00rootroot00000000000000/* * Copyright 2018 Sober Lemur S.a.s. di Vacondio Andrea * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.io; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; import java.nio.channels.Channels; import java.nio.channels.ClosedChannelException; import java.nio.channels.WritableByteChannel; import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; public class CountingWritableByteChannelTest { private ByteArrayOutputStream out; private CountingWritableByteChannel victim; private WritableByteChannel wrapped; private ByteBuffer src = ByteBuffer.wrap(new byte[] { '1', '1', '2', '1', '1' }); @BeforeEach public void setUp() { out = new ByteArrayOutputStream(); wrapped = Channels.newChannel(out); victim = new CountingWritableByteChannel(wrapped); } @Test public void nullConstructor() { assertThrows(IllegalArgumentException.class, () -> { new CountingWritableByteChannel(null); }, "Cannot decorate a null instance"); } @Test public void count() throws Exception { assertEquals(0, victim.count()); victim.write(src); assertEquals(5, victim.count()); } @Test public void closedWrite() throws Exception { victim.close(); assertThrows(ClosedChannelException.class, () -> { victim.write(src); }); } @Test public void write() throws Exception { victim.write(src); assertTrue(Arrays.equals(out.toByteArray(), src.array())); } @Test public void isOpen() { assertTrue(victim.isOpen()); assertTrue(wrapped.isOpen()); } @Test public void close() throws Exception { assertTrue(victim.isOpen()); assertTrue(wrapped.isOpen()); victim.close(); assertFalse(victim.isOpen()); assertFalse(wrapped.isOpen()); } @Test public void testFromWritableByteChannel() throws Exception { victim = CountingWritableByteChannel.from(Channels.newChannel(out)); victim.write(src); assertTrue(Arrays.equals(out.toByteArray(), src.array())); } @Test public void fromOutputStream() throws Exception { victim = CountingWritableByteChannel.from(out); victim.write(src); assertTrue(Arrays.equals(out.toByteArray(), src.array())); } @Test public void fromFile() throws Exception { Path tempFile = Files.createTempFile("SAMBox", null); try { assertEquals(0, Files.size(tempFile)); victim = CountingWritableByteChannel.from(tempFile.toFile()); victim.write(src); assertTrue(Arrays.equals(Files.readAllBytes(tempFile), src.array())); } finally { Files.deleteIfExists(tempFile); } } @Test public void fromString() throws Exception { Path tempFile = Files.createTempFile("SAMBox", null); try { assertEquals(0, Files.size(tempFile)); victim = CountingWritableByteChannel.from(tempFile.toAbsolutePath().toString()); victim.write(src); assertTrue(Arrays.equals(Files.readAllBytes(tempFile), src.array())); } finally { Files.deleteIfExists(tempFile); } } } sejda-io-2.1.4/src/test/java/org/sejda/io/DevNullWritableByteChannelTest.java000066400000000000000000000027061425511572700270650ustar00rootroot00000000000000/* * Copyright 2018 Sober Lemur S.a.s. di Vacondio Andrea * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.io; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import java.nio.ByteBuffer; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * @author Andrea Vacondio * */ public class DevNullWritableByteChannelTest { private DevNullWritableByteChannel victim; private ByteBuffer src = ByteBuffer.wrap(new byte[] { '1', '1', '2', '1', '1' }); @BeforeEach public void setUp() { victim = new DevNullWritableByteChannel(); } @Test public void write() { assertEquals(5, victim.write(src)); } @Test public void close() { assertTrue(victim.isOpen()); victim.close(); assertFalse(victim.isOpen()); } } sejda-io-2.1.4/src/test/java/org/sejda/io/FileChannelSeekableSourceTest.java000066400000000000000000000066471425511572700267020ustar00rootroot00000000000000/* * Copyright 2018 Sober Lemur S.a.s. di Vacondio Andrea * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.io; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * @author Andrea Vacondio */ public class FileChannelSeekableSourceTest extends BaseTestSeekableSource { private FileChannelSeekableSource victim; private Path tempFile; @BeforeEach public void setUp() throws Exception { tempFile = Files.createTempFile("SejdaIO", null); Files.copy(getClass().getResourceAsStream("/pdf/simple_test.pdf"), tempFile, StandardCopyOption.REPLACE_EXISTING); victim = new FileChannelSeekableSource(tempFile.toFile()); } @AfterEach public void after() throws IOException { Files.deleteIfExists(tempFile); } @Test public void failingConstructor() { assertThrows(IllegalArgumentException.class, () -> { new FileChannelSeekableSource(null); }, "Input file cannot be null"); } @Test public void read() throws IOException { assertEquals(0, victim.position()); assertNotNull(victim.read()); assertNotNull(victim.read()); assertEquals(2, victim.position()); victim.position(victim.size()); assertEquals(-1, victim.read()); } @Test public void readBuff() throws IOException { ByteBuffer dst = ByteBuffer.allocate(20); victim.read(dst); dst.flip(); assertEquals(20, dst.remaining()); assertEquals(20, victim.position()); victim.position(victim.size()); ByteBuffer empty = ByteBuffer.allocate(10); victim.read(empty); empty.flip(); assertFalse(empty.hasRemaining()); } @Test public void reset() throws IOException { ByteBuffer dst = ByteBuffer.allocate(20); victim.read(dst); assertEquals(20, victim.position()); victim.reset(); assertEquals(0, victim.position()); } @Test public void newInputStream() throws IOException { int length = 20; byte[] buffer1 = new byte[length]; byte[] buffer2 = new byte[length]; victim.asNewInputStream().read(buffer1); victim.asNewInputStream().read(buffer2); assertArrayEquals(buffer1, buffer2); assertEquals(length, victim.position()); } @Override SeekableSource victim() { return victim; } } sejda-io-2.1.4/src/test/java/org/sejda/io/MemoryMappedSeekableSourceTest.java000066400000000000000000000111731425511572700271170ustar00rootroot00000000000000/* * Copyright 2018 Sober Lemur S.a.s. di Vacondio Andrea * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.io; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; public class MemoryMappedSeekableSourceTest extends BaseTestSeekableSource { private MemoryMappedSeekableSource victim; private Path tempFile; @BeforeEach public void setUp() throws Exception { tempFile = Files.createTempFile("SejdaIO", null); Files.copy(getClass().getResourceAsStream("/pdf/simple_test.pdf"), tempFile, StandardCopyOption.REPLACE_EXISTING); victim = new MemoryMappedSeekableSource(tempFile.toFile()); } @AfterEach public void after() throws IOException { System.getProperties().remove(SeekableSources.MEMORY_MAPPED_PAGE_SIZE_PROPERTY); Files.deleteIfExists(tempFile); } @Test public void failingConstructor() { assertThrows(IllegalArgumentException.class, () -> { new MemoryMappedSeekableSource(null); }, "Input file cannot be null"); } @Test public void read() throws IOException { assertEquals(0, victim.position()); assertNotNull(victim.read()); assertNotNull(victim.read()); assertEquals(2, victim.position()); victim.position(victim.size()); assertEquals(-1, victim.read()); } @Test public void pagedRead() throws IOException { System.setProperty(SeekableSources.MEMORY_MAPPED_PAGE_SIZE_PROPERTY, "50"); Path tempFile = Files.createTempFile("SejdaIO", null); try { Files.copy(getClass().getResourceAsStream("/pdf/simple_test.pdf"), tempFile, StandardCopyOption.REPLACE_EXISTING); victim = new MemoryMappedSeekableSource(tempFile.toFile()); victim.position(49); assertNotNull(victim.read()); assertNotNull(victim.read()); assertNotNull(victim.read()); assertEquals(52, victim.position()); } finally { Files.deleteIfExists(tempFile); } } @Test public void readBuff() throws IOException { ByteBuffer dst = ByteBuffer.allocate(20); victim.read(dst); dst.flip(); assertEquals(20, dst.remaining()); assertEquals(20, victim.position()); victim.position(victim.size()); ByteBuffer empty = ByteBuffer.allocate(10); victim.read(empty); empty.flip(); assertFalse(empty.hasRemaining()); } @Test public void pagedReadBuff() throws IOException { System.setProperty(SeekableSources.MEMORY_MAPPED_PAGE_SIZE_PROPERTY, "50"); Path tempFile = Files.createTempFile("SejdaIO", null); try { Files.copy(getClass().getResourceAsStream("/pdf/simple_test.pdf"), tempFile, StandardCopyOption.REPLACE_EXISTING); victim = new MemoryMappedSeekableSource(tempFile.toFile()); ByteBuffer dst = ByteBuffer.allocate(70); victim.read(dst); dst.flip(); assertEquals(70, dst.remaining()); assertEquals(70, victim.position()); victim.position(victim.size() - 70); ByteBuffer dst2 = ByteBuffer.allocate(120); victim.read(dst2); dst2.flip(); assertEquals(70, dst2.remaining()); victim.position(victim.size()); ByteBuffer empty = ByteBuffer.allocate(10); victim.read(empty); empty.flip(); assertFalse(empty.hasRemaining()); } finally { Files.deleteIfExists(tempFile); } } @Override SeekableSource victim() { return victim; } } sejda-io-2.1.4/src/test/java/org/sejda/io/OffsettableSeekableSourceImplTest.java000066400000000000000000000071211425511572700275760ustar00rootroot00000000000000package org.sejda.io; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.io.IOException; import java.nio.ByteBuffer; import static org.junit.jupiter.api.Assertions.*; /* * Copyright 2022 Sober Lemur S.a.s. di Vacondio Andrea and Sejda BV * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ public class OffsettableSeekableSourceImplTest extends BaseTestSeekableSource { private ByteArraySeekableSource wrapped; private OffsettableSeekableSource victim; @BeforeEach public void setUp() throws IOException { wrapped = new ByteArraySeekableSource(new byte[] { 'd', 'e', 'f', 'a', 'b', 'c' }); victim = SeekableSources.asOffsettable(wrapped); victim.offset(3); } @Test public void size() { assertEquals(3, victim.size()); } @Test public void failingConstructor() { assertThrows(IllegalArgumentException.class, () -> { new OffsettableSeekableSourceImpl(null); }, "Input decorated SeekableSource cannot be null"); } @Test public void constructor() { assertEquals(wrapped.id(), victim.id()); } @Override @Test public void close() throws IOException { victim.read(); assertTrue(victim.isOpen()); assertTrue(wrapped.isOpen()); victim.close(); assertFalse(victim.isOpen()); assertFalse(wrapped.isOpen()); } @Test public void read() throws IOException { assertEquals(97, victim.read()); assertEquals(1, victim.position()); assertEquals(98, victim.read()); assertEquals(2, victim.position()); assertEquals(99, victim.read()); assertEquals(3, victim.position()); assertEquals(-1, victim.read()); assertEquals(3, victim.position()); } @Test public void readBuff() throws IOException { victim.position(1); ByteBuffer dst = ByteBuffer.allocate(10); victim.read(dst); dst.flip(); assertEquals(2, dst.remaining()); assertEquals(98, dst.get()); assertEquals(99, dst.get()); ByteBuffer empty = ByteBuffer.allocate(10); victim.read(empty); empty.flip(); assertFalse(empty.hasRemaining()); } @Test public void position() throws IOException { assertEquals(0, victim.position()); assertEquals(97, victim.read()); victim.position(0); assertEquals(0, victim.position()); victim.position(0); assertEquals(0, victim.position()); victim.position(2); assertEquals(2, victim.position()); victim.read(); assertEquals(3, victim.position()); assertEquals(-1, victim.read()); victim.position(2); assertEquals(2, victim.position()); victim.position(20); assertEquals(3, victim.position()); assertEquals(-1, victim.read()); } @Test public void closedWrapped() throws IOException { this.wrapped.close(); assertFalse(victim.isOpen()); } @Override SeekableSource victim() { return victim; } }sejda-io-2.1.4/src/test/java/org/sejda/io/SeekableSourceInputStreamTest.java000066400000000000000000000122361425511572700267740ustar00rootroot00000000000000/* * Copyright 2018 Sober Lemur S.a.s. di Vacondio Andrea * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.io; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.io.IOException; import java.nio.ByteBuffer; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; /** * @author Andrea Vacondio * */ public class SeekableSourceInputStreamTest { private SeekableSource source; private SeekableSourceInputStream victim; @BeforeEach public void setUp() { source = mock(SeekableSource.class); when(source.isOpen()).thenReturn(true); victim = new SeekableSourceInputStream(source); } @Test public void nullSource() { assertThrows(IllegalArgumentException.class, () -> { new SeekableSourceInputStream(null); }, "Cannot decorate a null instance"); } @Test public void read() throws IOException { victim.read(); verify(source).read(); } @Test public void readClosed() { when(source.isOpen()).thenReturn(false); assertThrows(IllegalStateException.class, () -> { victim.read(); }); } @Test public void readByteArray() throws IOException { ArgumentCaptor captor = ArgumentCaptor.forClass(ByteBuffer.class); byte[] b = new byte[10]; when(source.size()).thenReturn(20L); when(source.position()).thenReturn(0L); victim.read(b); verify(source).read(captor.capture()); ByteBuffer captured = captor.getValue(); assertEquals(10, captured.capacity()); assertEquals(0, captured.position()); assertTrue(captured.hasArray()); } @Test public void readByteArrayClosed() { when(source.isOpen()).thenReturn(false); assertThrows(IllegalStateException.class, () -> { victim.read(new byte[10]); }); } @Test public void readByteArrayWithPos() throws IOException { ArgumentCaptor captor = ArgumentCaptor.forClass(ByteBuffer.class); byte[] b = new byte[10]; when(source.size()).thenReturn(20L); when(source.position()).thenReturn(0L); victim.read(b, 5, 2); verify(source).read(captor.capture()); ByteBuffer captured = captor.getValue(); assertEquals(10, captured.capacity()); assertEquals(5, captured.position()); assertEquals(7, captured.limit()); assertTrue(captured.hasArray()); } @Test public void readByteArrayWithPosClosed() { when(source.isOpen()).thenReturn(false); assertThrows(IllegalStateException.class, () -> { victim.read(new byte[10], 5, 2); }); } @Test public void readByteArrayWhenEndOfStream() throws IOException { ByteArraySeekableSource source = new ByteArraySeekableSource(new byte[] { -1, 1, 0, 1 }); SeekableSourceInputStream victim = new SeekableSourceInputStream(source); source.position(4); assertEquals(-1, source.read()); byte[] b = new byte[10]; assertEquals(-1, victim.read(b, 5, 2)); } @Test public void available() throws IOException { when(source.size()).thenReturn(20L); when(source.position()).thenReturn(3L); assertEquals(17, victim.available()); } @Test public void availableNotNegative() throws IOException { ByteArraySeekableSource source = new ByteArraySeekableSource(new byte[] { -1, 1, 0, 1 }); SeekableSourceInputStream victim = new SeekableSourceInputStream(source); source.position(10); assertEquals(0, victim.available()); } @Test public void close() throws IOException { victim.close(); verify(source, never()).close(); } @Test public void skip() throws IOException { ByteArraySeekableSource source = new ByteArraySeekableSource(new byte[] { -1, 1, 0, 1 }); SeekableSourceInputStream victim = new SeekableSourceInputStream(source); assertEquals(0, source.position()); victim.skip(2); assertEquals(2, source.position()); assertEquals(2, victim.skip(1000)); } @Test public void skipClosed() { when(source.isOpen()).thenReturn(false); assertThrows(IllegalStateException.class, () -> { victim.skip(5); }); } } sejda-io-2.1.4/src/test/java/org/sejda/io/SeekableSourceViewTest.java000066400000000000000000000124061425511572700254320ustar00rootroot00000000000000/* * Copyright 2018 Sober Lemur S.a.s. di Vacondio Andrea * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.io; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** * @author Andrea Vacondio * */ public class SeekableSourceViewTest extends BaseTestSeekableSource { private SeekableSourceView victim; private Path tempFile; @BeforeEach public void setUp() throws Exception { tempFile = Files.createTempFile("SejdaIO", null); Files.copy(getClass().getResourceAsStream("/pdf/simple_test.pdf"), tempFile, StandardCopyOption.REPLACE_EXISTING); victim = new SeekableSourceView(() -> new FileChannelSeekableSource(tempFile.toFile()), "id", 50, 100); } @AfterEach public void after() throws IOException { Files.deleteIfExists(tempFile); } @Test public void nullSourceConstructor() { assertThrows(IllegalArgumentException.class, () -> { new SeekableSourceView(null, "id", 50, 100); }, "Input decorated SeekableSource cannot be null"); } @Test public void negativeStartPositionConstructor() { assertThrows(IllegalArgumentException.class, () -> { new SeekableSourceView(() -> new ByteArraySeekableSource(new byte[] { -1 }), "id", -10, 100); }, "Starting position cannot be negative"); } @Test public void outOfBoundsStartPositionConstructor() { assertThrows(IllegalArgumentException.class, () -> { new SeekableSourceView(() -> new ByteArraySeekableSource(new byte[] { -1, 2 }), "id", 3, 100); }, "Starting position cannot be higher then wrapped source size"); } @Test public void nullNonPositiveLengthConstructor() { assertThrows(IllegalArgumentException.class, () -> { new SeekableSourceView(() -> new ByteArraySeekableSource(new byte[] { -1 }), "id", 0, 0); }, "View length must be positive"); } @Test public void size() { assertEquals(100, victim.size()); } @Test public void sizeTrimmed() throws IOException { assertEquals(2, new SeekableSourceView(() -> new ByteArraySeekableSource(new byte[] { -1, 2 }), "id", 0, 100).size()); } @Override @Test public void view() throws IOException { assertThrows(RuntimeException.class, () -> { victim().view(0, 2); }, "Cannot create a view of a view"); } @Override @Test public void viewClosed() throws IOException { victim().close(); assertThrows(RuntimeException.class, () -> { victim().view(0, 2); }, "Cannot create a view of a view"); } @Test public void parentClosed() throws IOException { ByteArraySeekableSource wrapped = new ByteArraySeekableSource(new byte[] { -1 }); victim = new SeekableSourceView(() -> wrapped, "id", 0, 1); wrapped.close(); assertTrue(victim.isOpen()); assertThrows(IllegalStateException.class, () -> { victim.read(); }); } @Test public void closeDoesntCloseParent() throws IOException { ByteArraySeekableSource wrapped = new ByteArraySeekableSource(new byte[] { -1 }); victim = new SeekableSourceView(() -> wrapped, "id", 0, 1); victim.close(); assertTrue(wrapped.isOpen()); } @Override SeekableSource victim() { return victim; } @Test public void read() throws IOException { assertEquals(0, victim.position()); assertNotNull(victim.read()); assertNotNull(victim.read()); assertEquals(2, victim.position()); victim.position(victim.size()); assertEquals(-1, victim.read()); } @Test public void readBuff() throws IOException { victim.position(1); ByteBuffer dst = ByteBuffer.allocate(10); victim.read(dst); dst.flip(); assertEquals(10, dst.remaining()); victim.position(victim.size()); ByteBuffer empty = ByteBuffer.allocate(10); victim.read(empty); empty.flip(); assertFalse(empty.hasRemaining()); } @Test public void readBigBuff() throws IOException { ByteBuffer dst = ByteBuffer.allocate(8000); assertEquals(100, victim.read(dst)); } } sejda-io-2.1.4/src/test/java/org/sejda/io/SeekableSourcesTest.java000066400000000000000000000153411425511572700247630ustar00rootroot00000000000000/* * Copyright 2018 Sober Lemur S.a.s. di Vacondio Andrea * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.io; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.StringEndsWith.endsWith; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.sejda.io.SeekableSources.DISABLE_MEMORY_MAPPED_PROPERTY; import static org.sejda.io.SeekableSources.MAPPED_SIZE_THRESHOLD_PROPERTY; import static org.sejda.io.SeekableSources.asOffsettable; import static org.sejda.io.SeekableSources.inMemorySeekableSourceFrom; import static org.sejda.io.SeekableSources.onTempFileSeekableSourceFrom; import static org.sejda.io.SeekableSources.seekableSourceFrom; /** * @author Andrea Vacondio */ public class SeekableSourcesTest { private static String BITNESS; @BeforeAll public static void before() { BITNESS = System.getProperty("sun.arch.data.model"); System.setProperty("sun.arch.data.model", "64"); } @AfterAll public static void after() { System.setProperty("sun.arch.data.model", BITNESS); } @Test public void nullSeekableSourceFrom() { assertThrows(NullPointerException.class, () -> { seekableSourceFrom(null); }); } @Test public void nullInMemorySeekableSourceFromBytes() { assertThrows(NullPointerException.class, () -> { inMemorySeekableSourceFrom((byte[]) null); }); } @Test public void nullInMemorySeekableSourceFromStream() { assertThrows(NullPointerException.class, () -> { inMemorySeekableSourceFrom((InputStream) null); }); } @Test public void nullOnTempFileSeekableSourceFrom() { assertThrows(NullPointerException.class, () -> { onTempFileSeekableSourceFrom(null); }); } @Test public void nullOffsettableSource() { assertThrows(NullPointerException.class, () -> { asOffsettable(null); }); } @Test public void seekableSourceFromTest(@TempDir Path temp) throws IOException { Path test = temp.resolve("test.txt"); Files.createFile(test); assertNotNull(seekableSourceFrom(test.toFile())); } @Test public void aboveThresholdSeekableSourceFrom() throws IOException { try { System.setProperty(MAPPED_SIZE_THRESHOLD_PROPERTY, "10"); Path tempFile = Files.createTempFile("SejdaIO", null); Files.copy(getClass().getResourceAsStream("/pdf/simple_test.pdf"), tempFile, StandardCopyOption.REPLACE_EXISTING); SeekableSource source = seekableSourceFrom(tempFile.toFile()); assertNotNull(source); assertTrue(source instanceof BufferedSeekableSource); assertTrue(((BufferedSeekableSource) source).wrapped() instanceof MemoryMappedSeekableSource); } finally { System.getProperties().remove(MAPPED_SIZE_THRESHOLD_PROPERTY); } } @Test public void disableMemoryMapped() throws IOException { try { System.setProperty(MAPPED_SIZE_THRESHOLD_PROPERTY, "10"); System.setProperty(DISABLE_MEMORY_MAPPED_PROPERTY, "true"); Path tempFile = Files.createTempFile("SejdaIO", null); Files.copy(getClass().getResourceAsStream("/pdf/simple_test.pdf"), tempFile, StandardCopyOption.REPLACE_EXISTING); SeekableSource source = seekableSourceFrom(tempFile.toFile()); assertNotNull(source); assertTrue(source instanceof BufferedSeekableSource); assertTrue(((BufferedSeekableSource) source).wrapped() instanceof FileChannelSeekableSource); } finally { System.getProperties().remove(MAPPED_SIZE_THRESHOLD_PROPERTY); System.getProperties().remove(DISABLE_MEMORY_MAPPED_PROPERTY); } } @Test public void nonMappedMemoryFor32bits() throws IOException { try { System.setProperty(MAPPED_SIZE_THRESHOLD_PROPERTY, "10"); System.setProperty("sun.arch.data.model", "32"); Path tempFile = Files.createTempFile("SejdaIO", null); Files.copy(getClass().getResourceAsStream("/pdf/simple_test.pdf"), tempFile, StandardCopyOption.REPLACE_EXISTING); SeekableSource source = seekableSourceFrom(tempFile.toFile()); assertNotNull(source); assertTrue(source instanceof BufferedSeekableSource); assertTrue(((BufferedSeekableSource) source).wrapped() instanceof FileChannelSeekableSource); } finally { System.getProperties().remove(MAPPED_SIZE_THRESHOLD_PROPERTY); System.setProperty("sun.arch.data.model", BITNESS); } } @Test public void inMemorySeekableSourceFromBytes() { assertNotNull(inMemorySeekableSourceFrom(new byte[] { -1 })); } @Test public void inMemorySeekableSourceFromStream() throws IOException { assertNotNull( inMemorySeekableSourceFrom(getClass().getResourceAsStream("/pdf/simple_test.pdf"))); } @Test public void asOffsettableTest() throws IOException { assertNotNull(asOffsettable(onTempFileSeekableSourceFrom(new ByteArrayInputStream(new byte[] { -1 })))); } @Test public void onTempFileSeekableSourceFromTest() throws IOException { assertNotNull(onTempFileSeekableSourceFrom(new ByteArrayInputStream(new byte[] { -1 }))); } @Test public void onTempFileSeekableSourceFromWithFilenameHint() throws IOException { String filenameHint = "input.pdf"; SeekableSource result = onTempFileSeekableSourceFrom( new ByteArrayInputStream(new byte[] { -1 }), filenameHint); assertThat(result.id(), endsWith(filenameHint)); } } sejda-io-2.1.4/src/test/java/org/sejda/io/ThreadBoundCopiesSupplierTest.java000066400000000000000000000062721425511572700267750ustar00rootroot00000000000000/* * Copyright 2018 Sober Lemur S.a.s. di Vacondio Andrea * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.io; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import java.io.IOException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.function.Supplier; import org.junit.jupiter.api.Test; /** * @author Andrea Vacondio * */ public class ThreadBoundCopiesSupplierTest { @Test public void closeCopies() throws IOException { SeekableSource copy = mock(SeekableSource.class); ThreadBoundCopiesSupplier victim = new ThreadBoundCopiesSupplier<>(() -> copy); assertEquals(copy, victim.get()); victim.close(); verify(copy).close(); } @Test public void differentCopyPerThread() throws IOException, InterruptedException, ExecutionException { SeekableSourceSupplier supplier = () -> new ByteArraySeekableSource(new byte[0]); ThreadBoundCopiesSupplier victim = new ThreadBoundCopiesSupplier<>(supplier); ByteArraySeekableSource first = victim.get(); assertNotNull(first); ByteArraySeekableSource second = CompletableFuture.supplyAsync(() -> { try { return victim.get(); } catch (Exception e) { return null; } }).get(); assertNotNull(second); assertNotEquals(first, second); } @Test public void sameThreadSameCopy() throws IOException, InterruptedException, ExecutionException { SeekableSourceSupplier supplier = () -> new ByteArraySeekableSource(new byte[0]); ThreadBoundCopiesSupplier victim = new ThreadBoundCopiesSupplier<>(supplier); assertEquals(victim.get(), victim.get()); Executor executor = Executors.newSingleThreadExecutor(); Supplier completableSupplier = () -> { try { return victim.get(); } catch (Exception e) { return null; } }; ByteArraySeekableSource first = CompletableFuture.supplyAsync(completableSupplier, executor).get(); ByteArraySeekableSource second = CompletableFuture.supplyAsync(completableSupplier, executor).get(); assertEquals(first, second); } } sejda-io-2.1.4/src/test/resources/000077500000000000000000000000001425511572700170025ustar00rootroot00000000000000sejda-io-2.1.4/src/test/resources/pdf/000077500000000000000000000000001425511572700175535ustar00rootroot00000000000000sejda-io-2.1.4/src/test/resources/pdf/simple_test.pdf000066400000000000000000000014621425511572700226010ustar00rootroot00000000000000%PDF-1.4 %öäüß 1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj 2 0 obj << /Type /Pages /Kids [3 0 R] /Count 1 >> endobj 3 0 obj << /Type /Page /Parent 2 0 R /Resources 4 0 R /MediaBox [0 0 500 800] /Contents 5 0 R /Annots [6 0 R] >> endobj 4 0 obj << /Font << /F1 7 0 R >> >> endobj 5 0 obj << /Length 44 >> stream BT /F1 24 Tf 175 720 Td (Hello World!)Tj ET endstream endobj 6 0 obj << /Type /Annot /Subtype /Text /Rect [175 720 175 720] /Contents (Hello Annotation!) /Open true >> endobj 7 0 obj << /Type /Font /Subtype /Type1 /BaseFont /Helvetica >> endobj 8 0 obj << /Root 1 0 R /ID [ ] /Type /XRef /Size 9 /Filter /FlateDecode /Index [1 7] /W [1 2 0] /Length 29 >> stream xœcdàgdp`d¨ddøÈÈ(ÃÈXÃÈøÆJ endstream endobj startxref 564 %%EOF