1 // Copyright (c) 2011 The Chromium 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 #ifndef CHROME_FRAME_URLMON_BIND_STATUS_CALLBACK_H_ 6 #define CHROME_FRAME_URLMON_BIND_STATUS_CALLBACK_H_ 7 8 #include <atlbase.h> 9 #include <atlcom.h> 10 11 #include "base/memory/scoped_ptr.h" 12 #include "chrome_frame/bind_status_callback_impl.h" 13 #include "chrome_frame/stream_impl.h" 14 15 16 // A fake stream class to serve cached data to arbitrary 17 // IBindStatusCallback 18 class CacheStream : public CComObjectRoot, public StreamImpl { 19 public: 20 BEGIN_COM_MAP(CacheStream) 21 COM_INTERFACE_ENTRY(IStream) 22 COM_INTERFACE_ENTRY(ISequentialStream) 23 END_COM_MAP() 24 25 CacheStream() : size_(0), position_(0), eof_(false) { 26 } 27 HRESULT Initialize(const char* cache, size_t size, bool eof); 28 static HRESULT BSCBFeedData(IBindStatusCallback* bscb, const char* data, 29 size_t size, CLIPFORMAT clip_format, 30 size_t flags, bool eof); 31 32 // IStream overrides 33 STDMETHOD(Read)(void* pv, ULONG cb, ULONG* read); 34 35 protected: 36 scoped_ptr<char[]> cache_; 37 size_t size_; 38 size_t position_; 39 bool eof_; 40 41 private: 42 DISALLOW_COPY_AND_ASSIGN(CacheStream); 43 }; 44 45 // Utility class for data sniffing 46 class SniffData { 47 public: 48 SniffData() : renderer_type_(OTHER), size_(0), eof_(false) {} 49 50 enum RendererType { 51 UNDETERMINED, 52 CHROME, 53 OTHER 54 }; 55 56 HRESULT InitializeCache(const std::wstring& url); 57 HRESULT ReadIntoCache(IStream* stream, bool force_determination); 58 HRESULT DrainCache(IBindStatusCallback* bscb, DWORD bscf, 59 CLIPFORMAT clip_format); 60 void DetermineRendererType(bool last_chance); 61 62 bool is_undetermined() const { 63 return (UNDETERMINED == renderer_type_); 64 } 65 bool is_chrome() const { 66 return (CHROME == renderer_type_); 67 } 68 69 RendererType renderer_type() const { 70 return renderer_type_; 71 } 72 73 size_t size() const { 74 return size_; 75 } 76 77 bool is_cache_valid() { 78 return (size_ != 0); 79 } 80 81 base::win::ScopedComPtr<IStream> cache_; 82 std::wstring url_; 83 RendererType renderer_type_; 84 size_t size_; 85 86 static const size_t kMaxSniffSize = 2 * 1024; 87 bool eof_; 88 89 private: 90 DISALLOW_COPY_AND_ASSIGN(SniffData); 91 }; 92 93 // A wrapper for bind status callback in IMoniker::BindToStorage 94 class BSCBStorageBind : public BSCBImpl { 95 public: 96 typedef BSCBImpl CallbackImpl; 97 BSCBStorageBind(); 98 ~BSCBStorageBind(); 99 100 BEGIN_COM_MAP(BSCBStorageBind) 101 COM_INTERFACE_ENTRY(IBindStatusCallback) 102 COM_INTERFACE_ENTRY_CHAIN(CallbackImpl) 103 END_COM_MAP() 104 105 HRESULT Initialize(IMoniker* moniker, IBindCtx* bind_ctx); 106 HRESULT MayPlayBack(DWORD flags); 107 108 // IBindStatusCallback 109 STDMETHOD(OnProgress)(ULONG progress, ULONG progress_max, ULONG status_code, 110 LPCWSTR status_text); 111 STDMETHOD(OnDataAvailable)(DWORD flags, DWORD size, FORMATETC* format_etc, 112 STGMEDIUM* stgmed); 113 STDMETHOD(OnStopBinding)(HRESULT hresult, LPCWSTR error); 114 115 protected: 116 // is it a good time to start caching progress notifications 117 bool ShouldCacheProgress(ULONG status_code) const; 118 119 protected: 120 SniffData data_sniffer_; 121 122 // A structure to cache the progress notifications. 123 class Progress { 124 public: 125 Progress(ULONG progress, ULONG progress_max, ULONG status_code, 126 const wchar_t* status_text) 127 : progress_(progress), 128 progress_max_(progress_max), 129 status_code_(status_code) { 130 if (status_text) { 131 int len = lstrlenW(status_text) + 1; 132 status_text_.reset(new wchar_t[len]); 133 if (status_text_.get()) { 134 lstrcpynW(status_text_.get(), status_text, len); 135 } else { 136 NOTREACHED(); 137 } 138 } 139 } 140 141 ~Progress() { 142 } 143 144 ULONG progress() const { 145 return progress_; 146 } 147 148 ULONG progress_max() const { 149 return progress_max_; 150 } 151 152 ULONG status_code() const { 153 return status_code_; 154 } 155 156 const wchar_t* status_text() const { 157 return status_text_.get(); 158 } 159 160 protected: 161 ULONG progress_; 162 ULONG progress_max_; 163 ULONG status_code_; 164 // We don't use std::wstring here since we want to be able to play 165 // progress notifications back exactly as we got them. NULL and L"" are 166 // not equal. 167 scoped_ptr<wchar_t[]> status_text_; 168 }; 169 170 typedef std::vector<Progress*> ProgressVector; 171 ProgressVector saved_progress_; 172 CLIPFORMAT clip_format_; 173 174 private: 175 DISALLOW_COPY_AND_ASSIGN(BSCBStorageBind); 176 }; 177 178 #endif // CHROME_FRAME_URLMON_BIND_STATUS_CALLBACK_H_ 179