1b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato/* 2b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * ProGuard -- shrinking, optimization, obfuscation, and preverification 3b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * of Java bytecode. 4b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 5b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) 6b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 7b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This program is free software; you can redistribute it and/or modify it 8b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * under the terms of the GNU General Public License as published by the Free 9b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Software Foundation; either version 2 of the License, or (at your option) 10b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * any later version. 11b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 12b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This program is distributed in the hope that it will be useful, but WITHOUT 13b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * more details. 16b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 17b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * You should have received a copy of the GNU General Public License along 18b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * with this program; if not, write to the Free Software Foundation, Inc., 19b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 21b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratopackage proguard.classfile.util; 22b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 23b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.ClassConstants; 24b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 25b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport java.util.Stack; 26b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 27b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato/** 28b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * A <code>DescriptorClassEnumeration</code> provides an enumeration of all 29b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * classes mentioned in a given descriptor or signature. 30b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 31b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * @author Eric Lafortune 32b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 33b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratopublic class DescriptorClassEnumeration 34b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato{ 35b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private String descriptor; 36b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 37b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private int index; 38b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private int nestingLevel; 39b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private boolean isInnerClassName; 40b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private String accumulatedClassName; 41b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private Stack accumulatedClassNames; 42b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 43b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 44b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 45b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Creates a new DescriptorClassEnumeration for the given descriptor. 46b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 47b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public DescriptorClassEnumeration(String descriptor) 48b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 49b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato this.descriptor = descriptor; 50b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 51b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 52b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 53b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 54b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Returns the number of classes contained in the descriptor. This 55b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * is the number of class names that the enumeration will return. 56b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 57b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public int classCount() 58b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 59b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int count = 0; 60b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 61b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato nextFluff(); 62b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato while (hasMoreClassNames()) 63b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 64b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato count++; 65b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 66b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato nextClassName(); 67b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato nextFluff(); 68b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 69b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 70b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato index = 0; 71b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 72b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato return count; 73b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 74b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 75b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 76b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 77b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Returns whether the enumeration can provide more class names from the 78b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * descriptor. 79b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 80b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public boolean hasMoreClassNames() 81b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 82b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato return index < descriptor.length(); 83b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 84b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 85b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 86b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 87b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Returns the next fluff (surrounding class names) from the descriptor. 88b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 89b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public String nextFluff() 90b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 91b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int fluffStartIndex = index; 92b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 93b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Find the first token marking the start of a class name 'L' or '.'. 94b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato loop: while (index < descriptor.length()) 95b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 96b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato switch (descriptor.charAt(index++)) 97b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 98b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato case ClassConstants.INTERNAL_TYPE_GENERIC_START: 99b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 100b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato nestingLevel++; 101b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 102b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Make sure we have a stack. 103b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (accumulatedClassNames == null) 104b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 105b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato accumulatedClassNames = new Stack(); 106b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 107b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 108b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Remember the accumulated class name. 109b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato accumulatedClassNames.push(accumulatedClassName); 110b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 111b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato break; 112b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 113b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato case ClassConstants.INTERNAL_TYPE_GENERIC_END: 114b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 115b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato nestingLevel--; 116b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 117b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Return to the accumulated class name outside the 118b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // generic block. 119b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato accumulatedClassName = (String)accumulatedClassNames.pop(); 120b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 121b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato continue loop; 122b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 123b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato case ClassConstants.INTERNAL_TYPE_GENERIC_BOUND: 124b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 125b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato continue loop; 126b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 127b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato case ClassConstants.INTERNAL_TYPE_CLASS_START: 128b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 129b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // We've found the start of an ordinary class name. 130b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato nestingLevel += 2; 131b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato isInnerClassName = false; 132b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato break loop; 133b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 134b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato case ClassConstants.INTERNAL_TYPE_CLASS_END: 135b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 136b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato nestingLevel -= 2; 137b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato break; 138b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 139b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato case ClassConstants.EXTERNAL_INNER_CLASS_SEPARATOR: 140b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 141b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // We've found the start of an inner class name in a signature. 142b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato isInnerClassName = true; 143b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato break loop; 144b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 145b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato case ClassConstants.INTERNAL_TYPE_GENERIC_VARIABLE_START: 146b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 147b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // We've found the start of a type identifier. Skip to the end. 148b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato while (descriptor.charAt(index++) != ClassConstants.INTERNAL_TYPE_CLASS_END); 149b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato break; 150b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 151b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 152b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 153b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (nestingLevel == 1 && 154b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato descriptor.charAt(index) != ClassConstants.INTERNAL_TYPE_GENERIC_END) 155b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 156b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // We're at the start of a type parameter. Skip to the start 157b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // of the bounds. 158b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato while (descriptor.charAt(index++) != ClassConstants.INTERNAL_TYPE_GENERIC_BOUND); 159b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 160b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 161b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 162b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato return descriptor.substring(fluffStartIndex, index); 163b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 164b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 165b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 166b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 167b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Returns the next class name from the descriptor. 168b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 169b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public String nextClassName() 170b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 171b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int classNameStartIndex = index; 172b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 173b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Find the first token marking the end of a class name '<' or ';'. 174b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato loop: while (true) 175b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 176b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato switch (descriptor.charAt(index)) 177b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 178b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato case ClassConstants.INTERNAL_TYPE_GENERIC_START: 179b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato case ClassConstants.INTERNAL_TYPE_CLASS_END: 180b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato case ClassConstants.EXTERNAL_INNER_CLASS_SEPARATOR: 181b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 182b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato break loop; 183b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 184b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 185b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 186b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato index++; 187b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 188b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 189b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato String className = descriptor.substring(classNameStartIndex, index); 190b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 191b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Recompose the inner class name if necessary. 192b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato accumulatedClassName = isInnerClassName ? 193b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato accumulatedClassName + ClassConstants.INTERNAL_INNER_CLASS_SEPARATOR + className : 194b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato className; 195b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 196b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato return accumulatedClassName; 197b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 198b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 199b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 200b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 201b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Returns whether the most recently returned class name was a recomposed 202b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * inner class name from a signature. 203b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 204b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public boolean isInnerClassName() 205b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 206b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato return isInnerClassName; 207b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 208b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 209b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 210b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 211b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * A main method for testing the class name enumeration. 212b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 213b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public static void main(String[] args) 214b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 215b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato try 216b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 217b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato for (int index = 0; index < args.length; index++) 218b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 219b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato String descriptor = args[index]; 220b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 221b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.out.println("Descriptor ["+descriptor+"]"); 222b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato DescriptorClassEnumeration enumeration = new DescriptorClassEnumeration(descriptor); 223b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.out.println(" Fluff: ["+enumeration.nextFluff()+"]"); 224b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato while (enumeration.hasMoreClassNames()) 225b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 226b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.out.println(" Name: ["+enumeration.nextClassName()+"]"); 227b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.out.println(" Fluff: ["+enumeration.nextFluff()+"]"); 228b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 229b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 230b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 231b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato catch (Exception ex) 232b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 233b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato ex.printStackTrace(); 234b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 235b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 236b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato} 237