1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#include "Serialization/BsFileSerializer.h"
4
5#include "Error/BsException.h"
6#include "Reflection/BsIReflectable.h"
7#include "Serialization/BsBinarySerializer.h"
8#include "FileSystem/BsFileSystem.h"
9#include "FileSystem/BsDataStream.h"
10#include "Debug/BsDebug.h"
11#include <numeric>
12
13using namespace std::placeholders;
14
15namespace bs
16{
17 FileEncoder::FileEncoder(const Path& fileLocation)
18 {
19 mWriteBuffer = (UINT8*)bs_alloc(WRITE_BUFFER_SIZE);
20
21 Path parentDir = fileLocation.getDirectory();
22 if (!FileSystem::exists(parentDir))
23 FileSystem::createDir(parentDir);
24
25 mOutputStream.open(fileLocation.toPlatformString().c_str(), std::ios::out | std::ios::binary);
26 if (mOutputStream.fail())
27 {
28 LOGWRN("Failed to save file: \"" + fileLocation.toString() + "\". Error: " + strerror(errno) + ".");
29 }
30 }
31
32 FileEncoder::~FileEncoder()
33 {
34 bs_free(mWriteBuffer);
35
36 mOutputStream.close();
37 mOutputStream.clear();
38 }
39
40 void FileEncoder::encode(IReflectable* object, SerializationContext* context)
41 {
42 if (object == nullptr)
43 return;
44
45 UINT64 curPos = (UINT64)mOutputStream.tellp();
46 mOutputStream.seekp(sizeof(UINT32), std::ios_base::cur);
47
48 BinarySerializer bs;
49 UINT32 totalBytesWritten = 0;
50 bs.encode(object, mWriteBuffer, WRITE_BUFFER_SIZE, &totalBytesWritten,
51 std::bind(&FileEncoder::flushBuffer, this, _1, _2, _3), false, context);
52
53 mOutputStream.seekp(curPos);
54 mOutputStream.write((char*)&totalBytesWritten, sizeof(totalBytesWritten));
55 mOutputStream.seekp(totalBytesWritten, std::ios_base::cur);
56 }
57
58 UINT8* FileEncoder::flushBuffer(UINT8* bufferStart, UINT32 bytesWritten, UINT32& newBufferSize)
59 {
60 mOutputStream.write((const char*)bufferStart, bytesWritten);
61
62 return bufferStart;
63 }
64
65 FileDecoder::FileDecoder(const Path& fileLocation)
66 {
67 mInputStream = FileSystem::openFile(fileLocation, true);
68
69 if (mInputStream == nullptr)
70 return;
71
72 if (mInputStream->size() > std::numeric_limits<UINT32>::max())
73 {
74 BS_EXCEPT(InternalErrorException,
75 "File size is larger that UINT32 can hold. Ask a programmer to use a bigger data type.");
76 }
77 }
78
79 SPtr<IReflectable> FileDecoder::decode(SerializationContext* context)
80 {
81 if (mInputStream->eof())
82 return nullptr;
83
84 UINT32 objectSize = 0;
85 mInputStream->read(&objectSize, sizeof(objectSize));
86
87 BinarySerializer bs;
88 SPtr<IReflectable> object = bs.decode(mInputStream, objectSize, context);
89
90 return object;
91 }
92
93 UINT32 FileDecoder::getSize() const
94 {
95 if (mInputStream->eof())
96 return 0;
97
98 UINT32 objectSize = 0;
99 mInputStream->read(&objectSize, sizeof(objectSize));
100 mInputStream->seek(mInputStream->tell() - sizeof(objectSize));
101
102 return objectSize;
103 }
104
105 void FileDecoder::skip()
106 {
107 if (mInputStream->eof())
108 return;
109
110 UINT32 objectSize = 0;
111 mInputStream->read(&objectSize, sizeof(objectSize));
112 mInputStream->skip(objectSize);
113 }
114}
115