content: /*
   * Copyright (C) 2014 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package dexfuzz.rawdex;
  
  import java.io.IOException;
  
  public class ClassDataItem implements RawDexObject {
    public int staticFieldsSize;
    public int instanceFieldsSize;
    public int directMethodsSize;
    public int virtualMethodsSize;
  
    public EncodedField[] staticFields;
    public EncodedField[] instanceFields;
    public EncodedMethod[] directMethods;
    public EncodedMethod[] virtualMethods;
  
    public static class MetaInfo {
      public ClassDefItem classDefItem;
    }
  
    public MetaInfo meta = new MetaInfo();
  
    @Override
    public void read(DexRandomAccessFile file) throws IOException {
      file.getOffsetTracker().getNewOffsettable(file, this);
      staticFieldsSize = file.readUleb128();
      instanceFieldsSize = file.readUleb128();
      directMethodsSize = file.readUleb128();
      virtualMethodsSize = file.readUleb128();
  
      staticFields = new EncodedField[staticFieldsSize];
      for (int i = 0; i < staticFieldsSize; i++) {
        (staticFields[i] = new EncodedField()).read(file);
      }
      instanceFields = new EncodedField[instanceFieldsSize];
      for (int i = 0; i < instanceFieldsSize; i++) {
        (instanceFields[i] = new EncodedField()).read(file);
      }
      directMethods = new EncodedMethod[directMethodsSize];
      for (int i = 0; i < directMethodsSize; i++) {
        (directMethods[i] = new EncodedMethod()).read(file);
      }
      virtualMethods = new EncodedMethod[virtualMethodsSize];
      for (int i = 0; i < virtualMethodsSize; i++) {
        (virtualMethods[i] = new EncodedMethod()).read(file);
      }
    }
  
    @Override
    public void write(DexRandomAccessFile file) throws IOException {
      file.getOffsetTracker().updatePositionOfNextOffsettable(file);
      file.writeUleb128(staticFieldsSize);
      file.writeUleb128(instanceFieldsSize);
      file.writeUleb128(directMethodsSize);
      file.writeUleb128(virtualMethodsSize);
      for (int i = 0; i < staticFieldsSize; i++) {
        staticFields[i].write(file);
      }
      for (int i = 0; i < instanceFieldsSize; i++) {
        instanceFields[i].write(file);
      }
      for (int i = 0; i < directMethodsSize; i++) {
        directMethods[i].write(file);
      }
      for (int i = 0; i < virtualMethodsSize; i++) {
        virtualMethods[i].write(file);
      }
    }
  
    private void incrementEncodedFields(int insertedIdx, EncodedField[] fields) {
      int fieldIdx = 0;
      for (EncodedField field : fields) {
        fieldIdx = field.fieldIdxDiff;
        if (fieldIdx >= insertedIdx) {
          field.fieldIdxDiff++;
          // Only need to increment one, as all the others are diffed from the previous.
          break;
        }
      }
    }
  
    private void incrementEncodedMethods(int insertedIdx, EncodedMethod[] methods) {
      int methodIdx = 0;
      for (EncodedMethod method : methods) {
        methodIdx = method.methodIdxDiff;
        if (methodIdx >= insertedIdx) {
          method.methodIdxDiff++;
          // Only need to increment one, as all the others are diffed from the previous.
          break;
        }
      }
    }
  
    @Override
    public void incrementIndex(IndexUpdateKind kind, int insertedIdx) {
      if (kind == IndexUpdateKind.FIELD_ID) {
        incrementEncodedFields(insertedIdx, staticFields);
        incrementEncodedFields(insertedIdx, instanceFields);
      }
      if (kind == IndexUpdateKind.METHOD_ID) {
        incrementEncodedMethods(insertedIdx, directMethods);
        incrementEncodedMethods(insertedIdx, virtualMethods);
      }
    }
  
    /**
     * For a given field index, search this ClassDataItem for a definition of this field.
     * @return null if the field isn't in this ClassDataItem.
     */
    public EncodedField getEncodedFieldWithIndex(int fieldIdx) {
      int searchFieldIdx = 0;
      for (EncodedField field : instanceFields) {
        searchFieldIdx += field.fieldIdxDiff;
        if (searchFieldIdx == fieldIdx) {
          return field;
        }
      }
      searchFieldIdx = 0;
      for (EncodedField field : staticFields) {
        searchFieldIdx += field.fieldIdxDiff;
        if (searchFieldIdx == fieldIdx) {
          return field;
        }
      }
      return null;
    }
  }
  