com.github.junrar.unpack.ppm.SubAllocator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of junrar Show documentation
Show all versions of junrar Show documentation
rar decompression library in plain java
/*
* Copyright (c) 2007 innoSysTec (R) GmbH, Germany. All rights reserved.
* Original author: Edmund Wagner
* Creation date: 31.05.2007
*
* Source: $HeadURL$
* Last changed: $LastChangedDate$
*
* the unrar licence applies to all junrar source and binary distributions
* you are not allowed to use this source to re-create the RAR compression algorithm
*
* Here some html entities which can be used for escaping javadoc tags:
* "&": "&" or "&"
* "<": "<" or "<"
* ">": ">" or ">"
* "@": "@"
*/
package com.github.junrar.unpack.ppm;
import java.util.Arrays;
/**
* DOCUMENT ME
*
* @author $LastChangedBy$
* @version $LastChangedRevision$
*/
public class SubAllocator {
public static final int N1 = 4, N2 = 4, N3 = 4, N4 = (128 + 3 - 1 * N1 - 2
* N2 - 3 * N3) / 4;
public static final int N_INDEXES = N1 + N2 + N3 + N4;
public static final int UNIT_SIZE = Math.max(PPMContext.size,
RarMemBlock.size);
public static final int FIXED_UNIT_SIZE = 12;
private int subAllocatorSize;
// byte Indx2Units[N_INDEXES], Units2Indx[128], GlueCount;
private final int[] indx2Units = new int[N_INDEXES];
private final int[] units2Indx = new int[128];
private int glueCount;
// byte *HeapStart,*LoUnit, *HiUnit;
private int heapStart, loUnit, hiUnit;
private final RarNode[] freeList = new RarNode[N_INDEXES];
// byte *pText, *UnitsStart,*HeapEnd,*FakeUnitsStart;
private int pText, unitsStart, heapEnd, fakeUnitsStart;
private byte[] heap;
private int freeListPos;
private int tempMemBlockPos;
// Temp fields
private RarNode tempRarNode = null;
private RarMemBlock tempRarMemBlock1 = null;
private RarMemBlock tempRarMemBlock2 = null;
private RarMemBlock tempRarMemBlock3 = null;
public SubAllocator() {
clean();
}
public void clean() {
subAllocatorSize = 0;
}
private void insertNode(int p/* rarnode ptr */, int indx) {
RarNode temp = tempRarNode;
temp.setAddress(p);
temp.setNext(freeList[indx].getNext());
freeList[indx].setNext(temp);
}
public void incPText() {
pText++;
}
private int removeNode(int indx) {
int retVal = freeList[indx].getNext();
RarNode temp = tempRarNode;
temp.setAddress(retVal);
freeList[indx].setNext(temp.getNext());
return retVal;
}
private int U2B(int NU) {
return /* 8*NU+4*NU */UNIT_SIZE * NU;
}
/* memblockptr */
private int MBPtr(int BasePtr, int Items) {
return (BasePtr + U2B(Items));
}
private void splitBlock(int pv/* ptr */, int oldIndx, int newIndx) {
int i, uDiff = indx2Units[oldIndx] - indx2Units[newIndx];
int p = pv + U2B(indx2Units[newIndx]);
if (indx2Units[i = units2Indx[uDiff - 1]] != uDiff) {
insertNode(p, --i);
p += U2B(i = indx2Units[i]);
uDiff -= i;
}
insertNode(p, units2Indx[uDiff - 1]);
}
public void stopSubAllocator() {
if (subAllocatorSize != 0) {
subAllocatorSize = 0;
heap = null;
heapStart = 1;
// rarfree(HeapStart);
// Free temp fields
tempRarNode = null;
tempRarMemBlock1 = null;
tempRarMemBlock2 = null;
tempRarMemBlock3 = null;
}
}
public int GetAllocatedMemory() {
return subAllocatorSize;
}
public boolean startSubAllocator(int SASize) {
int t = SASize << 20;
if (subAllocatorSize == t) {
return true;
}
stopSubAllocator();
int allocSize = t / FIXED_UNIT_SIZE * UNIT_SIZE + UNIT_SIZE;
// adding space for freelist (needed for poiters)
// 1+ for null pointer
int realAllocSize = 1 + allocSize + 4 * N_INDEXES;
// adding space for an additional memblock
tempMemBlockPos = realAllocSize;
realAllocSize += RarMemBlock.size;
heap = new byte[realAllocSize];
heapStart = 1;
heapEnd = heapStart + allocSize - UNIT_SIZE;
subAllocatorSize = t;
// Bug fixed
freeListPos = heapStart + allocSize;
assert (realAllocSize - tempMemBlockPos == RarMemBlock.size) : realAllocSize
+ " " + tempMemBlockPos + " " + RarMemBlock.size;
// Init freeList
for (int i = 0, pos = freeListPos; i < freeList.length; i++, pos += RarNode.size) {
freeList[i] = new RarNode(heap);
freeList[i].setAddress(pos);
}
// Init temp fields
tempRarNode = new RarNode(heap);
tempRarMemBlock1 = new RarMemBlock(heap);
tempRarMemBlock2 = new RarMemBlock(heap);
tempRarMemBlock3 = new RarMemBlock(heap);
return true;
}
private void glueFreeBlocks() {
RarMemBlock s0 = tempRarMemBlock1;
s0.setAddress(tempMemBlockPos);
RarMemBlock p = tempRarMemBlock2;
RarMemBlock p1 = tempRarMemBlock3;
int i, k, sz;
if (loUnit != hiUnit) {
heap[loUnit] = 0;
}
for (i = 0, s0.setPrev(s0), s0.setNext(s0); i < N_INDEXES; i++) {
while (freeList[i].getNext() != 0) {
p.setAddress(removeNode(i)); // =(RAR_MEM_BLK*)RemoveNode(i);
p.insertAt(s0); // p->insertAt(&s0);
p.setStamp(0xFFFF); // p->Stamp=0xFFFF;
p.setNU(indx2Units[i]); // p->NU=Indx2Units[i];
}
}
for (p.setAddress(s0.getNext()); p.getAddress() != s0.getAddress(); p
.setAddress(p.getNext())) {
// while ((p1=MBPtr(p,p->NU))->Stamp == 0xFFFF && int(p->NU)+p1->NU
// < 0x10000)
// Bug fixed
p1.setAddress(MBPtr(p.getAddress(), p.getNU()));
while (p1.getStamp() == 0xFFFF && p.getNU() + p1.getNU() < 0x10000) {
p1.remove();
p.setNU(p.getNU() + p1.getNU()); // ->NU += p1->NU;
p1.setAddress(MBPtr(p.getAddress(), p.getNU()));
}
}
// while ((p=s0.next) != &s0)
// Bug fixed
p.setAddress(s0.getNext());
while (p.getAddress() != s0.getAddress()) {
for (p.remove(), sz = p.getNU(); sz > 128; sz -= 128, p
.setAddress(MBPtr(p.getAddress(), 128))) {
insertNode(p.getAddress(), N_INDEXES - 1);
}
if (indx2Units[i = units2Indx[sz - 1]] != sz) {
k = sz - indx2Units[--i];
insertNode(MBPtr(p.getAddress(), sz - k), k - 1);
}
insertNode(p.getAddress(), i);
p.setAddress(s0.getNext());
}
}
private int allocUnitsRare(int indx) {
if (glueCount == 0) {
glueCount = 255;
glueFreeBlocks();
if (freeList[indx].getNext() != 0) {
return removeNode(indx);
}
}
int i = indx;
do {
if (++i == N_INDEXES) {
glueCount--;
i = U2B(indx2Units[indx]);
int j = FIXED_UNIT_SIZE * indx2Units[indx];
if (fakeUnitsStart - pText > j) {
fakeUnitsStart -= j;
unitsStart -= i;
return unitsStart;
}
return (0);
}
} while (freeList[i].getNext() == 0);
int retVal = removeNode(i);
splitBlock(retVal, i, indx);
return retVal;
}
public int allocUnits(int NU) {
int indx = units2Indx[NU - 1];
if (freeList[indx].getNext() != 0) {
return removeNode(indx);
}
int retVal = loUnit;
loUnit += U2B(indx2Units[indx]);
if (loUnit <= hiUnit) {
return retVal;
}
loUnit -= U2B(indx2Units[indx]);
return allocUnitsRare(indx);
}
public int allocContext() {
if (hiUnit != loUnit) {
return (hiUnit -= UNIT_SIZE);
}
if (freeList[0].getNext() != 0) {
return removeNode(0);
}
return allocUnitsRare(0);
}
public int expandUnits(int oldPtr, int OldNU) {
int i0 = units2Indx[OldNU - 1];
int i1 = units2Indx[OldNU - 1 + 1];
if (i0 == i1) {
return oldPtr;
}
int ptr = allocUnits(OldNU + 1);
if (ptr != 0) {
// memcpy(ptr,OldPtr,U2B(OldNU));
System.arraycopy(heap, oldPtr, heap, ptr, U2B(OldNU));
insertNode(oldPtr, i0);
}
return ptr;
}
public int shrinkUnits(int oldPtr, int oldNU, int newNU) {
// System.out.println("SubAllocator.shrinkUnits(" + OldPtr + ", " +
// OldNU + ", " + NewNU + ")");
int i0 = units2Indx[oldNU - 1];
int i1 = units2Indx[newNU - 1];
if (i0 == i1) {
return oldPtr;
}
if (freeList[i1].getNext() != 0) {
int ptr = removeNode(i1);
// memcpy(ptr,OldPtr,U2B(NewNU));
// for (int i = 0; i < U2B(NewNU); i++) {
// heap[ptr + i] = heap[OldPtr + i];
// }
System.arraycopy(heap, oldPtr, heap, ptr, U2B(newNU));
insertNode(oldPtr, i0);
return ptr;
} else {
splitBlock(oldPtr, i0, i1);
return oldPtr;
}
}
public void freeUnits(int ptr, int OldNU) {
insertNode(ptr, units2Indx[OldNU - 1]);
}
public int getFakeUnitsStart() {
return fakeUnitsStart;
}
public void setFakeUnitsStart(int fakeUnitsStart) {
this.fakeUnitsStart = fakeUnitsStart;
}
public int getHeapEnd() {
return heapEnd;
}
public int getPText() {
return pText;
}
public void setPText(int text) {
pText = text;
}
public void decPText(int dPText) {
setPText(getPText() - dPText);
}
public int getUnitsStart() {
return unitsStart;
}
public void setUnitsStart(int unitsStart) {
this.unitsStart = unitsStart;
}
public void initSubAllocator() {
int i, k;
Arrays.fill(heap, freeListPos, freeListPos + sizeOfFreeList(), (byte) 0);
pText = heapStart;
int size2 = FIXED_UNIT_SIZE
* (subAllocatorSize / 8 / FIXED_UNIT_SIZE * 7);
int realSize2 = size2 / FIXED_UNIT_SIZE * UNIT_SIZE;
int size1 = subAllocatorSize - size2;
int realSize1 = size1 / FIXED_UNIT_SIZE * UNIT_SIZE + size1
% FIXED_UNIT_SIZE;
hiUnit = heapStart + subAllocatorSize;
loUnit = unitsStart = heapStart + realSize1;
fakeUnitsStart = heapStart + size1;
hiUnit = loUnit + realSize2;
for (i = 0, k = 1; i < N1; i++, k += 1) {
indx2Units[i] = k & 0xff;
}
for (k++; i < N1 + N2; i++, k += 2) {
indx2Units[i] = k & 0xff;
}
for (k++; i < N1 + N2 + N3; i++, k += 3) {
indx2Units[i] = k & 0xff;
}
for (k++; i < (N1 + N2 + N3 + N4); i++, k += 4) {
indx2Units[i] = k & 0xff;
}
for (glueCount = 0, k = 0, i = 0; k < 128; k++) {
i += ((indx2Units[i] < (k + 1)) ? 1 : 0);
units2Indx[k] = i & 0xff;
}
}
private int sizeOfFreeList() {
return freeList.length * RarNode.size;
}
public byte[] getHeap() {
return heap;
}
// Debug
// public void dumpHeap() {
// File file = new File("P:\\test\\heapdumpj");
// OutputStream out = null;
// try {
// out = new FileOutputStream(file);
// out.write(heap, heapStart, heapEnd - heapStart);
// out.flush();
// System.out.println("Heap dumped to " + file.getAbsolutePath());
// }
// catch (IOException e) {
// e.printStackTrace();
// }
// finally {
// FileUtil.close(out);
// }
// }
// Debug
public String toString() {
StringBuilder buffer = new StringBuilder();
buffer.append("SubAllocator[");
buffer.append("\n subAllocatorSize=");
buffer.append(subAllocatorSize);
buffer.append("\n glueCount=");
buffer.append(glueCount);
buffer.append("\n heapStart=");
buffer.append(heapStart);
buffer.append("\n loUnit=");
buffer.append(loUnit);
buffer.append("\n hiUnit=");
buffer.append(hiUnit);
buffer.append("\n pText=");
buffer.append(pText);
buffer.append("\n unitsStart=");
buffer.append(unitsStart);
buffer.append("\n]");
return buffer.toString();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy