1 /*
2  * Copyright (c) 2017 Juliette Foucaut & Doug Binks
3  *
4  * This software is provided 'as-is', without any express or implied
5  * warranty. In no event will the authors be held liable for any damages
6  * arising from the use of this software.
7  *
8  * Permission is granted to anyone to use this software for any purpose,
9  * including commercial applications, and to alter it and redistribute it
10  * freely, subject to the following restrictions:
11  *
12  * 1. The origin of this software must not be misrepresented; you must not
13  *    claim that you wrote the original software. If you use this software
14  *    in a product, an acknowledgement in the product documentation would be
15  *    appreciated but is not required.
16  * 2. Altered source versions must be plainly marked as such, and must not be
17  *    misrepresented as being the original software.
18  * 3. This notice may not be removed or altered from any source distribution.
19  */
20 #pragma once
21 
22 #include <stdint.h>
23 #include "miniz.h"
24 
25 #ifdef __cplusplus
26 extern "C" {
27 #endif
28 
29 #define ENKI_MI_REGION_CHUNKS_NUMBER 1024
30 
31 // http://web.archive.org/web/20110723210920/http://www.minecraft.net/docs/NBT.txt
32 typedef enum
33 {
34 	enkiNBTTAG_End = 0,
35 	enkiNBTTAG_Byte = 1,
36 	enkiNBTTAG_Short = 2,
37 	enkiNBTTAG_Int = 3,
38 	enkiNBTTAG_Long = 4,
39 	enkiNBTTAG_Float = 5,
40 	enkiNBTTAG_Double = 6,
41 	enkiNBTTAG_Byte_Array = 7,
42 	enkiNBTTAG_String = 8,
43 	enkiNBTTAG_List = 9,
44 	enkiNBTTAG_Compound = 10,
45 	enkiNBTTAG_Int_Array = 11,
46 } enkiNBTTAG_ID;
47 
48 
49 typedef struct enkiNBTTagHeader_s
50 {
51 	char* pName;
52 
53 	// if the tag is a list, we need the following variables
54 	int32_t listNumItems;
55 	int32_t listCurrItem;
56 	uint8_t listItemTagId;
57 
58 	// the tagId of type enkiNBTTAG_ID
59 	uint8_t tagId;
60 } enkiNBTTagHeader;
61 
62 
63 const char* enkiGetNBTTagIDAsString( uint8_t tagID_ );
64 const char* enkiGetNBTTagHeaderIDAsString( enkiNBTTagHeader tagID_ );
65 
66 typedef struct enkiNBTDataStream_s
67 {
68 	enkiNBTTagHeader parentTags[ 512 ];
69 	enkiNBTTagHeader currentTag;
70 	uint8_t* pCurrPos;
71 	uint8_t* pDataEnd;
72 	uint8_t* pData;
73 	uint8_t* pNextTag;
74 	uint8_t* pAllocation;
75 	uint32_t dataLength;
76 	int32_t level;
77 } enkiNBTDataStream;
78 
79 
80 // Initialize stream from memory pointer.
81 // pData_ and it's contents should remain valid until
82 // after enkiNBTDataStream no longer needed.
83 // Contents of buffer will be modified for easier reading,
84 // namely tag name strings will moved down a byte, null terminated,
85 // and prefixed with 0xFF instead of int16_t string length.
86 // Make a copy if you need to use the buffer in another lib.
87 // Other strings in file will not be altered.
88 // pUnCompressedData_ should be freed by caller.
89 // FreeMemoryAllocated() should still be called to free any internal allocations.
90 void enkiNBTInitFromMemoryUncompressed( enkiNBTDataStream* pStream_, uint8_t* pUnCompressedData_, uint32_t dataSize_ );
91 
92 // Initialize stream from memory pointer to compressed content.
93 // This function will allocate space for uncompressed stream and decompress it with zlib.
94 // If uncompressedSizeHint_ > compressedDataSize_ it will be used as the starting hint size for allocating
95 // the uncompressed size.
96 // returns 1 if successfull, 0 if not.
97 int enkiNBTInitFromMemoryCompressed( enkiNBTDataStream* pStream_, uint8_t* pCompressedData_,
98 									    uint32_t compressedDataSize_, uint32_t uncompressedSizeHint_ );
99 
100 
101 // returns 0 if no next tag, 1 if there was
102 int enkiNBTReadNextTag( enkiNBTDataStream* pStream_ );
103 
104 
105 // Rewind stream so it can be read again from beginning
106 void enkiNBTRewind( enkiNBTDataStream* pStream_ );
107 
108 // Frees any internally allocated memory.
109 void enkiNBTFreeAllocations( enkiNBTDataStream* pStream_ );
110 
111 int8_t  enkiNBTReadInt8(   enkiNBTDataStream* pStream_ );
112 int8_t  enkiNBTReadByte(   enkiNBTDataStream* pStream_ );
113 int16_t enkiNBTReadInt16(  enkiNBTDataStream* pStream_ );
114 int16_t enkiNBTReadShort(  enkiNBTDataStream* pStream_ );
115 int32_t enkiNBTReadInt32(  enkiNBTDataStream* pStream_ );
116 int32_t enkiNBTReadInt(    enkiNBTDataStream* pStream_ );
117 float   enkiNBTReadFloat(  enkiNBTDataStream* pStream_ );
118 int64_t enkiNBTReadInt64(  enkiNBTDataStream* pStream_ );
119 int64_t enkiNBTReadlong(   enkiNBTDataStream* pStream_ );
120 double  enkiNBTReadDouble( enkiNBTDataStream* pStream_ );
121 
122 typedef struct enkiNBTString_s
123 {
124 	int16_t     size;
125 	const char* pStrNotNullTerminated;
126 } enkiNBTString;
127 
128 enkiNBTString enkiNBTReadString( enkiNBTDataStream* pStream_ );
129 
130 typedef struct enkiRegionFile_s
131 {
132 	uint8_t* pRegionData;
133 	uint32_t regionDataSize;
134 } enkiRegionFile;
135 
136 // enkiRegionFileInit simply zeros data
137 void enkiRegionFileInit( enkiRegionFile* pRegionFile_ );
138 
139 enkiRegionFile enkiRegionFileLoad( FILE* fp_ );
140 
141 void enkiInitNBTDataStreamForChunk( enkiRegionFile regionFile_, int32_t chunkNr_, enkiNBTDataStream* pStream_ );
142 
143 int32_t enkiGetTimestampForChunk( enkiRegionFile regionFile_, int32_t chunkNr_ );
144 
145 // enkiFreeRegionFileData frees data allocated in enkiRegionFile
146 void enkiRegionFileFreeAllocations( enkiRegionFile* pRegionFile_ );
147 
148 // Check if lhs_ and rhs_ are equal, return 1 if so, 0 if not.
149 // Safe to pass in NULL for either
150 // Note that both NULL gives 0.
151 int enkiAreStringsEqual( const char* lhs_, const char* rhs_ );
152 
153 #define ENKI_MI_NUM_SECTIONS_PER_CHUNK 16
154 #define ENKI_MI_SIZE_SECTIONS 16
155 
156 typedef struct enkiMICoordinate_s
157 {
158 	int32_t x;
159 	int32_t y; // height
160 	int32_t z;
161 } enkiMICoordinate;
162 
163 typedef struct enkiChunkBlockData_s
164 {
165 	uint8_t* sections[ ENKI_MI_NUM_SECTIONS_PER_CHUNK ];
166 	int32_t xPos; // section coordinates
167 	int32_t zPos; // section coordinates
168 	int32_t countOfSections;
169 } enkiChunkBlockData;
170 
171 // enkiChunkInit simply zeros data
172 void enkiChunkInit( enkiChunkBlockData* pChunk_ );
173 
174 // enkiNBTReadChunk gets a chunk from an enkiNBTDataStream
175 // No allocation occurs - section data points to enkiNBTDataStream.
176 // pStream_ mush be kept valid whilst chunk is in use.
177 enkiChunkBlockData enkiNBTReadChunk( enkiNBTDataStream* pStream_ );
178 
179 
180 enkiMICoordinate enkiGetChunkOrigin( enkiChunkBlockData* pChunk_ );
181 
182 // get the origin of a section (0 <-> ENKI_MI_NUM_SECTIONS_PER_CHUNK).
183 enkiMICoordinate enkiGetChunkSectionOrigin( enkiChunkBlockData* pChunk_, int32_t section_ );
184 
185 // sectionOffset_ is the position from enkiGetChunkSectionOrigin
186 // Performs no safety checks.
187 // check pChunk_->sections[ section_ ] for NULL first in your code.
188 // and ensure sectionOffset_ coords with 0 to ENKI_MI_NUM_SECTIONS_PER_CHUNK
189 uint8_t enkiGetChunkSectionVoxel( enkiChunkBlockData* pChunk_, int32_t section_, enkiMICoordinate sectionOffset_ );
190 
191 uint32_t* enkiGetMineCraftPalette(); //returns a 256 array of uint32_t's in uint8_t rgba order.
192 
193 #ifdef __cplusplus
194 };
195 #endif
196