1 // Written by Christopher E. Miller 2 // See the included license.txt for copyright and license details. 3 4 5 module dfl.internal.com; 6 7 private import dfl.internal.winapi, dfl.internal.wincom, dfl.internal.dlib; 8 9 10 version(DFL_TANGO_SEEK_COMPAT) 11 { 12 } 13 else 14 { 15 version = DFL_TANGO_NO_SEEK_COMPAT; 16 } 17 18 19 // Importing dfl.application here causes the compiler to crash. 20 //import dfl.application; 21 private extern(C) 22 { 23 size_t C_refCountInc(void* p); 24 size_t C_refCountDec(void* p); 25 } 26 27 28 // Won't be killed by GC if not referenced in D and the refcount is > 0. 29 class DflComObject: ComObject // package 30 { 31 extern(Windows): 32 33 override ULONG AddRef() 34 { 35 //cprintf("AddRef `%.*s`\n", cast(int)toString().length, toString().ptr); 36 return C_refCountInc(cast(void*)this); 37 } 38 39 override ULONG Release() 40 { 41 //cprintf("Release `%.*s`\n", cast(int)toString().length, toString().ptr); 42 return C_refCountDec(cast(void*)this); 43 } 44 } 45 46 47 class DStreamToIStream: DflComObject, dfl.internal.wincom.IStream 48 { 49 this(DStream sourceDStream) 50 { 51 this.stm = sourceDStream; 52 } 53 54 55 extern(Windows): 56 57 override HRESULT QueryInterface(IID* riid, void** ppv) 58 { 59 if(*riid == _IID_IStream) 60 { 61 *ppv = cast(void*)cast(dfl.internal.wincom.IStream)this; 62 AddRef(); 63 return S_OK; 64 } 65 else if(*riid == _IID_ISequentialStream) 66 { 67 *ppv = cast(void*)cast(dfl.internal.wincom.ISequentialStream)this; 68 AddRef(); 69 return S_OK; 70 } 71 else if(*riid == _IID_IUnknown) 72 { 73 *ppv = cast(void*)cast(IUnknown)this; 74 AddRef(); 75 return S_OK; 76 } 77 else 78 { 79 *ppv = null; 80 return E_NOINTERFACE; 81 } 82 } 83 84 85 HRESULT Read(void* pv, ULONG cb, ULONG* pcbRead) 86 { 87 ULONG read; 88 HRESULT result = S_OK; 89 90 try 91 { 92 read = stm.readBlock(pv, cb); 93 } 94 catch(DStreamException e) 95 { 96 result = S_FALSE; // ? 97 } 98 99 if(pcbRead) 100 *pcbRead = read; 101 //if(!read) 102 // result = S_FALSE; 103 return result; 104 } 105 106 107 HRESULT Write(void* pv, ULONG cb, ULONG* pcbWritten) 108 { 109 ULONG written; 110 HRESULT result = S_OK; 111 112 try 113 { 114 if(!stm.writeable) 115 return E_NOTIMPL; 116 written = stm.writeBlock(pv, cb); 117 } 118 catch(DStreamException e) 119 { 120 result = S_FALSE; // ? 121 } 122 123 if(pcbWritten) 124 *pcbWritten = written; 125 //if(!written) 126 // result = S_FALSE; 127 return result; 128 } 129 130 131 version(DFL_TANGO_NO_SEEK_COMPAT) 132 { 133 } 134 else 135 { 136 long _fakepos = 0; 137 } 138 139 140 HRESULT Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) 141 { 142 HRESULT result = S_OK; 143 144 //cprintf("seek move=%u, origin=0x%x\n", cast(uint)dlibMove.QuadPart, dwOrigin); 145 146 try 147 { 148 if(!stm.seekable) 149 //return S_FALSE; // ? 150 return E_NOTIMPL; // ? 151 152 ulong pos; 153 switch(dwOrigin) 154 { 155 case STREAM_SEEK_SET: 156 pos = stm.seekSet(dlibMove.QuadPart); 157 if(plibNewPosition) 158 plibNewPosition.QuadPart = pos; 159 break; 160 161 case STREAM_SEEK_CUR: 162 pos = stm.seekCur(dlibMove.QuadPart); 163 if(plibNewPosition) 164 plibNewPosition.QuadPart = pos; 165 break; 166 167 case STREAM_SEEK_END: 168 pos = stm.seekEnd(dlibMove.QuadPart); 169 if(plibNewPosition) 170 plibNewPosition.QuadPart = pos; 171 break; 172 173 default: 174 result = STG_E_INVALIDFUNCTION; 175 } 176 } 177 catch(DStreamException e) 178 { 179 result = S_FALSE; // ? 180 } 181 182 return result; 183 } 184 185 186 HRESULT SetSize(ULARGE_INTEGER libNewSize) 187 { 188 return E_NOTIMPL; 189 } 190 191 192 HRESULT CopyTo(IStream pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) 193 { 194 // TODO: implement. 195 return E_NOTIMPL; 196 } 197 198 199 HRESULT Commit(DWORD grfCommitFlags) 200 { 201 // Ignore -grfCommitFlags- and just flush the stream.. 202 //stm.flush(); 203 stm.flush(); 204 return S_OK; // ? 205 } 206 207 208 HRESULT Revert() 209 { 210 return E_NOTIMPL; // ? S_FALSE ? 211 } 212 213 214 HRESULT LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) 215 { 216 return E_NOTIMPL; 217 } 218 219 220 HRESULT UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) 221 { 222 return E_NOTIMPL; 223 } 224 225 226 HRESULT Stat(STATSTG* pstatstg, DWORD grfStatFlag) 227 { 228 return E_NOTIMPL; // ? 229 } 230 231 232 HRESULT Clone(IStream* ppstm) 233 { 234 // Cloned stream needs its own seek position. 235 return E_NOTIMPL; // ? 236 } 237 238 239 extern(D): 240 241 private: 242 DStream stm; 243 } 244 245 class MemoryIStream: DflComObject, dfl.internal.wincom.IStream 246 { 247 this(void[] memory) 248 { 249 this.mem = memory; 250 } 251 252 253 extern(Windows): 254 255 override HRESULT QueryInterface(IID* riid, void** ppv) 256 { 257 if(*riid == _IID_IStream) 258 { 259 *ppv = cast(void*)cast(dfl.internal.wincom.IStream)this; 260 AddRef(); 261 return S_OK; 262 } 263 else if(*riid == _IID_ISequentialStream) 264 { 265 *ppv = cast(void*)cast(dfl.internal.wincom.ISequentialStream)this; 266 AddRef(); 267 return S_OK; 268 } 269 else if(*riid == _IID_IUnknown) 270 { 271 *ppv = cast(void*)cast(IUnknown)this; 272 AddRef(); 273 return S_OK; 274 } 275 else 276 { 277 *ppv = null; 278 return E_NOINTERFACE; 279 } 280 } 281 282 283 HRESULT Read(void* pv, ULONG cb, ULONG* pcbRead) 284 { 285 // Shouldn't happen unless the mem changes, which doesn't happen yet. 286 if(seekpos > mem.length) 287 return S_FALSE; // ? 288 289 size_t count = mem.length - seekpos; 290 if(count > cb) 291 count = cb; 292 293 pv[0 .. count] = mem[seekpos .. seekpos + count]; 294 seekpos += count; 295 296 if(pcbRead) 297 *pcbRead = count; 298 return S_OK; 299 } 300 301 302 HRESULT Write(void* pv, ULONG cb, ULONG* pcbWritten) 303 { 304 //return STG_E_ACCESSDENIED; 305 return E_NOTIMPL; 306 } 307 308 309 HRESULT Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) 310 { 311 //cprintf("seek move=%u, origin=0x%x\n", cast(uint)dlibMove.QuadPart, dwOrigin); 312 313 auto toPos = cast(long)dlibMove.QuadPart; 314 switch(dwOrigin) 315 { 316 case STREAM_SEEK_SET: 317 break; 318 319 case STREAM_SEEK_CUR: 320 toPos = cast(long)seekpos + toPos; 321 break; 322 323 case STREAM_SEEK_END: 324 toPos = cast(long)mem.length - toPos; 325 break; 326 327 default: 328 return STG_E_INVALIDFUNCTION; 329 } 330 331 if(withinbounds(toPos)) 332 { 333 seekpos = cast(size_t)toPos; 334 if(plibNewPosition) 335 plibNewPosition.QuadPart = seekpos; 336 return S_OK; 337 } 338 else 339 { 340 return 0x80030005; //STG_E_ACCESSDENIED; // Seeking past end needs write access. 341 } 342 } 343 344 345 HRESULT SetSize(ULARGE_INTEGER libNewSize) 346 { 347 return E_NOTIMPL; 348 } 349 350 351 HRESULT CopyTo(IStream pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) 352 { 353 // TODO: implement. 354 return E_NOTIMPL; 355 } 356 357 358 HRESULT Commit(DWORD grfCommitFlags) 359 { 360 return S_OK; // ? 361 } 362 363 364 HRESULT Revert() 365 { 366 return E_NOTIMPL; // ? S_FALSE ? 367 } 368 369 370 HRESULT LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) 371 { 372 return E_NOTIMPL; 373 } 374 375 376 HRESULT UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) 377 { 378 return E_NOTIMPL; 379 } 380 381 382 HRESULT Stat(STATSTG* pstatstg, DWORD grfStatFlag) 383 { 384 return E_NOTIMPL; // ? 385 } 386 387 388 HRESULT Clone(IStream* ppstm) 389 { 390 // Cloned stream needs its own seek position. 391 return E_NOTIMPL; // ? 392 } 393 394 395 extern(D): 396 397 private: 398 void[] mem; 399 size_t seekpos = 0; 400 401 402 bool withinbounds(long pos) 403 { 404 if(pos < seekpos.min || pos > seekpos.max) 405 return false; 406 // Note: it IS within bounds if it's AT the end, it just can't read there. 407 return cast(size_t)pos <= mem.length; 408 } 409 } 410