2010-08-15 15 views
6

十年前,我曾經是一名C++專家,但在過去的10年中,我一直在編寫Java。我剛開始使用小型第三方XML解析器的C++項目。 XML解析器接受STL istream。我的XML數據來自Windows COM IStream。我認爲我會做正確的事情,並創建一個適配器來接收IStream數據,並通過istream將其呈現給XML解析器。如何爲自定義istream/streambuf實現seekg()?

我按照http://www.mr-edd.co.uk/blog/beginners_guide_streambuf的優秀教程創建了一個COMStreambuf,它從底層COM IStream獲取數據,並將其用作自定義COMIstream的緩衝區。一切看起來不錯,但我從解析器中得到一個讀取錯誤。

原來,解析器通過在istream上使用seekg()來查找其大小,然後用seekg()一次性讀取它,從而將整個文件讀入內存。不出所料,上述教程決定「保存另一篇文章的[實施求職指導]」,這顯然從未寫過。

有人能告訴我我需要做什麼來實現seekg()與我的自定義istream/streambuf?我會冒昧地自己做(我的第一個傾向是重寫istream中的東西),但是由於我在STL中缺乏深入的經驗,並且憑藉我的Java心態,我擔心我會做一些不完整的事情並且有一個脆弱的解決方案。 (例如,在沒有閱讀教程的情況下,例如,我從來不會想到通過編寫新的streambuf來創建自定義istream,或者我需要使用默認語言環境調用imbue()等)。

謝謝你的幫助。我對這個網站印象非常深刻 - 既有參與者的知識,又有友善,誠實的性格,承認誰擁有最好的答案。 :)

回答

3

我假設「seekg」的意思是seekoffseekpos

直截了當的方式來實現成員的你COMStreambuf是包裹IStream接口的Seek方法seekoffseekpos。例如,這樣的事情應該工作:

// COMStreambuf.cpp 
COMStreambuf::pos_type COMStreambuf::seekoff(COMStreambuf::off_type off_, std::ios_base::seekdir way_, std::ios_base::openmode which_) 
{ 
    union { 
     LARGE_INTEGER liMove; 
     ULARGE_INTEGER uliMove; 
    }; 
    liMove.QuadPart = off_; 

    DWORD dwOrigin = STREAM_SEEK_SET; 
    if (way_ == std::ios_base::cur) { 
     dwOrigin = STREAM_SEEK_CUR; 
    } else if (way_ == std::ios_base::end) { 
     dwOrigin = STREAM_SEEK_END; 
    } else { 
     assert(way_ == std::ios_base::beg); 
     dwOrigin = STREAM_SEEK_SET; 
     uliMove.QuadPart = off_; 
    } 

    ULARGE_INTEGER uliNewPosition; 
    if (which_ & std::ios_base::in) { 
     if (which_ & std::ios_base::out) 
      return pos_type(off_type(-1)); 
     HRESULT hres = streamIn->Seek(liMove, dwOrigin, &uliNewPosition); 
     if (hres != S_OK) 
      return pos_type(off_type(-1)); 

     setg(eback(), egptr(), egptr()); 
    } else if (which_ & std::ios_base::out) { 
     HRESULT hres = streamOut->Seek(liMove, dwOrigin, &uliNewPosition); 
     if (hres != S_OK) 
      return pos_type(off_type(-1)); 

     setp(pbase(), epptr(), epptr()); 
    } else { 
     return pos_type(off_type(-1)); 
    } 

    return pos_type(uliNewPosition.QuadPart); 
} 

COMStreambuf::pos_type COMStreambuf::seekpos(COMStreambuf::pos_type sp_, std::ios_base::openmode which_) 
{ 
    return seekoff(off_type(sp_), std::ios_base::beg, which_); 
} 

在這個清單中,設定的streamIn我所說的位置後:

setg(eback(), egptr(), egptr()); 

經過尋找,sputbackcsungetc將舊數據進行操作。您可能需要考慮這是否對您的應用程序有意義,並採取不同的行動。

+0

什麼是'gback()'?你的意思是'eback()'? – 0x499602D2 2014-01-20 19:29:49

+0

@ 0x499602D2:是的。感謝您發現這一點。 – 2014-01-22 14:01:44