1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package dexfuzz.rawdex;
18 
19 import dexfuzz.Log;
20 
21 import java.io.IOException;
22 import java.nio.charset.StandardCharsets;
23 
24 public class StringDataItem implements RawDexObject {
25   private int size;
26   private String data;
27   private byte[] dataAsBytes;
28   private boolean writeRawBytes;
29 
30   @Override
read(DexRandomAccessFile file)31   public void read(DexRandomAccessFile file) throws IOException {
32     file.getOffsetTracker().getNewOffsettable(file, this);
33     size = file.readUleb128();
34     if (size != 0) {
35       dataAsBytes = file.readDexUtf(size);
36       data = new String(dataAsBytes, StandardCharsets.US_ASCII);
37       if (size != data.length()) {
38         Log.warn("Don't have full support for decoding MUTF-8 yet, DEX file "
39             + "may be incorrectly mutated. Avoid using this test case for now.");
40         writeRawBytes = true;
41       }
42     } else {
43       // Read past the null byte.
44       file.readByte();
45     }
46   }
47 
48   @Override
write(DexRandomAccessFile file)49   public void write(DexRandomAccessFile file) throws IOException {
50     file.getOffsetTracker().updatePositionOfNextOffsettable(file);
51     file.writeUleb128(size);
52     if (size > 0) {
53       if (writeRawBytes) {
54         file.writeDexUtf(dataAsBytes);
55       } else {
56         file.writeDexUtf(data.getBytes(StandardCharsets.US_ASCII));
57       }
58     } else {
59       // Write out the null byte.
60       file.writeByte(0);
61     }
62   }
63 
64   @Override
incrementIndex(IndexUpdateKind kind, int insertedIdx)65   public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
66     // Do nothing.
67   }
68 
setSize(int size)69   public void setSize(int size) {
70     this.size = size;
71   }
72 
getSize()73   public int getSize() {
74     return size;
75   }
76 
setString(String data)77   public void setString(String data) {
78     this.data = data;
79   }
80 
getString()81   public String getString() {
82     if (writeRawBytes) {
83       Log.warn("Reading a string that hasn't been properly decoded! Returning empty string.");
84       return "";
85     }
86     return data;
87   }
88 }
89