    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&#46;) 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}