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
32package org.jf.dexlib2.writer.builder;
33
34import com.google.common.base.Function;
35import com.google.common.collect.ImmutableList;
36import com.google.common.collect.ImmutableSet;
37import com.google.common.collect.Iterators;
38import org.jf.dexlib2.ValueType;
39import org.jf.dexlib2.iface.AnnotationElement;
40import org.jf.dexlib2.iface.value.*;
41import org.jf.dexlib2.writer.builder.BuilderEncodedValues.*;
42import org.jf.util.ExceptionWithContext;
43
44import javax.annotation.Nonnull;
45import javax.annotation.Nullable;
46import java.util.Set;
47
48class BuilderContext {
49    // keep our own local references to the various pools, using the Builder specific pool type;
50    @Nonnull final BuilderStringPool stringPool;
51    @Nonnull final BuilderTypePool typePool;
52    @Nonnull final BuilderFieldPool fieldPool;
53    @Nonnull final BuilderMethodPool methodPool;
54    @Nonnull final BuilderProtoPool protoPool;
55    @Nonnull final BuilderClassPool classPool;
56
57    @Nonnull final BuilderTypeListPool typeListPool;
58    @Nonnull final BuilderAnnotationPool annotationPool;
59    @Nonnull final BuilderAnnotationSetPool annotationSetPool;
60
61
62    BuilderContext() {
63        this.stringPool = new BuilderStringPool();
64        this.typePool = new BuilderTypePool(this);
65        this.fieldPool = new BuilderFieldPool(this);
66        this.methodPool = new BuilderMethodPool(this);
67        this.protoPool = new BuilderProtoPool(this);
68        this.classPool = new BuilderClassPool();
69
70        this.typeListPool = new BuilderTypeListPool(this);
71        this.annotationPool = new BuilderAnnotationPool(this);
72        this.annotationSetPool = new BuilderAnnotationSetPool(this);
73    }
74
75    @Nonnull Set<? extends BuilderAnnotationElement> internAnnotationElements(
76            @Nonnull Set<? extends AnnotationElement> elements) {
77        return ImmutableSet.copyOf(
78                Iterators.transform(elements.iterator(),
79                        new Function<AnnotationElement, BuilderAnnotationElement>() {
80                            @Nullable @Override
81                            public BuilderAnnotationElement apply(AnnotationElement input) {
82                                return internAnnotationElement(input);
83                            }
84                        }));
85    }
86
87    @Nonnull private BuilderAnnotationElement internAnnotationElement(@Nonnull AnnotationElement annotationElement) {
88        return new BuilderAnnotationElement(stringPool.internString(annotationElement.getName()),
89                internEncodedValue(annotationElement.getValue()));
90    }
91
92    @Nullable BuilderEncodedValue internNullableEncodedValue(@Nullable EncodedValue encodedValue) {
93        if (encodedValue == null) {
94            return null;
95        }
96        return internEncodedValue(encodedValue);
97    }
98
99    @Nonnull private BuilderEncodedValue internEncodedValue(@Nonnull EncodedValue encodedValue) {
100        switch (encodedValue.getValueType()) {
101            case ValueType.ANNOTATION:
102                return internAnnotationEncodedValue((AnnotationEncodedValue)encodedValue);
103            case ValueType.ARRAY:
104                return internArrayEncodedValue((ArrayEncodedValue)encodedValue);
105            case ValueType.BOOLEAN:
106                boolean value = ((BooleanEncodedValue)encodedValue).getValue();
107                return value?BuilderBooleanEncodedValue.TRUE_VALUE:BuilderBooleanEncodedValue.FALSE_VALUE;
108            case ValueType.BYTE:
109                return new BuilderByteEncodedValue(((ByteEncodedValue)encodedValue).getValue());
110            case ValueType.CHAR:
111                return new BuilderCharEncodedValue(((CharEncodedValue)encodedValue).getValue());
112            case ValueType.DOUBLE:
113                return new BuilderDoubleEncodedValue(((DoubleEncodedValue)encodedValue).getValue());
114            case ValueType.ENUM:
115                return internEnumEncodedValue((EnumEncodedValue)encodedValue);
116            case ValueType.FIELD:
117                return internFieldEncodedValue((FieldEncodedValue)encodedValue);
118            case ValueType.FLOAT:
119                return new BuilderFloatEncodedValue(((FloatEncodedValue)encodedValue).getValue());
120            case ValueType.INT:
121                return new BuilderIntEncodedValue(((IntEncodedValue)encodedValue).getValue());
122            case ValueType.LONG:
123                return new BuilderLongEncodedValue(((LongEncodedValue)encodedValue).getValue());
124            case ValueType.METHOD:
125                return internMethodEncodedValue((MethodEncodedValue)encodedValue);
126            case ValueType.NULL:
127                return BuilderNullEncodedValue.INSTANCE;
128            case ValueType.SHORT:
129                return new BuilderShortEncodedValue(((ShortEncodedValue)encodedValue).getValue());
130            case ValueType.STRING:
131                return internStringEncodedValue((StringEncodedValue)encodedValue);
132            case ValueType.TYPE:
133                return internTypeEncodedValue((TypeEncodedValue)encodedValue);
134            default:
135                throw new ExceptionWithContext("Unexpected encoded value type: %d", encodedValue.getValueType());
136        }
137    }
138
139    @Nonnull private BuilderAnnotationEncodedValue internAnnotationEncodedValue(@Nonnull AnnotationEncodedValue value) {
140        return new BuilderAnnotationEncodedValue(
141                typePool.internType(value.getType()),
142                internAnnotationElements(value.getElements()));
143    }
144
145    @Nonnull private BuilderArrayEncodedValue internArrayEncodedValue(@Nonnull ArrayEncodedValue value) {
146        return new BuilderArrayEncodedValue(
147                ImmutableList.copyOf(
148                        Iterators.transform(value.getValue().iterator(),
149                                new Function<EncodedValue, BuilderEncodedValue>() {
150                                    @Nullable @Override public BuilderEncodedValue apply(EncodedValue input) {
151                                        return internEncodedValue(input);
152                                    }
153                                })));
154    }
155
156    @Nonnull private BuilderEnumEncodedValue internEnumEncodedValue(@Nonnull EnumEncodedValue value) {
157        return new BuilderEnumEncodedValue(fieldPool.internField(value.getValue()));
158    }
159
160    @Nonnull private BuilderFieldEncodedValue internFieldEncodedValue(@Nonnull FieldEncodedValue value) {
161        return new BuilderFieldEncodedValue(fieldPool.internField(value.getValue()));
162    }
163
164    @Nonnull private BuilderMethodEncodedValue internMethodEncodedValue(@Nonnull MethodEncodedValue value) {
165        return new BuilderMethodEncodedValue(methodPool.internMethod(value.getValue()));
166    }
167
168    @Nonnull private BuilderStringEncodedValue internStringEncodedValue(@Nonnull StringEncodedValue string) {
169        return new BuilderStringEncodedValue(stringPool.internString(string.getValue()));
170    }
171
172    @Nonnull private BuilderTypeEncodedValue internTypeEncodedValue(@Nonnull TypeEncodedValue type) {
173        return new BuilderTypeEncodedValue(typePool.internType(type.getValue()));
174    }
175}
176