1 // Copyright (c) 1996 James Clark
2 // See the file COPYING for copying permission.
3
4 #include "splib.h"
5
6 #ifdef SP_WININET
7
8 #include "WinInetStorage.h"
9 #include "WinInetStorageMessages.h"
10 #include "RewindStorageObject.h"
11 #include "UnivCharsetDesc.h"
12 #include "MessageArg.h"
13 #include "MessageBuilder.h"
14 #include "macros.h"
15
16 #define STRICT
17 #include <windows.h>
18 #include <wininet.h>
19
20 #ifdef SP_NAMESPACE
21 namespace SP_NAMESPACE {
22 #endif
23
24 static UnivCharsetDesc::Range range = { 0, 128, 0 };
25 static CharsetInfo iso646Charset(UnivCharsetDesc(&range, 1));
26
toAscii(const StringC & buf)27 String<char> toAscii(const StringC &buf)
28 {
29 String<char> s;
30 for (size_t i = 0; i < buf.size(); i++)
31 s += buf[i];
32 s += '\0';
33 return s;
34 }
35 class Win32MessageArg : public MessageArg {
36 public:
Win32MessageArg(DWORD n)37 Win32MessageArg(DWORD n) : n_(n) { }
copy() const38 MessageArg *copy() const { return new Win32MessageArg(*this); }
39 void append(MessageBuilder &) const;
40 private:
41 DWORD n_;
42 };
43
append(MessageBuilder & builder) const44 void Win32MessageArg::append(MessageBuilder &builder) const
45 {
46 void *msg;
47 if (!FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM
48 |FORMAT_MESSAGE_ALLOCATE_BUFFER,
49 0,
50 n_,
51 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
52 (LPSTR)&msg,
53 0,
54 0)) {
55 // FIXME interpret common internet messages here
56 builder.appendNumber(n_);
57 return;
58 }
59 String<Char> s;
60 for (char *tem = (char *)msg; *tem; tem++)
61 s += *tem;
62 LocalFree(msg);
63 builder.appendChars(s.data(), s.size());
64 }
65
66 class WinInetStorageObject : public RewindStorageObject {
67 public:
68 WinInetStorageObject(HINTERNET fd, Boolean mayRewind, const StringC &url);
69 ~WinInetStorageObject();
70 Boolean read(char *buf, size_t bufSize, Messenger &mgr, size_t &nread);
71 Boolean seekToStart(Messenger &);
72 private:
73 WinInetStorageObject(const WinInetStorageObject &); // undefined
74 void operator=(const WinInetStorageObject &); // undefined
75 Boolean eof_;
76 HINTERNET fd_;
77 StringC url_;
78 };
79
WinInetStorageManager(const char * type)80 WinInetStorageManager::WinInetStorageManager(const char *type)
81 : type_(type), IdStorageManager(&iso646Charset), session_(0)
82 {
83 }
84
~WinInetStorageManager()85 WinInetStorageManager::~WinInetStorageManager()
86 {
87 if (session_) {
88 InternetCloseHandle(session_);
89 session_ = 0;
90 }
91 }
92
type() const93 const char *WinInetStorageManager::type() const
94 {
95 return type_;
96 }
97
initSession()98 Boolean WinInetStorageManager::initSession()
99 {
100 if (!session_) {
101 session_ = InternetOpenA("SP",
102 INTERNET_OPEN_TYPE_PRECONFIG,
103 0,
104 0,
105 0);
106 }
107 return 1;
108 }
109
guessIsId(const StringC & id,const CharsetInfo & charset) const110 Boolean WinInetStorageManager::guessIsId(const StringC &id,
111 const CharsetInfo &charset) const
112 {
113 if (id.size() < 8)
114 return 0;
115 size_t i = 0;
116 // guess other schemes supported by download protocols
117 for (const char *s = "http://"; *s; s++, i++)
118 if (id[i] != charset.execToDesc(*s)
119 && (!islower(*s) || id[i] != charset.execToDesc(toupper(*s))))
120 return 0;
121 return 1;
122 }
123
makeStorageObject(const StringC & specId,const StringC & baseId,Boolean,Boolean mayRewind,Messenger & mgr,StringC & id)124 StorageObject *WinInetStorageManager::makeStorageObject(const StringC &specId,
125 const StringC &baseId,
126 Boolean,
127 Boolean mayRewind,
128 Messenger &mgr,
129 StringC &id)
130 {
131 if (!initSession())
132 return 0;
133 id = specId;
134 resolveRelative(baseId, id, 0);
135 String<char> tem(toAscii(id));
136 HINTERNET fd = InternetOpenUrlA(session_, tem.data(), 0, 0, 0, 0);
137 if (!fd) {
138 DWORD err = GetLastError();
139 mgr.message(WinInetStorageMessages::cannotOpen,
140 StringMessageArg(id),
141 Win32MessageArg(err));
142 return 0;
143 }
144 // FIXME report an error
145 return new WinInetStorageObject(fd, mayRewind, id);
146 }
147
resolveRelative(const StringC & baseId,StringC & id,Boolean) const148 Boolean WinInetStorageManager::resolveRelative(const StringC &baseId,
149 StringC &id,
150 Boolean) const
151 {
152 DWORD bufSize = baseId.size() + id.size() + 1;
153 char *buf = new char[bufSize];
154 String<char> baseIdA (toAscii(baseId));
155 String<char> idA(toAscii(id));
156 if (InternetCombineUrlA(baseIdA.data(),
157 idA.data(),
158 buf,
159 &bufSize,
160 0)) {
161 id.resize(0);
162 for (size_t i = 0; i < bufSize; i++)
163 id += buf[i];
164 delete [] buf;
165 return 1;
166 }
167 delete [] buf;
168 return 0;
169 }
170
transformNeutral(StringC & str,Boolean fold,Messenger &) const171 Boolean WinInetStorageManager::transformNeutral(StringC &str, Boolean fold,
172 Messenger &) const
173 {
174 if (fold)
175 for (size_t i = 0; i < str.size(); i++) {
176 Char c = str[i];
177 if (c <= (unsigned char)-1)
178 str[i] = tolower(str[i]);
179 }
180 return 1;
181 }
182
183
WinInetStorageObject(HINTERNET fd,Boolean mayRewind,const StringC & url)184 WinInetStorageObject::WinInetStorageObject(HINTERNET fd,
185 Boolean mayRewind,
186 const StringC &url)
187 : RewindStorageObject(mayRewind, 0), fd_(fd), url_(url), eof_(0)
188 {
189 }
190
~WinInetStorageObject()191 WinInetStorageObject::~WinInetStorageObject()
192 {
193 if (fd_ != 0) {
194 (void)InternetCloseHandle(fd_);
195 fd_ = 0;
196 }
197 }
198
read(char * buf,size_t bufSize,Messenger & mgr,size_t & nread)199 Boolean WinInetStorageObject::read(char *buf, size_t bufSize, Messenger &mgr,
200 size_t &nread)
201 {
202 if (readSaved(buf, bufSize, nread))
203 return 1;
204 if (fd_ == 0 || eof_)
205 return 0;
206 DWORD n;
207 if (!InternetReadFile(fd_, buf, bufSize, &n)) {
208 DWORD err = GetLastError();
209 mgr.message(WinInetStorageMessages::readFailed,
210 StringMessageArg(url_),
211 Win32MessageArg(err));
212 return 0;
213 }
214 if (n) {
215 nread = n;
216 return 1;
217 }
218 eof_ = 1;
219 InternetCloseHandle(fd_);
220 fd_ = 0;
221 return 0;
222 }
223
seekToStart(Messenger &)224 Boolean WinInetStorageObject::seekToStart(Messenger &)
225 {
226 CANNOT_HAPPEN();
227 return 0;
228 }
229
230 #ifdef SP_NAMESPACE
231 }
232 #endif
233
234 #endif /* SP_WININET */
235