1 // Copyright 2017 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "core/fxcrt/fx_stream.h"
8
9 #include <algorithm>
10 #include <memory>
11 #include <utility>
12 #include <vector>
13
14 #include "build/build_config.h"
15 #include "core/fxcrt/fileaccess_iface.h"
16 #include "core/fxcrt/fx_safe_types.h"
17 #include "third_party/base/ptr_util.h"
18
19 #if defined(OS_WIN)
20 #include <direct.h>
21
22 struct FX_FolderHandle {
23 HANDLE m_Handle;
24 bool m_bEnd;
25 WIN32_FIND_DATAA m_FindData;
26 };
27 #else
28 #include <dirent.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <unistd.h>
32
33 struct FX_FolderHandle {
34 ByteString m_Path;
35 DIR* m_Dir;
36 };
37 #endif
38
39 namespace {
40
41 class CFX_CRTFileStream final : public IFX_SeekableStream {
42 public:
43 template <typename T, typename... Args>
44 friend RetainPtr<T> pdfium::MakeRetain(Args&&... args);
45
46 // IFX_SeekableStream:
GetSize()47 FX_FILESIZE GetSize() override { return m_pFile->GetSize(); }
IsEOF()48 bool IsEOF() override { return GetPosition() >= GetSize(); }
GetPosition()49 FX_FILESIZE GetPosition() override { return m_pFile->GetPosition(); }
ReadBlockAtOffset(void * buffer,FX_FILESIZE offset,size_t size)50 bool ReadBlockAtOffset(void* buffer,
51 FX_FILESIZE offset,
52 size_t size) override {
53 return m_pFile->ReadPos(buffer, size, offset) > 0;
54 }
ReadBlock(void * buffer,size_t size)55 size_t ReadBlock(void* buffer, size_t size) override {
56 return m_pFile->Read(buffer, size);
57 }
WriteBlockAtOffset(const void * buffer,FX_FILESIZE offset,size_t size)58 bool WriteBlockAtOffset(const void* buffer,
59 FX_FILESIZE offset,
60 size_t size) override {
61 return !!m_pFile->WritePos(buffer, size, offset);
62 }
Flush()63 bool Flush() override { return m_pFile->Flush(); }
64
65 private:
CFX_CRTFileStream(std::unique_ptr<FileAccessIface> pFA)66 explicit CFX_CRTFileStream(std::unique_ptr<FileAccessIface> pFA)
67 : m_pFile(std::move(pFA)) {}
~CFX_CRTFileStream()68 ~CFX_CRTFileStream() override {}
69
70 std::unique_ptr<FileAccessIface> m_pFile;
71 };
72
73 } // namespace
74
75 // static
CreateFromFilename(const char * filename,uint32_t dwModes)76 RetainPtr<IFX_SeekableStream> IFX_SeekableStream::CreateFromFilename(
77 const char* filename,
78 uint32_t dwModes) {
79 std::unique_ptr<FileAccessIface> pFA = FileAccessIface::Create();
80 if (!pFA->Open(filename, dwModes))
81 return nullptr;
82 return pdfium::MakeRetain<CFX_CRTFileStream>(std::move(pFA));
83 }
84
85 // static
CreateFromFilename(const wchar_t * filename,uint32_t dwModes)86 RetainPtr<IFX_SeekableStream> IFX_SeekableStream::CreateFromFilename(
87 const wchar_t* filename,
88 uint32_t dwModes) {
89 std::unique_ptr<FileAccessIface> pFA = FileAccessIface::Create();
90 if (!pFA->Open(filename, dwModes))
91 return nullptr;
92 return pdfium::MakeRetain<CFX_CRTFileStream>(std::move(pFA));
93 }
94
95 // static
CreateFromFilename(const char * filename)96 RetainPtr<IFX_SeekableReadStream> IFX_SeekableReadStream::CreateFromFilename(
97 const char* filename) {
98 return IFX_SeekableStream::CreateFromFilename(filename, FX_FILEMODE_ReadOnly);
99 }
100
WriteBlock(const void * pData,size_t size)101 bool IFX_SeekableWriteStream::WriteBlock(const void* pData, size_t size) {
102 return WriteBlockAtOffset(pData, GetSize(), size);
103 }
104
IsEOF()105 bool IFX_SeekableReadStream::IsEOF() {
106 return false;
107 }
108
GetPosition()109 FX_FILESIZE IFX_SeekableReadStream::GetPosition() {
110 return 0;
111 }
112
ReadBlock(void * buffer,size_t size)113 size_t IFX_SeekableReadStream::ReadBlock(void* buffer, size_t size) {
114 return 0;
115 }
116
WriteBlock(const void * buffer,size_t size)117 bool IFX_SeekableStream::WriteBlock(const void* buffer, size_t size) {
118 return WriteBlockAtOffset(buffer, GetSize(), size);
119 }
120
WriteString(ByteStringView str)121 bool IFX_SeekableStream::WriteString(ByteStringView str) {
122 return WriteBlock(str.unterminated_c_str(), str.GetLength());
123 }
124
FX_OpenFolder(const char * path)125 FX_FolderHandle* FX_OpenFolder(const char* path) {
126 auto handle = pdfium::MakeUnique<FX_FolderHandle>();
127 #if defined(OS_WIN)
128 handle->m_Handle =
129 FindFirstFileExA((ByteString(path) + "/*.*").c_str(), FindExInfoStandard,
130 &handle->m_FindData, FindExSearchNameMatch, nullptr, 0);
131 if (handle->m_Handle == INVALID_HANDLE_VALUE)
132 return nullptr;
133
134 handle->m_bEnd = false;
135 #else
136 DIR* dir = opendir(path);
137 if (!dir)
138 return nullptr;
139
140 handle->m_Path = path;
141 handle->m_Dir = dir;
142 #endif
143 return handle.release();
144 }
145
FX_GetNextFile(FX_FolderHandle * handle,ByteString * filename,bool * bFolder)146 bool FX_GetNextFile(FX_FolderHandle* handle,
147 ByteString* filename,
148 bool* bFolder) {
149 if (!handle)
150 return false;
151
152 #if defined(OS_WIN)
153 if (handle->m_bEnd)
154 return false;
155
156 *filename = handle->m_FindData.cFileName;
157 *bFolder =
158 (handle->m_FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
159 if (!FindNextFileA(handle->m_Handle, &handle->m_FindData))
160 handle->m_bEnd = true;
161 return true;
162 #else
163 struct dirent* de = readdir(handle->m_Dir);
164 if (!de)
165 return false;
166 ByteString fullpath = handle->m_Path + "/" + de->d_name;
167 struct stat deStat;
168 if (stat(fullpath.c_str(), &deStat) < 0)
169 return false;
170
171 *filename = de->d_name;
172 *bFolder = S_ISDIR(deStat.st_mode);
173 return true;
174 #endif
175 }
176
FX_CloseFolder(FX_FolderHandle * handle)177 void FX_CloseFolder(FX_FolderHandle* handle) {
178 if (!handle)
179 return;
180
181 #if defined(OS_WIN)
182 FindClose(handle->m_Handle);
183 #else
184 closedir(handle->m_Dir);
185 #endif
186 delete handle;
187 }
188