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 | 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 | 50 | \ No newline at end of file | ... | ... |