RuneHive-Game
Loading...
Searching...
No Matches
Archive.java
Go to the documentation of this file.
1package com.runehive.fs.cache.archive;
2
3import com.google.common.base.Preconditions;
4import com.runehive.fs.cache.Cache;
5import com.runehive.fs.util.ByteBufferUtil;
6import com.runehive.fs.util.CompressionUtil;
7import com.runehive.util.StringUtils;
8import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
9import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
10
11import java.io.IOException;
12import java.nio.ByteBuffer;
13import java.util.Map;
14import java.util.Optional;
15
16import static com.runehive.fs.cache.Cache.INDEX_SIZE;
17
18/**
19 * Represents an archive within the {@link Cache}. <p> An archive contains
20 * varied amounts of {@link ArchiveSector}s which contain compressed file system
21 * data. </p>
22 *
23 * @author Ryley Kimmel <ryley.kimmel@live.com>
24 */
25public final class Archive {
26
27 /** A {@link Map} of {@link ArchiveSector} hashes to {@link ArchiveSector}s. */
28 private final Int2ObjectMap<ArchiveSector> sectors;
29
30 /**
31 * Constructs a new {@link Archive} with the specified {@link Map} of {@link
32 * ArchiveSector}s.
33 *
34 * @param sectors The {@link Map} of sectors within this archive.
35 */
36 private Archive(Int2ObjectMap<ArchiveSector> sectors) {
37 this.sectors = sectors;
38 }
39
40 /**
41 * Decodes the data within this {@link Archive}.
42 *
43 * @param data The encoded data within this archive.
44 * @return Returns an {@link Archive} with the decoded data, never {@code
45 * null}.
46 * @throws IOException If some I/O exception occurs.
47 */
48 public static Archive decode(ByteBuffer data) throws IOException {
49 int length = ByteBufferUtil.getMedium(data);
50 int compressedLength = ByteBufferUtil.getMedium(data);
51
52 byte[] uncompressedData = data.array();
53
54 if (compressedLength != length) {
55 uncompressedData = CompressionUtil.unbzip2Headerless(data.array(), INDEX_SIZE, compressedLength);
56 data = ByteBuffer.wrap(uncompressedData);
57 }
58
59 int total = data.getShort() & 0xFF;
60 int offset = data.position() + total * 10;
61
62 Int2ObjectMap<ArchiveSector> sectors = new Int2ObjectOpenHashMap<>(total);
63 for (int i = 0; i < total; i++) {
64 int hash = data.getInt();
65 length = ByteBufferUtil.getMedium(data);
66 compressedLength = ByteBufferUtil.getMedium(data);
67
68 byte[] sectorData = new byte[length];
69
70 if (length != compressedLength) {
71 sectorData = CompressionUtil.unbzip2Headerless(uncompressedData, offset, compressedLength);
72 } else {
73 System.arraycopy(uncompressedData, offset, sectorData, 0, length);
74 }
75
76 sectors.put(hash, new ArchiveSector(ByteBuffer.wrap(sectorData), hash));
77 offset += compressedLength;
78 }
79
80 return new Archive(sectors);
81 }
82
83 /**
84 * Retrieves an {@link Optional<ArchiveSector>} for the specified hash.
85 *
86 * @param hash The archive sectors hash.
87 * @return The optional container.
88 */
89 private Optional<ArchiveSector> getSector(int hash) {
90 return Optional.ofNullable(sectors.get(hash));
91 }
92
93 /**
94 * Retrieves an {@link Optional<ArchiveSector>} for the specified name.
95 *
96 * @param name The archive sectors name.
97 * @return The optional container.
98 */
99 private Optional<ArchiveSector> getSector(String name) {
100 int hash = StringUtils.hashArchive(name);
101 return getSector(hash);
102 }
103
104 /**
105 * Returns the data within the {@link ArchiveSector} for the specified
106 * {@code String} name.
107 *
108 * @param name The name of the {@link ArchiveSector}.
109 * @return The data within the {@link ArchiveSector} or nothing, this method
110 * fails-fast if no {@link ArchiveSector} exists for the specified {@code
111 * name}.
112 */
113 public ByteBuffer getData(String name) {
114 Optional<ArchiveSector> optionalData = getSector(name);
115 Preconditions.checkArgument(optionalData.isPresent());
116 ArchiveSector dataSector = optionalData.get();
117 return dataSector.getData();
118 }
119
120}
Optional< ArchiveSector > getSector(int hash)
Retrieves an Optional<ArchiveSector> for the specified hash.
Definition Archive.java:89
static Archive decode(ByteBuffer data)
Decodes the data within this Archive.
Definition Archive.java:48
Optional< ArchiveSector > getSector(String name)
Retrieves an Optional<ArchiveSector> for the specified name.
Definition Archive.java:99
final Int2ObjectMap< ArchiveSector > sectors
A Map of ArchiveSector hashes to ArchiveSectors.
Definition Archive.java:28
Archive(Int2ObjectMap< ArchiveSector > sectors)
Constructs a new Archive with the specified Map of ArchiveSectors.
Definition Archive.java:36
ByteBuffer getData(String name)
Returns the data within the ArchiveSector for the specified String name.
Definition Archive.java:113
Represents a sector within an Archive.
ByteBuffer getData()
Returns the data within this sector.
A static-utility class containing extension or helper methods for ByteBuffers.
static int getMedium(ByteBuffer buffer)
Gets a 24-bit medium integer from the specified ByteBuffer, this method does not mark the ByteBuffers...
A static-utility class containing containing extension or helper methods for compressor-deccompressor...
static byte[] unbzip2Headerless(byte[] data, int offset, int length)
Uncompresses a byte array of b-zipped data that does not contain a header.
static int hashArchive(String string)
Hashes a String using Jagex's algorithm, this method should be used to convert actual names to hashed...