int mcr_chunk_set(MCR *mcr, int x, int z, nbt_node *root) { assert(mcr && x < 32 && z < 32 && x >= 0 && z >= 0); if (mcr->readonly) { errno = EPERM; return -1; } struct MCRChunk *chunk = &mcr->chunk[x][z]; if (root == NULL) { // delete chunk free(chunk->data); chunk->data = NULL; chunk->len = 0; chunk->timestamp = 0; } else { // compress chunk struct buffer compressed = nbt_dump_compressed(root, STRAT_INFLATE); chunk->len = compressed.len+1; uint8_t *data = (uint8_t*)malloc(chunk->len); if (data == NULL) { buffer_free(&compressed); return -1; } data[0] = 2; // compression type memcpy(data+1, compressed.data, compressed.len); buffer_free(&compressed); chunk->timestamp = mcr->last_timestamp; free(chunk->data); chunk->data = data; } return 0; }
/* * Once again, all we're doing is handing the actual compression off to * nbt_dump_compressed, then dumping it into the file. */ nbt_status nbt_dump_file(const nbt_node* tree, FILE* fp, nbt_compression_strategy strat) { struct buffer compressed = nbt_dump_compressed(tree, strat); if(compressed.data == NULL) return (nbt_status)errno; nbt_status ret = write_file(fp, compressed.data, compressed.len); buffer_free(&compressed); return ret; }
int write_chunk(regionfile* region, int32_t cx, int32_t cz, chunk* chunk) { if (region == NULL) return -1; if (chunk == NULL) return -1; cx &= 0x1f; cz &= 0x1f; uint32_t offset = region->offsets[cx + cz * 32]; if (offset == 0) return -2; uint32_t numSectors = offset & 0xff; if (numSectors == 0) return -3; nbt_node* raw = new_chunk_data_to_nbt(chunk); if (raw == NULL) return -1; uint32_t sectorStart = offset >> 8; FILE* f; if (region->keepopen == 1) { if (region->file) f = region->file; else { f = fopen(region->filename, "rb+"); region->file = f; } } else f = fopen(region->filename, "rb+"); struct buffer buf = nbt_dump_compressed(raw, STRAT_INFLATE); uint16_t sectorsNeeded = (buf.len + 5) / SECTOR_BYTES + 1; if (sectorsNeeded >= 256) goto error; if (sectorStart != 0 && numSectors >= sectorsNeeded) { if (fseek(f, sectorStart*SECTOR_BYTES, SEEK_SET) != 0) goto error; uint32_t size = htobe32(buf.len); if (fwrite(&size, 1, sizeof(uint32_t), f) != sizeof(uint32_t)) goto error; static const char COMPRESSION = 2; if (fwrite(&COMPRESSION, 1, sizeof(COMPRESSION), f) != sizeof(COMPRESSION)) goto error; if (fwrite(buf.data, 1, buf.len, f) != buf.len) goto error; goto success; } else { size_t i; size_t runLength = 0; uint32_t runStart = 0; unsigned char* curSector = region->freeSectors; for (i = 0; curSector[i] != 0x00; i++) { if (runLength > 0) { if (curSector[i] == 0x01) runLength++; else runLength = 0; } else if (curSector[i] == 0x01) { runStart = i; runLength = 1; } if (runLength >= sectorsNeeded) break; } if (runLength >= sectorsNeeded) { region->offsets[cx + cz * 32] = runStart << 8 | sectorsNeeded; if (__region_write_offsets(region) != 0) goto error; if (fseek(f, runStart*SECTOR_BYTES, SEEK_SET) != 0) goto error; uint32_t size = htobe32(buf.len); if (fwrite(&size, 1, sizeof(uint32_t), f) != sizeof(uint32_t)) goto error; static const char COMPRESSION = 2; if (fwrite(&COMPRESSION, 1, sizeof(COMPRESSION), f) != sizeof(COMPRESSION)) goto error; if (fwrite(buf.data, 1, buf.len, f) != buf.len) goto error; goto success; } else { if (fseek(f, 0L, SEEK_END) != 0) goto error; long filesize = ftell(f); uint32_t sectorNumber = filesize/SECTOR_BYTES; filesize += sectorsNeeded * SECTOR_BYTES; if (ftruncate(fileno(f), filesize) != 0) goto error; region->offsets[cx + cz * 32] = sectorNumber << 8 | sectorsNeeded; if (__region_write_offsets(region) != 0) goto error; if (fseek(f, sectorNumber*SECTOR_BYTES, SEEK_SET) != 0) goto error; uint32_t size = htobe32(buf.len); if (fwrite(&size, 1, sizeof(uint32_t), f) != sizeof(uint32_t)) goto error; static const char COMPRESSION = 2; if (fwrite(&COMPRESSION, 1, sizeof(COMPRESSION), f) != sizeof(COMPRESSION)) goto error; if (fwrite(buf.data, 1, buf.len, f) != buf.len) goto error; uint32_t freeSectorsLength = filesize/SECTOR_BYTES; region->freeSectors = realloc(region->freeSectors, sizeof(unsigned char) * (freeSectorsLength+1)); region->freeSectors[freeSectorsLength] = 0x00; for (; sectorNumber < freeSectorsLength; sectorNumber++) region->freeSectors[sectorNumber] = 0x02; goto success; } } error: nbt_free(raw); if (f && region->file != f) fclose(f); buffer_free(&buf); return 1; success: nbt_free(raw); buffer_free(&buf); if (region->file != f) fclose(f); region->timestamps[cx + cz * 32] = time(NULL); __region_write_timestamps(region); return 0; };