DCL 3.7.4
Loading...
Searching...
No Matches
FileInputStream.cpp
Go to the documentation of this file.
1#include <dcl/Config.h>
2
3#ifdef __WINNT__
4 #include <windows.h>
5#else
6 #include <errno.h>
7 #include <unistd.h> // isatty
8 #include <sys/stat.h> // fstat
9#endif
10
11#include <string.h> // memcpy
12#include <stdlib.h> // malloc, free
13
14#include <dcl/size_t.h>
15#include <dcl/Object.h>
16#include <dcl/FileInputStream.h>
17
18#if __DCL_HAVE_ALLOC_DEBUG
19#undef __DCL_ALLOC_LEVEL
20#define __DCL_ALLOC_LEVEL __DCL_ALLOC_INTERNAL
21#endif
22
23#if __DCL_HAVE_THIS_FILE__
24#undef __THIS_FILE__
25static const char_t __THIS_FILE__[] = __T("dcl/FileInputStream.cpp");
26#endif
27
28__DCL_BEGIN_NAMESPACE
29
31
32String FileInputStream::toString() const
33{
34 StringBuilder r = className();
35 if (__file)
36 r += __T("(") + __file->toString() + __T(")");
37 else
38 r += __T(" closed");
39 return r;
40}
41
42FileInputStream::FileInputStream(const String& _path)
44{
45 __file = NULL;
46 open(_path);
47}
48
49#ifdef _MSC_VER
50FileInputStream::FileInputStream(const wchar_t* _path)
52{
53 __file = NULL;
54 open(_path);
55}
56#endif
57
60{
61 __buf = NULL;
62 __bufSize = 0;
63#ifdef __WINNT__
64 switch (_file->fileType()) {
65 case File::REGULAR:
66 __bufSize = 4096;
67 break;
68#if 0
69 case File::PIPE: {
70 DWORD dwInBufferSize = 0;
71 if (GetNamedPipeInfo(_file->handle(), NULL, NULL, &dwInBufferSize, NULL))
72 __bufSize = dwInBufferSize;
73 break;
74 }
75#endif
76 default: {
77 // __bufSize = 0;
78 }
79 }
80
81#else
82 if (!isatty(_file->handle())) {
83 struct stat st;
84 if (fstat(_file->handle(), &st)) {
85 throw new IOException(_file->path(), errno);
86 }
87 __bufSize = st.st_blksize;
88 }
89#endif
91 __cacheSize = 0;
92}
93
94FileInputStream::FileInputStream(File& _file)
96{
97 init(&_file);
98 __file = &_file;
99 __closeDestroy = false;
100}
101
102FileInputStream::FileInputStream(File::HandleType _handle)
104{
105 File* file = new File(_handle, 0, false);
106 try {
107 init(file);
108 }
109 catch (Exception* _e) {
110 delete file;
111 throw _e;
112 }
113 __file = file;
114 __closeDestroy = true;
115}
116
117void FileInputStream::open(const String& _path)
119{
120 if (__file) {
121 close();
122 }
123
124 File* file = new File(_path, File::READONLY);
125 try {
126 init(file);
127 }
128 catch (Exception* _e) {
129 delete file;
130 throw _e;
131 }
132 __file = file;
133 __closeDestroy = true;
134}
135
136FileInputStream::~FileInputStream()
137{
138 if (__file != NULL) {
139 try {
140 close();
141 }
142 catch (IOException* _e) {
143 __DCL_TRACE1(L"!FileInputStream close error! %ls\n",
144 _e->toString().data());
145 _e->destroy();
146 }
147 }
149}
150
151void FileInputStream::close()
153{
155
156 if (__buf) {
157 free(__buf);
160 }
161
162 Exception* e = NULL;
163 File* file = __file;
164 __file = NULL;
165 if (__closeDestroy) {
166 try {
167 file->close();
168 }
169 catch (Exception* _cause) {
170 e = _cause;
171 }
172 file->destroy();
173 }
174 if (e) {
175 throw e;
176 }
177}
178
179size_t FileInputStream::available() const
181{
183
184 return __ADD_OVERFLOW_MAX(__file->available(), __cacheSize);
185}
186
187size_t FileInputStream::read(void* _buf, size_t _nbytes)
189{
190 __DCL_ASSERT_HANDLE(__file != NULL);
191 __DCL_ASSERT_PARAM(_buf != NULL);
192
193 if (!_nbytes)
194 return 0;
195
196 if (!__bufSize) {
197 // 버퍼링을 하지 않는다.
198 return __file->read(_buf, _nbytes);
199 }
200
201 size_t nbytes = _nbytes;
202 byte_t* buf = (byte_t*)_buf;
203
204 if (__cacheSize) {
205 __DCL_ASSERT(__buf != NULL);
206 __DCL_ASSERT(__cacheStart != NULL);
207
208 size_t nCopy = __MIN(__cacheSize, nbytes);
209 memcpy(buf, __cacheStart, nCopy);
210 __cacheStart += nCopy;
211 __cacheSize -= nCopy;
212
213 buf += nCopy;
214 nbytes -= nCopy;
215 }
216
217 if (nbytes) {
218 // 이미 캐시되어 있는 데이터는 복사했다.
219 __DCL_ASSERT(__cacheSize == 0);
220
221 // Non-Block이 가능한 양만큼 __file에서 직접 읽는다.
222 size_t nAvail = (__MIN(nbytes, __file->available()) / __bufSize) * __bufSize;
223 if (nAvail) {
224 size_t nRead = __file->read(buf, nAvail);
225 if (nRead) {
226 buf += nRead;
227 nbytes -= nRead;
228 nAvail -= nRead;
229 }
230 }
231
232 if (!nAvail) {
233 // Non-Block에서 읽을 것이 없었거나, 또는 모두 읽었다면 더 읽는다.
234 // Non-Block에서 요구된 것 보다 덜 읽었다면 다음을 실패할 가능성이 높다.
235 size_t nCacheRead = nbytes % __bufSize;
236 if (nCacheRead) {
237 if (!__buf) {
238 __buf = (byte_t*)malloc(__bufSize);
239 __DCL_ASSERT(__buf != NULL); // out of memory
240 }
241
242 // 이곳에서 Block 될 수 있다.
243 size_t nRead = __file->read(__buf, __bufSize);
244 if (nRead) {
245 // __DCL_TRACE2("CacheRead : %d, %d\n", __bufSize, nRead);
246 __cacheStart = __buf;
247 __cacheSize = nRead;
248
249 size_t nCopy = __MIN(__cacheSize, nbytes);
250 memcpy(buf, __cacheStart, nCopy);
251 __cacheStart += nCopy;
252 __cacheSize -= nCopy;
253
254 // buf += nCopySize;
255 nbytes -= nCopy;
256 }
257 }
258 }
259 }
260
261 return _nbytes - nbytes;
262}
263
264__DCL_END_NAMESPACE
#define __THIS_FILE__
Definition _trace.h:14
#define NULL
Definition Config.h:312
wchar_t char_t
Definition Config.h:247
unsigned char byte_t
Definition Config.h:246
#define __DCL_THROWS1(e)
Definition Config.h:152
IOException *size_t r
Definition MediaInfo.cpp:82
#define __DCL_TRACE1(fmt, arg1)
Definition Object.h:399
#define __DCL_ASSERT_PARAM(expr)
Definition Object.h:409
#define __DCL_ASSERT(expr)
Definition Object.h:394
#define IMPLEMENT_CLASSINFO(class_name, base_class_name)
Definition Object.h:245
#define __T(str)
Definition Object.h:60
#define __DCL_ASSERT_HANDLE(expr)
Definition Object.h:408
virtual void destroy()
Definition Exception.cpp:74
Definition File.h:42
virtual void close() __DCL_THROWS1(IOException *)
Definition File.cpp:369
virtual String toString() const
const byte_t * __cacheStart
void init(File *_file)
virtual String toString() const
virtual String toString() const
Definition Object.cpp:187
virtual void destroy()
Definition Object.cpp:192
String className() const
Definition Object.cpp:163
size_t __MIN(size_t x, size_t y)
Definition size_t.h:27
__DCL_BEGIN_NAMESPACE size_t __ADD_OVERFLOW_MAX(size_t x, size_t y)
Definition size_t.h:18