    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 source (byte array, file, etc&#46;) to an image format.
    029 */
    030public class FormatCompliance {
    031
    032    private static final Logger LOGGER = Logger.getLogger(FormatCompliance.class.getName());
    033
    034    public static FormatCompliance getDefault() {
    035        return new FormatCompliance("ignore", false);
    036    }
    037
    038    private final boolean failOnError;
    039    private final String description;
    040
    041    private final List<String> comments = new ArrayList<>();
    042
    043    public FormatCompliance(final String description) {
    044        this.description = description;
    045        this.failOnError = false;
    046    }
    047
    048    public FormatCompliance(final String description, final boolean failOnError) {
    049        this.description = description;
    050        this.failOnError = failOnError;
    051    }
    052
    053    public void addComment(final String comment) throws ImagingException {
    054        comments.add(comment);
    055        if (failOnError) {
    056            throw new ImagingException(comment);
    057        }
    058    }
    059
    060    public void addComment(final String comment, final int value) throws ImagingException {
    061        addComment(comment + ": " + getValueDescription(value));
    062    }
    063
    064    public boolean checkBounds(final String name, final int min, final int max, final int actual) throws ImagingException {
    065        if (actual < min || actual > max) {
    066            addComment(name + ": " + "bounds check: " + min + " <= " + actual + " <= " + max + ": false");
    067            return false;
    068        }
    069
    070        return true;
    071    }
    072
    073    public boolean compare(final String name, final int valid, final int actual) throws ImagingException {
    074        return compare(name, new int[] { valid, }, actual);
    075    }
    076
    077    public boolean compare(final String name, final int[] valid, final int actual) throws ImagingException {
    078        for (final int element : valid) {
    079            if (actual == element) {
    080                return true;
    081            }
    082        }
    083
    084        final StringBuilder result = new StringBuilder(43);
    085        result.append(name);
    086        result.append(": Unexpected value: (valid: ");
    087        if (valid.length > 1) {
    088            result.append('{');
    089        }
    090        for (int i = 0; i < valid.length; i++) {
    091            if (i > 0) {
    092                result.append(", ");
    093            }
    094            result.append(getValueDescription(valid[i]));
    095        }
    096        if (valid.length > 1) {
    097            result.append('}');
    098        }
    099        result.append(", actual: ").append(getValueDescription(actual)).append(")");
    100        addComment(result.toString());
    101        return false;
    102    }
    103
    104    public boolean compareBytes(final String name, final byte[] expected, final byte[] actual) throws ImagingException {
    105        if (expected.length != actual.length) {
    106            addComment(name + ": " + "Unexpected length: (expected: " + expected.length + ", actual: " + actual.length + ")");
    107            return false;
    108        }
    109        for (int i = 0; i < expected.length; i++) {
    110            // System.out.println("expected: "
    111            // + getValueDescription(expected[i]) + ", actual: "
    112            // + getValueDescription(actual[i]) + ")");
    113            if (expected[i] != actual[i]) {
    114                addComment(
    115                        name + ": " + "Unexpected value: (expected: " + getValueDescription(expected[i]) + ", actual: " + getValueDescription(actual[i]) + ")");
    116                return false;
    117            }
    118        }
    119
    120        return true;
    121    }
    122
    123    public void dump() {
    124        try (StringWriter sw = new StringWriter();
    125                PrintWriter pw = new PrintWriter(sw)) {
    126            dump(pw);
    127            pw.flush();
    128            sw.flush();
    129            LOGGER.fine(sw.toString());
    130        } catch (final IOException e) {
    131            LOGGER.log(Level.SEVERE, e.getMessage(), e);
    132        }
    133    }
    134
    135    public void dump(final PrintWriter pw) {
    136        pw.println("Format Compliance: " + description);
    137
    138        if (comments.isEmpty()) {
    139            pw.println("\t" + "No comments.");
    140        } else {
    141            for (int i = 0; i < comments.size(); i++) {
    142                pw.println("\t" + (i + 1) + ": " + comments.get(i));
    143            }
    144        }
    145        pw.println("");
    146        pw.flush();
    147    }
    148
    149    private String getValueDescription(final int value) {
    150        return value + " (" + Integer.toHexString(value) + ")";
    151    }
    152
    153    @Override
    154    public String toString() {
    155        final StringWriter sw = new StringWriter();
    156        final PrintWriter pw = new PrintWriter(sw);
    157
    158        dump(pw);
    159
    160        return sw.getBuffer().toString();
    161    }
    162}