-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathStdFileInStream.cpp
150 lines (130 loc) · 4.03 KB
/
StdFileInStream.cpp
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#include "StdFileInStream.h"
#include <cassert>
#include <algorithm>
#include <fmt/format.h>
#include <fmt/std.h>
/*
ISequentialInStream::Read()
The requirement for caller: (processedSize != NULL).
The callee can allow (processedSize == NULL) for compatibility reasons.
if (size == 0), this function returns S_OK and (*processedSize) is set to 0.
if (size != 0)
{
Partial read is allowed: (*processedSize <= avail_size && *processedSize <= size),
where (avail_size) is the size of remaining bytes in stream.
If (avail_size != 0), this function must read at least 1 byte: (*processedSize > 0).
You must call Read() in loop, if you need to read exact amount of data.
}
If seek pointer before Read() call was changed to position past the end of stream:
if (seek_pointer >= stream_size), this function returns S_OK and (*processedSize) is set to 0.
ERROR CASES:
If the function returns error code, then (*processedSize) is size of
data written to (data) buffer (it can be data before error or data with errors).
The recommended way for callee to work with reading errors:
1) write part of data before error to (data) buffer and return S_OK.
2) return error code for further calls of Read().
*/
Z7_COM7F_IMF(StdFileInStream::Read(void* data, UInt32 size, UInt32* processedSize))
{
if (size == 0 || InputStream.eof())
{
if (processedSize != nullptr)
*processedSize = 0u;
return S_OK;
}
constexpr UInt32 MaxChunkSize = 1 << 20;
if (size > MaxChunkSize)
{
fmt::print("Large chunk {}\n", size);
}
size = std::min(size, MaxChunkSize);
auto* Bytes = static_cast<std::fstream::char_type*>(data);
const auto ChunkSize = static_cast<std::streamsize>(size);
std::memset(data, 0, size);
InputStream.read(Bytes, ChunkSize);
if (processedSize != nullptr)
*processedSize = (UInt32)InputStream.gcount();
return S_OK;
}
/*
IInStream::Seek() / IOutStream::Seek()
If you seek to position before the beginning of the stream,
Seek() function returns error code:
Recommended error code is __HRESULT_FROM_WIN32(ERROR_NEGATIVE_SEEK).
or STG_E_INVALIDFUNCTION
It is allowed to seek past the end of the stream.
if Seek() returns error, then the value of *newPosition is undefined.
*/
Z7_COM7F_IMF(StdFileInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64* newPosition))
{
if (seekOrigin == STREAM_SEEK_SET)
{
if (offset < 0) {
InputStream.seekg(0, std::ios_base::beg);
return ERROR_NEGATIVE_SEEK;
}
InputStream.seekg(offset, std::ios_base::beg);
if (newPosition)
*newPosition = InputStream.tellg();
return S_OK;
}
if (seekOrigin == STREAM_SEEK_CUR)
{
const auto CurrentPosition = InputStream.tellg();
if (CurrentPosition < 0)
{
InputStream.seekg(offset, std::ios_base::beg);
}
else if (offset < -(Int64)CurrentPosition) {
InputStream.seekg(0, std::ios_base::beg);
return ERROR_NEGATIVE_SEEK;
}
else
{
InputStream.seekg(offset, std::ios_base::cur);
}
if (newPosition)
*newPosition = InputStream.tellg();
return S_OK;
}
if (seekOrigin == STREAM_SEEK_END)
{
const auto CurrentPosition = FileSize;
if (offset < -(Int64)FileSize) {
InputStream.seekg(0, std::ios_base::beg);
return ERROR_NEGATIVE_SEEK;
}
if (offset == 0)
{
InputStream.seekg(0, std::ios_base::end);
if (newPosition)
*newPosition = FileSize;
return S_OK;
}
InputStream.seekg(offset, std::ios_base::end);
if (newPosition)
*newPosition = InputStream.tellg();
return S_OK;
}
return STG_E_INVALIDFUNCTION;
}
StdFileInStream::StdFileInStream(std::filesystem::path PathOfArchive)
: InputStream(PathOfArchive, std::ios_base::in | std::ios::binary),
FileSize(0)
{
if (!std::filesystem::exists(PathOfArchive))
{
fmt::print("Archive at {} does not exist.\n", PathOfArchive);
return;
}
std::error_code ErrorCode;
FileSize = std::filesystem::file_size(PathOfArchive, ErrorCode);
if (ErrorCode)
{
FileSize = 0;
fmt::print("Unable to determine file size for {}! Error code: {}.\n", PathOfArchive, ErrorCode);
}
}
StdFileInStream::~StdFileInStream()
{
}