
de.innosystec.unrar.unpack.ppm.SubAllocator Maven / Gradle / Ivy
The newest version!
/*
* 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 de.innosystec.unrar.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 int[] indx2Units = new int[N_INDEXES];
private 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 - 2025 Weber Informatics LLC | Privacy Policy