View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.imaging.internal;
18  
19  import java.awt.color.ICC_Profile;
20  import java.io.File;
21  import java.text.DateFormat;
22  import java.text.SimpleDateFormat;
23  import java.util.ArrayList;
24  import java.util.Calendar;
25  import java.util.Date;
26  import java.util.List;
27  import java.util.Locale;
28  import java.util.Map;
29  import java.util.Objects;
30  import java.util.logging.Level;
31  import java.util.logging.Logger;
32  
33  /**
34   * Internal-only debug class. Used for collecting extra information when parsing or modifying images or metadata. These methods are useful for troubleshooting
35   * 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.
36   */
37  public final class Debug {
38  
39      private static final Logger LOGGER = Logger.getLogger(Debug.class.getName());
40  
41      // public static String newline = System.getProperty("line.separator");
42      private static final String NEWLINE = "\r\n";
43      private static long counter;
44  
45      private static String byteQuadToString(final int byteQuad) {
46          final byte b1 = (byte) (byteQuad >> 24 & 0xff);
47          final byte b2 = (byte) (byteQuad >> 16 & 0xff);
48          final byte b3 = (byte) (byteQuad >> 8 & 0xff);
49          final byte b4 = (byte) (byteQuad >> 0 & 0xff);
50  
51          final char c1 = (char) b1;
52          final char c2 = (char) b2;
53          final char c3 = (char) b3;
54          final char c4 = (char) b4;
55          // return new String(new char[] { c1, c2, c3, c4 });
56          final StringBuilder buffer = new StringBuilder(31);
57          buffer.append(new String(new char[] { c1, c2, c3, c4 }));
58          buffer.append(" byteQuad: ");
59          buffer.append(byteQuad);
60          buffer.append(" b1: ");
61          buffer.append(b1);
62          buffer.append(" b2: ");
63          buffer.append(b2);
64          buffer.append(" b3: ");
65          buffer.append(b3);
66          buffer.append(" b4: ");
67          buffer.append(b4);
68  
69          return buffer.toString();
70      }
71  
72      public static void debug() {
73          if (LOGGER.isLoggable(Level.FINEST)) {
74              LOGGER.finest(NEWLINE);
75          }
76      }
77  
78      public static void debug(final String message) {
79          if (LOGGER.isLoggable(Level.FINEST)) {
80              LOGGER.finest(message);
81          }
82      }
83  
84      private static void debug(final String message, final byte[] v) {
85          debug(getDebug(message, v));
86      }
87  
88      private static void debug(final String message, final Calendar value) {
89          final DateFormat df = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss", Locale.ROOT);
90          debug(message, value == null ? "null" : df.format(value.getTime()));
91      }
92  
93      private static void debug(final String message, final char[] v) {
94          debug(getDebug(message, v));
95      }
96  
97      private static void debug(final String message, final Date value) {
98          final DateFormat df = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss", Locale.ROOT);
99          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.ROOT);
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 }