Commit 8ea3640398f7d39378ee8b64ecf67fa701265eaf
1 parent
6f9d59b6
Fixing bugs and changing chunk interface to something more sensible
Showing
2 changed files
with
226 additions
and
0 deletions
chunk.c
0 → 100644
1 | +#include "chunk.h" | ||
2 | + | ||
3 | +RegionID translateChunkToRegion(int x, int z); | ||
4 | +RegionID translateCoordsToRegion(double x, double y, double z); | ||
5 | +ChunkID translateCoordsToChunk(double x, double y, double z); | ||
6 | +int overwriteChunk(const char* regionFolder, ChunkID chunk, void* chunkData, size_t chunkLength); | ||
7 | +ssize_t loadChunk(const char* regionFolder, ChunkID chunk, void** chunkData); | ||
8 | + | ||
9 | +RegionID translateChunkToRegion(int x, int z) { | ||
10 | + RegionID region; | ||
11 | + region.x = x/CHUNKS_PER_REGION; | ||
12 | + region.z = z/CHUNKS_PER_REGION; | ||
13 | + return region; | ||
14 | +} | ||
15 | + | ||
16 | +RegionID translateCoordsToRegion(double x, double y, double z) { | ||
17 | + ChunkID chunk = translateCoordsToChunk(x,y,z); | ||
18 | + return translateChunkToRegion(chunk.x,chunk.z); | ||
19 | +} | ||
20 | + | ||
21 | +ChunkID translateCoordsToChunk(double x, double y, double z) { | ||
22 | + ChunkID chunk; | ||
23 | + chunk.x = x/BLOCKS_PER_CHUNK; | ||
24 | + chunk.z = z/BLOCKS_PER_CHUNK; | ||
25 | + return chunk; | ||
26 | +} | ||
27 | + | ||
28 | +int overwriteChunk(const char* regionFolder, ChunkID chunk, void* chunkData, size_t chunkLength) { | ||
29 | + RegionID region = translateChunkToRegion(chunk.x,chunk.z); | ||
30 | + ChunkID relativeChunk; | ||
31 | + relativeChunk.x = chunk.x % 32; | ||
32 | + relativeChunk.z = chunk.z % 32; | ||
33 | + | ||
34 | + char* regionFilename = calloc(MAX_REGION_FILENAME_LENGTH + strlen(regionFolder),sizeof(char)); | ||
35 | + sprintf(regionFilename,"%s/r.%d.%d.mca.new",regionFolder,region.x,region.z); | ||
36 | + | ||
37 | + if(access(regionFilename,R_OK | W_OK) == -1) { | ||
38 | + fprintf(stderr,"Can't access file %s: %s\n",regionFilename,strerror(errno)); | ||
39 | + return -1; | ||
40 | + } | ||
41 | + | ||
42 | + int fd = open(regionFilename,O_RDWR); | ||
43 | + if(fd == -1) { | ||
44 | + fprintf(stderr,"Unable to open region file %s: %s\n",regionFilename,strerror(errno)); | ||
45 | + return -2; | ||
46 | + } | ||
47 | + free(regionFilename); | ||
48 | + | ||
49 | + uint32_t chunkHeaderOffset; | ||
50 | + if(pread(fd,&chunkHeaderOffset,sizeof(uint32_t),(relativeChunk.x + relativeChunk.z * CHUNK_OFFSET_LENGTH) * sizeof(uint32_t)) == -1) { | ||
51 | + close(fd); | ||
52 | + fprintf(stderr,"Unable to read chunk header offset: %s\n",strerror(errno)); | ||
53 | + return -3; | ||
54 | + } | ||
55 | + uint32_t totalChunkLength = (chunkHeaderOffset >> 24) * 4096; | ||
56 | + chunkHeaderOffset = (__bswap_32(chunkHeaderOffset & 0x00FFFFFF) >> 8) * CHUNK_SECTOR_SIZE; | ||
57 | + int pos = lseek(fd,chunkHeaderOffset,SEEK_SET); | ||
58 | + if(pos == -1) { | ||
59 | + close(fd); | ||
60 | + fprintf(stderr,"Unable to seek to header offset: %s\n",strerror(errno)); | ||
61 | + return -4; | ||
62 | + } | ||
63 | + | ||
64 | + ChunkHeader header; | ||
65 | + if(pread(fd,&header,sizeof(ChunkHeader),pos) <= 0) { | ||
66 | + close(fd); | ||
67 | + fprintf(stderr,"Unable to read chunk header: %s\n",strerror(errno)); | ||
68 | + return -5; | ||
69 | + } | ||
70 | + header.length = __bswap_32(header.length); | ||
71 | + | ||
72 | + void* compressedChunk; | ||
73 | + ssize_t compressedChunkLength = deflateGzip(chunkData,chunkLength,&compressedChunk,(header.compressionType == COMPRESSION_TYPE_ZLIB)); | ||
74 | + if(compressedChunkLength > totalChunkLength) { | ||
75 | + // insert new 4096 blocks | ||
76 | + } | ||
77 | + header.length = __bswap_32((uint32_t)compressedChunkLength+1); | ||
78 | + if(write(fd,&header,sizeof(ChunkHeader)) <= 0) { | ||
79 | + close(fd); | ||
80 | + free(compressedChunk); | ||
81 | + fprintf(stderr,"Unable to read chunk header: %s\n",strerror(errno)); | ||
82 | + return -6; | ||
83 | + } | ||
84 | + ssize_t nWritten = 0; | ||
85 | + size_t totalWritten = 0; | ||
86 | + | ||
87 | + while((nWritten = write(fd,compressedChunk+totalWritten,compressedChunkLength-totalWritten))) { | ||
88 | + if(nWritten == -1) { | ||
89 | + if(errno == EINTR) { | ||
90 | + continue; | ||
91 | + } | ||
92 | + fprintf(stderr,"Unable to write chunk: %s\n",strerror(errno)); | ||
93 | + close(fd); | ||
94 | + free(compressedChunk); | ||
95 | + return -7; | ||
96 | + } | ||
97 | + totalWritten += nWritten; | ||
98 | + } | ||
99 | + close(fd); | ||
100 | + free(compressedChunk); | ||
101 | + return 0; | ||
102 | +} | ||
103 | + | ||
104 | +ssize_t loadChunk(const char* regionFolder, ChunkID chunk, void** chunkData) { | ||
105 | + RegionID region = translateChunkToRegion(chunk.x,chunk.z); | ||
106 | + ChunkID relativeChunk; | ||
107 | + relativeChunk.x = chunk.x % 32; | ||
108 | + relativeChunk.z = chunk.z % 32; | ||
109 | + | ||
110 | + char* regionFilename = calloc(MAX_REGION_FILENAME_LENGTH + strlen(regionFolder),sizeof(char)); | ||
111 | + sprintf(regionFilename,"%s/r.%d.%d.mca",regionFolder,region.x,region.z); | ||
112 | + | ||
113 | + if(access(regionFilename,R_OK) == -1) { | ||
114 | + fprintf(stderr,"Can't access file %s: %s\n",regionFilename,strerror(errno)); | ||
115 | + return -1; | ||
116 | + } | ||
117 | + | ||
118 | + int fd = open(regionFilename,O_RDONLY); | ||
119 | + if(fd == -1) { | ||
120 | + fprintf(stderr,"Unable to open region file %s: %s\n",regionFilename,strerror(errno)); | ||
121 | + return -2; | ||
122 | + } | ||
123 | + free(regionFilename); | ||
124 | + | ||
125 | + uint32_t chunkHeaderOffset; | ||
126 | + if(pread(fd,&chunkHeaderOffset,sizeof(uint32_t),(relativeChunk.x + relativeChunk.z * CHUNK_OFFSET_LENGTH) * sizeof(uint32_t)) == -1) { | ||
127 | + close(fd); | ||
128 | + fprintf(stderr,"Unable to read chunk header offset: %s\n",strerror(errno)); | ||
129 | + return -3; | ||
130 | + } | ||
131 | + chunkHeaderOffset = (__bswap_32(chunkHeaderOffset & 0x00FFFFFF) >> 8) * CHUNK_SECTOR_SIZE; | ||
132 | + | ||
133 | + if(lseek(fd,chunkHeaderOffset,SEEK_SET) == -1) { | ||
134 | + close(fd); | ||
135 | + fprintf(stderr,"Unable to seek to header offset: %s\n",strerror(errno)); | ||
136 | + return -4; | ||
137 | + } | ||
138 | + | ||
139 | + ChunkHeader header; | ||
140 | + if(read(fd,&header,sizeof(ChunkHeader)) <= 0) { | ||
141 | + close(fd); | ||
142 | + fprintf(stderr,"Unable to read chunk header: %s\n",strerror(errno)); | ||
143 | + return -5; | ||
144 | + } | ||
145 | + header.length = __bswap_32(header.length); | ||
146 | + ssize_t chunkLength = header.length; | ||
147 | + | ||
148 | + void* compressedChunk = calloc(chunkLength,sizeof(char)); | ||
149 | + ssize_t nRead = 0; | ||
150 | + size_t totalRead = 0; | ||
151 | + | ||
152 | + while((nRead = read(fd,compressedChunk+totalRead,chunkLength-totalRead))) { | ||
153 | + if(nRead == -1) { | ||
154 | + if(errno == EINTR) { | ||
155 | + continue; | ||
156 | + } | ||
157 | + fprintf(stderr,"Unable to read chunk: %s\n",strerror(errno)); | ||
158 | + close(fd); | ||
159 | + free(compressedChunk); | ||
160 | + return -6; | ||
161 | + } | ||
162 | + totalRead += nRead; | ||
163 | + } | ||
164 | + close(fd); | ||
165 | + | ||
166 | + void *decompressedChunk; | ||
167 | + chunkLength = inflateGzip(compressedChunk,chunkLength,&decompressedChunk,(header.compressionType == COMPRESSION_TYPE_ZLIB)); | ||
168 | + | ||
169 | + if(chunkLength <= 0) { | ||
170 | + fprintf(stderr,"Error while decompressing chunk\n"); | ||
171 | + return -8; | ||
172 | + } | ||
173 | + free(compressedChunk); | ||
174 | + | ||
175 | + *chunkData = decompressedChunk; | ||
176 | + return chunkLength; | ||
177 | +} | ||
0 | \ No newline at end of file | 178 | \ No newline at end of file |
chunk.h
0 → 100644
1 | +#ifndef _CHUNK_H | ||
2 | +#define _CHUNK_H | ||
3 | + | ||
4 | +#include <stdlib.h> | ||
5 | +#include <unistd.h> | ||
6 | +#include <stdio.h> | ||
7 | +#include <errno.h> | ||
8 | +#include <fcntl.h> | ||
9 | +#include <stdint.h> | ||
10 | +#include <string.h> | ||
11 | +#include <byteswap.h> | ||
12 | + | ||
13 | +#include "compression.h" | ||
14 | + | ||
15 | +#define BLOCKS_PER_CHUNK 16 | ||
16 | +#define CHUNKS_PER_REGION 32 | ||
17 | +#define CHUNK_OFFSET_LENGTH 32 | ||
18 | +#define CHUNK_SECTOR_SIZE 4096 | ||
19 | + | ||
20 | +// 58593 is the maximum number of regions containing 32 chunks in any direction | ||
21 | +// Thus, biggest filename is: | ||
22 | +// r.-58593.-58593.mca | ||
23 | +#define MAX_REGION_FILENAME_LENGTH 32 // Just to round up | ||
24 | + | ||
25 | +enum COMPRESSION_TYPE { | ||
26 | + COMPRESSION_TYPE_GZIP = 1, | ||
27 | + COMPRESSION_TYPE_ZLIB = 2 | ||
28 | +}; | ||
29 | + | ||
30 | +typedef struct RegionID { | ||
31 | + int x; | ||
32 | + int z; | ||
33 | +} RegionID; | ||
34 | + | ||
35 | +typedef struct ChunkID { | ||
36 | + int x; | ||
37 | + int z; | ||
38 | +} ChunkID; | ||
39 | + | ||
40 | +typedef struct __attribute__((packed)) ChunkHeader { | ||
41 | + uint32_t length; | ||
42 | + uint8_t compressionType; | ||
43 | +} ChunkHeader; | ||
44 | + | ||
45 | +ChunkID translateCoordsToChunk(double x, double y, double z); | ||
46 | +int overwriteChunk(const char* regionFolder, ChunkID chunk, void* chunkData, size_t chunkLength); | ||
47 | +ssize_t loadChunk(const char* regionFolder, ChunkID chunk, void** chunkData); | ||
48 | + | ||
49 | +#endif | ||
0 | \ No newline at end of file | 50 | \ No newline at end of file |