Compare commits

..

7 Commits

Author SHA1 Message Date
78db656a92 write function for bulk removal of chunks 2025-08-27 12:30:38 +02:00
767f3a5c13 refactor of mcx_delchunk to make things a bit more clear and flexible 2025-08-27 12:30:38 +02:00
43e3e4fe85 fix: not converting big-endian numbers to host.
I swear I did have this here at some point... I've got no idea when I
removed it, or even why.
2025-08-27 12:30:38 +02:00
fad6f366b4 fix: mcx_delchunk was not updating the byte offset of affected chunks. 2025-08-27 12:30:38 +02:00
b7859d56d9 add function for computing the bytesize of the *.mcX file 2025-08-27 12:30:38 +02:00
7a45724de7 modify planned features in README.md, to add a few of my ideas. 2025-08-27 11:43:17 +02:00
1c863099a9 write a function for deleting a specific chunk. 2025-08-27 11:43:17 +02:00
3 changed files with 65 additions and 16 deletions

View File

@@ -19,7 +19,12 @@ I have picked C as the language for the core portions of the application, where
This version is not intended to serve to entirely replace MCA selector, just to offer an alternative. Both tools will have their strengths and weaknesses.
# planned features
- [ ] (very basic) world map viewing
- [ ] (very basic) world map viewing (Y level + surface)
- [ ] filtering chunks based on time spent in them
- [ ] chunk-level removal of data.
- [ ] CLI-only version
- [ ] (idea) change chunk compression
- [ ] (idea) view chunk metadata
- [ ] (idea) change chunk sNBT (this'll be tricky to add)
*note that entries marked with `(idea)` aren't guaranteed to be implemented.
Due to their viability and usefulness is still to be measured.*

View File

@@ -9,23 +9,61 @@
#include "../util/compat/endian.h"
#include "../util/intdef.h"
void mcx_delchunk(u8 *restrict buf, int idx) {
/* Deletes chunk `sidx`, by moving chunks up to `eidx` back over `sidx` in `buf`.
* `rmb` is an optional additional offset that can be applied, and signifies bytes already removed.
* Returns the bytes removed by this function. */
static size_t delchunk(u8 *restrict buf, size_t rmb, int sidx, int eidx) {
// load the table data, and clear it
u32 *table = (u32 *)buf;
size_t chunk = (table[idx] >> 8) * 0x1000; // compute the byte offset the chunk starts in
size_t blen = (table[idx] & 0xFF) * 0x1000; // compute the byte length of the chunk
table[idx] = 0;
table[idx + 0x400] = time(NULL); // assign the current time to the timestamp, for correctness NOTE: might need to zero-out instead
size_t slen, bidx, blen;
slen = be32toh(table[sidx] & 0xFF); // acquire the sector length of the chunk
bidx = be32toh(table[sidx] >> 8) * 0x1000; // acquire and compute the byte offset the chunk starts at
blen = slen * 0x1000; // compute the byte length of the chunk
table[sidx] = 0;
table[sidx + 0x400] = time(NULL); // assign the current time to the timestamp, for correctness NOTE: might need to zero-out instead
// store the head and tail end of the current chunk
u8 *head = buf + chunk;
u8 *tail = buf + chunk + blen;
// count the amount of bytes that we must move
u8 *dst = buf + bidx - rmb;
u8 *src = buf + bidx + blen;
rmb = blen;
blen = 0;
for (idx++; idx < 0x400; idx++)
blen += table[idx] & 0xFF * 0x1000;
memmove(head, tail, blen);
for (sidx++; sidx < eidx; sidx++) {
blen += be32toh(table[sidx] & 0xFF) * 0x1000;
table[sidx] -= htobe32(slen << 8);
}
memmove(dst, src, blen);
return rmb;
}
size_t mcx_delchunk(u8 *restrict buf, int chunk) {
return delchunk(buf, 0, chunk, 0x400);
}
/* comparer function for to be inputted into `qsort` to compare two */
static int cmp_chunkids(const void *restrict x, const void *restrict y) {
u16 x2 = *(u16 *)x;
u16 y2 = *(u16 *)y;
return (x2 > y2) - (x2 < y2);
}
void mcx_delchunks(u8 *restrict buf, const u16 *restrict chunks, int chunkc) {
// ensure the chunks ids we're working on are sorted from least to greatest
u16 chunkids[chunkc + 1];
memcpy(chunkids, chunks, chunkc);
qsort(chunkids, chunkc, sizeof(int), cmp_chunkids);
chunkids[chunkc] = 0; // set the spare chunk to zero, to prevent out-of-bounds access
size_t rmb = 0;
for (int i = 0; i < chunkc; i++)
rmb += delchunk(buf, rmb, chunkids[i], chunkids[i + 1]);
}
/* Sum together the 4th byte in each location integer to compute the sector size of all chunks.
* Multiplying by `0x1000`, and adding the size of the table itself. */
size_t mcx_calcsize(const u8 *restrict buf) {
size_t size = 0;
for (uint i = 0; i < 0x400; i++)
size += *(buf + (i * 4) + 3);
return (size * 0x1000) + 0x2000;
}
/* an `*.mcX` contains a `0x2000` byte long table, the first `0x1000` containing

View File

@@ -14,9 +14,15 @@ struct mcx_chunk {
u32 time; // modification time in epoch seconds
};
// TODO: should return some form of feedback about its success
/* Deletes chunk `idx` from `buf`, moving all chunks downwards in the process. */
void mcx_delchunk(u8 *restrict buf, int idx);
size_t mcx_delchunk(u8 *restrict buf, int idx);
/* Deletes `chunkc` chunks specified in `chunks` from the `*.mcX` file.
* This is done in a way to perform minimal memmove operations. */
void mcx_delchunks(u8 *restrict buf, const u16 *restrict chunks, int chunkc);
/* Computes the byte size of the `*.mcX` file in `buf` and returns it. */
size_t mcx_calcsize(const u8 *restrict buf) NONNULL((1)) PURE;
/* indexes the chunks in an `*.mcX` file, writing `0x400` of entries to `chunks` */
void mcx_index(const u8 *restrict buf, struct mcx_chunk *restrict chunks) NONNULL((1, 2));