Skip to content

Commit 2109840

Browse files
committed
initial support for parsing hpkg files
1 parent 714be08 commit 2109840

19 files changed

+543
-139
lines changed

haikudepotserver-packagefile/src/main/java/org/haiku/pkg/AttributeIterator.java

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,13 @@ public Attribute next() {
103103
int encoding = deriveAttributeTagEncoding(tag);
104104
int id = deriveAttributeTagId(tag);
105105

106-
if (id <= 0 || id >= AttributeId.values().length) {
106+
if (id < 0 || id >= AttributeId.values().length) {
107107
throw new HpkException("illegal id; " + id);
108108
}
109109
AttributeId attributeId = AttributeId.values()[id];
110110
result = readAttributeByTagType(deriveAttributeTagType(tag), encoding, attributeId);
111111
ensureAttributeType(result);
112112

113-
114113
if(result.getAttributeId().getAttributeType() != result.getAttributeType()) {
115114
throw new HpkException(String.format(
116115
"mismatch in attribute type for id %s; expecting %s, but got %s",
@@ -179,15 +178,15 @@ private Attribute readAttributeByTagType(int tagType, int encoding, AttributeId
179178

180179
private byte[] readBufferForInt(int encoding) {
181180
ensureValidEncodingForInt(encoding);
182-
byte[] buffer = new byte[encoding+1];
183-
context.getHeapReader().readHeap(buffer, 0, new HeapCoordinates(offset, encoding + 1));
184-
offset += encoding + 1;
181+
int bytesToRead = 1 << encoding;
182+
byte[] buffer = new byte[bytesToRead];
183+
context.getHeapReader().readHeap(buffer, 0, new HeapCoordinates(offset, bytesToRead));
184+
offset += bytesToRead;
185185
return buffer;
186186
}
187187

188188
private Attribute readString(int encoding, AttributeId attributeId) {
189189
switch (encoding) {
190-
191190
case ATTRIBUTE_ENCODING_STRING_INLINE:
192191
return readStringInline(attributeId);
193192
case ATTRIBUTE_ENCODING_STRING_TABLE:
@@ -285,7 +284,7 @@ private int deriveAttributeTagEncoding(BigInteger tag) {
285284
}
286285

287286
private boolean deriveAttributeTagHasChildAttributes(BigInteger tag) {
288-
return 0!=tag.subtract(BigInteger.valueOf(1L)).shiftRight(10).and(BigInteger.ONE).intValue();
287+
return 0 != tag.subtract(BigInteger.valueOf(1L)).shiftRight(10).and(BigInteger.ONE).intValue();
289288
}
290289

291290
private BigInteger getNextTag() {
@@ -321,7 +320,6 @@ private void ensureValidEncodingForInt(int encoding) {
321320
case ATTRIBUTE_ENCODING_INT_32_BIT:
322321
case ATTRIBUTE_ENCODING_INT_64_BIT:
323322
break;
324-
325323
default:
326324
throw new IllegalStateException("unknown encoding on a signed integer");
327325
}

haikudepotserver-packagefile/src/main/java/org/haiku/pkg/FileHelper.java

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,16 @@
55

66
package org.haiku.pkg;
77

8-
import java.io.IOException;
9-
import java.io.RandomAccessFile;
8+
import com.google.common.base.Charsets;
9+
import com.google.common.io.Files;
10+
import org.haiku.pkg.model.FileType;
11+
12+
import java.io.*;
1013
import java.math.BigInteger;
14+
import java.util.Arrays;
15+
import java.util.EnumSet;
16+
import java.util.Locale;
17+
import java.util.Optional;
1118

1219
/**
1320
* <p>This helps out with typical common reads that might be performed as part of
@@ -18,7 +25,18 @@ public class FileHelper {
1825

1926
private final static BigInteger MAX_BIGINTEGER_FILE = new BigInteger(Long.toString(Long.MAX_VALUE));
2027

21-
private byte[] buffer8 = new byte[8];
28+
private final byte[] buffer8 = new byte[8];
29+
30+
public FileType getType(RandomAccessFile file) throws IOException {
31+
return tryGetType(file).orElseThrow(() -> new HpkException("unable to establish the file type"));
32+
}
33+
34+
public Optional<FileType> tryGetType(RandomAccessFile file) throws IOException {
35+
String magicString = new String(readMagic(file));
36+
return EnumSet.allOf(FileType.class).stream()
37+
.filter(e -> e.name().toLowerCase(Locale.ROOT).equals(magicString))
38+
.findFirst();
39+
}
2240

2341
public int readUnsignedShortToInt(RandomAccessFile randomAccessFile) throws IOException {
2442

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
package org.haiku.pkg;
2+
3+
import com.google.common.base.Preconditions;
4+
import org.haiku.pkg.heap.HeapCompression;
5+
import org.haiku.pkg.heap.HpkHeapReader;
6+
import org.haiku.pkg.model.FileType;
7+
8+
import java.io.Closeable;
9+
import java.io.File;
10+
import java.io.IOException;
11+
import java.io.RandomAccessFile;
12+
13+
/**
14+
* <p>This object represents an object that can extract an Hpkg (Haiku Pkg) file. If you are wanting to
15+
* read HPKG files then you should instantiate an instance of this class and then make method calls to it in order to
16+
* read values such as the attributes of the file.</p>
17+
*/
18+
19+
public class HpkgFileExtractor implements Closeable {
20+
21+
private final File file;
22+
23+
private final HpkgHeader header;
24+
25+
private final HpkHeapReader heapReader;
26+
27+
private final HpkStringTable tocStringTable;
28+
29+
private final HpkStringTable packageAttributesStringTable;
30+
31+
public HpkgFileExtractor(File file) throws IOException {
32+
33+
super();
34+
Preconditions.checkNotNull(file);
35+
Preconditions.checkState(file.isFile() && file.exists(), "the file does not exist or is not a file");
36+
37+
this.file = file;
38+
this.header = readHeader();
39+
40+
try {
41+
heapReader = new HpkHeapReader(
42+
file,
43+
header.getHeapCompression(),
44+
header.getHeaderSize(),
45+
header.getHeapChunkSize(), // uncompressed size
46+
header.getHeapSizeCompressed(), // including the compressed chunk lengths.
47+
header.getHeapSizeUncompressed() // excludes the compressed chunk lengths.
48+
);
49+
50+
tocStringTable = new HpkStringTable(
51+
heapReader,
52+
header.getHeapSizeUncompressed()
53+
- (header.getPackageAttributesLength() + header.getTocLength()),
54+
header.getTocStringsLength(),
55+
header.getTocStringsCount());
56+
57+
packageAttributesStringTable = new HpkStringTable(
58+
heapReader,
59+
header.getHeapSizeUncompressed() - header.getPackageAttributesLength(),
60+
header.getPackageAttributesStringsLength(),
61+
header.getPackageAttributesStringsCount());
62+
}
63+
catch (Exception e) {
64+
close();
65+
throw new HpkException("unable to setup the hpkg file extractor",e);
66+
}
67+
catch (Throwable th) {
68+
close();
69+
throw new RuntimeException("unable to setup the hpkg file extractor",th);
70+
}
71+
}
72+
73+
@Override
74+
public void close() {
75+
if (null != heapReader) {
76+
heapReader.close();
77+
}
78+
}
79+
80+
public AttributeContext getPackageAttributeContext() {
81+
AttributeContext context = new AttributeContext();
82+
context.setHeapReader(heapReader);
83+
context.setStringTable(packageAttributesStringTable);
84+
return context;
85+
}
86+
87+
public AttributeIterator getPackageAttributesIterator() {
88+
long offset = (header.getHeapSizeUncompressed() - header.getPackageAttributesLength())
89+
+ header.getPackageAttributesStringsLength();
90+
return new AttributeIterator(getPackageAttributeContext(), offset);
91+
}
92+
93+
public AttributeContext getTocContext() {
94+
AttributeContext context = new AttributeContext();
95+
context.setHeapReader(heapReader);
96+
context.setStringTable(tocStringTable);
97+
return context;
98+
}
99+
100+
public AttributeIterator getTocIterator() {
101+
long tocOffset = (header.getHeapSizeUncompressed()
102+
- (header.getPackageAttributesLength() + header.getTocLength()));
103+
long tocAttributeOffset = tocOffset + header.getTocStringsLength();
104+
return new AttributeIterator(getTocContext(), tocAttributeOffset);
105+
}
106+
107+
private HpkgHeader readHeader() throws IOException {
108+
Preconditions.checkNotNull(file);
109+
FileHelper fileHelper = new FileHelper();
110+
111+
try (RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r")) {
112+
113+
if (fileHelper.getType(randomAccessFile) != FileType.HPKG) {
114+
throw new HpkException("magic incorrect at the start of the hpkg file");
115+
}
116+
117+
HpkgHeader result = new HpkgHeader();
118+
119+
result.setHeaderSize(fileHelper.readUnsignedShortToInt(randomAccessFile));
120+
result.setVersion(fileHelper.readUnsignedShortToInt(randomAccessFile));
121+
result.setTotalSize(fileHelper.readUnsignedLongToLong(randomAccessFile));
122+
result.setMinorVersion(fileHelper.readUnsignedShortToInt(randomAccessFile));
123+
124+
result.setHeapCompression(HeapCompression.getByNumericValue(fileHelper.readUnsignedShortToInt(randomAccessFile)));
125+
result.setHeapChunkSize(fileHelper.readUnsignedIntToLong(randomAccessFile));
126+
result.setHeapSizeCompressed(fileHelper.readUnsignedLongToLong(randomAccessFile));
127+
result.setHeapSizeUncompressed(fileHelper.readUnsignedLongToLong(randomAccessFile));
128+
129+
result.setPackageAttributesLength(fileHelper.readUnsignedIntToLong(randomAccessFile));
130+
result.setPackageAttributesStringsLength(fileHelper.readUnsignedIntToLong(randomAccessFile));
131+
result.setPackageAttributesStringsCount(fileHelper.readUnsignedIntToLong(randomAccessFile));
132+
randomAccessFile.skipBytes(4); // reserved uint32
133+
134+
result.setTocLength(fileHelper.readUnsignedLongToLong(randomAccessFile));
135+
result.setTocStringsLength(fileHelper.readUnsignedLongToLong(randomAccessFile));
136+
result.setTocStringsCount(fileHelper.readUnsignedLongToLong(randomAccessFile));
137+
138+
return result;
139+
}
140+
}
141+
142+
}
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package org.haiku.pkg;
2+
3+
import org.haiku.pkg.heap.HeapCompression;
4+
5+
public class HpkgHeader {
6+
7+
private long headerSize;
8+
private int version;
9+
private long totalSize;
10+
private int minorVersion;
11+
12+
// heap
13+
private HeapCompression heapCompression;
14+
private long heapChunkSize;
15+
private long heapSizeCompressed;
16+
private long heapSizeUncompressed;
17+
18+
private long packageAttributesLength;
19+
private long packageAttributesStringsLength;
20+
private long packageAttributesStringsCount;
21+
22+
private long tocLength;
23+
private long tocStringsLength;
24+
private long tocStringsCount;
25+
26+
public long getHeaderSize() {
27+
return headerSize;
28+
}
29+
30+
public void setHeaderSize(long headerSize) {
31+
this.headerSize = headerSize;
32+
}
33+
34+
public int getVersion() {
35+
return version;
36+
}
37+
38+
public void setVersion(int version) {
39+
this.version = version;
40+
}
41+
42+
public long getTotalSize() {
43+
return totalSize;
44+
}
45+
46+
public void setTotalSize(long totalSize) {
47+
this.totalSize = totalSize;
48+
}
49+
50+
public int getMinorVersion() {
51+
return minorVersion;
52+
}
53+
54+
public void setMinorVersion(int minorVersion) {
55+
this.minorVersion = minorVersion;
56+
}
57+
58+
public HeapCompression getHeapCompression() {
59+
return heapCompression;
60+
}
61+
62+
public void setHeapCompression(HeapCompression heapCompression) {
63+
this.heapCompression = heapCompression;
64+
}
65+
66+
public long getHeapChunkSize() {
67+
return heapChunkSize;
68+
}
69+
70+
public void setHeapChunkSize(long heapChunkSize) {
71+
this.heapChunkSize = heapChunkSize;
72+
}
73+
74+
public long getHeapSizeCompressed() {
75+
return heapSizeCompressed;
76+
}
77+
78+
public void setHeapSizeCompressed(long heapSizeCompressed) {
79+
this.heapSizeCompressed = heapSizeCompressed;
80+
}
81+
82+
public long getHeapSizeUncompressed() {
83+
return heapSizeUncompressed;
84+
}
85+
86+
public void setHeapSizeUncompressed(long heapSizeUncompressed) {
87+
this.heapSizeUncompressed = heapSizeUncompressed;
88+
}
89+
90+
public long getPackageAttributesLength() {
91+
return packageAttributesLength;
92+
}
93+
94+
public void setPackageAttributesLength(long packageAttributesLength) {
95+
this.packageAttributesLength = packageAttributesLength;
96+
}
97+
98+
public long getPackageAttributesStringsLength() {
99+
return packageAttributesStringsLength;
100+
}
101+
102+
public void setPackageAttributesStringsLength(long packageAttributesStringsLength) {
103+
this.packageAttributesStringsLength = packageAttributesStringsLength;
104+
}
105+
106+
public long getPackageAttributesStringsCount() {
107+
return packageAttributesStringsCount;
108+
}
109+
110+
public void setPackageAttributesStringsCount(long packageAttributesStringsCount) {
111+
this.packageAttributesStringsCount = packageAttributesStringsCount;
112+
}
113+
114+
public long getTocLength() {
115+
return tocLength;
116+
}
117+
118+
public void setTocLength(long tocLength) {
119+
this.tocLength = tocLength;
120+
}
121+
122+
public long getTocStringsLength() {
123+
return tocStringsLength;
124+
}
125+
126+
public void setTocStringsLength(long tocStringsLength) {
127+
this.tocStringsLength = tocStringsLength;
128+
}
129+
130+
public long getTocStringsCount() {
131+
return tocStringsCount;
132+
}
133+
134+
public void setTocStringsCount(long tocStringsCount) {
135+
this.tocStringsCount = tocStringsCount;
136+
}
137+
}

0 commit comments

Comments
 (0)