2014-01-15 10 views
2

Я пытаюсь написать программу на PHP, которая принимает список из 9 бит int (0-511) и 10 бит int (0-1023) и записывает их как двоичные Затем файл считывает его обратно. например:PHP pack 9 бит int then 10 bit int

$dataIn = array(array(275, 863), array(7, 93), array(510, 1010)); 

$binData = writeBin($dataIn); 
$dataOut = readBin($binData); 

var_dump($dataIn, $dataOut, $binData); 


function writeBin($data) { 
    $bin = ""; 
    foreach ($data as $d) { 
     //     9 bit 10 bit 
     $bin .= pack('SS', $d[0], $d[1]); 
    } 

    return $bin; 
} 

function readBin($bin) { 
    $bin = str_split($bin, 4); 
    $data = array(); 
    foreach ($bin as $b) { 
     $up = unpack('SS', $b); // im only getting 275, 7 and 510 here 
     $data[] = $up; 
    } 

    return $data; 
} 

Но как я могу внести их в двоичном файле/строки, так что каждый раздел 19 битов в длину, а затем разделить его на 19 бит при чтении его обратно? Таким образом, файл с 10 из этих записей в нем должна быть только 190 бит

+0

Я бы предпочел 'unsigned char' для упаковки. вы не можете использовать 'shuffle (range (1, 1024)' [shuffle] (http://www.php.net/manual/en/function.shuffle.php) за исключением параметра по ссылке и возвращает bool – bansi

+0

Следует отметить, что '512' - это 10-битное число, а' 1024' - 11-разрядное число. –

+0

@bansi, код 'shuffle', который он отлично работает. – BenM

ответ

0

Я решил эту проблему, написав свой собственный класс, чтобы читать и писать отличаясь битовых чисел длины в двоичную:

$listLen = 10; 

// get an array of 10 random 9 bit ints 
$b9s = range(0, 511); 
shuffle($b9s); 
$b9s = array_slice($b9s, 0, $listLen); 
// get an array of 10 random 10 bit ints 
$b10s = range(0, 1023); 
shuffle($b10s); 
$b10s = array_slice($b10s, 0, $listLen); 

//build array of input data 
$dataIn = array(); 
for ($i = 0; $i < $listLen; $i++) { 
    $dataIn[] = array($b9s[$i], $b10s[$i]); 
} 

//------- 


//initialise 
$bitFormat = array(9, 10); 
$BC = new BinConverter($bitFormat); 

//pack 
$BC->addData($dataIn); 
$binData = $BC->getBin(); 

//unpack 
$BC->setBin($binData); 
$dataOut = $BC->getData(); 

var_dump($dataOut, $binData); 



Class BinConverter { 
    private $bitFormat; 
    private $maxSectLen; 
    private $binary; 
    private $binData; 
    private $dataOffset; 

    // $bitFormat = list of bit lengths e.g. array(9, 10) 
    public function __construct($bitFormat) { 
     $this->setBitFormat($bitFormat); 
     $this->binary = ""; 
     $this->binData = ""; 
     $this->dataOffset = 0; 
    } 

    // $bitFormat = list of bit lengths e.g. array(9, 10) 
    public function setBitFormat($bitFormat) { 
     $bitFormat = array_merge($bitFormat); 
     $this->bitFormat = $bitFormat; 
     $this->maxSectLen = 0; 
     foreach ($this->bitFormat as $bpos => $bf) { 
      $this->bitFormat[$bpos] = (int) $bf; 
      $this->maxSectLen += $this->bitFormat[$bpos]; 
     } 
    } 

    // $data = list of data sections to convert e.g. array(array(167, 89), array(62, 32), array(325, 975)) 
    public function addData($data) { 
     foreach ($data as $d) { 
      $d = array_merge($d); 
      if (is_array($d) && count($d) != count($this->bitFormat)) { 
       throw new Exception("Invalid data section"); 
      } 

      foreach ($d as $dpos => $dbit) { 
       $dbit = (int) $dbit; 
       $tbin = decbin($dbit); 
       if (strlen($tbin) > $this->bitFormat[$dpos]) { 
        throw new Exception("Data (".$dbit.") too big for ".$this->bitFormat[$dpos]." bit segment"); 
       } 
       $this->binary .= $this->binPad($tbin, $this->bitFormat[$dpos]); 
      } 
     } 
    } 

    //returns binary representation of added data 
    public function getBin() { 
     $bin = ""; 
     if ($this->binary) { 
      $bits = str_split($this->binary, 4); 
      foreach ($bits as $bpos => $bit) { 
       $bp = bindec($this->binPad($bit, 4)); 
       $bin .= pack('C', $bp); 
      } 
     } 

     return $bin; 
    } 

    //$bin = string of binary data 
    public function setBin($bin) { 
     if (!is_string($bin)) { 
      throw new Exception("Invalid binary format"); 
     } 

     $bdata = ""; 
     foreach (str_split($bin) as $b) { 
      $unpacked = unpack('C', $b); 
      $binbit = $this->binPad(decbin($unpacked[1]), 4); 
      $bdata .= $binbit; 
     } 
     $this->binData = $bdata; 
    } 

    //returns unpacked data in the current bit format 
    public function getData() { 
     $data = array(); 
     $binlen = strlen($this->binData); 

     if ($binlen) { 
      $bdata = $this->binData; 

      $overflow = $binlen % $this->maxSectLen % 4; 
      $lastbit = substr($bdata, -4); 
      $overflowBit = substr($lastbit, 0, $overflow); 
      $binbit = substr($lastbit, $overflow); 
      $bdata = substr($bdata, 0, -4) . $binbit; 

      $tdata = str_split($bdata, $this->maxSectLen); 
      foreach ($tdata as $d) { 
       if (strlen($d) != $this->maxSectLen) { 
        throw new Exception("Invalid binary format"); 
       } 
       $offset = 0; 
       $ds = array(); 
       foreach ($this->bitFormat as $bf) { 
        $ds[] = bindec(substr($d, $offset, $bf)); 
        $offset += $bf; 
       } 
       $data[] = $ds; 
      } 
     } 
     return $data; 
    } 

    //returns unpacked data in the current bit format for (int) $ni number of sections 
    public function getNextSection($ni = null) { 
     $data = array(); 
     $binlen = strlen($this->binData); 

     if ($binlen) { 
      $n = $ni; 
      if ($n === null) { 
       $n = 1; 
      } 
      $glen = $n*$this->maxSectLen; 
      $bdata = substr($this->binData, $this->dataOffset, $glen); 

      if (strlen($bdata) != $glen) { 
       throw new Exception("Invalid data format used"); 
      } 

      $this->dataOffset += $glen; 
      if ($this->dataOffset+4 > $binlen) { 
       $overflow = $binlen - $this->dataOffset; 
       $lastbit = substr($this->binData, -4); 
       $overflowBit = substr($lastbit, 0, $overflow); 
       $binbit = substr($lastbit, $overflow); 
       $bdata = substr($bdata, 0, -(4-$overflow)) . $binbit; 
      } 

      $tdata = str_split($bdata, $this->maxSectLen); 
      foreach ($tdata as $d) { 
       if (strlen($d) != $this->maxSectLen) { 
        throw new Exception("Invalid binary format"); 
       } 
       $offset = 0; 
       $ds = array(); 
       foreach ($this->bitFormat as $bf) { 
        $ds[] = bindec(substr($d, $offset, $bf)); 
        $offset += $bf; 
       } 
       $data[] = $ds; 
      } 

      if ($ni === null) { 
       return $data[0]; 
      } 
     } 
     return $data; 
    } 

    private function binPad($var, $a) { 
     return str_pad($var, $a, '0', STR_PAD_LEFT); 
    } 
} 

и пример как использовать несколько битовых форматов в одном файле:

$listLen1 = rand(1, 20); 

// get an array of 10 random 9 bit ints 
$b9s = range(0, 511); 
shuffle($b9s); 
$b9s = array_slice($b9s, 0, $listLen1); 
// get an array of 10 random 10 bit ints 
$b10s = range(0, 1023); 
shuffle($b10s); 
$b10s = array_slice($b10s, 0, $listLen1); 

//build array of input data 
$dataIn1 = array(); 
for ($i = 0; $i < $listLen1; $i++) { 
    $dataIn1[] = array($b9s[$i], $b10s[$i]); 
} 

$listLen2 = rand(1, 20); 

// get an array of 10 random 16 bit ints 
$b16s = range(0, 65535); 
shuffle($b16s); 
$b16s = array_slice($b16s, 0, $listLen2); 
// get an array of 10 random 8 bit ints 
$b8s = range(0, 255); 
shuffle($b8s); 
$b8s = array_slice($b8s, 0, $listLen2); 
// get an array of 10 random 14 bit ints 
$b14s = range(0, 16383); 
shuffle($b14s); 
$b14s = array_slice($b14s, 0, $listLen2); 

$dataIn2 = array(); 
for ($i = 0; $i < $listLen2; $i++) { 
    $dataIn2[] = array($b16s[$i], $b8s[$i], $b14s[$i]); 
} 

//------- 

$file = './binfile.bf'; 


//initialise 
$bitFormat1 = array(9, 10); 
$bitFormat2 = array(16, 8, 14); 

$BC = new BinConvert($bitFormat1); 
//pack 
$BC->addData($dataIn1); 
$BC->setBitFormat($bitFormat2); 
$BC->addData($dataIn2); 

$binData = $BC->getBin(); 

file_put_contents($file,$binData); 


//unpack 
$binData = file_get_contents($file); 

$BC->setBin($binData); 

$BC->setBitFormat($bitFormat1); 
$dataOut1 = $BC->getNextSection($listLen1); 
$BC->setBitFormat($bitFormat2); 
$dataOut2 = $BC->getNextSection($listLen2); 

var_dump($dataOut1, $dataOut2, $binData); 
+0

Есть ли лучший или более эффективный способ сделать это? – nevernew

Смежные вопросы