├── .classpath ├── .cvsignore ├── .gitignore ├── .project ├── .settings ├── org.eclipse.core.resources.prefs ├── org.eclipse.jdt.core.prefs └── org.eclipse.jdt.ui.prefs ├── LICENSE.txt ├── NOTICE.txt ├── build.xml ├── lib ├── ant.jar ├── commons-cli-1.0-LICENSE ├── commons-cli-1.0.jar └── junit.jar ├── project.properties ├── project.xml ├── readme.txt ├── resources └── logging.properties ├── src ├── main │ └── zipdiff │ │ ├── DifferenceCalculator.java │ │ ├── Differences.java │ │ ├── Main.java │ │ ├── ant │ │ ├── ZipDiffTask.java │ │ └── package.html │ │ ├── output │ │ ├── AbstractBuilder.java │ │ ├── Builder.java │ │ ├── BuilderFactory.java │ │ ├── HtmlBuilder.java │ │ ├── TextBuilder.java │ │ ├── XmlBuilder.java │ │ ├── ZipBuilder.java │ │ └── package.html │ │ ├── package.html │ │ └── util │ │ └── StringUtil.java ├── metadata │ └── JAR-manifest.txt └── test │ └── zipdiff │ └── DifferenceCalculatorTest.java └── xdocs ├── credits.xml ├── index.xml ├── navigation.xml ├── output.xml ├── related.xml ├── sample-output.html └── tools.xml /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.cvsignore: -------------------------------------------------------------------------------- 1 | target 2 | maven.log 3 | velocity.log 4 | build 5 | bin 6 | junit-reports 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | maven.log 3 | velocity.log 4 | build 5 | bin 6 | junit-reports 7 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | zipdiff 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | #Fri Jul 15 10:17:52 CEST 2011 2 | eclipse.preferences.version=1 3 | encoding/=UTF-8 4 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | #Tue Aug 02 14:27:43 CEST 2011 2 | eclipse.preferences.version=1 3 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 4 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 5 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 6 | org.eclipse.jdt.core.compiler.compliance=1.5 7 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 8 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 9 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 10 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 11 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 12 | org.eclipse.jdt.core.compiler.source=1.5 13 | org.eclipse.jdt.core.formatter.align_type_members_on_columns=false 14 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 15 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 16 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 17 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 18 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16 19 | org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 20 | org.eclipse.jdt.core.formatter.alignment_for_assignment=0 21 | org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16 22 | org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 23 | org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80 24 | org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 25 | org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 26 | org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 27 | org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 28 | org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16 29 | org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16 30 | org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 31 | org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 32 | org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 33 | org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 34 | org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 35 | org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 36 | org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 37 | org.eclipse.jdt.core.formatter.blank_lines_after_package=1 38 | org.eclipse.jdt.core.formatter.blank_lines_before_field=1 39 | org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 40 | org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 41 | org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 42 | org.eclipse.jdt.core.formatter.blank_lines_before_method=1 43 | org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 44 | org.eclipse.jdt.core.formatter.blank_lines_before_package=0 45 | org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 46 | org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 47 | org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line 48 | org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line 49 | org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line 50 | org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line 51 | org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line 52 | org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line 53 | org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line 54 | org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line 55 | org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line 56 | org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line 57 | org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line 58 | org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false 59 | org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false 60 | org.eclipse.jdt.core.formatter.comment.format_block_comments=false 61 | org.eclipse.jdt.core.formatter.comment.format_header=false 62 | org.eclipse.jdt.core.formatter.comment.format_html=true 63 | org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=false 64 | org.eclipse.jdt.core.formatter.comment.format_line_comments=false 65 | org.eclipse.jdt.core.formatter.comment.format_source_code=true 66 | org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true 67 | org.eclipse.jdt.core.formatter.comment.indent_root_tags=true 68 | org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert 69 | org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert 70 | org.eclipse.jdt.core.formatter.comment.line_length=3000 71 | org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true 72 | org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true 73 | org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false 74 | org.eclipse.jdt.core.formatter.compact_else_if=true 75 | org.eclipse.jdt.core.formatter.continuation_indentation=4 76 | org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=4 77 | org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off 78 | org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on 79 | org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false 80 | org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true 81 | org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true 82 | org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true 83 | org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true 84 | org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true 85 | org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true 86 | org.eclipse.jdt.core.formatter.indent_empty_lines=false 87 | org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true 88 | org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true 89 | org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true 90 | org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true 91 | org.eclipse.jdt.core.formatter.indentation.size=4 92 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert 93 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert 94 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert 95 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert 96 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert 97 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert 98 | org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert 99 | org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert 100 | org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert 101 | org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=insert 102 | org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert 103 | org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert 104 | org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert 105 | org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert 106 | org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert 107 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert 108 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert 109 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert 110 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert 111 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert 112 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert 113 | org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert 114 | org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert 115 | org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert 116 | org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert 117 | org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert 118 | org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert 119 | org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert 120 | org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert 121 | org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert 122 | org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert 123 | org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert 124 | org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert 125 | org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert 126 | org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert 127 | org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert 128 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert 129 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert 130 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert 131 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert 132 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert 133 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert 134 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert 135 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert 136 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert 137 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert 138 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert 139 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert 140 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert 141 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert 142 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert 143 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert 144 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert 145 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert 146 | org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert 147 | org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert 148 | org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert 149 | org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert 150 | org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert 151 | org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert 152 | org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert 153 | org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert 154 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert 155 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert 156 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert 157 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert 158 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert 159 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert 160 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert 161 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert 162 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert 163 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert 164 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert 165 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert 166 | org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert 167 | org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert 168 | org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert 169 | org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert 170 | org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert 171 | org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert 172 | org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert 173 | org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert 174 | org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert 175 | org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert 176 | org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert 177 | org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert 178 | org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert 179 | org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert 180 | org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert 181 | org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert 182 | org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert 183 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert 184 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert 185 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert 186 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert 187 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert 188 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert 189 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert 190 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert 191 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert 192 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert 193 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert 194 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert 195 | org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert 196 | org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert 197 | org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert 198 | org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert 199 | org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert 200 | org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert 201 | org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert 202 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert 203 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert 204 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert 205 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert 206 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert 207 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert 208 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert 209 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert 210 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert 211 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert 212 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert 213 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert 214 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert 215 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert 216 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert 217 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert 218 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert 219 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert 220 | org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert 221 | org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert 222 | org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert 223 | org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert 224 | org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert 225 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert 226 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert 227 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert 228 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert 229 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert 230 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert 231 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert 232 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert 233 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert 234 | org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert 235 | org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert 236 | org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert 237 | org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert 238 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert 239 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert 240 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert 241 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert 242 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert 243 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert 244 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert 245 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert 246 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert 247 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert 248 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert 249 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert 250 | org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert 251 | org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert 252 | org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert 253 | org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert 254 | org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert 255 | org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert 256 | org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert 257 | org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert 258 | org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert 259 | org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert 260 | org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert 261 | org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert 262 | org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert 263 | org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert 264 | org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert 265 | org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert 266 | org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert 267 | org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert 268 | org.eclipse.jdt.core.formatter.join_lines_in_comments=true 269 | org.eclipse.jdt.core.formatter.join_wrapped_lines=true 270 | org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=true 271 | org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false 272 | org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=true 273 | org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=true 274 | org.eclipse.jdt.core.formatter.lineSplit=300 275 | org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false 276 | org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false 277 | org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 278 | org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=50 279 | org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true 280 | org.eclipse.jdt.core.formatter.tabulation.char=tab 281 | org.eclipse.jdt.core.formatter.tabulation.size=4 282 | org.eclipse.jdt.core.formatter.use_on_off_tags=true 283 | org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false 284 | org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true 285 | org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true 286 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.ui.prefs: -------------------------------------------------------------------------------- 1 | #Tue Aug 02 14:21:30 CEST 2011 2 | cleanup.add_default_serial_version_id=false 3 | cleanup.add_generated_serial_version_id=true 4 | cleanup.add_missing_annotations=true 5 | cleanup.add_missing_deprecated_annotations=true 6 | cleanup.add_missing_methods=false 7 | cleanup.add_missing_nls_tags=false 8 | cleanup.add_missing_override_annotations=true 9 | cleanup.add_missing_override_annotations_interface_methods=true 10 | cleanup.add_serial_version_id=true 11 | cleanup.always_use_blocks=true 12 | cleanup.always_use_parentheses_in_expressions=true 13 | cleanup.always_use_this_for_non_static_field_access=false 14 | cleanup.always_use_this_for_non_static_method_access=false 15 | cleanup.convert_to_enhanced_for_loop=false 16 | cleanup.correct_indentation=true 17 | cleanup.format_source_code=true 18 | cleanup.format_source_code_changes_only=false 19 | cleanup.make_local_variable_final=false 20 | cleanup.make_parameters_final=false 21 | cleanup.make_private_fields_final=false 22 | cleanup.make_type_abstract_if_missing_method=false 23 | cleanup.make_variable_declarations_final=false 24 | cleanup.never_use_blocks=false 25 | cleanup.never_use_parentheses_in_expressions=false 26 | cleanup.organize_imports=true 27 | cleanup.qualify_static_field_accesses_with_declaring_class=false 28 | cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true 29 | cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true 30 | cleanup.qualify_static_member_accesses_with_declaring_class=true 31 | cleanup.qualify_static_method_accesses_with_declaring_class=false 32 | cleanup.remove_private_constructors=false 33 | cleanup.remove_trailing_whitespaces=true 34 | cleanup.remove_trailing_whitespaces_all=true 35 | cleanup.remove_trailing_whitespaces_ignore_empty=false 36 | cleanup.remove_unnecessary_casts=true 37 | cleanup.remove_unnecessary_nls_tags=true 38 | cleanup.remove_unused_imports=true 39 | cleanup.remove_unused_local_variables=false 40 | cleanup.remove_unused_private_fields=true 41 | cleanup.remove_unused_private_members=true 42 | cleanup.remove_unused_private_methods=true 43 | cleanup.remove_unused_private_types=true 44 | cleanup.sort_members=false 45 | cleanup.sort_members_all=false 46 | cleanup.use_blocks=true 47 | cleanup.use_blocks_only_for_return_and_throw=false 48 | cleanup.use_parentheses_in_expressions=true 49 | cleanup.use_this_for_non_static_field_access=false 50 | cleanup.use_this_for_non_static_field_access_only_if_necessary=true 51 | cleanup.use_this_for_non_static_method_access=false 52 | cleanup.use_this_for_non_static_method_access_only_if_necessary=true 53 | cleanup_profile=_HIS 54 | cleanup_settings_version=2 55 | eclipse.preferences.version=1 56 | formatter_profile=_zipdiff 57 | formatter_settings_version=12 58 | org.eclipse.jdt.ui.ignorelowercasenames=true 59 | org.eclipse.jdt.ui.importorder=java;javax;org;com; 60 | org.eclipse.jdt.ui.ondemandthreshold=99 61 | org.eclipse.jdt.ui.staticondemandthreshold=99 62 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | zipdiff is available under the terms of the 3 | Apache License, version 2.0 4 | 5 | Link: http://www.apache.org/licenses/ 6 | -------------------------------------------------------------------------------- /NOTICE.txt: -------------------------------------------------------------------------------- 1 | This product includes software developed by the 2 | Apache Software Foundation (http://www.apache.org/). 3 | -------------------------------------------------------------------------------- /build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 58 | 59 | 60 | 61 | 62 | 63 | 66 | 68 | 69 | 70 | 71 | 72 | 77 | 78 | 79 | 80 | 81 | 82 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /lib/ant.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhnb/zipdiff/a113cc4bbe63d8a7ef29cfa74aa06a7128265ec8/lib/ant.jar -------------------------------------------------------------------------------- /lib/commons-cli-1.0-LICENSE: -------------------------------------------------------------------------------- 1 | /* 2 | * $Header: /home/cvs/jakarta-commons/LICENSE,v 1.4 2002/04/11 13:24:02 dion Exp $ 3 | * $Revision: 1.4 $ 4 | * $Date: 2002/04/11 13:24:02 $ 5 | * 6 | * ==================================================================== 7 | * 8 | * The Apache Software License, Version 1.1 9 | * 10 | * Copyright (c) 1999-2001 The Apache Software Foundation. All rights 11 | * reserved. 12 | * 13 | * Redistribution and use in source and binary forms, with or without 14 | * modification, are permitted provided that the following conditions 15 | * are met: 16 | * 17 | * 1. Redistributions of source code must retain the above copyright 18 | * notice, this list of conditions and the following disclaimer. 19 | * 20 | * 2. Redistributions in binary form must reproduce the above copyright 21 | * notice, this list of conditions and the following disclaimer in 22 | * the documentation and/or other materials provided with the 23 | * distribution. 24 | * 25 | * 3. The end-user documentation included with the redistribution, if 26 | * any, must include the following acknowlegement: 27 | * "This product includes software developed by the 28 | * Apache Software Foundation (http://www.apache.org/)." 29 | * Alternately, this acknowlegement may appear in the software itself, 30 | * if and wherever such third-party acknowlegements normally appear. 31 | * 32 | * 4. The names "The Jakarta Project", "Commons", and "Apache Software 33 | * Foundation" must not be used to endorse or promote products derived 34 | * from this software without prior written permission. For written 35 | * permission, please contact apache@apache.org. 36 | * 37 | * 5. Products derived from this software may not be called "Apache" 38 | * nor may "Apache" appear in their names without prior written 39 | * permission of the Apache Group. 40 | * 41 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 42 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 43 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 44 | * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 45 | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 46 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 47 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 48 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 49 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 50 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 51 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 52 | * SUCH DAMAGE. 53 | * ==================================================================== 54 | * 55 | * This software consists of voluntary contributions made by many 56 | * individuals on behalf of the Apache Software Foundation. For more 57 | * information on the Apache Software Foundation, please see 58 | * . 59 | * 60 | */ 61 | -------------------------------------------------------------------------------- /lib/commons-cli-1.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhnb/zipdiff/a113cc4bbe63d8a7ef29cfa74aa06a7128265ec8/lib/commons-cli-1.0.jar -------------------------------------------------------------------------------- /lib/junit.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nhnb/zipdiff/a113cc4bbe63d8a7ef29cfa74aa06a7128265ec8/lib/junit.jar -------------------------------------------------------------------------------- /project.properties: -------------------------------------------------------------------------------- 1 | # 2 | # $Header: /cvsroot/zipdiff/zipdiff/project.properties,v 1.1 2004/04/12 19:24:15 sullis Exp $ 3 | # 4 | # 5 | # 6 | maven.username=sullis 7 | # ------------------------------------------------------------------------ 8 | # M A V E N J A R O V E R R I D E 9 | # ------------------------------------------------------------------------ 10 | maven.jar.override=on 11 | 12 | # ------------------------------------------------------------------------ 13 | # Jars set explicity by path. 14 | # ------------------------------------------------------------------------ 15 | maven.jar.j2ee=/j2sdkee1.3.1/lib/j2ee.jar 16 | maven.jar.javamail=/javamail-1.3.1/lib/mailapi.jar 17 | 18 | # 19 | # 20 | # If "maven.javadoc.private=true", the javadocs will include 21 | # all classes and all methods 22 | # 23 | # 24 | maven.javadoc.private=false 25 | -------------------------------------------------------------------------------- /project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 3 11 | zipdiff 12 | zipdiff 13 | 0.4 14 | 15 | zipdiff.sourceforge.net 16 | http://zipdiff.sourceforge.net/ 17 | 18 | 2004 19 | zipdiff 20 | 21 | zipdiff 22 | 23 | 24 | zipdiff 25 | 26 | 27 | http://zipdiff.sourceforge.net/ 28 | 29 | http://sourceforge.net/tracker/?group_id=106727 30 | 31 | shell.sourceforge.net 32 | /home/groups/z/zi/zipdiff/htdocs 33 | /home/groups/z/zi/zipdiff/htdocs/download 34 | 35 | 36 | scm:cvs:pserver:anonymous@cvs.sourceforge.net:/cvsroot/zipdiff:zipdiff 37 | http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/zipdiff/ 38 | 39 | 40 | 41 | 42 | zipdiff user list 43 | http://lists.sourceforge.net/lists/listinfo/zipdiff-users 44 | http://lists.sourceforge.net/lists/listinfo/zipdiff-users 45 | http://sourceforge.net/mailarchive/forum.php?forum=zipdiff-users 46 | 47 | 48 | zipdiff CVS list 49 | http://lists.sourceforge.net/lists/listinfo/zipdiff-cvs 50 | http://lists.sourceforge.net/lists/listinfo/zipdiff-cvs 51 | http://sourceforge.net/mailarchive/forum.php?forum=zipdiff-cvs 52 | 53 | 54 | 55 | 56 | 57 | Sean C. Sullivan 58 | sullis 59 | sean --*-- seansullivan --*-- com 60 | 61 | 62 | 63 | James Stewart 64 | jemsquash1 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | ant 73 | ant 74 | 1.6 75 | http://ant.apache.org/ 76 | 77 | 78 | commons-cli 79 | commons-cli 80 | 1.0 81 | http://jakarta.apache.org/commons/cli/ 82 | 83 | 84 | 85 | 86 | zipdiff 87 | ${basedir}/src/main 88 | 89 | 90 | 91 | maven-javadoc-plugin 92 | maven-jxr-plugin 93 | maven-changes-plugin 94 | maven-changelog-plugin 95 | maven-checkstyle-plugin 96 | maven-jdepend-plugin 97 | maven-pmd-plugin 98 | maven-developer-activity-plugin 99 | maven-file-activity-plugin 100 | maven-junit-report-plugin 101 | maven-license-plugin 102 | maven-simian-plugin 103 | maven-tasklist-plugin 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | ZipDiff compares two .zip (.jar, .war, .jar) files and creates a list of differences. Plain text, .xml, .html and even a .zip file are supported as output formats. 2 | 3 | ZipDiff can be executed as command line tool or ant task. 4 | 5 | 6 | Command line arguments 7 | ---------------------- 8 | 9 | java -jar zipdiff.jar -file1 foo.zip -file2 bar.zip [ options] 10 | 11 | Valid options are: 12 | 13 | --comparecrcvalues compares the crc values instead of the file content 14 | --comparetimestamps compares timestamps instead of file content 15 | --ignorecvsfiles ignores differences in CVS folders 16 | --outputfile name of the output file 17 | --skipoutputprefixes n number of path segment to skip in the output file 18 | --skipprefixes1 n number of path segment to skip in the first file 19 | --skipprefixes2 n number of path segment to skip in the second file 20 | --exitwitherrorondifference use an error code other than 0, if differences have been detected 21 | --verbose print detail messages 22 | 23 | 24 | 25 | This version can be found at https://github.com/nhnb/zipdiff 26 | 27 | 28 | The original zipdiff project was developed by Sean C. Sullivan and James Stewart at http://zipdiff.sourceforge.net/ 29 | 30 | License: see LICENSE.txt 31 | -------------------------------------------------------------------------------- /resources/logging.properties: -------------------------------------------------------------------------------- 1 | # run with -Djava.util.logging.config.file=resources/logging.properties 2 | 3 | handlers= java.util.logging.ConsoleHandler 4 | 5 | .level = FINEST 6 | 7 | java.util.logging.ConsoleHandler.level=FINEST 8 | 9 | java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter 10 | 11 | zipdiff.DifferenceCalculator.level=FINER 12 | 13 | -------------------------------------------------------------------------------- /src/main/zipdiff/DifferenceCalculator.java: -------------------------------------------------------------------------------- 1 | /* zipdiff is available under the terms of the 2 | * Apache License, version 2.0 3 | * 4 | * Link: http://www.apache.org/licenses/ 5 | */ 6 | package zipdiff; 7 | 8 | import java.io.File; 9 | import java.io.IOException; 10 | import java.io.InputStream; 11 | import java.util.Enumeration; 12 | import java.util.HashMap; 13 | import java.util.HashSet; 14 | import java.util.Iterator; 15 | import java.util.Map; 16 | import java.util.Set; 17 | import java.util.logging.Level; 18 | import java.util.logging.Logger; 19 | import java.util.regex.Matcher; 20 | import java.util.regex.Pattern; 21 | import java.util.zip.ZipEntry; 22 | import java.util.zip.ZipFile; 23 | import java.util.zip.ZipInputStream; 24 | 25 | import zipdiff.util.StringUtil; 26 | 27 | /** 28 | * Checks and compiles differences between two zip files. 29 | * It also has the ability to exclude entries from the comparison 30 | * based on a regular expression. 31 | * 32 | * @author Sean C. Sullivan, Hendrik Brummermann 33 | */ 34 | public class DifferenceCalculator { 35 | 36 | private final Logger logger = Logger.getLogger(getClass().getName()); 37 | 38 | private final ZipFile file1; 39 | 40 | private final ZipFile file2; 41 | 42 | private int numberOfPrefixesToSkip1 = 0; 43 | 44 | private int numberOfPrefixesToSkip2 = 0; 45 | 46 | private boolean ignoreTimestamps = false; 47 | 48 | private boolean ignoreCVSFiles = false; 49 | 50 | private boolean compareCRCValues = true; 51 | 52 | private Pattern filesToIgnorePattern; 53 | 54 | private boolean bVerbose = false; 55 | 56 | protected void debug(Object msg) { 57 | if (isVerboseEnabled()) { 58 | System.out.println("[" + DifferenceCalculator.class.getName() + "] " + String.valueOf(msg)); 59 | } 60 | } 61 | 62 | /** 63 | * Set the verboseness of the debug output. 64 | * @param b true to make verbose 65 | */ 66 | public void setVerbose(boolean b) { 67 | bVerbose = b; 68 | } 69 | 70 | protected boolean isVerboseEnabled() { 71 | return bVerbose; 72 | } 73 | 74 | /** 75 | * Constructor taking 2 filenames to compare 76 | * @throws java.io.IOException 77 | */ 78 | public DifferenceCalculator(String filename1, String filename2) throws java.io.IOException { 79 | this(new File(filename1), new File(filename2)); 80 | } 81 | 82 | /** 83 | * Constructor taking 2 Files to compare 84 | * @throws java.io.IOException 85 | */ 86 | public DifferenceCalculator(File f1, File f2) throws java.io.IOException { 87 | this(new ZipFile(f1), new ZipFile(f2)); 88 | } 89 | 90 | /** 91 | * Constructor taking 2 ZipFiles to compare 92 | */ 93 | public DifferenceCalculator(ZipFile zf1, ZipFile zf2) { 94 | file1 = zf1; 95 | file2 = zf2; 96 | } 97 | 98 | /** 99 | * 100 | * @param Set A set of regular expressions that when matched against a ZipEntry 101 | * then that ZipEntry will be ignored from the comparison. 102 | * @see java.util.regex 103 | */ 104 | public void setFilenameRegexToIgnore(Set patterns) { 105 | if (patterns == null) { 106 | filesToIgnorePattern = null; 107 | } else if (patterns.isEmpty()) { 108 | filesToIgnorePattern = null; 109 | } else { 110 | String regex = ""; 111 | 112 | Iterator iter = patterns.iterator(); 113 | while (iter.hasNext()) { 114 | String pattern = (String) iter.next(); 115 | if (regex.length() > 0) { 116 | regex += "|"; 117 | } 118 | regex += "(" + pattern + ")"; 119 | } 120 | filesToIgnorePattern = Pattern.compile(regex); 121 | logger.log(Level.FINE, "Regular expression is : " + regex); 122 | } 123 | } 124 | 125 | /** 126 | * returns true if fileToIgnorePattern matches the filename given. 127 | * @param filepath 128 | * @param filename The name of the file to check to see if it should be ignored. 129 | * @return true if the file should be ignored. 130 | */ 131 | protected boolean ignoreThisFile(String filepath, String entryName) { 132 | if (entryName == null) { 133 | return false; 134 | } else if (isCVSFile(filepath, entryName) && (ignoreCVSFiles())) { 135 | return true; 136 | } else if (filesToIgnorePattern == null) { 137 | return false; 138 | } else { 139 | Matcher m = filesToIgnorePattern.matcher(entryName); 140 | boolean match = m.matches(); 141 | if (match) { 142 | logger.log(Level.FINEST, "Found a match against : " + entryName + " so excluding"); 143 | } 144 | return match; 145 | } 146 | } 147 | 148 | protected boolean isCVSFile(String filepath, String entryName) { 149 | if (entryName == null) { 150 | return false; 151 | } else if ((filepath.indexOf("CVS/") != -1) || (entryName.indexOf("CVS/") != -1)) { 152 | return true; 153 | } else { 154 | return false; 155 | } 156 | } 157 | 158 | /** 159 | * Ensure that the comparison checks against the CRCs of the entries. 160 | * @param b true ensures that CRCs will be checked 161 | */ 162 | public void setCompareCRCValues(boolean b) { 163 | compareCRCValues = b; 164 | } 165 | 166 | /** 167 | * @return true if this instance will check the CRCs of each ZipEntry 168 | */ 169 | public boolean getCompareCRCValues() { 170 | return compareCRCValues; 171 | } 172 | 173 | /** 174 | * sets the number of directory prefixes to skip in the first file 175 | * 176 | * @param numberOfPrefixesToSkip1 number of directory prefixes to skip 177 | */ 178 | public void setNumberOfPrefixesToSkip1(int numberOfPrefixesToSkip1) { 179 | this.numberOfPrefixesToSkip1 = numberOfPrefixesToSkip1; 180 | } 181 | 182 | /** 183 | * @return number of directory prefixes to skip 184 | */ 185 | public int getNumberOfPrefixesToSkip1() { 186 | return numberOfPrefixesToSkip1; 187 | } 188 | 189 | /** 190 | * sets the number of directory prefixes to skip in the first file 191 | * 192 | * @param numberOfPrefixesToSkip2 number of directory prefixes to skip 193 | */ 194 | public void setNumberOfPrefixesToSkip2(int numberOfPrefixesToSkip2) { 195 | this.numberOfPrefixesToSkip2 = numberOfPrefixesToSkip2; 196 | } 197 | 198 | /** 199 | * @return number of directory prefixes to skip 200 | */ 201 | public int getNumberOfPrefixesToSkip2() { 202 | return numberOfPrefixesToSkip2; 203 | } 204 | 205 | 206 | /** 207 | * Opens the ZipFile and builds up a map of all the entries. The key is the name of 208 | * the entry and the value is the ZipEntry itself. 209 | * @param zf The ZipFile for which to build up the map of ZipEntries 210 | * @return The map containing all the ZipEntries. The key being the name of the ZipEntry. 211 | * @throws java.io.IOException 212 | * @Deprecated 213 | */ 214 | protected Map buildZipEntryMap(ZipFile zf) throws java.io.IOException { 215 | return buildZipEntryMap(zf, 0); 216 | } 217 | 218 | /** 219 | * Opens the ZipFile and builds up a map of all the entries. The key is the name of 220 | * the entry and the value is the ZipEntry itself. 221 | * @param zf The ZipFile for which to build up the map of ZipEntries 222 | * @param number of directory prefixes to skip 223 | * @return The map containing all the ZipEntries. The key being the name of the ZipEntry. 224 | * @throws java.io.IOException 225 | */ 226 | protected Map buildZipEntryMap(ZipFile zf, int p) throws java.io.IOException { 227 | Map zipEntryMap = new HashMap(); 228 | try { 229 | Enumeration entries = zf.entries(); 230 | while (entries.hasMoreElements()) { 231 | ZipEntry entry = (ZipEntry) entries.nextElement(); 232 | InputStream is = null; 233 | try { 234 | is = zf.getInputStream(entry); 235 | processZipEntry("", entry, is, zipEntryMap, p); 236 | } finally { 237 | if (is != null) { 238 | is.close(); 239 | } 240 | } 241 | } 242 | } finally { 243 | zf.close(); 244 | } 245 | 246 | return zipEntryMap; 247 | } 248 | 249 | /** 250 | * Will place ZipEntries for a given ZipEntry into the given Map. More ZipEntries will result 251 | * if zipEntry is itself a ZipFile. All embedded ZipFiles will be processed with their names 252 | * prefixed onto the names of their ZipEntries. 253 | * @param prefix The prefix of the ZipEntry that should be added to the key. Typically used 254 | * when processing embedded ZipFiles. The name of the embedded ZipFile would be the prefix of 255 | * all the embedded ZipEntries. 256 | * @param zipEntry The ZipEntry to place into the Map. If it is a ZipFile then all its ZipEntries 257 | * will also be placed in the Map. 258 | * @param is The InputStream of the corresponding ZipEntry. 259 | * @param zipEntryMap The Map in which to place all the ZipEntries into. The key will 260 | * be the name of the ZipEntry. 261 | * @throws IOException 262 | * @Deprecated 263 | */ 264 | protected void processZipEntry(String prefix, ZipEntry zipEntry, InputStream is, Map zipEntryMap) throws IOException { 265 | processZipEntry(prefix, zipEntry, is, zipEntryMap, 0); 266 | } 267 | 268 | 269 | /** 270 | * Will place ZipEntries for a given ZipEntry into the given Map. More ZipEntries will result 271 | * if zipEntry is itself a ZipFile. All embedded ZipFiles will be processed with their names 272 | * prefixed onto the names of their ZipEntries. 273 | * @param prefix The prefix of the ZipEntry that should be added to the key. Typically used 274 | * when processing embedded ZipFiles. The name of the embedded ZipFile would be the prefix of 275 | * all the embedded ZipEntries. 276 | * @param zipEntry The ZipEntry to place into the Map. If it is a ZipFile then all its ZipEntries 277 | * will also be placed in the Map. 278 | * @param is The InputStream of the corresponding ZipEntry. 279 | * @param zipEntryMap The Map in which to place all the ZipEntries into. The key will 280 | * be the name of the ZipEntry. 281 | * @param p number of directory prefixes to skip 282 | * @throws IOException 283 | */ 284 | protected void processZipEntry(String prefix, ZipEntry zipEntry, InputStream is, Map zipEntryMap, int p) throws IOException { 285 | if (ignoreThisFile(prefix, zipEntry.getName())) { 286 | logger.log(Level.FINE, "ignoring file: " + zipEntry.getName()); 287 | } else { 288 | String name = StringUtil.removeDirectoryPrefix(prefix + zipEntry.getName(), p); 289 | if ((name == null) || name.equals("")) { 290 | return; 291 | } 292 | 293 | logger.log(Level.FINEST, "processing ZipEntry: " + name); 294 | zipEntryMap.put(name, zipEntry); 295 | 296 | if (!zipEntry.isDirectory() && isZipFile(name)) { 297 | processEmbeddedZipFile(name + "!", is, zipEntryMap); 298 | } 299 | } 300 | } 301 | 302 | 303 | 304 | protected void processEmbeddedZipFile(String prefix, InputStream is, Map m) throws java.io.IOException { 305 | ZipInputStream zis = new ZipInputStream(is); 306 | 307 | ZipEntry entry = zis.getNextEntry(); 308 | 309 | while (entry != null) { 310 | processZipEntry(prefix, entry, zis, m); 311 | zis.closeEntry(); 312 | entry = zis.getNextEntry(); 313 | } 314 | 315 | } 316 | 317 | /** 318 | * Returns true if the filename has a valid zip extension. 319 | * i.e. jar, war, ear, zip etc. 320 | * @param filename The name of the file to check. 321 | * @return true if it has a valid extension. 322 | */ 323 | public static boolean isZipFile(String filename) { 324 | boolean result; 325 | 326 | if (filename == null) { 327 | result = false; 328 | } else { 329 | String lowercaseName = filename.toLowerCase(); 330 | if (lowercaseName.endsWith(".zip")) { 331 | result = true; 332 | } else if (lowercaseName.endsWith(".ear")) { 333 | result = true; 334 | } else if (lowercaseName.endsWith(".war")) { 335 | result = true; 336 | } else if (lowercaseName.endsWith(".rar")) { 337 | result = true; 338 | } else if (lowercaseName.endsWith(".jar")) { 339 | result = true; 340 | } else { 341 | result = false; 342 | } 343 | } 344 | 345 | return result; 346 | } 347 | 348 | /** 349 | * Calculates all the differences between two zip files. 350 | * It builds up the 2 maps of ZipEntries for the two files 351 | * and then compares them. 352 | * @param zf1 The first ZipFile to compare 353 | * @param zf2 The second ZipFile to compare 354 | * @return All the differences between the two files. 355 | * @throws java.io.IOException 356 | * @Deprecated 357 | */ 358 | protected Differences calculateDifferences(ZipFile zf1, ZipFile zf2) throws java.io.IOException { 359 | return calculateDifferences(zf1, zf2, 0, 0); 360 | } 361 | 362 | /** 363 | * Calculates all the differences between two zip files. 364 | * It builds up the 2 maps of ZipEntries for the two files 365 | * and then compares them. 366 | * @param zf1 The first ZipFile to compare 367 | * @param zf2 The second ZipFile to compare 368 | * @param p1 number of directory prefixes to skip in the 1st file 369 | * @param p2 number of directory prefixes to skip in the 2nd file 370 | * @return All the differences between the two files. 371 | * @throws java.io.IOException 372 | */ 373 | protected Differences calculateDifferences(ZipFile zf1, ZipFile zf2, int p1, int p2) throws java.io.IOException { 374 | Map map1 = buildZipEntryMap(zf1, p1); 375 | Map map2 = buildZipEntryMap(zf2, p2); 376 | 377 | return calculateDifferences(map1, map2); 378 | } 379 | 380 | /** 381 | * Given two Maps of ZipEntries it will generate a Differences of all the 382 | * differences found between the two maps. 383 | * @return All the differences found between the two maps 384 | */ 385 | protected Differences calculateDifferences(Map m1, Map m2) { 386 | Differences d = new Differences(); 387 | 388 | Set names1 = m1.keySet(); 389 | Set names2 = m2.keySet(); 390 | 391 | Set allNames = new HashSet(); 392 | allNames.addAll(names1); 393 | allNames.addAll(names2); 394 | 395 | Iterator iterAllNames = allNames.iterator(); 396 | while (iterAllNames.hasNext()) { 397 | String name = (String) iterAllNames.next(); 398 | if (ignoreThisFile("", name)) { 399 | // do nothing 400 | } else if (names1.contains(name) && (!names2.contains(name))) { 401 | d.fileRemoved(name, (ZipEntry) m1.get(name)); 402 | } else if (names2.contains(name) && (!names1.contains(name))) { 403 | d.fileAdded(name, (ZipEntry) m2.get(name)); 404 | } else if (names1.contains(name) && (names2.contains(name))) { 405 | ZipEntry entry1 = (ZipEntry) m1.get(name); 406 | ZipEntry entry2 = (ZipEntry) m2.get(name); 407 | if (!entriesMatch(entry1, entry2)) { 408 | d.fileChanged(name, entry1, entry2); 409 | } 410 | } else { 411 | throw new IllegalStateException("unexpected state"); 412 | } 413 | } 414 | 415 | return d; 416 | } 417 | 418 | /** 419 | * returns true if the two entries are equivalent in type, name, size, compressed size 420 | * and time or CRC. 421 | * @param entry1 The first ZipEntry to compare 422 | * @param entry2 The second ZipEntry to compare 423 | * @return true if the entries are equivalent. 424 | */ 425 | protected boolean entriesMatch(ZipEntry entry1, ZipEntry entry2) { 426 | boolean result; 427 | 428 | result = (entry1.isDirectory() == entry2.isDirectory()) && (entry1.getSize() == entry2.getSize()) && (entry1.getCompressedSize() == entry2.getCompressedSize()); 429 | 430 | if (!isIgnoringTimestamps()) { 431 | result = result && (entry1.getTime() == entry2.getTime()); 432 | } 433 | 434 | if (getCompareCRCValues()) { 435 | result = result && (entry1.getCrc() == entry2.getCrc()); 436 | } 437 | return result; 438 | } 439 | 440 | public void setIgnoreTimestamps(boolean b) { 441 | ignoreTimestamps = b; 442 | } 443 | 444 | public boolean isIgnoringTimestamps() { 445 | return ignoreTimestamps; 446 | } 447 | 448 | public boolean ignoreCVSFiles() { 449 | return ignoreCVSFiles; 450 | } 451 | 452 | public void setIgnoreCVSFiles(boolean b) { 453 | ignoreCVSFiles = b; 454 | } 455 | 456 | /** 457 | * 458 | * @return all the differences found between the two zip files. 459 | * @throws java.io.IOException 460 | */ 461 | public Differences getDifferences() throws java.io.IOException { 462 | Differences d = calculateDifferences(file1, file2, numberOfPrefixesToSkip1, numberOfPrefixesToSkip2); 463 | d.setFilename1(file1.getName()); 464 | d.setFilename2(file2.getName()); 465 | 466 | return d; 467 | } 468 | } 469 | -------------------------------------------------------------------------------- /src/main/zipdiff/Differences.java: -------------------------------------------------------------------------------- 1 | /* zipdiff is available under the terms of the 2 | * Apache License, version 2.0 3 | * 4 | * Link: http://www.apache.org/licenses/ 5 | */ 6 | package zipdiff; 7 | 8 | import java.util.Iterator; 9 | import java.util.Map; 10 | import java.util.Set; 11 | import java.util.TreeMap; 12 | import java.util.zip.ZipEntry; 13 | 14 | /** 15 | * Used to keep track of difference between 2 zip files. 16 | * 17 | * @author Sean C. Sullivan 18 | */ 19 | public class Differences { 20 | private final Map added = new TreeMap(); 21 | 22 | private final Map removed = new TreeMap(); 23 | 24 | private final Map changed = new TreeMap(); 25 | 26 | private final Map ignored = new TreeMap(); 27 | 28 | private String filename1; 29 | 30 | private String filename2; 31 | 32 | public Differences() { 33 | // todo 34 | } 35 | 36 | public void setFilename1(String filename) { 37 | filename1 = filename; 38 | } 39 | 40 | public void setFilename2(String filename) { 41 | filename2 = filename; 42 | } 43 | 44 | public String getFilename1() { 45 | return filename1; 46 | } 47 | 48 | public String getFilename2() { 49 | return filename2; 50 | } 51 | 52 | public void fileAdded(String fqn, ZipEntry ze) { 53 | added.put(fqn, ze); 54 | } 55 | 56 | public void fileRemoved(String fqn, ZipEntry ze) { 57 | removed.put(fqn, ze); 58 | } 59 | 60 | public void fileIgnored(String fqn, ZipEntry ze) { 61 | ignored.put(fqn, ze); 62 | } 63 | 64 | public void fileChanged(String fqn, ZipEntry z1, ZipEntry z2) { 65 | ZipEntry[] entries = new ZipEntry[2]; 66 | entries[0] = z1; 67 | entries[1] = z2; 68 | changed.put(fqn, entries); 69 | } 70 | 71 | public Map getAdded() { 72 | return added; 73 | } 74 | 75 | public Map getRemoved() { 76 | return removed; 77 | } 78 | 79 | public Map getChanged() { 80 | return changed; 81 | } 82 | 83 | public Map getIgnored() { 84 | return ignored; 85 | } 86 | 87 | public boolean hasDifferences() { 88 | return ((getChanged().size() > 0) || (getAdded().size() > 0) || (getRemoved().size() > 0)); 89 | } 90 | 91 | @Override 92 | public String toString() { 93 | StringBuffer sb = new StringBuffer(); 94 | 95 | if (added.size() == 1) { 96 | sb.append("1 file was"); 97 | } else { 98 | sb.append(added.size() + " files were"); 99 | } 100 | sb.append(" added to " + this.getFilename2() + "\n"); 101 | 102 | Iterator iter = added.keySet().iterator(); 103 | while (iter.hasNext()) { 104 | String name = (String) iter.next(); 105 | sb.append("\t[added] " + name + "\n"); 106 | } 107 | 108 | if (removed.size() == 1) { 109 | sb.append("1 file was"); 110 | } else { 111 | sb.append(removed.size() + " files were"); 112 | } 113 | sb.append(" removed from " + this.getFilename2() + "\n"); 114 | 115 | iter = removed.keySet().iterator(); 116 | while (iter.hasNext()) { 117 | String name = (String) iter.next(); 118 | sb.append("\t[removed] " + name + "\n"); 119 | } 120 | 121 | if (changed.size() == 1) { 122 | sb.append("1 file changed\n"); 123 | } else { 124 | sb.append(changed.size() + " files changed\n"); 125 | } 126 | 127 | Set keys = getChanged().keySet(); 128 | iter = keys.iterator(); 129 | while (iter.hasNext()) { 130 | String name = (String) iter.next(); 131 | ZipEntry[] entries = (ZipEntry[]) getChanged().get(name); 132 | sb.append("\t[changed] " + name + " "); 133 | sb.append(" ( size " + entries[0].getSize()); 134 | sb.append(" : " + entries[1].getSize()); 135 | sb.append(" )\n"); 136 | } 137 | int differenceCount = added.size() + changed.size() + removed.size(); 138 | 139 | sb.append("Total differences: " + differenceCount); 140 | return sb.toString(); 141 | } 142 | 143 | } 144 | -------------------------------------------------------------------------------- /src/main/zipdiff/Main.java: -------------------------------------------------------------------------------- 1 | /* zipdiff is available under the terms of the 2 | * Apache License, version 2.0 3 | * 4 | * Link: http://www.apache.org/licenses/ 5 | */ 6 | package zipdiff; 7 | 8 | import java.io.File; 9 | import java.util.HashSet; 10 | import java.util.Set; 11 | 12 | import org.apache.commons.cli.CommandLine; 13 | import org.apache.commons.cli.CommandLineParser; 14 | import org.apache.commons.cli.GnuParser; 15 | import org.apache.commons.cli.HelpFormatter; 16 | import org.apache.commons.cli.Option; 17 | import org.apache.commons.cli.Options; 18 | import org.apache.commons.cli.ParseException; 19 | 20 | import zipdiff.output.Builder; 21 | import zipdiff.output.BuilderFactory; 22 | 23 | /** 24 | * Provides a command line interface to zipdiff 25 | * 26 | * @author Sean C. Sullivan, J.Stewart, Hendrik Brummermann 27 | */ 28 | public class Main { 29 | private static final int EXITCODE_ERROR = 2; 30 | 31 | private static final int EXITCODE_DIFF = 1; 32 | 33 | private static final String OPTION_COMPARE_CRC_VALUES = "comparecrcvalues"; 34 | 35 | private static final String OPTION_COMPARE_TIMESTAMPS = "comparetimestamps"; 36 | 37 | private static final String OPTION_IGNORE_CVS_FILES = "ignorecvsfiles"; 38 | 39 | private static final String OPTION_OUTPUT_FILE = "outputfile"; 40 | 41 | private static final String OPTION_FILE1 = "file1"; 42 | 43 | private static final String OPTION_FILE2 = "file2"; 44 | 45 | private static final String OPTION_SKIP_OUTPUT_PREFIXES = "skipoutputprefixes"; 46 | 47 | private static final String OPTION_SKIP_PREFIX1 = "skipprefixes1"; 48 | 49 | private static final String OPTION_SKIP_PREFIX2 = "skipprefixes2"; 50 | 51 | private static final String OPTION_REGEX = "regex"; 52 | 53 | private static final String OPTION_EXIT_WITH_ERROR_ON_DIFF = "exitwitherrorondifference"; 54 | 55 | private static final String OPTION_VERBOSE = "verbose"; 56 | 57 | private static final Options options; 58 | 59 | // static initializer 60 | static { 61 | options = new Options(); 62 | 63 | Option compareTS = new Option(OPTION_COMPARE_TIMESTAMPS, OPTION_COMPARE_TIMESTAMPS, false, "Compare timestamps"); 64 | compareTS.setRequired(false); 65 | 66 | Option compareCRC = new Option(OPTION_COMPARE_CRC_VALUES, OPTION_COMPARE_CRC_VALUES, false, "Compare CRC values"); 67 | compareCRC.setRequired(false); 68 | 69 | Option file1 = new Option(OPTION_FILE1, OPTION_FILE1, true, " first file to compare"); 70 | file1.setRequired(true); 71 | 72 | Option file2 = new Option(OPTION_FILE2, OPTION_FILE2, true, " second file to compare"); 73 | file2.setRequired(true); 74 | 75 | Option numberOfOutputPrefixesToSkip = new Option(OPTION_SKIP_OUTPUT_PREFIXES, OPTION_SKIP_OUTPUT_PREFIXES, true, " number of directory prefix to skip in the output file (if supported by outputter"); 76 | numberOfOutputPrefixesToSkip.setRequired(false); 77 | 78 | 79 | Option numberOfPrefixesToSkip1 = new Option(OPTION_SKIP_PREFIX1, OPTION_SKIP_PREFIX1, true, " number of directory prefix to skip for the first file"); 80 | numberOfPrefixesToSkip1.setRequired(false); 81 | 82 | Option numberOfPrefixesToSkip2 = new Option(OPTION_SKIP_PREFIX2, OPTION_SKIP_PREFIX2, true, " number of directory prefix to skip for the second file"); 83 | numberOfPrefixesToSkip2.setRequired(false); 84 | 85 | Option outputFileOption = new Option(OPTION_OUTPUT_FILE, OPTION_OUTPUT_FILE, true, "output filename"); 86 | outputFileOption.setRequired(false); 87 | 88 | Option regex = new Option(OPTION_REGEX, OPTION_REGEX, true, "regular expression to match files to exclude e.g. (?i)meta-inf.*"); 89 | regex.setRequired(false); 90 | 91 | Option ignoreCVSFilesOption = new Option(OPTION_IGNORE_CVS_FILES, OPTION_IGNORE_CVS_FILES, false, "ignore CVS files"); 92 | ignoreCVSFilesOption.setRequired(false); 93 | 94 | Option exitWithError = new Option(OPTION_EXIT_WITH_ERROR_ON_DIFF, OPTION_EXIT_WITH_ERROR_ON_DIFF, false, "if a difference is found then exit with error " + EXITCODE_DIFF); 95 | 96 | Option verboseOption = new Option(OPTION_VERBOSE, OPTION_VERBOSE, false, "verbose mode"); 97 | 98 | options.addOption(compareTS); 99 | options.addOption(compareCRC); 100 | options.addOption(file1); 101 | options.addOption(file2); 102 | options.addOption(numberOfOutputPrefixesToSkip); 103 | options.addOption(numberOfPrefixesToSkip1); 104 | options.addOption(numberOfPrefixesToSkip2); 105 | options.addOption(regex); 106 | options.addOption(ignoreCVSFilesOption); 107 | options.addOption(exitWithError); 108 | options.addOption(verboseOption); 109 | options.addOption(outputFileOption); 110 | } 111 | 112 | private static void checkFile(java.io.File f) { 113 | String filename = f.toString(); 114 | 115 | if (!f.exists()) { 116 | System.err.println("'" + filename + "' does not exist"); 117 | System.exit(EXITCODE_ERROR); 118 | } 119 | 120 | if (!f.canRead()) { 121 | System.err.println("'" + filename + "' is not readable"); 122 | System.exit(EXITCODE_ERROR); 123 | } 124 | 125 | if (f.isDirectory()) { 126 | System.err.println("'" + filename + "' is a directory"); 127 | System.exit(EXITCODE_ERROR); 128 | } 129 | 130 | } 131 | 132 | private static void writeOutputFile(String filename, int numberOfOutputPrefixesToSkip, Differences d) throws java.io.IOException { 133 | Builder builder = BuilderFactory.create(filename); 134 | builder.build(filename, numberOfOutputPrefixesToSkip, d); 135 | } 136 | 137 | /** 138 | * 139 | * The command line interface to zipdiff utility 140 | * 141 | * @param args The command line parameters 142 | * 143 | */ 144 | public static void main(String[] args) { 145 | CommandLineParser parser = new GnuParser(); 146 | 147 | try { 148 | CommandLine line = parser.parse(options, args); 149 | 150 | String filename1 = null; 151 | String filename2 = null; 152 | 153 | filename1 = line.getOptionValue(OPTION_FILE1); 154 | filename2 = line.getOptionValue(OPTION_FILE2); 155 | 156 | File f1 = new File(filename1); 157 | File f2 = new File(filename2); 158 | 159 | checkFile(f1); 160 | checkFile(f2); 161 | 162 | System.out.println("File 1 = " + f1); 163 | System.out.println("File 2 = " + f2); 164 | 165 | DifferenceCalculator calc = new DifferenceCalculator(f1, f2); 166 | 167 | int numberOfPrefixesToSkip1 = 0; 168 | if (line.getOptionValue(OPTION_SKIP_PREFIX1) != null) { 169 | numberOfPrefixesToSkip1 = Integer.parseInt(line.getOptionValue(OPTION_SKIP_PREFIX1)); 170 | } 171 | int numberOfPrefixesToSkip2 = 0; 172 | if (line.getOptionValue(OPTION_SKIP_PREFIX2) != null) { 173 | numberOfPrefixesToSkip2 = Integer.parseInt(line.getOptionValue(OPTION_SKIP_PREFIX2)); 174 | } 175 | int numberOfOutputPrefixesToSkip = 0; 176 | if (line.getOptionValue(OPTION_SKIP_OUTPUT_PREFIXES) != null) { 177 | numberOfOutputPrefixesToSkip = Integer.parseInt(line.getOptionValue(OPTION_SKIP_OUTPUT_PREFIXES)); 178 | } 179 | 180 | calc.setNumberOfPrefixesToSkip1(numberOfPrefixesToSkip1); 181 | calc.setNumberOfPrefixesToSkip2(numberOfPrefixesToSkip2); 182 | 183 | String regularExpression = null; 184 | 185 | // todo - calc.setFilenamesToIgnore(); 186 | 187 | if (line.hasOption(OPTION_COMPARE_CRC_VALUES)) { 188 | calc.setCompareCRCValues(true); 189 | } else { 190 | calc.setCompareCRCValues(false); 191 | } 192 | 193 | if (line.hasOption(OPTION_IGNORE_CVS_FILES)) { 194 | calc.setIgnoreCVSFiles(true); 195 | } else { 196 | calc.setIgnoreCVSFiles(false); 197 | } 198 | 199 | if (line.hasOption(OPTION_COMPARE_TIMESTAMPS)) { 200 | calc.setIgnoreTimestamps(false); 201 | } else { 202 | calc.setIgnoreTimestamps(true); 203 | } 204 | 205 | if (line.hasOption(OPTION_REGEX)) { 206 | regularExpression = line.getOptionValue(OPTION_REGEX); 207 | Set regexSet = new HashSet(); 208 | regexSet.add(regularExpression); 209 | 210 | calc.setFilenameRegexToIgnore(regexSet); 211 | } 212 | 213 | boolean exitWithErrorOnDiff = false; 214 | if (line.hasOption(OPTION_EXIT_WITH_ERROR_ON_DIFF)) { 215 | exitWithErrorOnDiff = true; 216 | } 217 | 218 | Differences d = calc.getDifferences(); 219 | 220 | if (line.hasOption(OPTION_OUTPUT_FILE)) { 221 | String outputFilename = line.getOptionValue(OPTION_OUTPUT_FILE); 222 | writeOutputFile(outputFilename, numberOfOutputPrefixesToSkip, d); 223 | } 224 | 225 | 226 | if (d.hasDifferences()) { 227 | if (line.hasOption(OPTION_VERBOSE)) { 228 | System.out.println(d); 229 | System.out.println(d.getFilename1() + " and " + d.getFilename2() + " are different."); 230 | } 231 | if (exitWithErrorOnDiff) { 232 | System.exit(EXITCODE_DIFF); 233 | } 234 | } else { 235 | System.out.println("No differences found."); 236 | } 237 | } catch (ParseException pex) { 238 | System.err.println(pex.getMessage()); 239 | HelpFormatter formatter = new HelpFormatter(); 240 | formatter.printHelp("zipdiff.Main [options] ", options); 241 | System.exit(EXITCODE_ERROR); 242 | } catch (Exception ex) { 243 | ex.printStackTrace(); 244 | System.exit(EXITCODE_ERROR); 245 | } 246 | 247 | } 248 | 249 | } 250 | -------------------------------------------------------------------------------- /src/main/zipdiff/ant/ZipDiffTask.java: -------------------------------------------------------------------------------- 1 | /* zipdiff is available under the terms of the 2 | * Apache License, version 2.0 3 | * 4 | * Link: http://www.apache.org/licenses/ 5 | */ 6 | package zipdiff.ant; 7 | 8 | import java.io.IOException; 9 | 10 | import org.apache.tools.ant.BuildException; 11 | import org.apache.tools.ant.Task; 12 | 13 | import zipdiff.DifferenceCalculator; 14 | import zipdiff.Differences; 15 | import zipdiff.output.Builder; 16 | import zipdiff.output.BuilderFactory; 17 | 18 | /** 19 | * Ant task for running zipdiff from a build.xml file 20 | * 21 | * 22 | * @author Sean C. Sullivan 23 | */ 24 | public class ZipDiffTask extends Task { 25 | private String filename1; 26 | 27 | private String filename2; 28 | 29 | private int numberOfOutputPrefixesToSkip; 30 | 31 | private int skipPrefixes1 = 0; 32 | 33 | private int SkipPrefixes2 = 0; 34 | 35 | private String destfile; 36 | 37 | private boolean ignoreTimestamps = false; 38 | 39 | private boolean ignoreCVSFiles = false; 40 | 41 | private boolean compareCRCValues = true; 42 | 43 | public void setFilename1(String name) { 44 | filename1 = name; 45 | } 46 | 47 | public void setFilename2(String name) { 48 | filename2 = name; 49 | } 50 | 51 | 52 | 53 | public int getNumberOfOutputPrefixesToSkip() { 54 | return numberOfOutputPrefixesToSkip; 55 | } 56 | 57 | public void setNumberOfOutputPrefixesToSkip(int numberOfOutputPrefixesToSkip) { 58 | this.numberOfOutputPrefixesToSkip = numberOfOutputPrefixesToSkip; 59 | } 60 | 61 | public int getSkipPrefixes1() { 62 | return skipPrefixes1; 63 | } 64 | 65 | public void setSkipPrefixes1(int numberOfPrefixesToSkip1) { 66 | this.skipPrefixes1 = numberOfPrefixesToSkip1; 67 | } 68 | 69 | public int getSkipPrefixes2() { 70 | return SkipPrefixes2; 71 | } 72 | 73 | public void setSkipPrefixes2(int numberOfPrefixesToSkip2) { 74 | this.SkipPrefixes2 = numberOfPrefixesToSkip2; 75 | } 76 | 77 | public void setIgnoreTimestamps(boolean b) { 78 | ignoreTimestamps = b; 79 | } 80 | 81 | public boolean getIgnoreTimestamps() { 82 | return ignoreTimestamps; 83 | } 84 | 85 | public void setIgnoreCVSFiles(boolean b) { 86 | ignoreCVSFiles = b; 87 | } 88 | 89 | public boolean getIgnoreCVSFiles() { 90 | return ignoreCVSFiles; 91 | } 92 | 93 | public void setCompareCRCValues(boolean b) { 94 | compareCRCValues = b; 95 | } 96 | 97 | public boolean getCompareCRCValues() { 98 | return compareCRCValues; 99 | } 100 | 101 | @Override 102 | public void execute() throws BuildException { 103 | validate(); 104 | 105 | // this.log("Filename1=" + filename1, Project.MSG_DEBUG); 106 | // this.log("Filename2=" + filename2, Project.MSG_DEBUG); 107 | // this.log("destfile=" + getDestFile(), Project.MSG_DEBUG); 108 | 109 | Differences d = calculateDifferences(); 110 | 111 | try { 112 | writeDestFile(d); 113 | } catch (java.io.IOException ex) { 114 | throw new BuildException(ex); 115 | } 116 | 117 | } 118 | 119 | /** 120 | * writes the output file 121 | * 122 | * @param d set of Differences 123 | * @throws IOException 124 | */ 125 | protected void writeDestFile(Differences d) throws IOException { 126 | String destfilename = getDestFile(); 127 | Builder builder = BuilderFactory.create(destfilename); 128 | builder.build(destfilename, numberOfOutputPrefixesToSkip, d); 129 | } 130 | 131 | /** 132 | * gets the name of the target file 133 | * 134 | * @return target file 135 | */ 136 | public String getDestFile() { 137 | return destfile; 138 | } 139 | 140 | /** 141 | * sets the name of the target file 142 | * 143 | * @param name filename 144 | */ 145 | public void setDestFile(String name) { 146 | destfile = name; 147 | } 148 | 149 | /** 150 | * calculates the differences 151 | * 152 | * @return set of Differences 153 | * @throws BuildException in case of an input/output error 154 | */ 155 | protected Differences calculateDifferences() throws BuildException { 156 | DifferenceCalculator calculator; 157 | 158 | Differences d = null; 159 | 160 | try { 161 | calculator = new DifferenceCalculator(filename1, filename2); 162 | calculator.setNumberOfPrefixesToSkip1(skipPrefixes1); 163 | calculator.setNumberOfPrefixesToSkip2(SkipPrefixes2); 164 | calculator.setCompareCRCValues(getCompareCRCValues()); 165 | calculator.setIgnoreTimestamps(getIgnoreTimestamps()); 166 | calculator.setIgnoreCVSFiles(getIgnoreCVSFiles()); 167 | 168 | // todo : calculator.setFilenamesToIgnore(patterns); 169 | 170 | d = calculator.getDifferences(); 171 | } catch (IOException ex) { 172 | throw new BuildException(ex); 173 | } 174 | 175 | return d; 176 | } 177 | 178 | /** 179 | * validates the parameters 180 | * 181 | * @throws BuildException in case of invalid parameters 182 | */ 183 | protected void validate() throws BuildException { 184 | if ((filename1 == null) || (filename1.length() < 1)) { 185 | throw new BuildException("filename1 is required"); 186 | } 187 | 188 | if ((filename2 == null) || (filename2.length() < 1)) { 189 | throw new BuildException("filename2 is required"); 190 | } 191 | 192 | String destinationfile = getDestFile(); 193 | 194 | if ((destinationfile == null) || (destinationfile.length() < 1)) { 195 | throw new BuildException("destfile is required"); 196 | } 197 | } 198 | 199 | } 200 | -------------------------------------------------------------------------------- /src/main/zipdiff/ant/package.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | Provides ant tasks for the zipdiff utility. 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/main/zipdiff/output/AbstractBuilder.java: -------------------------------------------------------------------------------- 1 | /* zipdiff is available under the terms of the 2 | * Apache License, version 2.0 3 | * 4 | * Link: http://www.apache.org/licenses/ 5 | */ 6 | package zipdiff.output; 7 | 8 | import java.io.FileOutputStream; 9 | import java.io.IOException; 10 | import java.io.OutputStream; 11 | 12 | import zipdiff.Differences; 13 | 14 | /** 15 | * abstract base class for Builders. 16 | * 17 | * @author Sean C. Sullivan, Hendrik Brummermann 18 | */ 19 | public abstract class AbstractBuilder implements Builder { 20 | 21 | /** number of directory prefixes to skip in the output file */ 22 | protected int numberOfOutputPrefixesToSkip; 23 | 24 | /** 25 | * builds the output 26 | * 27 | * @param filename name of output file 28 | * @param numberOfPrefixesToSkip number of directory prefixes to skip 29 | * @param d differences 30 | * @throws IOException in case of an input/output error 31 | */ 32 | public void build(String filename, int numberOfPrefixesToSkip, Differences d) throws IOException { 33 | this.numberOfOutputPrefixesToSkip = numberOfPrefixesToSkip; 34 | OutputStream os = null; 35 | if ((filename == null) || filename.equals("-")) { 36 | os = System.out; 37 | } else { 38 | os = new FileOutputStream(filename); 39 | } 40 | build(os, d); 41 | os.flush(); 42 | } 43 | 44 | /** 45 | * builds the output 46 | * 47 | * @param out OutputStream to write to 48 | * @param d differences 49 | */ 50 | public abstract void build(OutputStream out, Differences d); 51 | } 52 | -------------------------------------------------------------------------------- /src/main/zipdiff/output/Builder.java: -------------------------------------------------------------------------------- 1 | /* zipdiff is available under the terms of the 2 | * Apache License, version 2.0 3 | * 4 | * Link: http://www.apache.org/licenses/ 5 | */ 6 | package zipdiff.output; 7 | 8 | import java.io.IOException; 9 | 10 | import zipdiff.Differences; 11 | 12 | /** 13 | * Builder pattern: 14 | * http://wiki.cs.uiuc.edu/patternStories/BuilderPattern 15 | * 16 | * @author Sean C. Sullivan 17 | */ 18 | public interface Builder { 19 | 20 | /** 21 | * builds the output 22 | * 23 | * @param filename name of output file 24 | * @param numberOfOutputPrefixesToSkip number of directory prefixes to skip 25 | * @param d differences 26 | * @throws IOException in case of an input/output error 27 | */ 28 | public void build(String filename, int numberOfOutputPrefixesToSkip, Differences d) throws IOException; 29 | } 30 | -------------------------------------------------------------------------------- /src/main/zipdiff/output/BuilderFactory.java: -------------------------------------------------------------------------------- 1 | /* zipdiff is available under the terms of the 2 | * Apache License, version 2.0 3 | * 4 | * Link: http://www.apache.org/licenses/ 5 | */ 6 | package zipdiff.output; 7 | 8 | /** 9 | * creates builders based on the filename extension. 10 | * 11 | * @author Hendrik Brummermann, HIS GmbH 12 | */ 13 | public class BuilderFactory { 14 | 15 | /** 16 | * creates a builder based on the name of the output file 17 | * 18 | * @param filename name of output file 19 | * @return Builder 20 | */ 21 | public static Builder create(String filename) { 22 | Builder builder = null; 23 | 24 | if ((filename == null) || filename.equals("-")) { 25 | builder = new TextBuilder(); 26 | 27 | } else if (filename.endsWith(".html")) { 28 | builder = new HtmlBuilder(); 29 | 30 | } else if (filename.endsWith(".txt")) { 31 | builder = new TextBuilder(); 32 | 33 | } else if (filename.endsWith(".xml")) { 34 | builder = new XmlBuilder(); 35 | 36 | } else if (filename.endsWith(".zip")) { 37 | builder = new ZipBuilder(); 38 | 39 | } else { 40 | System.err.println("Unknown extension, using text output"); 41 | builder = new TextBuilder(); 42 | } 43 | return builder; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/zipdiff/output/HtmlBuilder.java: -------------------------------------------------------------------------------- 1 | /* zipdiff is available under the terms of the 2 | * Apache License, version 2.0 3 | * 4 | * Link: http://www.apache.org/licenses/ 5 | */ 6 | package zipdiff.output; 7 | 8 | import java.io.OutputStream; 9 | import java.io.PrintWriter; 10 | import java.util.Iterator; 11 | import java.util.Set; 12 | 13 | import zipdiff.Differences; 14 | 15 | /** 16 | * Generates html output for a Differences instance 17 | * 18 | * @author Sean C. Sullivan 19 | */ 20 | public class HtmlBuilder extends AbstractBuilder { 21 | 22 | /** 23 | * builds the output 24 | * 25 | * @param out OutputStream to write to 26 | * @param d differences 27 | */ 28 | @Override 29 | public void build(OutputStream out, Differences d) { 30 | PrintWriter pw = new PrintWriter(out); 31 | 32 | pw.println(""); 33 | pw.println(""); 34 | pw.println(""); 35 | pw.println("File differences"); 36 | pw.println(""); 37 | 38 | pw.println(""); 39 | 40 | pw.println(getStyleTag()); 41 | pw.print("

First file: "); 42 | String filename1 = d.getFilename1(); 43 | 44 | if (filename1 == null) { 45 | filename1 = "filename1.zip"; 46 | } 47 | pw.print(filename1); 48 | pw.println("
"); 49 | 50 | pw.print("Second file: "); 51 | 52 | String filename2 = d.getFilename2(); 53 | 54 | if (filename2 == null) { 55 | filename2 = "filename2.zip"; 56 | } 57 | pw.print(filename2); 58 | pw.println("

"); 59 | 60 | writeAdded(pw, d.getAdded().keySet()); 61 | writeRemoved(pw, d.getRemoved().keySet()); 62 | writeChanged(pw, d.getChanged().keySet()); 63 | pw.println("
"); 64 | pw.println("

"); 65 | pw.println("Generated at " + new java.util.Date()); 66 | pw.println("

"); 67 | pw.println(""); 68 | 69 | pw.println(""); 70 | 71 | pw.flush(); 72 | 73 | } 74 | 75 | /** 76 | * writes the list of added files 77 | * 78 | * @param pw write to write to 79 | * @param added set of added files 80 | */ 81 | protected void writeAdded(PrintWriter pw, Set added) { 82 | writeDiffSet(pw, "Added", added); 83 | } 84 | 85 | /** 86 | * writes the list of removed files 87 | * 88 | * @param pw write to write to 89 | * @param removed set of removed files 90 | */ 91 | protected void writeRemoved(PrintWriter pw, Set removed) { 92 | writeDiffSet(pw, "Removed", removed); 93 | } 94 | 95 | /** 96 | * writes the list of modified files 97 | * 98 | * @param pw write to write to 99 | * @param changed set of modified files 100 | */ 101 | protected void writeChanged(PrintWriter pw, Set changed) { 102 | writeDiffSet(pw, "Changed", changed); 103 | } 104 | 105 | /** 106 | * writes a set of differences 107 | * 108 | * @param pw write to write to 109 | * @param name heading 110 | * @param s set 111 | */ 112 | protected void writeDiffSet(PrintWriter pw, String name, Set s) { 113 | pw.println(""); 114 | pw.println(""); 115 | pw.println(""); 116 | pw.println(""); 117 | pw.println(""); 118 | pw.println(""); 120 | pw.println(""); 133 | pw.println(""); 134 | pw.println("
" + name + " (" + s.size() + " entries)
"); 119 | pw.println(""); 121 | if (s.size() > 0) { 122 | pw.println("
    "); 123 | Iterator iter = s.iterator(); 124 | while (iter.hasNext()) { 125 | String key = (String) iter.next(); 126 | pw.print("
  • "); 127 | pw.print(key); 128 | pw.println("
  • "); 129 | } 130 | pw.println("
"); 131 | } 132 | pw.println("
"); 135 | 136 | } 137 | 138 | /** 139 | * generates the style-html-tag. 140 | * 141 | * @return content of style-tag 142 | */ 143 | protected String getStyleTag() { 144 | StringBuffer sb = new StringBuffer(); 145 | 146 | sb.append("\n"); 165 | 166 | return sb.toString(); 167 | } 168 | 169 | } 170 | -------------------------------------------------------------------------------- /src/main/zipdiff/output/TextBuilder.java: -------------------------------------------------------------------------------- 1 | /* zipdiff is available under the terms of the 2 | * Apache License, version 2.0 3 | * 4 | * Link: http://www.apache.org/licenses/ 5 | */ 6 | package zipdiff.output; 7 | 8 | import java.io.OutputStream; 9 | import java.io.PrintWriter; 10 | 11 | import zipdiff.Differences; 12 | 13 | /** 14 | * creates a list of differences. 15 | * 16 | * @author Sean C. Sullivan 17 | */ 18 | public class TextBuilder extends AbstractBuilder { 19 | 20 | /** 21 | * builds the output 22 | * 23 | * @param out OutputStream to write to 24 | * @param d differences 25 | */ 26 | @Override 27 | public void build(OutputStream out, Differences d) { 28 | PrintWriter pw = new PrintWriter(out); 29 | pw.println(d.toString()); 30 | pw.flush(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/zipdiff/output/XmlBuilder.java: -------------------------------------------------------------------------------- 1 | /* zipdiff is available under the terms of the 2 | * Apache License, version 2.0 3 | * 4 | * Link: http://www.apache.org/licenses/ 5 | */ 6 | package zipdiff.output; 7 | 8 | import java.io.OutputStream; 9 | import java.io.PrintWriter; 10 | import java.util.Iterator; 11 | import java.util.Set; 12 | 13 | import zipdiff.Differences; 14 | 15 | /** 16 | * 17 | * Generates xml output for a Differences instance 18 | * 19 | * @author Sean C. Sullivan 20 | * 21 | */ 22 | public class XmlBuilder extends AbstractBuilder { 23 | 24 | /** 25 | * builds the output 26 | * 27 | * @param out OutputStream to write to 28 | * @param d differences 29 | */ 30 | @Override 31 | public void build(OutputStream out, Differences d) { 32 | PrintWriter pw = new PrintWriter(out); 33 | 34 | pw.println(""); 35 | pw.print(""); 52 | 53 | pw.println(""); 54 | writeAdded(pw, d.getAdded().keySet()); 55 | writeRemoved(pw, d.getRemoved().keySet()); 56 | writeChanged(pw, d.getChanged().keySet()); 57 | pw.println(""); 58 | pw.println(""); 59 | 60 | pw.flush(); 61 | } 62 | 63 | /** 64 | * writes the list of added files 65 | * 66 | * @param pw write to write to 67 | * @param added set of added files 68 | */ 69 | protected void writeAdded(PrintWriter pw, Set added) { 70 | Iterator iter = added.iterator(); 71 | while (iter.hasNext()) { 72 | String key = (String) iter.next(); 73 | pw.print(""); 74 | pw.print(key); 75 | pw.println(""); 76 | } 77 | 78 | } 79 | 80 | /** 81 | * writes the list of removed files 82 | * 83 | * @param pw write to write to 84 | * @param removed set of removed files 85 | */ 86 | protected void writeRemoved(PrintWriter pw, Set removed) { 87 | Iterator iter = removed.iterator(); 88 | while (iter.hasNext()) { 89 | String key = (String) iter.next(); 90 | pw.print(""); 91 | pw.print(key); 92 | pw.println(""); 93 | } 94 | } 95 | 96 | /** 97 | * writes the list of modified files 98 | * 99 | * @param pw write to write to 100 | * @param changed set of modified files 101 | */ 102 | protected void writeChanged(PrintWriter pw, Set changed) { 103 | Iterator iter = changed.iterator(); 104 | while (iter.hasNext()) { 105 | String key = (String) iter.next(); 106 | pw.print(""); 107 | pw.print(key); 108 | pw.println(""); 109 | } 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /src/main/zipdiff/output/ZipBuilder.java: -------------------------------------------------------------------------------- 1 | /* zipdiff is available under the terms of the 2 | * Apache License, version 2.0 3 | * 4 | * Link: http://www.apache.org/licenses/ 5 | */ 6 | package zipdiff.output; 7 | 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | import java.io.OutputStream; 11 | import java.util.Iterator; 12 | import java.util.Map; 13 | import java.util.Set; 14 | import java.util.TreeSet; 15 | import java.util.zip.ZipEntry; 16 | import java.util.zip.ZipFile; 17 | import java.util.zip.ZipOutputStream; 18 | 19 | import zipdiff.Differences; 20 | import zipdiff.util.StringUtil; 21 | 22 | /** 23 | * creates a zip file with the new versions of files that have been added or modified 24 | * 25 | * @author Hendrik Brummermann, HIS GmbH 26 | */ 27 | public class ZipBuilder extends AbstractBuilder { 28 | private Differences differences; 29 | 30 | private final Set filenames = new TreeSet(); 31 | 32 | /** 33 | * builds the output 34 | * 35 | * @param out OutputStream to write to 36 | * @param d differences 37 | */ 38 | @Override 39 | public void build(OutputStream out, Differences d) { 40 | differences = d; 41 | try { 42 | collectAddedFiles(); 43 | collectModifiedFiles(); 44 | copyEntries(out); 45 | } catch (IOException e) { 46 | System.err.println("Error while writing zip file: " + e); 47 | e.printStackTrace(); 48 | } 49 | } 50 | 51 | /** 52 | * collects all the files that have been added in the second zip archive 53 | */ 54 | private void collectAddedFiles() { 55 | Set entrySet = differences.getAdded().entrySet(); 56 | Iterator itr = entrySet.iterator(); 57 | while (itr.hasNext()) { 58 | Map.Entry mapEntry = (Map.Entry) itr.next(); 59 | if (mapEntry.getKey().toString().indexOf("!") < 0) { 60 | filenames.add(((ZipEntry) mapEntry.getValue()).getName()); 61 | } 62 | } 63 | } 64 | 65 | /** 66 | * collects all the files that have been added modified in the second zip archive 67 | */ 68 | private void collectModifiedFiles() { 69 | Set entrySet = differences.getChanged().entrySet(); 70 | Iterator itr = entrySet.iterator(); 71 | while (itr.hasNext()) { 72 | Map.Entry mapEntry = (Map.Entry) itr.next(); 73 | if (mapEntry.getKey().toString().indexOf("!") < 0) { 74 | filenames.add(((ZipEntry[]) mapEntry.getValue())[1].getName()); 75 | } 76 | } 77 | } 78 | 79 | /** 80 | * copies the zip entries (with data) from the second archive file to the output file. 81 | * 82 | * @param out output file 83 | * @throws IOException in case of an input/output error 84 | */ 85 | private void copyEntries(OutputStream out) throws IOException { 86 | ZipOutputStream os = new ZipOutputStream(out); 87 | ZipFile zipFile = new ZipFile(differences.getFilename2()); 88 | Iterator itr = filenames.iterator(); 89 | 90 | while (itr.hasNext()) { 91 | String filename = (String) itr.next(); 92 | ZipEntry zipEntry = zipFile.getEntry(filename); 93 | InputStream is = zipFile.getInputStream(zipEntry); 94 | ZipEntry z = new ZipEntry(StringUtil.removeDirectoryPrefix(filename, numberOfOutputPrefixesToSkip)); 95 | os.putNextEntry(z); 96 | copyStream(is, os); 97 | os.closeEntry(); 98 | is.close(); 99 | } 100 | 101 | zipFile.close(); 102 | os.close(); 103 | } 104 | 105 | /** 106 | * copies data from an input stream to an output stream 107 | * 108 | * @param input InputStream 109 | * @param output OutputStream 110 | * @throws IOException in case of an input/output error 111 | */ 112 | private void copyStream(InputStream input, OutputStream output) throws IOException { 113 | byte buffer[] = new byte[4096]; 114 | int count = input.read(buffer); 115 | while (count > -1) { 116 | output.write(buffer, 0, count); 117 | count = input.read(buffer); 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/main/zipdiff/output/package.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | Provides the interface and implementations used for formatting the output of the zipdiff Ant tasks. 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/main/zipdiff/package.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | Utilities for comparing the contents of 2 different zip files. 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/main/zipdiff/util/StringUtil.java: -------------------------------------------------------------------------------- 1 | /* zipdiff is available under the terms of the 2 | * Apache License, version 2.0 3 | * 4 | * Link: http://www.apache.org/licenses/ 5 | */ 6 | package zipdiff.util; 7 | 8 | /** 9 | * String manipulation methods 10 | * 11 | * @author Hendrik Brummermann 12 | */ 13 | public class StringUtil { 14 | 15 | /** 16 | * removes the specified number of prefix components from a path 17 | * @param name file name with path 18 | * @param number number of directory prefixed to remove 19 | * @return path without prefix 20 | */ 21 | public static String removeDirectoryPrefix(String name, int number) { 22 | int pos = 0; 23 | for (int i = 0; i < number; i++) { 24 | pos = name.indexOf("/", pos) + 1; 25 | } 26 | if (pos < 0) { 27 | return null; 28 | } 29 | return name.substring(pos); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/metadata/JAR-manifest.txt: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Created-By: Sean C. Sullivan 3 | Class-Path: commons-cli-1.0.jar 4 | Main-Class: zipdiff.Main 5 | -------------------------------------------------------------------------------- /src/test/zipdiff/DifferenceCalculatorTest.java: -------------------------------------------------------------------------------- 1 | /* zipdiff is available under the terms of the 2 | * Apache License, version 2.0 3 | * 4 | * Link: http://www.apache.org/licenses/ 5 | */ 6 | package zipdiff; 7 | 8 | import java.io.BufferedOutputStream; 9 | import java.io.ByteArrayOutputStream; 10 | import java.io.File; 11 | import java.io.FileNotFoundException; 12 | import java.io.FileOutputStream; 13 | import java.io.IOException; 14 | import java.util.Map; 15 | import java.util.jar.JarEntry; 16 | import java.util.jar.JarOutputStream; 17 | 18 | import junit.framework.TestCase; 19 | import zipdiff.output.AbstractBuilder; 20 | import zipdiff.output.HtmlBuilder; 21 | import zipdiff.output.TextBuilder; 22 | import zipdiff.output.XmlBuilder; 23 | 24 | /** 25 | * tests for DifferenceCalculator 26 | * 27 | * @author jastewart 28 | */ 29 | public class DifferenceCalculatorTest extends TestCase { 30 | private static String ENTRYA = "A"; 31 | 32 | private static String ENTRYB = "B"; 33 | 34 | private static String ENTRY_CVS = "CVS/Root"; 35 | 36 | public static final String SYSTEM_TMP_DIR_PROPERTY = "java.io.tmpdir"; 37 | 38 | public static final String TEST_DIR_POSTFIX = File.separator + "UnitTestsDifferenceCalculatorTest"; 39 | 40 | private static String testDirPathName; 41 | 42 | // naming convention The Capital letter denotes the entry so A will be the same as A 43 | // OneEntry denotes that the jar has one entry 44 | private static String testJarOneEntryA1Filename; 45 | 46 | private static String testJarOneEntryA2Filename; 47 | 48 | private static String testJarOneEntryB1Filename; 49 | 50 | private static String testJarOneEntryAContentsChangedFilename; 51 | 52 | { 53 | testDirPathName = System.getProperty(SYSTEM_TMP_DIR_PROPERTY); 54 | if (testDirPathName == null) { 55 | testDirPathName = File.separator + "temp" + TEST_DIR_POSTFIX; 56 | } 57 | testJarOneEntryA1Filename = testDirPathName + File.separator + "testJarOneEntryA1Filename.jar"; 58 | testJarOneEntryA2Filename = testDirPathName + File.separator + "testJarOneEntryA2Filename.jar"; 59 | testJarOneEntryB1Filename = testDirPathName + File.separator + "testJarOneEntryB1Filename.jar"; 60 | testJarOneEntryAContentsChangedFilename = testDirPathName + File.separator + "testJarOneEntryAContentsChangedFilename.jar"; 61 | } 62 | 63 | /** 64 | * Create a jar with only one entry in it. That entry being A 65 | * 66 | * @throws FileNotFoundException 67 | * @throws IOException 68 | */ 69 | public void createJarOneEntryA1() throws FileNotFoundException, IOException { 70 | // create a jar file with no duplicates 71 | File testDir = new File(testDirPathName); 72 | testDir.mkdirs(); 73 | JarOutputStream testJarOS = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(testJarOneEntryA1Filename))); 74 | 75 | // ad an entry 76 | JarEntry entry1 = new JarEntry(ENTRYA); 77 | testJarOS.putNextEntry(entry1); 78 | byte data1[] = new byte[2048]; 79 | for (int i = 0; i < data1.length; i++) { 80 | data1[i] = 'a'; 81 | } 82 | testJarOS.write(data1); 83 | 84 | testJarOS.flush(); 85 | testJarOS.close(); 86 | } 87 | 88 | /** 89 | * Create a jar with only one entry in it. That entry being A 90 | * 91 | * @throws FileNotFoundException 92 | * @throws IOException 93 | */ 94 | public void createJarOneEntryA2() throws FileNotFoundException, IOException { 95 | // create a jar file with no duplicates 96 | File testDir = new File(testDirPathName); 97 | testDir.mkdirs(); 98 | JarOutputStream testJarOS = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(testJarOneEntryA2Filename))); 99 | 100 | // ad an entry 101 | JarEntry entry1 = new JarEntry(ENTRYA); 102 | testJarOS.putNextEntry(entry1); 103 | byte data1[] = new byte[2048]; 104 | for (int i = 0; i < data1.length; i++) { 105 | data1[i] = 'a'; 106 | } 107 | testJarOS.write(data1); 108 | 109 | testJarOS.flush(); 110 | testJarOS.close(); 111 | } 112 | 113 | /** 114 | * Create a jar with only one entry in it. That entry being A 115 | * 116 | * @throws FileNotFoundException 117 | * @throws IOException 118 | */ 119 | public void createJarOneEntryAContentsChanged() throws FileNotFoundException, IOException { 120 | // create a jar file with no duplicates 121 | File testDir = new File(testDirPathName); 122 | testDir.mkdirs(); 123 | JarOutputStream testJarOS = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(testJarOneEntryAContentsChangedFilename))); 124 | 125 | // add an entry 126 | JarEntry entry1 = new JarEntry(ENTRYA); 127 | testJarOS.putNextEntry(entry1); 128 | byte data1[] = new byte[2048]; 129 | for (int i = 0; i < data1.length; i++) { 130 | data1[i] = 'a'; 131 | } 132 | // set a different content so that it will come up as changed 133 | data1[data1.length - 1] = 'b'; 134 | testJarOS.write(data1); 135 | 136 | // add another entry 137 | JarEntry cvs = new JarEntry(ENTRY_CVS); 138 | testJarOS.putNextEntry(cvs); 139 | 140 | testJarOS.flush(); 141 | testJarOS.close(); 142 | } 143 | 144 | /** 145 | * Create a jar with only one entry in it. That entry being A 146 | * 147 | * @throws FileNotFoundException 148 | * @throws IOException 149 | */ 150 | public void createJarOneEntryB1() throws FileNotFoundException, IOException { 151 | // create a jar file with no duplicates 152 | File testDir = new File(testDirPathName); 153 | testDir.mkdirs(); 154 | JarOutputStream testJarOS = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(testJarOneEntryB1Filename))); 155 | 156 | // ad an entry 157 | JarEntry entry1 = new JarEntry(ENTRYB); 158 | testJarOS.putNextEntry(entry1); 159 | byte data1[] = new byte[2048]; 160 | for (int i = 0; i < data1.length; i++) { 161 | data1[i] = 'b'; 162 | } 163 | testJarOS.write(data1); 164 | 165 | testJarOS.flush(); 166 | testJarOS.close(); 167 | } 168 | 169 | 170 | /** 171 | * Test for Differences calculateDifferences(ZipFile, ZipFile) 172 | * with the same file - no differences should be found 173 | */ 174 | public void testCalculateDifferencesSameZip() throws FileNotFoundException, IOException { 175 | createJarOneEntryA1(); 176 | DifferenceCalculator calc = new DifferenceCalculator(testJarOneEntryA1Filename, testJarOneEntryA1Filename); 177 | Differences differences = calc.getDifferences(); 178 | assertFalse(differences.hasDifferences()); 179 | Map addedEntries = differences.getAdded(); 180 | assertTrue(addedEntries.size() == 0); 181 | Map removedEntries = differences.getRemoved(); 182 | assertTrue(removedEntries.size() == 0); 183 | Map changedEntries = differences.getChanged(); 184 | assertTrue(changedEntries.size() == 0); 185 | 186 | exerciseOutputBuilders(differences); 187 | 188 | } 189 | 190 | /** 191 | * Test for Differences calculateDifferences(ZipFile, ZipFile) 192 | */ 193 | public void testCalculateDifferencesZipsSameEntries() throws FileNotFoundException, IOException { 194 | createJarOneEntryA1(); 195 | createJarOneEntryA2(); 196 | DifferenceCalculator calc = new DifferenceCalculator(testJarOneEntryA1Filename, testJarOneEntryA2Filename); 197 | Differences differences = calc.getDifferences(); 198 | assertFalse(differences.hasDifferences()); 199 | Map addedEntries = differences.getAdded(); 200 | assertTrue(addedEntries.size() == 0); 201 | Map removedEntries = differences.getRemoved(); 202 | assertTrue(removedEntries.size() == 0); 203 | Map changedEntries = differences.getChanged(); 204 | assertTrue(changedEntries.size() == 0); 205 | 206 | exerciseOutputBuilders(differences); 207 | } 208 | 209 | /** 210 | * Test for Differences calculateDifferences(ZipFile, ZipFile) 211 | * Test that the differences between two zips with A in one and B in the second. 212 | * A will have been removed and B will have been added. 213 | */ 214 | public void testCalculateDifferencesZipsDifferentEntries() throws FileNotFoundException, IOException { 215 | createJarOneEntryA1(); 216 | createJarOneEntryB1(); 217 | DifferenceCalculator calc = new DifferenceCalculator(testJarOneEntryA1Filename, testJarOneEntryB1Filename); 218 | Differences differences = calc.getDifferences(); 219 | assertTrue(differences.hasDifferences()); 220 | Map addedEntries = differences.getAdded(); 221 | assertTrue(addedEntries.containsKey("B")); 222 | Map removedEntries = differences.getRemoved(); 223 | assertTrue(removedEntries.containsKey("A")); 224 | Map changedEntries = differences.getChanged(); 225 | assertTrue(changedEntries.size() == 0); 226 | 227 | exerciseOutputBuilders(differences); 228 | 229 | } 230 | 231 | 232 | /** 233 | * Test for Differences calculateDifferences(ZipFile, ZipFile) 234 | * Test that the differences between two zips with A in one and A in the second with different content. 235 | * A will have been removed and B will have been added. 236 | */ 237 | public void testCalculateDifferencesZipsSameEntriesDifferentContent() throws FileNotFoundException, IOException { 238 | createJarOneEntryA1(); 239 | createJarOneEntryAContentsChanged(); 240 | DifferenceCalculator calc = new DifferenceCalculator(testJarOneEntryA1Filename, testJarOneEntryAContentsChangedFilename); 241 | calc.setIgnoreCVSFiles(true); 242 | Differences differences = calc.getDifferences(); 243 | assertTrue(differences.hasDifferences()); 244 | Map addedEntries = differences.getAdded(); 245 | assertTrue(addedEntries.size() == 0); 246 | Map removedEntries = differences.getRemoved(); 247 | assertTrue(removedEntries.size() == 0); 248 | Map changedEntries = differences.getChanged(); 249 | assertTrue(changedEntries.containsKey("A")); 250 | 251 | exerciseOutputBuilders(differences); 252 | 253 | } 254 | 255 | private void exerciseHtmlBuilder(Differences differences) { 256 | assertNotNull(differences); 257 | 258 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 259 | 260 | AbstractBuilder b = new HtmlBuilder(); 261 | b.build(baos, differences); 262 | 263 | assertTrue(baos.size() > 0); 264 | } 265 | 266 | private void exerciseXmlBuilder(Differences differences) { 267 | assertNotNull(differences); 268 | 269 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 270 | 271 | AbstractBuilder b = new XmlBuilder(); 272 | b.build(baos, differences); 273 | 274 | assertTrue(baos.size() > 0); 275 | } 276 | 277 | private void exerciseTextBuilder(Differences differences) { 278 | assertNotNull(differences); 279 | 280 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 281 | 282 | AbstractBuilder b = new TextBuilder(); 283 | b.build(baos, differences); 284 | 285 | assertTrue(baos.size() > 0); 286 | } 287 | 288 | private void exerciseOutputBuilders(Differences differences) { 289 | assertNotNull(differences); 290 | exerciseHtmlBuilder(differences); 291 | exerciseXmlBuilder(differences); 292 | exerciseTextBuilder(differences); 293 | } 294 | 295 | } 296 | -------------------------------------------------------------------------------- /xdocs/credits.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Credits 6 | 7 | 8 |
9 |

10 |

    11 |
  • Sean C. Sullivan - founder of the zipdiff project
  • 12 |
  • James Stewart - unit tests, improved command line options, documentation
  • 13 |
14 |

15 | 16 |
17 | 18 |
19 | -------------------------------------------------------------------------------- /xdocs/index.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Welcome 7 | 8 | 9 | 10 | 11 |
12 |

13 | Use the zipdiff tool when you need to compare the contents of two zip files. 14 | It is equally suited for comparing jar files, EAR files, WAR files or RAR files. 15 |

16 |

17 | Run it standalone or as an 18 | Ant task. 19 | The tool supports three output formats: plain text, XML, and HTML. 20 |

21 |

22 | zipdiff is written in Java 23 |

24 |

25 | The current version is 0.4 26 |

27 |
28 | 29 |
30 | 31 | java -jar zipdiff.jar -file1 foo.zip -file2 bar.zip [ -outputfile diffs.html ] [ -comparetimestamps ] [ -comparecrcvalues ] 32 | 33 |
34 | 35 |
36 | 37 | <taskdef name="zipdiff" classname="zipdiff.ant.ZipDiffTask"/> 38 | 39 | <zipdiff filename1="foo.zip" 40 | filename2="foo2.zip" 41 | ignoreTimestamps="true" 42 | compareCRCValues="true" 43 | destfile="zipdiff.xml"> 44 | </zipdiff> 45 | 46 |
47 | 48 |
49 |

50 | 51 | SourceForge.net Logo 53 |

54 |
55 | 56 |
57 | -------------------------------------------------------------------------------- /xdocs/navigation.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | zipdiff 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /xdocs/output.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sample output 7 | 8 | 9 | 10 | 11 |
12 |

13 |

  • HTML output
  • 14 |

    15 |
    16 | 17 | 18 | 19 |
    20 | -------------------------------------------------------------------------------- /xdocs/related.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Related information 6 | 7 | 8 |
    9 |

    10 | If you are interested in the zipdiff project, then you might also be 11 | interested in the following: 12 |

    13 | 14 | 15 | 28 | 29 | 30 | 31 | 36 | 37 | 38 | 39 | 47 | 48 | 49 | 50 | 58 | 59 | 60 | 61 | 66 | 67 | 68 | 69 | 73 | 74 | 75 | 76 | 79 | 80 | 81 | 82 | 83 | 88 | 89 | 90 | 91 | 95 | 96 | 97 | 98 | 102 | 103 | 104 |
    105 | 106 | 107 | 108 |
    109 | -------------------------------------------------------------------------------- /xdocs/sample-output.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | File differences 5 | 6 | 7 | 21 | 22 |

    First file: c:\a.zip
    23 | Second file: c:\b.zip

    24 | 25 | 26 | 27 | 28 | 29 | 31 | 37 | 38 |
    Added (2 entries)
    30 | 32 |
      33 |
    • zzz/foo.txt
    • 34 |
    • bar.txt
    • 35 |
    36 |
    39 | 40 | 41 | 42 | 43 | 44 | 46 | 48 | 49 |
    Removed (0 entries)
    45 | 47 |
    50 | 51 | 52 | 53 | 54 | 55 | 57 | 64 | 65 |
    Changed (3 entries)
    56 | 58 |
      59 |
    • my.jar
    • 60 |
    • my.jar/Util.class
    • 61 |
    • hello.txt
    • 62 |
    63 |
    66 |
    67 |

    Generated at Sun Jun 27 14:05:48 GMT-08:00 2004

    68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /xdocs/tools.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Tools and libraries 7 | 8 | 9 | 10 | 11 |
    12 |

    13 |

    24 |

    25 |
    26 | 27 | 28 | 29 |
    30 | --------------------------------------------------------------------------------