[C++] binaire file parsen

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • Sir Isaac
  • Registratie: September 2002
  • Laatst online: 21-05 20:45
Ik wil een binaire file parsen waarin een aantal strings als markers staat. Hiervoor gebruik ik de stringfuncties uit de C library. Dit omdat ik verderop grote hoeveelheden data moet verwerken.
Het gaat overigens om een avi file. Ik weet dat er voor het lezen van avi files genoeg bibliotheken zijn, maar ik heb niets kunnen vinden dat avi files met 16 bits grijswaarde video data aan kan. Ik lees de file daarom in als 8 bits unsigned chars.
Het probleem dat ik heb is dat de strstr functie 0x0 teruggeeft. Raden wat er gebeurt als je van dat adres gaat lezen :)
Dit is de code:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <fstream>
#include <cstring>

using namespace std;

int main()
{   ifstream file("/home/ik/video/1400raw.avi", ios::binary);
    char b[128];
    file.read(b, 128);
    char* p = strstr(b, "avih");
    if (!p)
    {   cerr << "Not found!" << endl;
        return(-1);
    }
    // lees de eerste vier byes vanaf "avih' in.
    char s[5];
    memcpy(p, s, 4);
    s[4] = '\0';
    cout << s;
    return(0);
}


Een dump van het begin van de binaire file:
code:
1
2
3
4
5
6
7
8
00000000  52 49 46 46 10 16 f9 15  41 56 49 20 4c 49 53 54  |RIFF....AVI LIST|
00000010  c0 04 00 00 68 64 72 6c  61 76 69 68 38 00 00 00  |....hdrlavih8...|
00000020  40 0d 03 00 00 00 00 00  00 00 00 00 10 01 00 00  |@...............|
00000030  96 00 00 00 00 00 00 00  01 00 00 00 00 00 00 00  |................|
00000040  00 05 00 00 c0 03 00 00  00 00 00 00 00 00 00 00  |................|
00000050  00 00 00 00 00 00 00 00  4c 49 53 54 74 04 00 00  |........LISTt...|
00000060  73 74 72 6c 73 74 72 68  38 00 00 00 76 69 64 73  |strlstrh8...vids|
00000070  59 31 36 20 00 00 00 00  00 00 00 00 00 00 00 00  |Y16 ............|


Ik krijg dus "Not found" te zien ipv "avih". Het ligt niet aan het al dan niet aanwezig zijn van een \o karakter in de string literal die ik zoek. Iemand een idee?

Acties:
  • 0 Henk 'm!

  • CoolGamer
  • Registratie: Mei 2005
  • Laatst online: 21-09 18:08

CoolGamer

What is it? Dragons?

Een string gebaseerd op een char-array eindigd bij de null-char (\0). strstr zoekt dus tot hij het gevonden heeft of een null-char tegenkomt. Hieronder komt hij duidelijk een null-char tegen (positie 12) voordat hij de string "avih" vind.

¸.·´¯`·.¸.·´¯`·.¸><(((º>¸.·´¯`·.¸><(((º>¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸<º)))><¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸


Acties:
  • 0 Henk 'm!

Verwijderd

De input is geen string. Gebruik dan ook geen str* functies maar de mem* functies, bijvoorbeeld memmem.

Wat beter is, is dat je een struct definieert met daarin de velden die je verwacht, als de gegevens tenminste elke keer op dezelfde plaats staan en dan in 1 keer een zooi bytes inlezen.

Wat er bij jou misgaat is dat er vóór "avih" al \0 voorkomt en daar houden str* functies er dus mee op.

[ Voor 14% gewijzigd door Verwijderd op 22-03-2009 17:22 ]


Acties:
  • 0 Henk 'm!

  • Sir Isaac
  • Registratie: September 2002
  • Laatst online: 21-05 20:45
Geweldig. Ik had zitten experimenteren met wel of geen \0 aan het einde van de string, maar zag de nullen voor avih over het hoofd. Mijn code werkt nu, bedankt!
Ik kom op het web verschillende pagina's tegen (inclusief die van glibc) waarop staat dat memmem() een gnu extentie is. Op de wikipedia pagina over string.h wordt memmem() ook niet genoemd. Is memmem() tegenwoordig een standaard functie?
Mooi voorbeeld van het nut van een goed forum.

Acties:
  • 0 Henk 'm!

Verwijderd

Voor zover ik weet is memmem geen standaard-functie, maar mocht je ooit op een platform komen dat die functie niet ondersteunt, dan kan je altijd nog zelf de functie implementeren. Het klinkt niet zo ontzettend ingewikkeld. Gewoon door de array heen lopen en checken of dat patroon voorkomt.

Acties:
  • 0 Henk 'm!

  • MrBucket
  • Registratie: Juli 2003
  • Laatst online: 29-10-2022
Verwijderd schreef op zondag 22 maart 2009 @ 21:35:
Voor zover ik weet is memmem geen standaard-functie, maar mocht je ooit op een platform komen dat die functie niet ondersteunt, dan kan je altijd nog zelf de functie implementeren. Het klinkt niet zo ontzettend ingewikkeld. Gewoon door de array heen lopen en checken of dat patroon voorkomt.
Maar als je de keuze hebt, zou ik vooral de variant uit de standaard libraries gebruiken, aangezien deze op assembly-niveau geoptimaliseerd zijn (bijv. door de loop niet uit te schrijven, maar assembly opcodes als REP SCASB te gebruiken)

Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 23:05
MrBucket schreef op zondag 22 maart 2009 @ 22:19:
Maar als je de keuze hebt, zou ik vooral de variant uit de standaard libraries gebruiken, aangezien deze op assembly-niveau geoptimaliseerd zijn (bijv. door de loop niet uit te schrijven, maar assembly opcodes als REP SCASB te gebruiken)
Dat hangt er waarschijnlijk maar net vanaf welke C library je gebruikt. De glibc implementatie (str-two-way.h) is behoorlijk ingewikkeld (maar garandeert lineaire tijd én constant geheugengebruik). NetBSD (memmem.c) en FreeBSD (memmem.c) gebruiken een naïef algoritme zoals DOT ook voorstelde (beide zijn geen GNU platforms trouwens). Geen van de drie implementaties gebruikt een assembly implementatie.

Conclusie: doe niet teveel (ongefundeerde ;)) aannames over hoe de C library geïmplementeerd is. Over het algemeen kun je er wel op vertrouwen dat de C library functies redelijk efficiënt zijn, dus het is in 99% van de gevallen zinnig om die gewoon te gebruiken, maar soms valt er wel wat te verbeteren.

Acties:
  • 0 Henk 'm!

Verwijderd

Soultaker schreef op zondag 22 maart 2009 @ 23:33:
Conclusie: doe niet teveel (ongefundeerde ;)) aannames over hoe de C library geïmplementeerd is. Over het algemeen kun je er wel op vertrouwen dat de C library functies redelijk efficiënt zijn, dus het is in 99% van de gevallen zinnig om die gewoon te gebruiken, maar soms valt er wel wat te verbeteren.
Mja, ik ben ook van het type: pas optimaliseren als de meer gebruikte code geoptimaliseerd is. Het is nogal zonde om je tijd te besteden aan het bedenken en implementeren van het perfecte string-match algoritme als je 'm maar een paar keer aanroept. Hier wordt-ie 1 keer aangeroepen en doettie zo'n 20 keer een memcmp. Dan is het echt zonde van je tijd.

Acties:
  • 0 Henk 'm!

  • Sir Isaac
  • Registratie: September 2002
  • Laatst online: 21-05 20:45
In ieder geval lijken dietlibc en ulibc een memmem functie te hebben, tenminste als ze met de juiste opties worden gecompileerd. Dan de ham vraag: hebben Dinkum/MS en Intel deze gnu-extentie overgenomen?
Omdat de bovenstaande vooralsnog deel uitmaakt van een octave extentie voor eigen (professioneel) gebruik, ga ik niet aan de slag met het zelf inplementeren van een memmem functie.
Pagina: 1