All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.reandroid.arsc.array.OffsetBlockArray Maven / Gradle / Ivy

/*
 *  Copyright (C) 2022 github.com/REAndroid
 *
 *  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 com.reandroid.arsc.array;

import com.reandroid.arsc.base.Block;
import com.reandroid.arsc.base.BlockArray;
import com.reandroid.arsc.base.BlockCounter;
import com.reandroid.arsc.io.BlockLoad;
import com.reandroid.arsc.io.BlockReader;
import com.reandroid.arsc.item.AlignItem;
import com.reandroid.arsc.item.IntegerReference;


import java.io.IOException;
import java.io.OutputStream;

public abstract class OffsetBlockArray extends BlockArray implements BlockLoad {

    private final OffsetArray mOffsetArray;
    private final IntegerReference startReference;
    private final IntegerReference countReference;
    private final AlignItem alignItem;

    public OffsetBlockArray(OffsetArray offsets, IntegerReference countReference, IntegerReference startReference){
        super();
        this.mOffsetArray = offsets;
        this.countReference = countReference;
        this.startReference = startReference;
        this.alignItem = new AlignItem();
        if(countReference instanceof Block){
            ((Block)countReference).setBlockLoad(this);
        }
    }
    public boolean isEmpty(){
        return size() == 0;
    }
    @Override
    public void clear(){
        super.clear();
        mOffsetArray.clear();
        startReference.set(0);
        countReference.set(0);
        alignItem.clear();
    }
    OffsetArray getOffsetArray(){
        return mOffsetArray;
    }
    protected AlignItem getAlignItem(){
        return alignItem;
    }
    @Override
    public int countBytes(){
        int result = super.countBytes();
        int alignSize = getAlignItem().countBytes();
        return result + alignSize;
    }
    @Override
    public void onCountUpTo(BlockCounter counter){
        super.onCountUpTo(counter);
        if(counter.FOUND){
            return;
        }
        getAlignItem().onCountUpTo(counter);
    }
    @Override
    public byte[] getBytes(){
        byte[] results = super.getBytes();
        if(results == null){
            return null;
        }
        byte[] alignBytes = alignItem.getBytes();
        results = addBytes(results, alignBytes);
        return results;
    }
    @Override
    public int onWriteBytes(OutputStream stream) throws IOException {
        int result = super.onWriteBytes(stream);
        if(result == 0){
            return 0;
        }
        result += alignItem.writeBytes(stream);
        return result;
    }
    @Override
    protected void onRefreshed() {
        calculateOffsets();
        refreshCount();
        refreshStart();
        refreshAlignment(getAlignItem());
    }
    private void calculateOffsets() {
        int count = size();
        OffsetArray offsetArray = getOffsetArray();
        offsetArray.setSize(count);
        if(count == 0){
            return;
        }
        int sum = 0;
        for(int i = 0; i < count; i++){
            T item = get(i);
            int offset;
            if(item == null || item.isNull()){
                offset = -1;
            }else {
                offset = sum;
                sum += item.countBytes();
            }
            offsetArray.setOffset(i, offset);
        }
    }
    public void refreshCountAndStart(){
        refreshCount();
        refreshStart();
    }
    public void refreshCount(){
        countReference.set(size());
    }
    private void refreshStart(){
        int count = size();
        if(count == 0){
            startReference.set(0);
            alignItem.clear();
            return;
        }
        Block parent = getParent();
        if(parent == null){
            return;
        }
        int start = parent.countUpTo(this);
        startReference.set(start);
    }
    void refreshAlignment(BlockReader reader, AlignItem alignItem) throws IOException{
        refreshAlignment(alignItem);
    }
    void refreshAlignment(AlignItem alignItem){
        if(size() == 0){
            alignItem.clear();
        }else {
            alignItem.align(this);
        }
    }

    @Override
    public void onReadBytes(BlockReader reader) throws IOException{
        int size = size();
        if(size == 0){
            return;
        }
        int noEntry = OffsetArray.NO_ENTRY;
        int[] offsetArray = mOffsetArray.getOffsets();
        int zeroPosition = getZeroPosition();
        reader.seek(zeroPosition);
        int maximumPosition = zeroPosition;
        for(int i = 0; i < size; i++){
            T item = get(i);
            int offset = offsetArray[i];
            if(offset == noEntry){
                item.setNull(true);
                continue;
            }
            int itemStart = zeroPosition + offset;
            reader.seek(itemStart);
            item.readBytes(reader);
            int position = reader.getPosition();
            if(position > maximumPosition){
                maximumPosition = position;
            }
        }
        if(maximumPosition > 0){
            reader.seek(maximumPosition);
            refreshAlignment(reader, getAlignItem());
        }
    }
    private int getZeroPosition(){
        int start = startReference.get();
        if(start < 0){
            start = 0;
        }
        return start;
    }
    @Override
    public void onBlockLoaded(BlockReader reader, Block sender) throws IOException {
        if(sender == countReference){
            int count = countReference.get();
            setSize(count);
            getOffsetArray().setSize(count);
        }
    }

    @Override
    public String toString(){
        StringBuilder builder=new StringBuilder();
        builder.append(getClass().getSimpleName());
        builder.append(": size = ");
        int realCount = size();
        builder.append(realCount);
        int count = countReference.get();
        if(realCount != count){
            builder.append(", sizeValue = ");
            builder.append(count);
        }
        builder.append(", start = ");
        builder.append(startReference.get());
        return builder.toString();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy