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