2010-08-15 5 views
6

J'ai été un expert en C++ il y a une dizaine d'années, mais depuis 10 ans je programme Java. Je viens de démarrer un projet C++ qui utilise un petit analyseur XML tiers. L'analyseur XML accepte un flux d'entrée STL. Mes données XML proviennent d'un IStream COM Windows. Je pensais que je ferais la bonne chose et créer un adaptateur pour prendre les données IStream et les présenter à l'analyseur XML à travers un istream.Comment implémenter seekg() pour un istream/streambuf personnalisé?

J'ai suivi l'excellent tutoriel au http://www.mr-edd.co.uk/blog/beginners_guide_streambuf et créé un COMStreambuf qui prend des données du COM IStream sous-jacent, et l'utilisait comme tampon pour un flux COMI personnalisé. Tout semble bien, mais je reçois une erreur de lecture de l'analyseur.

Il s'avère que l'analyseur lit le fichier entier en mémoire en utilisant seekg() sur l'istream pour connaître sa taille, puis revient au début avec seekg() pour le lire en une fois. Sans surprise, le tutoriel précité a décidé de "sauvegarder [les instructions sur la mise en œuvre de la recherche] pour un autre poste" qui n'a apparemment jamais été écrit. Quelqu'un peut-il me dire ce que je dois faire pour implémenter seekg() avec mon istream personnalisé/streambuf? Je m'aventurerais à le faire moi-même (mon premier penchant serait de surcharger des trucs dans l'istream), mais avec mon inexpérience si profonde dans le STL et avec ma mentalité Java je crains de faire quelque chose d'incomplet et d'avoir une solution fragile. (Sans lire les tutoriels, par exemple, je n'aurais jamais deviné que l'on fasse un istream personnalisé en écrivant un nouveau streambuf, par exemple, ou que j'aurais besoin d'appeler imbue() avec un locale par défaut, etc.)

Merci pour toute aide. J'ai été très impressionné par ce site --- à la fois avec la connaissance des participants et leur nature amicale et honnête en concédant qui a la meilleure réponse. :)

Répondre

3

Je suppose que par "seekg" vous voulez dire seekoff et seekpos.

La façon simple à mettre en œuvre les membres seekoff et seekpos de votre COMStreambuf est d'envelopper la méthode Seek de l'interface IStream. Par exemple, quelque chose comme cela devrait fonctionner:

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

Dans cette liste, après avoir réglé la position de streamIn j'appelle:

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

Après une recherche, sputbackc ou sungetc fonctionnera sur des données anciennes. Vous voudrez peut-être examiner si cela a un sens pour votre application et faire quelque chose de différent.

+0

Qu'est-ce que 'gback()'? Voulez-vous dire «eback()»? – 0x499602D2

+0

@ 0x499602D2: Oui. Merci d'avoir remarqué cela. –

Questions connexes