Fichier d’parsing UNIX C

J’ai un format de fichier binary avec en-tête et corps. Les champs d’en-tête et le nombre d’octets pour chacun d’entre eux sont

  1. Magie: 1
  2. Header_size: 2
  3. Version 1
  4. No_of_sections: 1
  5. Section_headers: No_of_sections * sizeof (section_header) En-tête de section: 17 + 4 + 4 + 4 Sect_name: 17; Sect_type: 4; Sect_offset: 4; Sect_size: 4

Je dois vérifier certaines ressortingctions et imprimer ceci

version= nr_sections= section1:    

Ressortingctions:

  1. La valeur du champ magique doit être ‘Q’
  2. Les valeurs de la version du fichier doivent être comsockets entre 41 et 67, y compris les valeurs correspondantes.
  3. Le nombre de sections doit être compris entre 3 et 10, y compris les valeurs correspondantes.
  4. Le type de sections existant doit être seulement 44 68 35

J’ai fait la partie magie et version, mais je ne peux pas faire la partie section, elle imprime toujours des caractères.

Je sais que mon code est vraiment compliqué. Désolé 🙁

 void parse(const char *path) { int fd; unsigned char c[17]; char name[17]; int type; off_t size; fd = open(path, O_RDONLY); size= lseek(fd,0,SEEK_END); lseek(fd,0,SEEK_SET); for(int i = 0 ; i <=size; i++) { lseek(fd,0,SEEK_CUR); read(fd,&c,1); if(i==0) if(c[0]=='Q') printf("SUCCESS\n"); if(i=')' && c[0]<='C') printf("version=%d \n", c[0]); } lseek(fd,5,SEEK_SET); for(int j=1; j<10; j++) { read(fd, &name, 17); name[17]='\0'; read(fd, &type, 4); printf("section%d: %s %d\n", j + 1, name, type); } } 

Le second pour shoud be

 for(int j =1;j<=no_of_section;j++) 

mais je ne connais pas le nr_of_section 🙁 Ma sortie

 SUCCESS version=46 section2: fJ00pYisvmveDqS 44 section3: V 1515418709 section4: fRo 2054764888 section5: e6NpWyIifXZ -1392508919 section6: 738197570 section7: 1247047749 section8: J5ArY 1985282048 section9: 707OpGRoR8l9Yen# 381353984 section10: 2053662817 

Le résultat devrait être:

  SUCCESS version=46 nr_sections=7 section1: fJ00pYisvmveDqS 44 1016 section2: LLSWA0rSmUtSZfRo 44 890 section3: lX9yze6NpWyIifXZ 44 941 section4: de0cLp2V907jC9B 44 1178 section5: JrUrWEEpTJJ5ArY 68 724 section6: Uv707OpGRoR8l9Yen 35 1014 section7: BOWdKpZwrBaahhzz 44 972 

Exemple de fichier binary (il ne comprend que l’en-tête et 2 sections)

    Révision de votre code

    Il y a beaucoup de choses qui ne vont pas avec votre code. Passons par là:

     void parse(const char *path) { int fd; unsigned char c[17]; char name[17]; int type; off_t size; fd = open(path, O_RDONLY); 

    Vous n’avez pas vérifié si l’appel à open() réussi. S’il y a une erreur, fd sera -1 . Assurez-vous de vérifier et de gérer correctement ce cas.

      size= lseek(fd,0,SEEK_END); 

    De même, lseek() peut renvoyer une erreur. Certains fichiers peuvent ne pas être recherchés. Vous pouvez probablement éviter de devoir déterminer la taille du fichier, voir ci-dessous.

      lseek(fd,0,SEEK_SET); for(int i = 0 ; i <=size; i++) { 

    Si la size est de type off_t , il vaut mieux que i off_t également.

      lseek(fd,0,SEEK_CUR); 

    Cet appel ne fait rien! Pourquoi est-ce même ici?

      read(fd,&c,1); 

    Encore une fois, vous ne vérifiez pas la valeur de retour de read() . Il pourrait y avoir une erreur de lecture ou le fichier pourrait être plus petit que prévu. Vérifiez que la valeur de retour n'est pas -1 et qu'elle est la longueur attendue ( 1 ).

      if(i==0) if(c[0]=='Q') printf("SUCCESS\n"); 

    Cela ressemble à une tentative d'implémenter le modèle de commutateur de boucle . S'il vous plaît ne faites pas cela. Si vous voulez lire le premier octet et le traiter spécialement, ne le mettez pas en boucle.

      if(i<5 && c[0]>=')' && c[0]<='C') printf("version=%d \n", c[0]); 

    Vous dites ici que chacun des deuxième à cinquième octets du fichier doit être compris entre ')' et 'C' . Mais d'après votre description, ce n'est pas ce que vous voulez. Au lieu de cela, vous devriez lire deux octets (longueur d'en-tête), un octet (version) et un autre octet (nombre de sections). Faites cela sans une boucle for.

      } 

    Après le cinquième octet, votre boucle for ne fait que lire des octets pour rien.

      lseek(fd,5,SEEK_CUR); 

    Après avoir lu les octets de size , vous essayez maintenant d'ignorer cinq octets supplémentaires de la position actuelle, ce qui signifie que vous voulez passer 5 octets au-delà de la fin du fichier.

      for(int j=1; j<10; j++) { 

    Si vous lisez correctement le nombre de sections, vous pouvez l'utiliser au lieu de coder en dur le 10 . Aussi, êtes-vous sûr de vouloir commencer avec j = 1 ?

      read(fd, &name, 17); 

    Encore une fois, vérifiez la valeur de retour.

      name[17]='\0'; 

    Oups, c'est un buffer overflow! Vous avez déclaré que le name ne contient que 17 octets, et maintenant vous écrivez au dix-huitième.

      read(fd, &type, 4); 

    Êtes-vous sûr que ce type est suffisamment grand pour contenir 4 octets? En C, un int a une taille dépendante de la plate-forme. Bien sûr, 4 octets pour un int est commun, mais il est préférable d'utiliser int32_t si vous voulez vraiment un int de quatre octets.

      printf("section%d: %s %d\n", j + 1, name, type); 

    Comme vous commencez avec j=1 , la première ligne imprimée commencera par section2:

      } } 

    Chemin proposé

    La première chose à faire est d'essayer d'parsingr correctement l'en-tête. Assurez-vous d'avoir lu le nombre de sections dans l'en-tête, vous n'avez donc pas besoin de connaître la taille du fichier et / ou de coder des nombres. Ne pas utiliser lseek() . Ne vous préoccupez pas du rest du fichier tant que votre code ne gère pas l'en-tête.

    Une fois que tous les éléments de l'en-tête ont été analysés correctement, vous pouvez commencer à lire les sections qui suivent l'en-tête. Encore une fois, chaque section a un en-tête, donc commencez par parsingr correctement l'en-tête de section. Chaque en-tête de section a une valeur indiquant la longueur de la section et un décalage. Stockez-les dans un tableau.

    Maintenant que vous avez analysé les en-têtes de section, vous pouvez accéder aux données réelles. Vous devriez probablement maintenant utiliser lseek() pour accéder aux décalages du fichier mentionné dans les en-têtes de section, puis read() autant d'octets que la taille de la section.

    Comme @G. Sliepen a déjà mentionné que votre code contient de nombreux bogues.

    De mon commentaire, vous avez maintenant remplacé lseek(fd,5,SEEK_CUR); par lseek(fd,5,SEEK_SET); .

    Ainsi, le résultat de la première sortie est correct. Mais pour le 2., 3. et ainsi de suite, la sortie est fausse.

    Dans votre description du format binay que vous avez écrit

    1. Sect_name: 17
    2. Sect_type: 4
    3. Sect_offset: 4
    4. Sect_size: 4

    Mais dans le code de votre boucle, vous ne lisez que Sect_name et Sec_type . Maintenant, vous devez soit ignorer 8 octets (pour Sect_offset et Sect_size ), soit le lire. Sinon, vous obtiendrez le résultat comme vous l’avez déjà vu.