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.internal; 018 019import java.awt.color.ICC_Profile; 020import java.io.File; 021import java.text.DateFormat; 022import java.text.SimpleDateFormat; 023import java.util.ArrayList; 024import java.util.Calendar; 025import java.util.Date; 026import java.util.List; 027import java.util.Locale; 028import java.util.Map; 029import java.util.Objects; 030import java.util.logging.Level; 031import java.util.logging.Logger; 032 033/** 034 * Internal-only debug class. Used for collecting extra information when parsing or modifying images or metadata. These methods are useful for troubleshooting 035 * and issue analysis, but this should not be used directly by end-users, nor extended in any way. This may change or be removed at any time. 036 */ 037public final class Debug { 038 039 private static final Logger LOGGER = Logger.getLogger(Debug.class.getName()); 040 041 // public static String newline = System.getProperty("line.separator"); 042 private static final String NEWLINE = "\r\n"; 043 private static long counter; 044 045 private static String byteQuadToString(final int byteQuad) { 046 final byte b1 = (byte) (byteQuad >> 24 & 0xff); 047 final byte b2 = (byte) (byteQuad >> 16 & 0xff); 048 final byte b3 = (byte) (byteQuad >> 8 & 0xff); 049 final byte b4 = (byte) (byteQuad >> 0 & 0xff); 050 051 final char c1 = (char) b1; 052 final char c2 = (char) b2; 053 final char c3 = (char) b3; 054 final char c4 = (char) b4; 055 // return new String(new char[] { c1, c2, c3, c4 }); 056 final StringBuilder buffer = new StringBuilder(31); 057 buffer.append(new String(new char[] { c1, c2, c3, c4 })); 058 buffer.append(" byteQuad: "); 059 buffer.append(byteQuad); 060 buffer.append(" b1: "); 061 buffer.append(b1); 062 buffer.append(" b2: "); 063 buffer.append(b2); 064 buffer.append(" b3: "); 065 buffer.append(b3); 066 buffer.append(" b4: "); 067 buffer.append(b4); 068 069 return buffer.toString(); 070 } 071 072 public static void debug() { 073 if (LOGGER.isLoggable(Level.FINEST)) { 074 LOGGER.finest(NEWLINE); 075 } 076 } 077 078 public static void debug(final String message) { 079 if (LOGGER.isLoggable(Level.FINEST)) { 080 LOGGER.finest(message); 081 } 082 } 083 084 private static void debug(final String message, final byte[] v) { 085 debug(getDebug(message, v)); 086 } 087 088 private static void debug(final String message, final Calendar value) { 089 final DateFormat df = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss", Locale.ENGLISH); 090 debug(message, value == null ? "null" : df.format(value.getTime())); 091 } 092 093 private static void debug(final String message, final char[] v) { 094 debug(getDebug(message, v)); 095 } 096 097 private static void debug(final String message, final Date value) { 098 final DateFormat df = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss", Locale.ENGLISH); 099 debug(message, value == null ? "null" : df.format(value)); 100 } 101 102 private static void debug(final String message, final File file) { 103 debug(message + ": " + (file == null ? "null" : file.getPath())); 104 } 105 106 private static void debug(final String message, final ICC_Profile value) { 107 debug("ICC_Profile " + message + ": " + Objects.toString(value)); 108 if (value != null) { 109 debug("\t getProfileClass: " + byteQuadToString(value.getProfileClass())); 110 debug("\t getPCSType: " + byteQuadToString(value.getPCSType())); 111 debug("\t getColorSpaceType() : " + byteQuadToString(value.getColorSpaceType())); 112 } 113 } 114 115 private static void debug(final String message, final int[] v) { 116 debug(getDebug(message, v)); 117 } 118 119 private static void debug(final String message, final List<?> v) { 120 final String suffix = " [" + counter++ + "]"; 121 122 debug(message + " (" + v.size() + ")" + suffix); 123 for (final Object aV : v) { 124 debug("\t" + aV.toString() + suffix); 125 } 126 debug(); 127 } 128 129 private static void debug(final String message, final Map<?, ?> map) { 130 debug(getDebug(message, map)); 131 } 132 133 public static void debug(final String message, final Object value) { 134 if (value == null) { 135 debug(message, "null"); 136 } else if (value instanceof char[]) { 137 debug(message, (char[]) value); 138 } else if (value instanceof byte[]) { 139 debug(message, (byte[]) value); 140 } else if (value instanceof int[]) { 141 debug(message, (int[]) value); 142 } else if (value instanceof String) { 143 debug(message, (String) value); 144 } else if (value instanceof List) { 145 debug(message, (List<?>) value); 146 } else if (value instanceof Map) { 147 debug(message, (Map<?, ?>) value); 148 } else if (value instanceof ICC_Profile) { 149 debug(message, (ICC_Profile) value); 150 } else if (value instanceof File) { 151 debug(message, (File) value); 152 } else if (value instanceof Date) { 153 debug(message, (Date) value); 154 } else if (value instanceof Calendar) { 155 debug(message, (Calendar) value); 156 } else { 157 debug(message, value.toString()); 158 } 159 } 160 161 private static void debug(final String message, final String value) { 162 debug(message + " " + value); 163 } 164 165 public static void debug(final Throwable e) { 166 debug(getDebug(e)); 167 } 168 169 public static void debug(final Throwable e, final int value) { 170 debug(getDebug(e, value)); 171 } 172 173 private static String getDebug(final String message, final byte[] v) { 174 final int max = 250; 175 return getDebug(message, v, max); 176 } 177 178 private static String getDebug(final String message, final byte[] v, final int max) { 179 180 final StringBuilder result = new StringBuilder(); 181 182 if (v == null) { 183 result.append(message + " (" + null + ")" + NEWLINE); 184 } else { 185 result.append(message + " (" + v.length + ")" + NEWLINE); 186 for (int i = 0; i < max && i < v.length; i++) { 187 final int b = 0xff & v[i]; 188 189 char c; 190 if (b == 0 || b == 10 || b == 11 || b == 13) { 191 c = ' '; 192 } else { 193 c = (char) b; 194 } 195 196 result.append("\t" + i + ": " + b + " (" + c + ", 0x" + Integer.toHexString(b) + ")" + NEWLINE); 197 } 198 if (v.length > max) { 199 result.append("\t..." + NEWLINE); 200 } 201 202 result.append(NEWLINE); 203 } 204 return result.toString(); 205 } 206 207 private static String getDebug(final String message, final char[] v) { 208 final StringBuilder result = new StringBuilder(); 209 210 if (v == null) { 211 result.append(message + " (" + null + ")" + NEWLINE); 212 } else { 213 result.append(message + " (" + v.length + ")" + NEWLINE); 214 for (final char element : v) { 215 result.append("\t" + element + " (" + (0xff & element) + ")" + NEWLINE); 216 } 217 result.append(NEWLINE); 218 } 219 return result.toString(); 220 } 221 222 private static String getDebug(final String message, final int[] v) { 223 final StringBuilder result = new StringBuilder(); 224 225 if (v == null) { 226 result.append(message + " (" + null + ")" + NEWLINE); 227 } else { 228 result.append(message + " (" + v.length + ")" + NEWLINE); 229 for (final int element : v) { 230 result.append("\t" + element + NEWLINE); 231 } 232 result.append(NEWLINE); 233 } 234 return result.toString(); 235 } 236 237 private static String getDebug(final String message, final Map<?, ?> map) { 238 final StringBuilder result = new StringBuilder(); 239 240 if (map == null) { 241 return message + " map: " + null; 242 } 243 244 final List<Object> keys = new ArrayList<>(map.keySet()); 245 result.append(message + " map: " + keys.size() + NEWLINE); 246 for (int i = 0; i < keys.size(); i++) { 247 final Object key = keys.get(i); 248 final Object value = map.get(key); 249 result.append("\t" + i + ": '" + key + "' -> '" + value + "'" + NEWLINE); 250 } 251 252 result.append(NEWLINE); 253 254 return result.toString(); 255 } 256 257 private static String getDebug(final Throwable e) { 258 return getDebug(e, -1); 259 } 260 261 private static String getDebug(final Throwable e, final int max) { 262 final StringBuilder result = new StringBuilder(35); 263 264 final SimpleDateFormat timestamp = new SimpleDateFormat("yyyy-MM-dd kk:mm:ss:SSS", Locale.ENGLISH); 265 final String datetime = timestamp.format(new Date()).toLowerCase(); 266 267 result.append(NEWLINE); 268 result.append("Throwable: " + (e == null ? "" : "(" + e.getClass().getName() + ")") + ":" + datetime + NEWLINE); 269 result.append("Throwable: " + (e == null ? "null" : e.getLocalizedMessage()) + NEWLINE); 270 result.append(NEWLINE); 271 272 result.append(getStackTrace(e, max)); 273 274 result.append("Caught here:" + NEWLINE); 275 result.append(getStackTrace(new Exception(), max, 1)); 276 // Debug.dumpStack(); 277 result.append(NEWLINE); 278 return result.toString(); 279 } 280 281 private static String getStackTrace(final Throwable e, final int limit) { 282 return getStackTrace(e, limit, 0); 283 } 284 285 private static String getStackTrace(final Throwable e, final int limit, final int skip) { 286 final StringBuilder result = new StringBuilder(); 287 288 if (e != null) { 289 final StackTraceElement[] stes = e.getStackTrace(); 290 if (stes != null) { 291 for (int i = skip; i < stes.length && (limit < 0 || i < limit); i++) { 292 final StackTraceElement ste = stes[i]; 293 294 result.append( 295 "\tat " + ste.getClassName() + "." + ste.getMethodName() + "(" + ste.getFileName() + ":" + ste.getLineNumber() + ")" + NEWLINE); 296 } 297 if (limit >= 0 && stes.length > limit) { 298 result.append("\t..." + NEWLINE); 299 } 300 } 301 302 // e.printStackTrace(System.out); 303 result.append(NEWLINE); 304 } 305 306 return result.toString(); 307 } 308 309 private Debug() { 310 } 311}