1 
2 /*
3  * Copyright (c) 2017 Juliette Foucaut & Doug Binks
4  *
5  * This software is provided 'as-is', without any express or implied
6  * warranty. In no event will the authors be held liable for any damages
7  * arising from the use of this software.
8  *
9  * Permission is granted to anyone to use this software for any purpose,
10  * including commercial applications, and to alter it and redistribute it
11  * freely, subject to the following restrictions:
12  *
13  * 1. The origin of this software must not be misrepresented; you must not
14  *    claim that you wrote the original software. If you use this software
15  *    in a product, an acknowledgement in the product documentation would be
16  *    appreciated but is not required.
17  * 2. Altered source versions must be plainly marked as such, and must not be
18  *    misrepresented as being the original software.
19  * 3. This notice may not be removed or altered from any source distribution.
20  */
21 
22 #include "enkimi.h"
23 
24 
25 static const uint32_t SECTOR_SIZE = 4096;
26 
27 static const char* tagIdString[] =
28 {
29 	"TAG_End",
30 	"TAG_Byte",
31 	"TAG_Short",
32 	"TAG_Int",
33 	"TAG_Long",
34 	"TAG_Float",
35 	"TAG_Double",
36 	"TAG_Byte_Array",
37 	"TAG_String",
38 	"TAG_List",
39 	"TAG_Compound",
40 	"TAG_Int_Array",
41 };
42 
43 static uint32_t minecraftPalette[] =
44 {
45 	0xff000000, 0xff7d7d7d, 0xff4cb376, 0xff436086, 0xff7a7a7a, 0xff4e7f9c, 0xff256647, 0xff535353, 0xffdcaf70, 0xffdcaf70,
46 	0xff135bcf, 0xff125ad4, 0xffa0d3db, 0xff7a7c7e, 0xff7c8b8f, 0xff7e8287, 0xff737373, 0xff315166, 0xff31b245, 0xff54c3c2,
47 	0xfff4f0da, 0xff867066, 0xff894326, 0xff838383, 0xff9fd3dc, 0xff324364, 0xff3634b4, 0xff23c7f6, 0xff7c7c7c, 0xff77bf8e,
48 	0xffdcdcdc, 0xff296595, 0xff194f7b, 0xff538ba5, 0xff5e96bd, 0xffdddddd, 0xffe5e5e5, 0xff00ffff, 0xff0d00da, 0xff415778,
49 	0xff0d0fe1, 0xff4eecf9, 0xffdbdbdb, 0xffa1a1a1, 0xffa6a6a6, 0xff0630bc, 0xff0026af, 0xff39586b, 0xff658765, 0xff1d1214,
50 	0xff00ffff, 0xff005fde, 0xff31271a, 0xff4e87a6, 0xff2a74a4, 0xff0000ff, 0xff8f8c81, 0xffd5db61, 0xff2e5088, 0xff17593c,
51 	0xff335682, 0xff676767, 0xff00b9ff, 0xff5b9ab8, 0xff387394, 0xff345f79, 0xff5190b6, 0xff6a6a6a, 0xff5b9ab8, 0xff40596a,
52 	0xff7a7a7a, 0xffc2c2c2, 0xff65a0c9, 0xff6b6b84, 0xff2d2ddd, 0xff000066, 0xff0061ff, 0xff848484, 0xfff1f1df, 0xffffad7d,
53 	0xfffbfbef, 0xff1d830f, 0xffb0a49e, 0xff65c094, 0xff3b5985, 0xff42748d, 0xff1b8ce3, 0xff34366f, 0xff334054, 0xff45768f,
54 	0xffbf0a57, 0xff2198f1, 0xffffffec, 0xffb2b2b2, 0xffb2b2b2, 0xffffffff, 0xff2d5d7e, 0xff7c7c7c, 0xff7a7a7a, 0xff7cafcf,
55 	0xff78aaca, 0xff6a6c6d, 0xfff4efd3, 0xff28bdc4, 0xff69dd92, 0xff53ae73, 0xff0c5120, 0xff5287a5, 0xff2a4094, 0xff7a7a7a,
56 	0xff75718a, 0xff767676, 0xff1a162c, 0xff1a162c, 0xff1a162c, 0xff2d28a6, 0xffb1c454, 0xff51677c, 0xff494949, 0xff343434,
57 	0xffd18934, 0xffa5dfdd, 0xff0f090c, 0xff316397, 0xff42a0e3, 0xff4d84a1, 0xff49859e, 0xff1f71dd, 0xffa8e2e7, 0xff74806d,
58 	0xff3c3a2a, 0xff7c7c7c, 0xff5a5a5a, 0xff75d951, 0xff345e81, 0xff84c0ce, 0xff455f88, 0xff868b8e, 0xffd7dd74, 0xff595959,
59 	0xff334176, 0xff008c0a, 0xff17a404, 0xff5992b3, 0xffb0b0b0, 0xff434347, 0xff1d6b9e, 0xff70fdfe, 0xffe5e5e5, 0xff4c4a4b,
60 	0xffbdc6bf, 0xffddedfb, 0xff091bab, 0xff4f547d, 0xff717171, 0xffdfe6ea, 0xffe3e8eb, 0xff41819b, 0xff747474, 0xffa1b2d1,
61 	0xfff6f6f6, 0xff878787, 0xff395ab0, 0xff325cac, 0xff152c47, 0xff65c878, 0xff3534df, 0xffc7c7c7, 0xffa5af72, 0xffbec7ac,
62 	0xff9fd3dc, 0xffcacaca, 0xff425c96, 0xff121212, 0xfff4bfa2, 0xff1474cf, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xff1d56ac,
63 	0xff1d57ae, 0xff1d57ae, 0xff1d57ae, 0xff243c50, 0xff8dcddd, 0xff4d7aaf, 0xff0e2034, 0xff366bcf, 0xff355d7e, 0xff7bb8c7,
64 	0xff5f86bb, 0xff1e2e3f, 0xff3a6bc5, 0xff30536e, 0xffe0f3f7, 0xff5077a9, 0xff2955aa, 0xff21374e, 0xffcdc5dc, 0xff603b60,
65 	0xff856785, 0xffa679a6, 0xffaa7eaa, 0xffa879a8, 0xffa879a8, 0xffa879a8, 0xffaae6e1, 0xffaae6e1, 0xff457d98, 0xfff0f0f0,
66 	0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0,
67 	0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0,
68 	0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0,
69 	0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0,
70 	0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xfff0f0f0, 0xff242132 };
71 
72 
73 typedef struct SectionChunkInfo_s
74 {
75 	uint8_t offset_0;
76 	uint8_t offset_1;
77 	uint8_t offset_2;
78 	uint8_t sectorCount;
79 } SectionChunkInfo;
80 
GetChunkLocation(SectionChunkInfo section_)81 static int32_t GetChunkLocation( SectionChunkInfo section_ )
82 {
83 	return ( ( ( section_.offset_0 << 16 ) + ( section_.offset_1 << 8 ) + section_.offset_2 ) * SECTOR_SIZE );
84 }
85 
86 typedef struct BigEndian4BytesTo32BitInt_s
87 {
88 	uint8_t pos_0;
89 	uint8_t pos_1;
90 	uint8_t pos_2;
91 	uint8_t pos_3;
92 } BigEndian4BytesTo32BitInt;
93 
94 
Get32BitInt(BigEndian4BytesTo32BitInt in_)95 static int32_t Get32BitInt( BigEndian4BytesTo32BitInt in_ )
96 {
97 	return ( ( in_.pos_0 << 24 ) + ( in_.pos_1 << 16 ) + ( in_.pos_2 << 8 ) + in_.pos_3 );
98 }
99 
100 typedef struct RegionHeader_s
101 {
102 	SectionChunkInfo          sectionChunksInfos[ ENKI_MI_REGION_CHUNKS_NUMBER ]; // chunks locations
103 	BigEndian4BytesTo32BitInt sectionChunksTimestamps[ ENKI_MI_REGION_CHUNKS_NUMBER ]; // chunks timestamps
104 } RegionHeader;
105 
enkiGetNBTTagIDAsString(uint8_t tagID_)106 const char * enkiGetNBTTagIDAsString( uint8_t tagID_ )
107 {
108 	return tagIdString[ tagID_ ];
109 }
110 
enkiGetNBTTagHeaderIDAsString(enkiNBTTagHeader tagheader_)111 const char * enkiGetNBTTagHeaderIDAsString( enkiNBTTagHeader tagheader_ )
112 {
113 	return tagIdString[ tagheader_.tagId ];
114 }
115 
enkiNBTInitFromMemoryUncompressed(enkiNBTDataStream * pStream_,uint8_t * pData_,uint32_t dataSize_)116 void enkiNBTInitFromMemoryUncompressed( enkiNBTDataStream* pStream_, uint8_t * pData_, uint32_t dataSize_)
117 {
118 	memset( &pStream_->currentTag, 0, sizeof( enkiNBTTagHeader ) );
119 	pStream_->pData = pData_;
120 	pStream_->dataLength = dataSize_;
121 	pStream_->pCurrPos = pStream_->pData;
122 	pStream_->pDataEnd = pStream_->pData + pStream_->dataLength;
123 	pStream_->pNextTag = pStream_->pCurrPos;
124 	pStream_->level = -1;
125 	pStream_->pAllocation = NULL;
126 }
127 
enkiNBTInitFromMemoryCompressed(enkiNBTDataStream * pStream_,uint8_t * pCompressedData_,uint32_t compressedDataSize_,uint32_t uncompressedSizeHint_)128 int enkiNBTInitFromMemoryCompressed( enkiNBTDataStream* pStream_, uint8_t * pCompressedData_,
129 										uint32_t compressedDataSize_, uint32_t uncompressedSizeHint_)
130 {
131 	mz_ulong destLength = uncompressedSizeHint_;
132 	if( destLength <= compressedDataSize_ )
133 	{
134 		destLength = compressedDataSize_ * 4 + 1024; // estimate uncompressed size
135 	}
136 	mz_ulong startDestLength = destLength;
137 	uint8_t* dataUnCompressed = (uint8_t*)malloc( destLength );
138 	int retval = uncompress( dataUnCompressed, &destLength, pCompressedData_, compressedDataSize_ );
139 	if( retval == MZ_BUF_ERROR && startDestLength == destLength )
140 	{
141 		// failed to uncompress, buffer full
142 		for( int attempts = 0; ( retval != MZ_OK ) && ( attempts < 3 ); ++attempts )
143 		{
144 			free( dataUnCompressed );
145 			destLength *= 4 + 1024;
146 			dataUnCompressed = (uint8_t*)malloc( destLength );
147 			retval = uncompress( dataUnCompressed, &destLength, pCompressedData_, compressedDataSize_ );
148 		}
149 	}
150 	if( retval != MZ_OK )
151 	{
152 		enkiNBTInitFromMemoryUncompressed( pStream_, NULL, 0 );
153 		free( dataUnCompressed );
154 		return 0;
155 	}
156 
157 	dataUnCompressed = (uint8_t*)realloc( dataUnCompressed, destLength ); // reallocate to actual size
158 	enkiNBTInitFromMemoryUncompressed( pStream_, dataUnCompressed, ( uint32_t )destLength );
159 	pStream_->pAllocation = dataUnCompressed;
160 	return 1;
161 }
162 
enkiNBTFreeAllocations(enkiNBTDataStream * pStream_)163 void enkiNBTFreeAllocations( enkiNBTDataStream* pStream_ )
164 {
165 	free( pStream_->pAllocation );
166 	memset( pStream_, 0, sizeof(enkiNBTDataStream) );
167 }
168 
enkiNBTReadInt8(enkiNBTDataStream * pStream_)169 int8_t  enkiNBTReadInt8( enkiNBTDataStream* pStream_ )
170 {
171 	int8_t retVal = pStream_->pCurrPos[ 0 ];
172 	pStream_->pCurrPos += 1;
173 	return retVal;
174 }
175 
enkiNBTReadByte(enkiNBTDataStream * pStream_)176 int8_t  enkiNBTReadByte( enkiNBTDataStream* pStream_ )
177 {
178 	return enkiNBTReadInt8( pStream_ );
179 }
180 
enkiNBTReadInt16(enkiNBTDataStream * pStream_)181 int16_t enkiNBTReadInt16( enkiNBTDataStream* pStream_ )
182 {
183 	int16_t retVal = ( pStream_->pCurrPos[ 0 ] << 8 ) + pStream_->pCurrPos[ 1 ];
184 	pStream_->pCurrPos += 2;
185 	return retVal;
186 }
187 
enkiNBTReadShort(enkiNBTDataStream * pStream_)188 int16_t enkiNBTReadShort( enkiNBTDataStream* pStream_ )
189 {
190 	return enkiNBTReadInt16( pStream_ );
191 }
192 
enkiNBTReadInt32(enkiNBTDataStream * pStream_)193 int32_t enkiNBTReadInt32( enkiNBTDataStream* pStream_ )
194 {
195 	int32_t retVal = ( pStream_->pCurrPos[ 0 ] << 24 ) + ( pStream_->pCurrPos[ 1 ] << 16 ) + ( pStream_->pCurrPos[ 2 ] << 8 ) + pStream_->pCurrPos[ 3 ];
196 	pStream_->pCurrPos += 4;
197 	return retVal;
198 }
199 
enkiNBTReadInt(enkiNBTDataStream * pStream_)200 int32_t enkiNBTReadInt( enkiNBTDataStream* pStream_ )
201 {
202 	return enkiNBTReadInt32( pStream_ );
203 }
204 
enkiNBTReadFloat(enkiNBTDataStream * pStream_)205 float   enkiNBTReadFloat( enkiNBTDataStream* pStream_ )
206 {
207 	int32_t iVal = ( pStream_->pCurrPos[ 0 ] << 24 ) + ( pStream_->pCurrPos[ 1 ] << 16 ) + ( pStream_->pCurrPos[ 2 ] << 8 ) + pStream_->pCurrPos[ 3 ];
208 	float retVal = *( float* )&iVal;
209 	pStream_->pCurrPos += 4;
210 	return retVal;
211 }
212 
enkiNBTReadInt64(enkiNBTDataStream * pStream_)213 int64_t enkiNBTReadInt64( enkiNBTDataStream* pStream_ )
214 {
215 	int64_t retVal = ( ( int64_t )pStream_->pCurrPos[ 0 ] << 54 ) + ( ( int64_t )pStream_->pCurrPos[ 1 ] << 48 ) + ( ( int64_t )pStream_->pCurrPos[ 2 ] << 40 ) + ( ( int64_t )pStream_->pCurrPos[ 5 ] << 32 ) +
216 		             ( pStream_->pCurrPos[ 4 ] << 24 ) + ( pStream_->pCurrPos[ 5 ] << 16 ) + ( pStream_->pCurrPos[ 6 ] << 8 ) + pStream_->pCurrPos[ 7 ];
217 	pStream_->pCurrPos += 8;
218 	return retVal;
219 }
220 
enkiNBTReadlong(enkiNBTDataStream * pStream_)221 int64_t enkiNBTReadlong( enkiNBTDataStream* pStream_ )
222 {
223 	return enkiNBTReadInt64( pStream_ );
224 }
225 
enkiNBTReadDouble(enkiNBTDataStream * pStream_)226 double  enkiNBTReadDouble( enkiNBTDataStream* pStream_ )
227 {
228 	int64_t iVal = ( ( int64_t )pStream_->pCurrPos[ 0 ] << 54 ) + ( ( int64_t )pStream_->pCurrPos[ 1 ] << 48 ) + ( ( int64_t )pStream_->pCurrPos[ 2 ] << 40 ) + ( ( int64_t )pStream_->pCurrPos[ 5 ] << 32 ) +
229 		           ( pStream_->pCurrPos[ 4 ] << 24 ) + ( pStream_->pCurrPos[ 5 ] << 16 ) + ( pStream_->pCurrPos[ 6 ] << 8 ) + pStream_->pCurrPos[ 7 ];
230 	double retVal = *( double* )&iVal;
231 	pStream_->pCurrPos += 8;
232 	return retVal;
233 }
234 
enkiNBTReadString(enkiNBTDataStream * pStream_)235 enkiNBTString enkiNBTReadString( enkiNBTDataStream* pStream_ )
236 {
237 	enkiNBTString nbtString;
238 	nbtString.size = enkiNBTReadInt16( pStream_ );
239 	nbtString.pStrNotNullTerminated = (const char*)pStream_->pCurrPos;
240 	return nbtString;
241 }
242 
SkipDataToNextTag(enkiNBTDataStream * pStream_)243 static void SkipDataToNextTag( enkiNBTDataStream* pStream_ )
244 {
245 	switch( pStream_->currentTag.tagId )
246 	{
247 	case enkiNBTTAG_End:
248 		// no data, so do nothing.
249 		break;
250 	case enkiNBTTAG_Byte:
251 		pStream_->pNextTag += 1; // 1 byte
252 		break;
253 	case enkiNBTTAG_Short:
254 		pStream_->pNextTag += 2; // 2 bytes
255 		break;
256 	case enkiNBTTAG_Int:
257 		pStream_->pNextTag += 4;
258 		break;
259 	case enkiNBTTAG_Long:
260 		pStream_->pNextTag += 8;
261 		break;
262 	case enkiNBTTAG_Float:
263 		pStream_->pNextTag += 4;
264 		break;
265 	case enkiNBTTAG_Double:
266 		pStream_->pNextTag += 8;
267 		break;
268 	case enkiNBTTAG_Byte_Array:
269 	{
270 		int32_t length = enkiNBTReadInt32( pStream_ );
271 		pStream_->pNextTag = pStream_->pCurrPos + length * 1; // array of bytes
272 		break;
273 	}
274 	case enkiNBTTAG_String:
275 	{
276 		int32_t length = enkiNBTReadInt16( pStream_ );
277 		pStream_->pNextTag = pStream_->pCurrPos + length;
278 		break;
279 	}
280 	case enkiNBTTAG_List:
281 		// read as a compound type
282 		break;
283 	case enkiNBTTAG_Compound:
284 		// data is in standard format, so do nothing.
285 		break;
286 	case enkiNBTTAG_Int_Array:
287 	{
288 		int32_t length = enkiNBTReadInt32( pStream_ );
289 		pStream_->pNextTag = pStream_->pCurrPos + length * 4; // array of ints (4 bytes)
290 		break;
291 	}
292 	default:
293 		assert( 0 );
294 		break;
295 	}
296 }
297 
enkiNBTReadNextTag(enkiNBTDataStream * pStream_)298 int enkiNBTReadNextTag( enkiNBTDataStream* pStream_ )
299 {
300 	if( ( enkiNBTTAG_Compound == pStream_->currentTag.tagId ) || ( enkiNBTTAG_List == pStream_->currentTag.tagId ) )
301 	{
302 		pStream_->level++;
303 		pStream_->parentTags[ pStream_->level ] = pStream_->currentTag;
304 	}
305 	if( ( pStream_->level >= 0 ) && ( enkiNBTTAG_List == pStream_->parentTags[ pStream_->level ].tagId ) )
306 	{
307 		if( pStream_->parentTags[ pStream_->level ].listCurrItem == pStream_->parentTags[ pStream_->level ].listNumItems )
308 		{
309 			pStream_->level--;
310 		}
311 		else
312 		{
313 			pStream_->currentTag.tagId = pStream_->parentTags[ pStream_->level ].listItemTagId;
314 			pStream_->currentTag.pName = NULL;
315 			SkipDataToNextTag( pStream_ );
316 			pStream_->parentTags[ pStream_->level ].listCurrItem++;
317 			return 1;
318 		}
319 	}
320 
321 	if( pStream_->pNextTag >= pStream_->pDataEnd )
322 	{
323 		return 0;
324 	}
325 	pStream_->pCurrPos = pStream_->pNextTag;
326 
327 	// Get Tag Header
328 	pStream_->currentTag.pName = NULL;
329 	pStream_->currentTag.tagId = *(pStream_->pCurrPos++);
330 	if( enkiNBTTAG_End != pStream_->currentTag.tagId )
331 	{
332 		if( 0xff == *(pStream_->pCurrPos) )
333 		{
334 			pStream_->pCurrPos++;
335 			pStream_->currentTag.pName = ( char* )pStream_->pCurrPos;
336 			while( *(pStream_->pCurrPos++) != 0 );
337 		}
338 		else
339 		{
340 			int32_t lengthOfName = enkiNBTReadInt16( pStream_ );
341 			if( lengthOfName )
342 			{
343 				*( pStream_->pCurrPos - 2 ) = 0xff; // this value will not be seen as a length since it will be negative
344 				pStream_->currentTag.pName = ( char* )( pStream_->pCurrPos - 1 );
345 				memmove( pStream_->currentTag.pName, pStream_->pCurrPos, lengthOfName );
346 				pStream_->pCurrPos += lengthOfName - 1;
347 				pStream_->pCurrPos[ 0 ] = 0; // null terminator
348 				pStream_->pCurrPos += 1;
349 			}
350 		}
351 	}
352 	if( enkiNBTTAG_List == pStream_->currentTag.tagId )
353 	{
354 		pStream_->currentTag.listItemTagId = *(pStream_->pCurrPos++);
355 		pStream_->currentTag.listNumItems = enkiNBTReadInt32( pStream_ );
356 		pStream_->currentTag.listCurrItem = 0;
357 	}
358 	pStream_->pNextTag = pStream_->pCurrPos;
359 
360 	SkipDataToNextTag( pStream_ );
361 
362 	if( ( pStream_->level >= 0 ) && ( enkiNBTTAG_End == pStream_->currentTag.tagId ) )
363 	{
364 		pStream_->level--;
365 	}
366 
367 	return 1;
368 }
369 
370 
enkiNBTRewind(enkiNBTDataStream * pStream_)371 void enkiNBTRewind( enkiNBTDataStream* pStream_ )
372 {
373 	memset( &(pStream_->currentTag), 0, sizeof( enkiNBTTagHeader ) );
374 	pStream_->pCurrPos = pStream_->pData;
375 	pStream_->level = -1;
376 	pStream_->pNextTag = pStream_->pData;
377 }
378 
enkiRegionFileInit(enkiRegionFile * pRegionFile_)379 void enkiRegionFileInit( enkiRegionFile* pRegionFile_ )
380 {
381 	memset( pRegionFile_, 0, sizeof( enkiRegionFile ) );
382 }
383 
384 
enkiRegionFileLoad(FILE * fp_)385 enkiRegionFile enkiRegionFileLoad( FILE * fp_ )
386 {
387 	enkiRegionFile regionFile;
388 	enkiRegionFileInit( &regionFile );
389 	fseek( fp_, 0, SEEK_END );
390 	regionFile.regionDataSize = ftell( fp_ );
391 	fseek( fp_, 0, SEEK_SET ); // return to start position
392 
393 	// get the data in the chunks data section
394 	regionFile.pRegionData = (uint8_t*)malloc( regionFile.regionDataSize );
395 	fread( regionFile.pRegionData, 1, regionFile.regionDataSize, fp_ ); // note: because sectionDataChunks is an array of single bytes, sizeof( sectionDataChunks ) == sectionDataSize
396 
397 	return regionFile;
398 }
399 
400 
enkiInitNBTDataStreamForChunk(enkiRegionFile regionFile_,int32_t chunkNr_,enkiNBTDataStream * pStream_)401 void enkiInitNBTDataStreamForChunk( enkiRegionFile regionFile_, int32_t chunkNr_, enkiNBTDataStream* pStream_ )
402 {
403 	RegionHeader* header = (RegionHeader*)regionFile_.pRegionData;
404 	uint32_t locationOffset = GetChunkLocation( header->sectionChunksInfos[ chunkNr_ ] );
405 	if( locationOffset > sizeof( RegionHeader ) )
406 	{
407 		uint32_t length = Get32BitInt(  *( BigEndian4BytesTo32BitInt* )&regionFile_.pRegionData[ locationOffset ] );
408 		uint8_t compression_type = regionFile_.pRegionData[ locationOffset + 4 ]; // we ignore this as unused for now
409 		--length; // length includes compression_type
410 		// get the data and decompress it
411 		uint8_t* dataCompressed = &regionFile_.pRegionData[ locationOffset + 5 ];
412 		enkiNBTInitFromMemoryCompressed( pStream_, dataCompressed, length, 0 );
413 	}
414 	else
415 	{
416 		enkiNBTInitFromMemoryUncompressed( pStream_, NULL, 0 ); // clears stream
417 	}
418 }
419 
enkiGetTimestampForChunk(enkiRegionFile regionFile_,int32_t chunkNr_)420 int32_t enkiGetTimestampForChunk( enkiRegionFile regionFile_, int32_t chunkNr_ )
421 {
422 	RegionHeader* header = (RegionHeader*)regionFile_.pRegionData;
423 	return Get32BitInt( header->sectionChunksTimestamps[ chunkNr_ ] );
424 }
425 
enkiRegionFileFreeAllocations(enkiRegionFile * pRegionFile_)426 void enkiRegionFileFreeAllocations(enkiRegionFile * pRegionFile_)
427 {
428 	free( pRegionFile_->pRegionData );
429 	memset( pRegionFile_, 0, sizeof(enkiRegionFile) );
430 }
431 
enkiAreStringsEqual(const char * lhs_,const char * rhs_)432 int enkiAreStringsEqual( const char * lhs_, const char * rhs_ )
433 {
434 	if( lhs_ && rhs_ )
435 	{
436 		if( 0 == strcmp( lhs_, rhs_ ) )
437 		{
438 			return 1;
439 		}
440 	}
441 	return 0;
442 }
443 
enkiChunkInit(enkiChunkBlockData * pChunk_)444 void enkiChunkInit( enkiChunkBlockData* pChunk_ )
445 {
446 	memset( pChunk_, 0, sizeof( enkiChunkBlockData ) );
447 }
448 
enkiNBTReadChunk(enkiNBTDataStream * pStream_)449 enkiChunkBlockData enkiNBTReadChunk( enkiNBTDataStream * pStream_ )
450 {
451 	enkiChunkBlockData chunk;
452 	enkiChunkInit( &chunk );
453 	while( enkiNBTReadNextTag( pStream_ ) )
454 	{
455 		if( enkiAreStringsEqual( "Level", pStream_->currentTag.pName ) )
456 		{
457 			int foundXPos = 0;
458 			int foundZPos = 0;
459 			int foundSection = 0;
460 			while( enkiNBTReadNextTag( pStream_ ) )
461 			{
462 				if( enkiAreStringsEqual( "xPos", pStream_->currentTag.pName ) )
463 				{
464 					foundXPos = 1;
465 					chunk.xPos = enkiNBTReadInt32( pStream_ );
466 				}
467 				else if( enkiAreStringsEqual( "zPos", pStream_->currentTag.pName ) )
468 				{
469 					foundZPos = 1;
470 					chunk.zPos = enkiNBTReadInt32( pStream_ );
471 				}
472 				else if( enkiAreStringsEqual( "Sections", pStream_->currentTag.pName ) )
473 				{
474 					foundSection = 1;
475 					int32_t levelParent = pStream_->level;
476 					int8_t sectionY = -1;
477 					uint8_t* pBlocks = NULL;
478 					do
479 					{
480 						if( 0 == enkiNBTReadNextTag( pStream_ ) )
481 						{
482 							break;
483 						}
484 						if( enkiNBTTAG_Compound == pStream_->currentTag.tagId )
485 						{
486 							chunk.countOfSections++;
487 						}
488 						if( enkiAreStringsEqual( "Blocks", pStream_->currentTag.pName ) )
489 						{
490 							pBlocks = pStream_->pCurrPos;
491 						}
492 						if( enkiAreStringsEqual( "Y", pStream_->currentTag.pName ) )
493 						{
494 							sectionY = enkiNBTReadInt8( pStream_ );
495 						}
496 						if( pBlocks && ( 0 <= sectionY ) )
497 						{
498 							chunk.sections[ sectionY ] = pBlocks;
499 							sectionY = -1;
500 							pBlocks = NULL;
501 						}
502 					} while(  pStream_->level > levelParent );
503 				}
504 
505 				if( foundXPos && foundZPos && foundSection )
506 				{
507 					return chunk;
508 				}
509 			}
510 		}
511 	}
512 	// reset to empty
513 	enkiChunkInit( &chunk );
514 	return chunk;
515 }
516 
enkiGetChunkOrigin(enkiChunkBlockData * pChunk_)517 enkiMICoordinate enkiGetChunkOrigin(enkiChunkBlockData * pChunk_)
518 {
519 	enkiMICoordinate retVal;
520 	retVal.x = pChunk_->xPos * ENKI_MI_SIZE_SECTIONS;
521 	retVal.y = 0;
522 	retVal.z = pChunk_->zPos * ENKI_MI_SIZE_SECTIONS;
523 	return retVal;
524 }
525 
enkiGetChunkSectionOrigin(enkiChunkBlockData * pChunk_,int32_t section_)526 enkiMICoordinate enkiGetChunkSectionOrigin(enkiChunkBlockData * pChunk_, int32_t section_)
527 {
528 	enkiMICoordinate retVal;
529 	retVal.x = pChunk_->xPos * ENKI_MI_SIZE_SECTIONS;
530 	retVal.y = section_ * ENKI_MI_SIZE_SECTIONS;
531 	retVal.z = pChunk_->zPos * ENKI_MI_SIZE_SECTIONS;
532 	return retVal;
533 }
534 
enkiGetChunkSectionVoxel(enkiChunkBlockData * pChunk_,int32_t section_,enkiMICoordinate sectionOffset_)535 uint8_t enkiGetChunkSectionVoxel(enkiChunkBlockData * pChunk_, int32_t section_, enkiMICoordinate sectionOffset_)
536 {
537 	uint8_t retVal = 0;
538 	uint8_t* pSection = pChunk_->sections[ section_ ];
539 	uint8_t* pVoxel = pSection + sectionOffset_.y*ENKI_MI_SIZE_SECTIONS*ENKI_MI_SIZE_SECTIONS + sectionOffset_.z*ENKI_MI_SIZE_SECTIONS + sectionOffset_.x;
540 	retVal = *pVoxel;
541 	return retVal;
542 }
543 
enkiGetMineCraftPalette()544 uint32_t* enkiGetMineCraftPalette()
545 {
546 	return minecraftPalette;
547 }
548