IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage C++ Discussion :

Parser un flux binaire


Sujet :

Langage C++

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2004
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2004
    Messages : 66
    Points : 37
    Points
    37
    Par défaut Parser un flux binaire
    Bonjour,

    Je voudrai parser un flux binaire qui peut etre l'entrée standard un fichier ou une file (mkfifo).

    Dans ce flux, il y a des syncword (0x000001) qu'il faut que j'intercepte pour traiter les quelques octets suivants, ces syncword ont un espacement non-fixe qui peut être entre 5 octets et plusieurs Mo.

    j'ai essayé de mettre en place un système de buffer dans lequel je recherche le syncword. Seulement dans ce buffer il peut très bien n'y en avoir aucun comme plusieurs dizaines.

    j'ai testé naïvement ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    int search(const std::vector<char> &word, const uint start_pos)
    {
        if( (start_pos >= m_buffer_size) || (start_pos >= m_stream->gcount()) )
            return -1;
     
        std::vector<char>::iterator it;
        it = std::search(m_buffer.begin()+start_pos, m_buffer.begin()+m_buffer_size, word.begin(), word.end());
     
        if( it != m_buffer.end() )
            return (it-m_buffer.begin());
        else
            return -1;
    }
    Ou start_pos est utilisé en pour décaler la recherche dans le buffer.
    Cela fonctionne plutôt pas mal seulement je ne sais pas comment gérer de manière élégante le cas ou un syncword se retrouve à la fin du buffer, aux 3 derniers octets par exemple, si je veux pouvoir traiter les octets suivants je dois a nouveau remplir le buffer.

    Si quelqu’un connaît une solution élégante pour ce genre de choses

    ps: impossible d'utiliser du C++11 ou supérieur ainsi que boost

  2. #2
    Membre émérite
    Avatar de skeud
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2011
    Messages
    1 091
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 1 091
    Points : 2 724
    Points
    2 724
    Billets dans le blog
    1
    Par défaut
    Personnellement j'aurais fait de cette manière:

    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    std::vector<std::vector<char>> parse(std::vector<char> buffer, char separator)
    {
      // vector de tampon
      std::vector<char> tmp;
      // structure de retour
      std::vector<std::vector<char>> ret;
      // iterator sur notre buffer
      std::vector<char>::iterator it = buffer.begin();
      // Tant qu'on a pas parcouru tout le buffer
      while (it != buffer.end())
      {
         // Si l'element actuel est un séparateur
         if ((*it) == separator)
         {
            // On rajoute notre partie sauvegardée
            ret.push_back(tmp);
            // On flush le tampon
            tmp.clear();
         }
         else
         {
           // Sinon on rajoute l'élément actuel dans notre tampon
           tmp.push_back((*it));
         }
         // On passe à l'élément suivant
         it++;
      }
      return (ret);
    }

    Bien sur ce code peut être optimisé via les find etc ...
    Mais c'était pour montrer le principe.
    Pas de solution, pas de probleme

    Une réponse utile (ou +1) ->
    Une réponse inutile ou pas d'accord -> et expliquer pourquoi
    Une réponse à votre question


  3. #3
    Membre éclairé
    Avatar de Ekleog
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2012
    Messages
    448
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2012
    Messages : 448
    Points : 879
    Points
    879
    Par défaut
    Il me semble que ce n'est pas ce qui est demandé : tu sépares le flux aux syncwords, alors que l'OP me semble demander comment récupérer les N octets qui suivent chaque syncword.

    Déjà, pour récupérer tous les syncwords (et les octets qui les suivent), il "suffit" de faire une boucle. Ensuite, le cas compliqué est lorsque le syncword se retrouve à la fin du buffer.

    À ce moment, il me semble qu'il y a une possibilité plus élégante que les autres : utiliser un buffer de taille triple, et les remplir alternativement, afin de récupérer naturellement la suite.

    En encapsulant tout ça, ça donne plus ou moins (non testé) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    template <unsigned int Size> class pseudo_round_buffer {
      char buffer_[Size * 3];
      char step_ = 0;
    public:
      pseudo_round_buffer(std::istream &is) {
        fill(is, 0); fill(is, 1); step_ = 0;
      }
      void fill(std::istream &is, char step = -1) {
        if (step == -1) step = step_;
        is.read(buffer_ + step * Size, Size);
        step_ = (step_ + 1) % 3;
      }
      char operator[](unsigned int i) const {
        return buffer_[i + step_ * Size];
      }
      // etc...
    };
    Avec ça, tu as déjà de quoi faire en recodant toi-même l'équivalent de find() : tu initialises le triple buffer en lisant deux buffers de is ; puis tu traites le premier buffer en t'autorisant à piocher dans le deuxième buffer si il y a un sycword vers la fin. Lorsque ta recherche a atteint la fin du premier buffer (ie. [Size]), tu lis un autre buffer en appelant fill ; puis tu traites le deuxième buffer (les indices partent à nouveau de 0) en t'autorisant à nouveau à piocher dans la suite.

    Au moment où tu ne peux plus remplir un buffer à fond (ie. vérifier que is.gcount() < Size), il faudra prendre garde à ne pas dépasser la taille du buffer, en cas de fichier mal formé où le syncword ne serait pas suivi des N octets qu'il est censé indiquer.

    Dernière chose à noter : Avec un système comme celui-ci, il faut bien que Size soit supérieur au nombre d'octets que tu peux avoir besoin de prévisualiser après un syncword, afin de ne pas dépasser le buffer de look-ahead (ie. le deuxième).

    En espérant avoir répondu à la bonne question,

    Ekleog

Discussions similaires

  1. [SimpleXML] Parser un flux xml avec SimpleXMLElement
    Par DeezerD dans le forum Bibliothèques et frameworks
    Réponses: 2
    Dernier message: 22/11/2006, 18h07
  2. [C#] Comment parser un flux XML ?
    Par Dunkan dans le forum C#
    Réponses: 1
    Dernier message: 22/09/2006, 13h32
  3. Parser un flux XML
    Par Paulux1 dans le forum XML/XSL et SOAP
    Réponses: 1
    Dernier message: 31/07/2006, 09h07
  4. parser un flux xml provenant d'une anim flash
    Par pyd001 dans le forum Langage
    Réponses: 3
    Dernier message: 11/07/2006, 10h43

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo