1 /* 2 * Copyright 2013, Google Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 package org.jf.dexlib2.writer.pool; 33 34 import org.jf.dexlib2.Opcodes; 35 import org.jf.dexlib2.ValueType; 36 import org.jf.dexlib2.iface.Annotation; 37 import org.jf.dexlib2.iface.AnnotationElement; 38 import org.jf.dexlib2.iface.ClassDef; 39 import org.jf.dexlib2.iface.Field; 40 import org.jf.dexlib2.iface.reference.*; 41 import org.jf.dexlib2.iface.value.*; 42 import org.jf.dexlib2.writer.*; 43 import org.jf.dexlib2.writer.io.DexDataStore; 44 import org.jf.dexlib2.writer.io.FileDataStore; 45 import org.jf.util.ExceptionWithContext; 46 47 import javax.annotation.Nonnull; 48 import java.io.File; 49 import java.io.IOException; 50 import java.util.Collection; 51 import java.util.Set; 52 53 public class DexPool extends DexWriter<CharSequence, StringReference, CharSequence, TypeReference, 54 MethodProtoReference, FieldReference, MethodReference, PoolClassDef, 55 Annotation, Set<? extends Annotation>, 56 TypeListPool.Key<? extends Collection<? extends CharSequence>>, Field, PoolMethod, 57 EncodedValue, AnnotationElement, StringPool, TypePool, ProtoPool, FieldPool, MethodPool, ClassPool, 58 TypeListPool, AnnotationPool, AnnotationSetPool> { 59 60 private final Markable[] sections = new Markable[] { 61 stringSection, typeSection, protoSection, fieldSection, methodSection, classSection, typeListSection, 62 annotationSection, annotationSetSection 63 }; 64 65 public DexPool(Opcodes opcodes) { 66 super(opcodes); 67 } 68 69 @Nonnull @Override protected SectionProvider getSectionProvider() { 70 return new DexPoolSectionProvider(); 71 } 72 73 public static void writeTo(@Nonnull DexDataStore dataStore, @Nonnull org.jf.dexlib2.iface.DexFile input) 74 throws IOException { 75 DexPool dexPool = new DexPool(input.getOpcodes()); 76 for (ClassDef classDef: input.getClasses()) { 77 dexPool.internClass(classDef); 78 } 79 dexPool.writeTo(dataStore); 80 } 81 82 public static void writeTo(@Nonnull String path, @Nonnull org.jf.dexlib2.iface.DexFile input) throws IOException { 83 DexPool dexPool = new DexPool(input.getOpcodes()); 84 for (ClassDef classDef: input.getClasses()) { 85 dexPool.internClass(classDef); 86 } 87 dexPool.writeTo(new FileDataStore(new File(path))); 88 } 89 90 /** 91 * Interns a class into this DexPool 92 * @param classDef The class to intern 93 */ 94 public void internClass(ClassDef classDef) { 95 classSection.intern(classDef); 96 } 97 98 /** 99 * Creates a marked state that can be returned to by calling reset() 100 * 101 * This is useful to rollback the last added class if it causes a method/field/type overflow 102 */ 103 public void mark() { 104 for (Markable section: sections) { 105 section.mark(); 106 } 107 } 108 109 /** 110 * Resets to the last marked state 111 * 112 * This is useful to rollback the last added class if it causes a method/field/type overflow 113 */ 114 public void reset() { 115 for (Markable section: sections) { 116 section.reset(); 117 } 118 } 119 120 @Override protected void writeEncodedValue(@Nonnull InternalEncodedValueWriter writer, 121 @Nonnull EncodedValue encodedValue) throws IOException { 122 switch (encodedValue.getValueType()) { 123 case ValueType.ANNOTATION: 124 AnnotationEncodedValue annotationEncodedValue = (AnnotationEncodedValue)encodedValue; 125 writer.writeAnnotation(annotationEncodedValue.getType(), annotationEncodedValue.getElements()); 126 break; 127 case ValueType.ARRAY: 128 ArrayEncodedValue arrayEncodedValue = (ArrayEncodedValue)encodedValue; 129 writer.writeArray(arrayEncodedValue.getValue()); 130 break; 131 case ValueType.BOOLEAN: 132 writer.writeBoolean(((BooleanEncodedValue)encodedValue).getValue()); 133 break; 134 case ValueType.BYTE: 135 writer.writeByte(((ByteEncodedValue)encodedValue).getValue()); 136 break; 137 case ValueType.CHAR: 138 writer.writeChar(((CharEncodedValue)encodedValue).getValue()); 139 break; 140 case ValueType.DOUBLE: 141 writer.writeDouble(((DoubleEncodedValue)encodedValue).getValue()); 142 break; 143 case ValueType.ENUM: 144 writer.writeEnum(((EnumEncodedValue)encodedValue).getValue()); 145 break; 146 case ValueType.FIELD: 147 writer.writeField(((FieldEncodedValue)encodedValue).getValue()); 148 break; 149 case ValueType.FLOAT: 150 writer.writeFloat(((FloatEncodedValue)encodedValue).getValue()); 151 break; 152 case ValueType.INT: 153 writer.writeInt(((IntEncodedValue)encodedValue).getValue()); 154 break; 155 case ValueType.LONG: 156 writer.writeLong(((LongEncodedValue)encodedValue).getValue()); 157 break; 158 case ValueType.METHOD: 159 writer.writeMethod(((MethodEncodedValue)encodedValue).getValue()); 160 break; 161 case ValueType.NULL: 162 writer.writeNull(); 163 break; 164 case ValueType.SHORT: 165 writer.writeShort(((ShortEncodedValue)encodedValue).getValue()); 166 break; 167 case ValueType.STRING: 168 writer.writeString(((StringEncodedValue)encodedValue).getValue()); 169 break; 170 case ValueType.TYPE: 171 writer.writeType(((TypeEncodedValue)encodedValue).getValue()); 172 break; 173 default: 174 throw new ExceptionWithContext("Unrecognized value type: %d", encodedValue.getValueType()); 175 } 176 } 177 178 void internEncodedValue(@Nonnull EncodedValue encodedValue) { 179 switch (encodedValue.getValueType()) { 180 case ValueType.ANNOTATION: 181 AnnotationEncodedValue annotationEncodedValue = (AnnotationEncodedValue)encodedValue; 182 typeSection.intern(annotationEncodedValue.getType()); 183 for (AnnotationElement element: annotationEncodedValue.getElements()) { 184 stringSection.intern(element.getName()); 185 internEncodedValue(element.getValue()); 186 } 187 break; 188 case ValueType.ARRAY: 189 for (EncodedValue element: ((ArrayEncodedValue)encodedValue).getValue()) { 190 internEncodedValue(element); 191 } 192 break; 193 case ValueType.STRING: 194 stringSection.intern(((StringEncodedValue)encodedValue).getValue()); 195 break; 196 case ValueType.TYPE: 197 typeSection.intern(((TypeEncodedValue)encodedValue).getValue()); 198 break; 199 case ValueType.ENUM: 200 fieldSection.intern(((EnumEncodedValue)encodedValue).getValue()); 201 break; 202 case ValueType.FIELD: 203 fieldSection.intern(((FieldEncodedValue)encodedValue).getValue()); 204 break; 205 case ValueType.METHOD: 206 methodSection.intern(((MethodEncodedValue)encodedValue).getValue()); 207 break; 208 } 209 } 210 211 protected class DexPoolSectionProvider extends SectionProvider { 212 @Nonnull @Override public StringPool getStringSection() { 213 return new StringPool(DexPool.this); 214 } 215 216 @Nonnull @Override public TypePool getTypeSection() { 217 return new TypePool(DexPool.this); 218 } 219 220 @Nonnull @Override public ProtoPool getProtoSection() { 221 return new ProtoPool(DexPool.this); 222 } 223 224 @Nonnull @Override public FieldPool getFieldSection() { 225 return new FieldPool(DexPool.this); 226 } 227 228 @Nonnull @Override public MethodPool getMethodSection() { 229 return new MethodPool(DexPool.this); 230 } 231 232 @Nonnull @Override public ClassPool getClassSection() { 233 return new ClassPool(DexPool.this); 234 } 235 236 @Nonnull @Override public TypeListPool getTypeListSection() { 237 return new TypeListPool(DexPool.this); 238 } 239 240 @Nonnull @Override public AnnotationPool getAnnotationSection() { 241 return new AnnotationPool(DexPool.this); 242 } 243 244 @Nonnull @Override public AnnotationSetPool getAnnotationSetSection() { 245 return new AnnotationSetPool(DexPool.this); 246 } 247 } 248 } 249