Skip to content

Commit e028b34

Browse files
committed
Fixed loading of files with empty lists (many level.dat files) and implemented uncompressed nbt files (like servers.dat)
1 parent a5a6226 commit e028b34

9 files changed

Lines changed: 129 additions & 15 deletions

File tree

src/File/MemoryByteReader.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#include "MemoryByteReader.h"
2+
#include "Exception/GzipException.h"
3+
#include <cstring>
4+
#include "Exception/StreamOverflowException.h"
5+
#include <string>
6+
#include <iostream>
7+
8+
namespace File {
9+
MemoryByteReader::MemoryByteReader(Byte* data, uint dataLength) : data(data), dataLength(dataLength), offset(0) {
10+
}
11+
12+
MemoryByteReader::~MemoryByteReader() {
13+
data = NULL;
14+
dataLength = 0;
15+
offset = 0;
16+
}
17+
18+
Byte MemoryByteReader::ReadByte() {
19+
if (offset >= dataLength) {
20+
throw Exception::StreamOverflowException(offset, 1, dataLength);
21+
}
22+
23+
return data[offset++];
24+
}
25+
26+
Byte* MemoryByteReader::ReadBytes(uint length) {
27+
if (offset + length >= dataLength)
28+
throw Exception::StreamOverflowException(offset, length, dataLength);
29+
30+
Byte* readBytes = new Byte[length];
31+
memcpy(readBytes, data + offset, length);
32+
33+
offset += length;
34+
return readBytes;
35+
}
36+
}

src/File/MemoryByteReader.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#pragma once
2+
#include "ByteReader.h"
3+
4+
namespace File {
5+
class MemoryByteReader : public ByteReader {
6+
public:
7+
MemoryByteReader(Byte* data, uint dataLength);
8+
~MemoryByteReader();
9+
Byte ReadByte();
10+
Byte* ReadBytes(uint length);
11+
12+
private:
13+
Byte* data;
14+
uint dataLength;
15+
uint offset;
16+
};
17+
}

src/NBT/NBTReader.cpp

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "NBTCompound.h"
33
#include "File/ByteBuffer.h"
44
#include "File/GzipByteReader.h"
5+
#include "File/MemoryByteReader.h"
56
#include "File/WriteBuffer.h"
67
#include "File/GzipByteWriter.h"
78
#include "File/FileByteWriter.h"
@@ -13,7 +14,7 @@
1314
using namespace std;
1415

1516
namespace NBT {
16-
NBTCompound* NBTReader::LoadFromFile(const char* filePath) {
17+
NBTCompound* NBTReader::LoadFromFile(const char* filePath, NBTFileType* outType) {
1718
ifstream ifs(filePath, ios::binary | ios::ate);
1819
if (!ifs)
1920
throw Exception::FileException(strerror(errno), filePath, errno);
@@ -25,13 +26,33 @@ namespace NBT {
2526
ifs.read((char*)bytes, length);
2627
ifs.close();
2728

28-
return LoadFromData(bytes, length);
29+
return LoadFromData(bytes, length, outType);
2930
}
3031

31-
NBTCompound* NBTReader::LoadFromData(Byte* data, uint length) {
32+
NBTCompound* NBTReader::LoadFromData(Byte* data, uint length, NBTFileType* outType) {
33+
if (length > 1 && data[0] == NbtCompound) {
34+
// Maybe the file is uncompressed - try to load it without gzip compression
35+
std::cout << "Try to load the nbt file without compression." << std::endl;
36+
37+
File::MemoryByteReader reader(data, length);
38+
File::ByteBuffer buffer(&reader);
39+
40+
try {
41+
NBTCompound* compound = LoadFromUncompressedStream(&buffer);
42+
if (outType != NULL)
43+
*outType = NbtUncompressed;
44+
return compound;
45+
} catch (const Exception::Exception& ex) {
46+
std::cout << "Loading without compression failed: " << ex.GetMessage().c_str() << std::endl;
47+
}
48+
}
49+
3250
File::GzipByteReader reader(data, length);
3351
File::ByteBuffer buffer(&reader);
3452

53+
if (outType != NULL)
54+
*outType = NbtGzipCompressed;
55+
3556
return LoadFromUncompressedStream(&buffer);
3657
}
3758

@@ -68,4 +89,21 @@ namespace NBT {
6889
delete gzipWriter;
6990
}
7091

92+
void NBTReader::SaveToFileUncompressed(const char* filePath, NBTCompound* compound) {
93+
File::FileByteWriter* fileWriter = new File::FileByteWriter(std::string(filePath));
94+
95+
try {
96+
File::WriteBuffer buffer(fileWriter);
97+
buffer.WriteByte(NbtCompound);
98+
buffer.WriteString("");
99+
100+
compound->Write(&buffer);
101+
} catch (const Exception::Exception& ex) {
102+
delete fileWriter;
103+
throw ex;
104+
}
105+
106+
delete fileWriter;
107+
}
108+
71109
}

src/NBT/NBTReader.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
namespace NBT {
44
class NBTReader {
55
public:
6-
static NBTCompound* LoadFromFile(const char* filePath);
7-
static NBTCompound* LoadFromData(Byte* data, uint length);
6+
static NBTCompound* LoadFromFile(const char* filePath, NBTFileType* outType = NULL);
7+
static NBTCompound* LoadFromData(Byte* data, uint length, NBTFileType* outType = NULL);
88
static NBTCompound* LoadFromUncompressedStream(File::ByteBuffer* buffer);
99

1010
static void SaveToFile(const char* filePath, NBTCompound* compound);
11+
static void SaveToFileUncompressed(const char* filePath, NBTCompound* compound);
1112
};
1213
}

src/NBT/NBTTag.h

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -398,8 +398,11 @@ namespace NBT {
398398
NBTType type = static_cast<NBTType>(buffer->ReadByte());
399399
jint length = buffer->ReadInt();
400400

401-
if (type == NbtEnd && length != 0)
402-
throw Exception::NBTException("Missing type in list", NULL);
401+
if (type == NbtEnd) {
402+
if (length != 0)
403+
throw Exception::NBTException("Missing type in list", NULL);
404+
return new NBTList(type);
405+
}
403406

404407
const NBTTag* tag = NBTHelper::GetTagByType(type);
405408
if (tag == NULL)
@@ -421,12 +424,14 @@ namespace NBT {
421424
buffer->WriteByte(list.type);
422425
buffer->WriteInt((jint) list.entries.size());
423426

424-
const NBTTag* tag = NBTHelper::GetTagByType(list.type);
425-
if (tag == NULL)
426-
throw Exception::NBTException("Unknown nbt element type: " + std::to_string(list.type), NULL);
427+
if (list.type != NbtEnd) {
428+
const NBTTag* tag = NBTHelper::GetTagByType(list.type);
429+
if (tag == NULL)
430+
throw Exception::NBTException("Unknown nbt element type: " + std::to_string(list.type), NULL);
427431

428-
for (auto& entry : list.entries) {
429-
tag->Write(buffer, *entry);
432+
for (auto& entry : list.entries) {
433+
tag->Write(buffer, *entry);
434+
}
430435
}
431436
}
432437

src/NBT/NBTType.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,9 @@ namespace NBT {
1515
NbtCompound = 10,
1616
NbtIntArray = 11
1717
};
18+
19+
enum NBTFileType {
20+
NbtGzipCompressed = 0,
21+
NbtUncompressed = 1
22+
};
1823
}

src/UI/AddElementDialog.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ namespace UI {
4040

4141
void AddElementDialog::disableInputName() {
4242
widget.nameField->setEnabled(false);
43+
widget.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
4344
}
4445

4546
void AddElementDialog::InitTypeSelection() {

src/UI/MainForm.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
using namespace std;
1818

1919
namespace UI {
20-
MainForm::MainForm() : saveEnabled(false) {
20+
MainForm::MainForm() : currentFileType(NBT::NbtGzipCompressed), saveEnabled(false) {
2121
widget.setupUi(this);
2222
setAcceptDrops(true);
2323

@@ -55,7 +55,7 @@ namespace UI {
5555

5656
void MainForm::loadFile(QString file) {
5757
try {
58-
NBT::NBTCompound* compound = NBT::NBTReader::LoadFromFile(file.toStdString().c_str());
58+
NBT::NBTCompound* compound = NBT::NBTReader::LoadFromFile(file.toStdString().c_str(), &currentFileType);
5959
NBT::NBTEntry* rootEntry = new NBT::NBTEntry("", NBT::NbtCompound);
6060
rootEntry->value = compound;
6161

@@ -82,7 +82,15 @@ namespace UI {
8282
NBT::NBTEntry* rootEntry = model->GetRootEntry();
8383
NBT::NBTCompound* compound = NBT::NBTHelper::GetCompound(*rootEntry);
8484

85-
NBT::NBTReader::SaveToFile(file.toStdString().c_str(), compound);
85+
switch (currentFileType) {
86+
case NBT::NbtUncompressed:
87+
NBT::NBTReader::SaveToFileUncompressed(file.toStdString().c_str(), compound);
88+
break;
89+
case NBT::NbtGzipCompressed:
90+
NBT::NBTReader::SaveToFile(file.toStdString().c_str(), compound);
91+
break;
92+
}
93+
8694
currentFile = file;
8795
disableSaving();
8896
} catch (const Exception::Exception& ex) {
@@ -137,6 +145,7 @@ namespace UI {
137145
widget.treeView->setModel(newModel);
138146
widget.treeView->expandToDepth(1);
139147

148+
currentFileType = NBT::NbtGzipCompressed;
140149
currentFile.clear();
141150
if (oldModel != NULL)
142151
delete oldModel;

src/UI/MainForm.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "TreeContextMenu.h"
44
#include <QString>
55
#include <QDropEvent>
6+
#include "NBT/NBTType.h"
67

78
namespace UI {
89
class MainForm : public QMainWindow {
@@ -36,6 +37,7 @@ namespace UI {
3637
TreeContextMenu* contextMenu;
3738

3839
QString currentFile;
40+
NBT::NBTFileType currentFileType;
3941
bool saveEnabled;
4042

4143
void enableSaving();

0 commit comments

Comments
 (0)