2010-08-15 10 views
6

Byłem ekspertem C++ dekadę temu, ale przez ostatnie 10 lat programowałem Javę. Właśnie rozpocząłem projekt C++, który używa małego parsera XML innej firmy. Analizator składni XML akceptuje istnienie STL. Moje dane XML pochodzą z systemu IStream systemu Windows. Pomyślałem, że zrobię Right Thing i utworzę adapter, aby pobrać dane IStream i zaprezentować je parserowi XML za pośrednictwem istream.Jak zaimplementować seekg() dla niestandardowego istream/streambuf?

Podążyłem za doskonałym tutorialem pod numerem http://www.mr-edd.co.uk/blog/beginners_guide_streambuf i utworzyłem COMStreambuf, który pobiera dane z leżącego poniżej COM IStream, i użył go jako bufora dla niestandardowego COMIstream. Wszystko wygląda dobrze, ale dostaję błąd odczytu z analizatora składni.

Wyłącza analizator składni odczytuje cały plik do pamięci za pomocą funkcji seekg() na stronie głównej, aby ustalić jego rozmiar, a następnie powraca do początku za pomocą funkcji seekg(), aby przeczytać ją za jednym razem. Nic więc dziwnego, że wspomniany samouczek zdecydował się "zapisać [instrukcje dotyczące realizacji wyszukiwania] dla innego postu", który najwyraźniej nigdy nie został napisany.

Czy ktoś może mi powiedzieć, co muszę zrobić, aby zaimplementować seekg() z moim niestandardowym istream/streambuf? Zaryzykowałbym robienie tego samemu (moja pierwsza skłonność byłaby przesłonięciem rzeczy w istream), ale z moim brakiem doświadczenia to głęboko w STL i z moją mentalnością java, obawiam się, że zrobiłbym coś niekompletnego i ma kruche rozwiązanie. (Bez czytania samouczków, na przykład, nigdy bym nie zgadł, że jeden tworzy niestandardowy istream pisząc na przykład nowy streambuf lub że musiałbym nazywać imbue() z domyślnym locale, itp.)

Dzięki za pomoc. Byłem pod wielkim wrażeniem tej strony - zarówno ze znajomością uczestników, jak i ich przyjazną, uczciwą naturą w przyznawaniu, kto ma najlepszą odpowiedź. :)

Odpowiedz

3

Zakładam, że przez "seekg" masz na myśli seekoff i seekpos.

Prosta droga do wdrożenia członkach seekoff i seekpos twoich COMStreambuf jest zawinąć metodę interfejsu IStreamSeek. Na przykład, coś jak to powinno działać:

// 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_); 
} 

w tym wykazie, po ustawieniu pozycji streamIn nazywam:

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

Po poszukiwania, sputbackc lub sungetc będzie działać na starych danych. Możesz zastanowić się, czy ma to sens dla twojej aplikacji i zrobić coś innego.

+0

Co to jest 'gback()'? Czy chodziło Ci o 'eback()'? – 0x499602D2

+0

@ 0x499602D2: Tak. Dzięki za spostrzeżenie. –

Powiązane problemy