Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Kodowanie danych binarnie - serializacja, deserializacja
Forum PHP.pl > Forum > PHP
jestemPolakiem
Witam sedecznie =)

Mam dość niespotykany problem, i sam nie mogę sobie z nim poradzić - więc zwracam się tutaj na forum, choć w między czasie znów będę próbować. Wszystko polega na tym że chcę przepisać kod (jego działanie dokładnie) do języka PHP, co pozwoli na parsowanie (rozkodowywanie) danych, które mam na serwerze. Wszystko opiera się o zmienne i operacje bitowe, które w tym języku są dla mnie czarną magią.

Przejdę do setna sprawy, w czym problem. Posiadam sobie dajmy przykład taką zmienną:
Kod
$samplehex = "800300050061726D6F72020A0000000B006465736372697074696F6E011A0000000A5B41524D
4F523A202B315D0A5B4845414C54483A202B34315D04006E616D65011F00000053747572647920646
56D6F6E206C656773206F662053757374656E616E6365";

Wartosć jak widać jest przechowywana w systemie szesnastkowym, więc dla praktyczności wszystko przerabiam na tablicę binarną (czyli najpierw na string w systemie ASCII a później na wartości liczbowe).
Kod
$bytes = array();
    $l = 0;
    for ($i = 0; $i < strlen($samplehex); $i += 2)
    {    
        $bytes[$l] = ord(chr(hexdec($samplehex[$i].$samplehex[$i + 1])));
        print $bytes[$l]."|";
        $l++;
    }

W przykładzie sobie wszystko wypisałem, aby sprawdzić poprawność kodu. Teraz właśnie nie wiem co zrobić dalej - bo muszę ze stosu (czy jak to się profesjonalnie nazywa) powyciągać odpowiednio dane. Pokaże kod C++, który jest analogiczny do tego co chcę zrobić:
Kod
... funkcja używana niżej ..
        template <typename T>
        inline bool getType(T& ret)
        {
            if(size() < (int32_t)sizeof(T))
                return false;

            ret = *((T*)p);
            p += sizeof(T);
            return true;
        }
        inline bool getShort(uint16_t& ret) {return getType(ret);}
... kolejny etap kodu ..
uint16_t n;
    if(!stream.GET_USHORT(n))
        return true;

Więc teraz moim problem jest wyciągniecie z tego stosu liczby unsigned int (2 bajty = 18 bitów) - ale w PHP nie istnieje zmienna typu unsigned int (teoretycznie). Próbowałem dodać dwa kolejne bity, i nie wiem czy działa to dobrze - oto sposób:
Kod
$long = (int)($bytes[0] | $bytes[1])

Mam nadzieje, że ktoś udzieli mi pomocy, ponieważ już nie mam pojęcia jak temu zaradzić. Jeśli coś napisałem źle, lub nie zrozumiale chętnie się poprawię. Liczę na szybką i efektywną pomóc =).

regards,
jestemPolakiem~

YaQzi
2 bajty = 16 bitów smile.gif nie 18. Z tego co zrozumiałem to chcesz doprowadzić zapis szesnastkowy do liczb unsigned int...

  1. <?php
  2. $samplehex = "FF09106E616E6365";
  3. $bytes = array();
  4. $l = 0;
  5. for ($i = 0; $i < strlen($samplehex); $i += 2)
  6. {
  7. $bytes[$l] = hexdec($samplehex[$i].$samplehex[$i + 1]);
  8. print $bytes[$l]."|";
  9. $l++;
  10. }
  11. ?>


...które masz już w tym momencie w tablicy. :x Więc po co chcesz to jeszcze kotłować przez binarkę?

  1. $long = (int)($bytes[0] | $bytes[1])


Tutaj chcesz wyciągnąć unsigneda 32 bitowego? No to:

  1. $long = 256*$bytes[0] + $bytes[1]


Gdyby chodziło o liczby signed to wtedy byłby delikatny problem ale w unsignedach wszystkie bity dotyczą wartości więc hexdec() styka swobodnie.
melkorm
hexdec o_O - chyba że czegoś nie ogarnąłem to sorry.
jestemPolakiem
Dzięki za pomoc, ale to nadal mi nie wychodzi, ogólnie mam problem z tymi bajtami, bo nie mogę ich dobrze prze konwersować :/. Jest tak, że sami wszystko działa ładnie, ale na przykład na inne przykłady już jest źle (wydaje mi się przez to że są złe typy zmiennych). Dobra, przedstawię wam tutaj moją klasę (nie dosłownie) w C++:
Kod
class PropStream
{
    public:
        PropStream() {end = NULL; p = NULL;}
        virtual ~PropStream() {}

        void init(const char* a, uint32_t size)
        {
            p = a;
            end = a + size;
        }
        int32_t size() const {return end - p;}

        template <typename T>
        inline bool getType(T& ret)
        {
            if(size() < (int32_t)sizeof(T))
                return false;

            ret = *((T*)p);
            p += sizeof(T);
            return true;
        }

        template <typename T>
        inline bool getStruct(T* &ret)
        {
            if(size() < (int32_t)sizeof(T))
            {
                ret = NULL;
                return false;
            }

            ret = (T*)p;
            p += sizeof(T);
            return true;
        }

        inline bool getByte(uint8_t& ret) {return getType(ret);}
        inline bool getShort(uint16_t& ret) {return getType(ret);}
        inline bool getTime(time_t& ret) {return getType(ret);}
        inline bool getLong(uint32_t& ret) {return getType(ret);}

        inline bool getFloat(float& ret)
        {
            // ugly hack, but it makes reading not depending on arch
            if(size() < (int32_t)sizeof(uint32_t))
                return false;

            float f;
            memcpy(&f, (uint32_t*)p, sizeof(uint32_t));

            ret = f;
            p += sizeof(uint32_t);
            return true;
        }

        inline bool getString(std::string& ret)
        {
            uint16_t strLen;
            if(!getShort(strLen))
                return false;

            if(size() < (int32_t)strLen)
                return false;

            char* str = new char[strLen + 1];
            memcpy(str, p, strLen);
            str[strLen] = 0;

            ret.assign(str, strLen);
            delete[] str;
            p = p + strLen;
            return true;
        }

        inline bool getLongString(std::string& ret)
        {
            uint32_t strLen;
            if(!getLong(strLen))
                return false;

            if(size() < (int32_t)strLen)
                return false;

            char* str = new char[strLen + 1];
            memcpy(str, p, strLen);
            str[strLen] = 0;

            ret.assign(str, strLen);
            delete[] str;
            p = p + strLen;
            return true;
        }

        inline bool skip(int16_t n)
        {
            if(size() < n)
                return false;

            p += n;
            return true;
        }

    protected:
        const char* p;
        const char* end;
};

I nie wiem teraz jak to zrobić w PHP, mój sposób był taki że rozbijam wszystko na bajty, które potem ze sobą dodaje (lub próbuję to robić), ale przy dłuższych wartościach tekstowych nie działa mi wszystko. Tutaj podam kod mojej klasy, którą stworzyłem jako odpowiednik tego:
Kod
<?php
    /*
    ** P R O P S T R E A M . C L A S S . P H P
    ** &by Alehopper, from Otland.net
    **
    ** Class is usage to reading a informations from binary string or hexadecimal set of characters.
    ** With this class you can read a single byte, integers (short and long), string na booleans (true
    ** or false).
    */
    class PropStream
    {
        // private $bytes:Array
        // Variable store a currently stream, which consist from single bytes.
        private $bytes = array();
        
        // private $entry:Integer
        // Variable store a currently position of mark in stream.
        private $entry = 0;
        
        // public function PropStream:
        // @param $_string stream to reading (or encoding).
        // Function is usage to create a object, which let a unseralize a binary code from item attributes
        // or others "blob".
        public function PropStream($_string)
        {
            for ($i = 0; $i < strlen($_string); $i++)
                $this->bytes[$i] = ord($_string[$i]);
        }
        
        // public static function encodeHex:String
        // @param $_string hex code
        // Code a hex code to normal deafult string, which was explode to array.
        public static function encodeHex($_string)
        {
            $string = "";
            for ($i = 0; $i < strlen($_string); $i += 2)
            {
                $string .= chr(hexdec($_string[$i].$_string[$i+1]));
            }
            return $string;
        }
        
        // public function isEmpty:Boolean
        // Function check a currently status of object. If return true, it mean that system have a 1 or
        // more bytes.
        public function isEmpty()
        {
            return (empty($this->bytes[$this->entry]) || $this->bytes[$this->entry] == 0);
        }
        
        // public function getByte:Integer
        // Function return a next byte from the arrays with bytes to encode.
        public function getByte()
        {
            return $this->bytes[$this->entry++];
        }
        
        // public function skipBytes
        // @param $_count count of bytes to skip
        // Function skip a bytes (of course, count you should give a parametr, if is empty automatic is
        // set as 1) in array with binary code.
        public function skipBytes($_count = 1)
        {
            $this->entry += $_count;
        }
        
        // public function getShortIngeterInteger:Integer
        // Function return a two next bytes as a short integer.
        public function getShortInteger() {
            return (($this->getByte()) | ($this->getByte() >> 8));
        }
        
        // public function getLongInteger:Integer
        // Function return a four next byes as a long integer.
        public function getLongInteger() {
            return (($this->getByte()) | ($this->getByte() >> 8) | ($this->getByte() >> 16) | ($this->getByte() >> 24));
        }
        
        // public function getShortString:String
        // Function return a short string, consisting from a single bytes in classes array.
        public function getShortString() {
            $string = "";
            $counts = $this->getShortInteger();
            for ($i = 0; $i < $counts; $i++)
            {
                $string .= chr($this->getByte());
            }
            return $string;
        }
        
        // public function getLongString:String
        // Function return a long string, consisting from a single bytes in classes array.
        public function getLongString() {
            $string = "";
            $counts = $this->getLongInteger();
            for ($i = 0; $i < $counts; $i++)
            {
                $string .= chr($this->getByte());
            }
            return $string;
        }
        
        // public function getBoolean:Boolean
        // Function return a next byte as boolean from the classes array.
        function getBoolean()
        {
            return $this->getByte() != 0;
        }
        
    }    

?>

Wybaczcie za słabe komentarze w języku angielskim =) Ten język nie jest moją mocną stroną, jak i tak samo polski. Oczywiście wszystkim co próbowali serdecznie dziękuje. Jeśli moglibyście mi to wytłumaczyć, albo chociaż podać przykład jak to pobierać wszystko.

Noidea
Zainteresuj się funkcjami pack i unpack

http://codepad.org/kz7ACofS
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.