StringDataItem.java revision 1f29ee7351fd7fb48bb093b39b5f9ffddb34a3ea
1/* 2 * [The "BSD licence"] 3 * Copyright (c) 2010 Ben Gruver (JesusFreke) 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29package org.jf.dexlib; 30 31import org.jf.dexlib.Util.*; 32 33public class StringDataItem extends Item<StringDataItem> { 34 private int hashCode = 0; 35 36 private String stringValue; 37 38 /** 39 * Creates a new uninitialized <code>StringDataItem</code> 40 * @param dexFile The <code>DexFile</code> that this item belongs to 41 */ 42 protected StringDataItem(DexFile dexFile) { 43 super(dexFile); 44 } 45 46 /** 47 * Creates a new <code>StringDataItem</code> for the given string 48 * @param dexFile The <code>DexFile</code> that this item belongs to 49 * @param stringValue The string value that this item represents 50 */ 51 private StringDataItem(DexFile dexFile, String stringValue) { 52 super(dexFile); 53 54 this.stringValue = stringValue; 55 } 56 57 /** 58 * Returns a <code>StringDataItem</code> for the given values, and that has been interned into 59 * the given <code>DexFile</code> 60 * @param dexFile The <code>DexFile</code> that this item belongs to 61 * @param value The string value that this item represents 62 * @return a <code>StringDataItem</code> for the given values, and that has been interned into 63 * the given <code>DexFile</code> 64 */ 65 public static StringDataItem internStringDataItem(DexFile dexFile, String value) { 66 StringDataItem StringDataItem = new StringDataItem(dexFile, value); 67 return dexFile.StringDataSection.intern(StringDataItem); 68 } 69 70 /** 71 * Looks up the <code>StringDataItem</code> from the given <code>DexFile</code> for the given 72 * string value 73 * @param dexFile the <code>Dexfile</code> to find the string value in 74 * @param value The string value to look up 75 * @return a <code>StringDataItem</code> from the given <code>DexFile</code> for the given 76 * string value, or null if it doesn't exist 77 **/ 78 public static StringDataItem lookupStringDataItem(DexFile dexFile, String value) { 79 StringDataItem StringDataItem = new StringDataItem(dexFile, value); 80 return dexFile.StringDataSection.getInternedItem(StringDataItem); 81 } 82 83 /** {@inheritDoc} */ 84 protected void readItem(Input in, ReadContext readContext) { 85 in.readUnsignedLeb128(); //string length 86 stringValue = in.realNullTerminatedUtf8String(); 87 } 88 89 /** {@inheritDoc} */ 90 protected int placeItem(int offset) { 91 return offset + Leb128Utils.unsignedLeb128Size(stringValue.length()) + 92 Utf8Utils.stringToUtf8Bytes(stringValue).length + 1; 93 } 94 95 /** {@inheritDoc} */ 96 protected void writeItem(AnnotatedOutput out) { 97 byte[] encodedValue = Utf8Utils.stringToUtf8Bytes(stringValue); 98 if (out.annotates()) { 99 out.annotate("string_size: 0x" + Integer.toHexString(stringValue.length()) + " (" + stringValue.length() + 100 ")"); 101 out.writeUnsignedLeb128(stringValue.length()); 102 103 out.annotate(encodedValue.length + 1, "string_data: \"" + Utf8Utils.escapeString(stringValue) + "\""); 104 } else { 105 out.writeUnsignedLeb128(stringValue.length()); 106 } 107 out.write(encodedValue); 108 out.writeByte(0); 109 } 110 111 /** {@inheritDoc} */ 112 public ItemType getItemType() { 113 return ItemType.TYPE_STRING_DATA_ITEM; 114 } 115 116 /** {@inheritDoc} */ 117 public String getConciseIdentity() { 118 return "string_data_item: \"" + Utf8Utils.escapeString(getStringValue()) + "\""; 119 } 120 121 /** {@inheritDoc} */ 122 public int compareTo(StringDataItem o) { 123 return getStringValue().compareTo(o.getStringValue()); 124 } 125 126 /** 127 * Get the string value of this item as a <code>String</code> 128 * @return the string value of this item as a String 129 */ 130 public String getStringValue() { 131 return stringValue; 132 } 133 134 /** 135 * calculate and cache the hashcode 136 */ 137 private void calcHashCode() { 138 hashCode = getStringValue().hashCode(); 139 } 140 141 @Override 142 public int hashCode() { 143 //there's a small possibility that the actual hash code will be 0. If so, we'll 144 //just end up recalculating it each time 145 if (hashCode == 0) 146 calcHashCode(); 147 return hashCode; 148 } 149 150 @Override 151 public boolean equals(Object o) { 152 if (this==o) { 153 return true; 154 } 155 if (o==null || !this.getClass().equals(o.getClass())) { 156 return false; 157 } 158 159 //This assumes that the referenced items have been interned in both objects. 160 //This is a valid assumption because all outside code must use the static 161 //"getInterned..." style methods to make new items, and any item created 162 //internally is guaranteed to be interned 163 StringDataItem other = (StringDataItem)o; 164 return getStringValue().equals(other.getStringValue()); 165 } 166} 167