001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.imaging; 018 019import java.io.IOException; 020import java.io.PrintWriter; 021import java.io.StringWriter; 022import java.util.ArrayList; 023import java.util.List; 024import java.util.logging.Level; 025import java.util.logging.Logger; 026 027/** 028 * Provides information about the compliance of a specified data 029 * source (byte array, file, etc.) to an image format. 030 */ 031public class FormatCompliance { 032 033 private static final Logger LOGGER = Logger.getLogger(FormatCompliance.class.getName()); 034 035 private final boolean failOnError; 036 private final String description; 037 private final List<String> comments = new ArrayList<>(); 038 039 public FormatCompliance(final String description) { 040 this.description = description; 041 failOnError = false; 042 } 043 044 public FormatCompliance(final String description, final boolean failOnError) { 045 this.description = description; 046 this.failOnError = failOnError; 047 } 048 049 public static FormatCompliance getDefault() { 050 return new FormatCompliance("ignore", false); 051 } 052 053 public void addComment(final String comment) throws ImageReadException { 054 comments.add(comment); 055 if (failOnError) { 056 throw new ImageReadException(comment); 057 } 058 } 059 060 public void addComment(final String comment, final int value) throws ImageReadException { 061 addComment(comment + ": " + getValueDescription(value)); 062 } 063 064 @Override 065 public String toString() { 066 final StringWriter sw = new StringWriter(); 067 final PrintWriter pw = new PrintWriter(sw); 068 069 dump(pw); 070 071 return sw.getBuffer().toString(); 072 } 073 074 public void dump() { 075 try (StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw)) { 076 dump(pw); 077 pw.flush(); 078 sw.flush(); 079 LOGGER.fine(sw.toString()); 080 } catch (final IOException e) { 081 LOGGER.log(Level.SEVERE, e.getMessage(), e); 082 } 083 } 084 085 public void dump(final PrintWriter pw) { 086 pw.println("Format Compliance: " + description); 087 088 if (comments.isEmpty()) { 089 pw.println("\t" + "No comments."); 090 } else { 091 for (int i = 0; i < comments.size(); i++) { 092 pw.println("\t" + (i + 1) + ": " + comments.get(i)); 093 } 094 } 095 pw.println(""); 096 pw.flush(); 097 } 098 099 private String getValueDescription(final int value) { 100 return value + " (" + Integer.toHexString(value) + ")"; 101 } 102 103 public boolean compareBytes(final String name, final byte[] expected, final byte[] actual) 104 throws ImageReadException { 105 if (expected.length != actual.length) { 106 addComment(name + ": " + "Unexpected length: (expected: " 107 + expected.length + ", actual: " + actual.length + ")"); 108 return false; 109 } 110 for (int i = 0; i < expected.length; i++) { 111 // System.out.println("expected: " 112 // + getValueDescription(expected[i]) + ", actual: " 113 // + getValueDescription(actual[i]) + ")"); 114 if (expected[i] != actual[i]) { 115 addComment(name + ": " + "Unexpected value: (expected: " 116 + getValueDescription(expected[i]) + ", actual: " 117 + getValueDescription(actual[i]) + ")"); 118 return false; 119 } 120 } 121 122 return true; 123 } 124 125 public boolean checkBounds(final String name, final int min, final int max, final int actual) 126 throws ImageReadException { 127 if ((actual < min) || (actual > max)) { 128 addComment(name + ": " + "bounds check: " + min + " <= " + actual 129 + " <= " + max + ": false"); 130 return false; 131 } 132 133 return true; 134 } 135 136 public boolean compare(final String name, final int valid, final int actual) 137 throws ImageReadException { 138 return compare(name, new int[] { valid, }, actual); 139 } 140 141 public boolean compare(final String name, final int[] valid, final int actual) 142 throws ImageReadException { 143 for (final int element : valid) { 144 if (actual == element) { 145 return true; 146 } 147 } 148 149 final StringBuilder result = new StringBuilder(43); 150 result.append(name); 151 result.append(": Unexpected value: (valid: "); 152 if (valid.length > 1) { 153 result.append('{'); 154 } 155 for (int i = 0; i < valid.length; i++) { 156 if (i > 0) { 157 result.append(", "); 158 } 159 result.append(getValueDescription(valid[i])); 160 } 161 if (valid.length > 1) { 162 result.append('}'); 163 } 164 result.append(", actual: ").append(getValueDescription(actual)).append(")"); 165 addComment(result.toString()); 166 return false; 167 } 168}