[gelöst]Binary File wird nicht geöffnet :'(



  • Soweit so schlecht... 😃
    Mein Programm findet kein ffc0! o:
    Woran liegt das wohl?

    #include <iostream>
    #include <fstream>
    
    using namespace std;
    
    int main(int argc,char *argv[])
    {
    	char xSize[2];
    	char ySize[2];
    	char pattern[] = {0xff,0xc0};
        string linebuf;
    	ifstream oImage("C:\\colors2.JPG",ios::binary);
    	if(oImage)
    	{
            while(!oImage.eof())
            {
                getline(oImage,linebuf);
                if(int pos = linebuf.find(pattern) != -1)
                {
                    cout << "FFC0 found at " << pos << endl;
                    break;
                }
            }
            cout << "Couldn't find FFC0!" << endl;
            oImage.close();
        }
        else
        {
            cout << "Failed to open file!";
        }
    }
    


  • Okay, wenn du nur ein paar Headerinformationen haben möchtest, reicht es natürlich, immer wieder einzelne Zeichen aus der Datei zu lesen und abbrechen, wenn alles gefunden wurde. Anders sähe es natürlich aus, wenn du komplett dekodieren möchtest.

    bool bFound = false;
    char c;
    while(!oImage.eof() && !bFound)
    {
    	oImage.get(c);
    	if((BYTE)c!=0xFF)
    		continue;
    	oImage.get(c);
    	unsigned int i = ((BYTE)c) & 0xFF;
    	switch(i)
    	{
    		case 0xD8:
    			cout << "found start marker!"<<endl;
    			break;
    		case 0xC0:
    		{
    			const streampos offset = 3;
    			oImage.seekg(oImage.tellg()+offset);
    			ySize = GetWord(oImage);
    			xSize = GetWord(oImage);
    			cout << "w: "<< xSize << " , h: " << ySize << endl;
    			bFound = true;
    			break;
    		}
    		default:
    		{	const streampos offset = 2;
    			sValue = GetWord(oImage);
    			oImage.seekg(oImage.tellg()+(long)sValue-offset);
    			break;
    		}
    	}
    }
    

    Es wird zeichenweise eingelesen, überprüft ab der Wert 0xFF ist, wenn nein, wird einfach weitergemacht.
    Im default-Zweig wird die Größe gelesen und der Filepointer neu gesetzt (-2!).
    Für soetwas würde ich normalerweise die OS-Fkt. ReadFile nehmen, mit der man direkt in einen unsigned short lesen kann*. Naja, so gehts auch:

    unsigned short GetWord(ifstream& in)
    {
    	char c;
    	unsigned short s;
    	in.get(c);
    	s=(BYTE)c;
    	s<<=8;
    	in.get(c);
    	s|=(BYTE)c;
    	return s;
    }
    

    Es könnten natürlich Fehler drin stecken, ich habs gerade nur mit 2 Bildern probiert.

    * Mit einem ifstream gehts vielleicht auch, binär lese ich damit jedoch sonst nie.

    Edit: Ach ja die Casts kannste ja noch mal überarbeiten 😃



  • Ich hätte noch schreiben sollen, was bei deinem Code nicht passt. Du liest die Datei binär, ein getline ist deshalb zwecklos.
    Grundsätzlich ist das Lesen von fremden Dateiformaten keine schöne Angelegenheit. Du solltest dir einen Hex-Editor herunterladen und die Dateien analysieren (ich nutze http://www.softpedia.com/get/Others/Miscellaneous/tiny-hexer.shtml [windows]). Als wirklich gute Übung kannst du dir mal das Exif-Format anschauen und einen Tagger bauen 😉



  • Okay, durch deine ausführliche Antwort wurde mir hier einiges klar, allerdings bin ich mir bei deiner GetWord-Funktion noch unsicher...

    unsigned short GetWord(ifstream& in)
    {
        char c;
        unsigned short s;
        in.get(c);
        s=(BYTE)c;
        s<<=8;  //Diese Operation versteh ich nich. ^^
        in.get(c);
        s|=(BYTE)c; //Das íst mir auch noch unklar.
        return s;
    }
    

    Trotzdem vielen Dank und dickes Lob für die Ausführlichkeit 🙂



  • char = 8b it
    unsined short = 16 bit

    in.getc(c = 00110011)

    unsigned short = c
    00000000 00110011

    unsigned short << 8
    00110011 00000000

    in.getc(c = 10101010)

    unsigned short |= c
    00110011 00000000
    10101010
    -----------------
    00110011 10101010

    Stichwort: bitweise Operatoren, shiften

    http://www.cplusplus.com/doc/tutorial/operators/ weit unten



  • Klappte denn das Einlesen der Werte bei dir?
    Ein 16 Bit Wert ist folgendermaßen aufgebaut.

    16 Bit
    Hi                      Low
    15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
    

    Hi und Low sind zwei 8 Bit Werte. Wenn jetzt sizeof(BYTE) 1 ist, kann man Folgendes machen:

    s=(BYTE)c; // Low wird geschrieben
    s<<=8;  // bedeutet s = s<<8; es ist eben ein Linksshift um 8 Stellen,
            // dabei wird ausgenutzt, dass von rechts Nullen nachgeschoben werden.
            // Hi ist nun durch den Wert in Low besetzt, Low wird null (alle Bits von 07-00)
    s|=(BYTE)c; // hier hätte man auch s+=(BYTE)c schreiben können, die unteren 8 Bit 
                // werden geschrieben und der komplette 16 Bit Wert ist konstruiert
    


  • Ja, das einlesen der Werte hat funktioniert!
    Danke für die Erklärung der Operatoren 🙂
    Also wir brauchten 16 Bit um den Wert zu speichern, deswegen lesen wir die ersten 8 aus, dann machen wir einen linksshift, um "Platz" zu machen und dann addieren wir die restlichen 8 Bit auf die Variable?



  • Nimm die "magic number" eines jpgs.

    FFD8 einlesen
    BYTE einlesen -> FF
    unsigned short s = FF LOBYTE(s)=FF, HIBYTE(s)=0
    s<<=8; // HIBYTE(s)=FF, LOBYTE(s)=0
    nächstes BYTE einlesen -> D8
    s|=D8 // HIBYTE(s)=FF, LOBYTE(s)=D8, also s=FFD8
    

    Edit: Es geht hier nicht um "Platz schaffen", sondern darum, den Wert richtig abzuspeichern. Du brauchst bspw. die Breite des Bildes. Wenn diese größer als 255 (0xFF) ist, dann werden beide Bytes benötigt.



  • So, wieder eine Menge verstanden, wieder ein Problem o:
    Ich erstelle eine Struct um Werte aus einer ZIP Datei zu lesen. Gemäß diesem Modell von Wikipedia(http://en.wikipedia.org/wiki/ZIP_%28file_format%29#File_headers)
    Meine Struct sieht dementsprechend aus:

    struct zipRecord{               //Structure of file records
        char frSignature[4];
        unsigned short frVersion;
        unsigned short frFlags;
        unsigned short frCompression;
        unsigned short frFileTime;
        unsigned short frFileDate;
        unsigned int frCRC;
        unsigned int frCompressedSize;
        unsigned int frUncompressedSize;
        unsigned short frFileNameLength;
        unsigned short frExtraFieldLength;
    };
    

    Dann überprüfe ich ob es sich um eine zip datei handelt indem ich den Signaturwert auswerte, das funktioniert auch prächtig...
    Dannach versuche ich den CRC Wert zu ermitteln indem ich die Werte in die Struct lese und dann auf frCRC zugreife.

    zipRecord oRecord
    in.seekg(0,ios::beg);
    in.read((char*)&oRecord,sizeof(oRecord));
    printf("CRC Checksumme: %X \n",oRecord.frCRC);
    

    Der Wert in der Datei ist FFE73F0C, der Wert der ausgelesen wird ist allerdings 52FFE7....
    Alle Werte vor frFileTime sind auch korrekt, nur dannach stimmt nichts mehr o:
    Ich habe auch mal mit sizeof(oRecord) die größe der Struct analysiert, ich erwartete 30 Bytes, raus kamen allerdings 32, das würde die Verschiebung der Werte erklärung, aber wo bleiben sind die anderen 2 Bytes versteckt? Die Summe der Dateitypgrößen ist 30, das steht fest.
    Ich bitte nochmals um Hilfe,
    Xdab4yaX



  • push...



  • Im Hexeditor siehst du die Werte, wie sie tatsächlich im Speicher stehen. Du musst aber auf Systemen mit little endian eine Konvertierung durchführen.

    w1H W1L W2H W2L
    ->
    W2L W2H W1L W1H
    und
    WH WL
    ->
    WL WH
    

    Das heisst, sowohl die beiden Words als auch die Bytes in den Words werden getauscht.
    Manchmal ist es notwendig, eine Konvertierung durchzuführen. Bspw. unterstützt das Exif-Format sowohl big- als auch little endian. Dann muss man sich eben so etwas schreiben:

    void SwapBytes(unsigned int* pi)
    {
    	unsigned int i = *pi;
    	unsigned int ui;
    	ui = (i) & 0xFF;
    	ui<<=8;
    	ui|= (i>>8) & 0xFF;
    	ui<<=8;
    	ui|= (i>>16) & 0xFF;
    	ui<<=8;
    	ui|= (i>>24) & 0xFF;
    	*pi = ui;
    }
    void SwapBytes(unsigned short* ps)
    {
    	unsigned short s = *ps;
    	unsigned short us;
    	us = (s) & 0xFF;
    	us<<=8;
    	us|= (s>>8) & 0xFF;
    	*ps = us;
    }
    

    Dies führt die Konvertierung durch.
    Bspw. ist die Zip Signatur im Speicher 0x504B0304 und nicht 0x04034B50.



  • Gut. Jetzt siehts hier so aus:

    SwapBytes(&oRecord.frCRC);
    printf("CRC Checksumme: %X\n",oRecord.frCRC);
    

    Ausgabe:
    CRC Checksumme: E7FF5200

    Das stimmt immer noch nicht 😃
    Aber da nach der CRC Summe die CompressedSize kommt und diese bei mir 0x52(82) groß ist, nehme ich an, dass die 4 Bytes der Compressed Size in meine CRC Checksumme mit reingerutscht sind. Warum das? o:



  • Ich hatte ja geschrieben, dass SwapBytes aufgerufen werden kann, um die Variablen mit den Werten im Hexeditor einfacher zu vergleichen. Die Werte sind _ohne_ den Aufruf natürlich richtig.
    Und ja, zum falschen Einlsen:

    struct zipRecord{               //Structure of file records
        char frSignature[4]; // 4 Bytes
        unsigned short frVersion; // 6
        unsigned short frFlags; // 8
        unsigned short frCompression; // 10
        unsigned short frFileTime; // 12
        unsigned short frFileDate; // 14  -> 14%4!=0-> der Compiler schiebt hier 2 Bytes ein
        unsigned int frCRC;
        unsigned int frCompressedSize;
        unsigned int frUncompressedSize;
        unsigned short frFileNameLength;
        unsigned short frExtraFieldLength;
    };
    

    In den Standardeinstellungen kann man das "Padding" einstellen, standardmäßig ist es bei mir 8, kann aber auch 4 sein.
    Warum die Entwickler des Formats das so gemacht haben, keine Ahnung.
    Mit #pragma pack(push,2) kann dieses Padding beim MSVC auf 2 gesetzt werden. Unter der Struktur sollte dann #pragma pack(pop) stehen, um den alten Wert wieder herzustellen.

    Edit: Du kannst auch

    void SwapBytes(unsigned int* pi);
    // in
    unsigned int SwapBytes(unsigned int i);
    

    ändern, damit es sich nicht auf die Werte auswirkt.



  • So, ich habe jetzt das Programm fertiggestellt und wirklich einiges gelernt 🙂 Vielen Dank, hier ist mein Sourcecode:

    main.cpp

    #include <iostream>
    #include <fstream>
    #include "funcs.h"
    
    using namespace std;
    
    unsigned short frFileNameLength;
    unsigned int frCompressedSize;
    unsigned int frChecksum;
    int main()
    {
        ifstream oZip("C:\\Sample.zip",ios::binary);
    
        bool isValidZip = isZIP(oZip);
    
        if(isValidZip)
        {
            unsigned short numEntries = numberOfEntries(oZip);
            cout << "Gueltiges ZIP Format!" << endl;
            cout << "Zahl der Dateien: " << numEntries << endl;
            for(int i=0;i<numEntries;i++)
            {
                oZip.seekg(OFFSET_CRC, ios::cur);                                                       //Zur Checksumme springen
                oZip.read(reinterpret_cast<char*>(&frChecksum),sizeof(int));                            //Wert auslesen
    
                oZip.read(reinterpret_cast<char*>(&frCompressedSize),sizeof(int));
    
                oZip.seekg(4, ios::cur);
                oZip.read(reinterpret_cast<char*>(&frFileNameLength), sizeof(short));                   //Größe des Dateinamens ermitteln
    
                char *frFileName = new char[(frFileNameLength+1)];                                      //Speicher für den Dateinamen reservieren
    
                oZip.seekg(2, ios::cur);
                oZip.read(&(*frFileName),frFileNameLength);                                             //Dateinamen einlesen
    
                frFileName[11] = '\0';                                                                  //Null-Terminator an Dateinamen anhängen
    
                printf("Datei %d: %s (CRC Checksumme: %X)\n",(i+1),frFileName,frChecksum);                   //Daten ausgeben
                delete[] frFileName;                                                                    //Speicher für Dateinamen löschen
    
                oZip.seekg(frCompressedSize,ios::cur);                                                  //Den Data Block überspringen und nochmal anfangen
            }
        }
        else
        {
            cout << "Ungueltige Datei!" << endl;
            return 0;
        }
    }
    

    funcs.h

    #ifndef FUNCS_H_INCLUDED
    #define FUNCS_H_INCLUDED
    
    #include <fstream>
    #include <iostream>
    
    #define OFFSET_SIGNATURE 0
    #define OFFSET_VERSION 4
    #define OFFSET_FLAGS 6
    #define OFFSET_COMPRESSION 8
    #define OFFSET_FILE_TIME 10
    #define OFFSET_FILE_DATE 12
    #define OFFSET_CRC 14
    #define OFFSET_COMPRESSED_SIZE 18
    #define OFFSET_UNCOMPRESSED_SIZE 22
    #define OFFSET_FILE_NAME_LENGTH 26
    #define OFFSET_EXTRA_FIELD_LENGTH 28
    #define OFFSET_FILE_NAME 30
    
    using namespace std;
    
    typedef unsigned char BYTE;
    
    enum COMPTYPE{                          //Compression type
        COMP_STORED,
        COMP_SHRUNK,
        COMP_REDUCED1,
        COMP_REDUCED2,
        COMP_REDUCED3,
        COMP_REDUCED4,
        COMP_IMPLODED,
        COMP_TOKEN,
        COMP_DEFLATE,
        COMP_DEFLATE64
    };
    void SwapBytes(unsigned int* pi)
    {
        unsigned int i = *pi;
        unsigned int ui;
        ui = (i) & 0xFF;
        ui<<=8;
        ui|= (i>>8) & 0xFF;
        ui<<=8;
        ui|= (i>>16) & 0xFF;
        ui<<=8;
        ui|= (i>>24) & 0xFF;
        *pi = ui;
    }
    
    void SwapBytes(unsigned short* ps)
    {
        unsigned short s = *ps;
        unsigned short us;
        us = (s) & 0xFF;
        us<<=8;
        us|= (s>>8) & 0xFF;
        *ps = us;
    }
    
    unsigned short GetWord(ifstream& in)
    {
        char c;
        unsigned short s;
        in.get(c);
        s=(BYTE)c;
        s<<=8;
        in.get(c);
        s|=(BYTE)c;
        return s;
    }
    unsigned short GetByte(ifstream& in)
    {
        char c;
        unsigned short s;
        in.get(c);
        s=(BYTE)c;
        return s;
    }
    bool isZIP(ifstream& in)
    {
        bool bFound = false;
        streampos startPos = in.tellg();
        in.seekg(0,ios::beg);
        while(!in.eof() && !bFound)
        {
            char c;
            in.get(c);
            if((BYTE)c!=0x50)
                continue;
            in.get(c);
            if((BYTE)c!=0x4B)
                continue;
            else
            {
                bFound = true;
                in.seekg(startPos);
            }
        }
        return bFound;
    }
    unsigned short numberOfEntries(ifstream& in)
    {
        unsigned short num;
        streampos startPos = in.tellg();
        in.seekg(-12,ios::end);
        in.read(reinterpret_cast<char*>(&num),sizeof(short));
        in.seekg(startPos,ios::beg);
        return num;
    }
    #endif // FUNCS_H_INCLUDED
    

Anmelden zum Antworten