summaryrefslogtreecommitdiffstats
path: root/Tools/AnvilStats/ChunkExtract.cpp
blob: 67e8b46721990e8ac146f4ca7f759bd4301d5238 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112

// ChunkExtract.cpp

// Implements the cChunkExtract class representing a cCallback descendant that extracts raw chunk data into separate
// .chunk files

#include "Globals.h"
#include "ChunkExtract.h"
#include "../../src/OSSupport/GZipFile.h"





cChunkExtract::cChunkExtract(const AString & iWorldFolder) :
	mWorldFolder(iWorldFolder)
{
}





bool cChunkExtract::OnNewChunk(int a_ChunkX, int a_ChunkZ)
{
	int AnvilX = (a_ChunkX - ((a_ChunkX > 0) ? 0 : 31)) / 32;
	int AnvilZ = (a_ChunkZ - ((a_ChunkZ > 0) ? 0 : 31)) / 32;
	if ((AnvilX != mCurAnvilX) || (AnvilZ != mCurAnvilZ))
	{
		OpenAnvilFile(AnvilX, AnvilZ);
	}
	mCurChunkX = a_ChunkX;
	mCurChunkZ = a_ChunkZ;
	return false;
}





bool cChunkExtract::OnCompressedDataSizePos(int a_CompressedDataSize, int a_DataOffset, char a_CompressionMethod)
{
	if (!mAnvilFile.IsOpen())
	{
		return true;
	}
	cFile ChunkFile;
	AString ChunkPath = Printf("%d.%d.zchunk", mCurChunkX, mCurChunkZ);
	if (!ChunkFile.Open(ChunkPath, cFile::fmWrite))
	{
		LOG("Cannot open zchunk file \"%s\" for writing. Chunk [%d, %d] skipped.",
			ChunkPath.c_str(),
			mCurChunkX,
			mCurChunkZ);
		return false;
	}

	// Copy data from mAnvilFile to ChunkFile:
	mAnvilFile.Seek(a_DataOffset);
	for (int BytesToCopy = a_CompressedDataSize; BytesToCopy > 0;)
	{
		char Buffer[64000];
		int NumBytes = std::min(BytesToCopy, (int) sizeof(Buffer));
		int BytesRead = mAnvilFile.Read(Buffer, NumBytes);
		if (BytesRead != NumBytes)
		{
			LOG("Cannot copy chunk data, chunk [%d, %d] is probably corrupted. Skipping chunk.", mCurChunkX, mCurChunkZ
			);
			return false;
		}
		ChunkFile.Write(Buffer, BytesRead);
		BytesToCopy -= BytesRead;
	}  // for BytesToCopy
	return false;
}





bool cChunkExtract::OnDecompressedData(const char * a_DecompressedNBT, int a_DataSize)
{
	ASSERT(mAnvilFile.IsOpen());  // If it weren't, the OnCompressedDataSizePos would've prevented this from running
	AString FileName = Printf("%d.%d.gzchunk", mCurChunkX, mCurChunkZ);
	cGZipFile GZipChunk;
	if (!GZipChunk.Open(FileName, cGZipFile::fmWrite))
	{
		LOG("Cannot open gzchunk file \"%s\" for writing. Chunk [%d, %d] skipped.",
			FileName.c_str(),
			mCurChunkX,
			mCurChunkZ);
		return true;
	}
	GZipChunk.Write(a_DecompressedNBT, a_DataSize);
	return true;
}





void cChunkExtract::OpenAnvilFile(int a_AnvilX, int a_AnvilZ)
{
	mAnvilFile.Close();
	AString FileName = Printf("%s/r.%d.%d.mca", mWorldFolder.c_str(), a_AnvilX, a_AnvilZ);
	if (!mAnvilFile.Open(FileName, cFile::fmRead))
	{
		LOG("Cannot open Anvil file \"%s\" for reading", FileName.c_str());
	}
	mCurAnvilX = a_AnvilX;
	mCurAnvilZ = a_AnvilZ;
}