Changeset 89 for trunk/dbc/dbc.php


Ignore:
Timestamp:
Feb 11, 2009, 7:49:33 PM (16 years ago)
Author:
george
Message:
  • Přidáno: Funkce pro export do DBC souborů. Zatím veřejně nepovoleno v nabídce, protože doba generování 45 MB souboru Spells.dbc překračuje max. dobu vykonání PHP skriptu 30 sekund. Nutno zoptimalizovat.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/dbc/dbc.php

    r64 r89  
    11<?php
    22
    3 class BinaryReader
    4  {
    5    private $handle;  /// Handle na otevreny dbc soubor
    6    
    7    /// Konstruktor
    8    function __construct()
    9    {
    10      $this->handle = false;
    11    }
    12    
    13    /// Destruktor
    14    function __destruct()
    15    {
    16      if ($this->handle)
    17        fclose($this->handle);
    18    }
    19    
    20    public function loadFile($filename)
    21    {
    22      if ($this->handle)
    23        fclose($this->handle);
    24    
    25      $this->handle = @fopen($filename, "rb");
    26      if (!$this->handle)
    27        die ("Soubor $filename neexistuje"); 
    28    }
    29    
    30    /// Nacteni bytu
    31    public function readByte()
    32    {
    33      return ord(fread($this->handle, 1));
    34    } 
    35    
    36    /// Nacteni unsigned int
    37    public function readUint()
    38    {
    39      $val = unpack("V*", fread($this->handle, 4));
    40      return $val[1];
    41    }
    42    
    43    /// Nacteni signed int
    44    public function readInt()
    45    {
    46      $val = unpack("I*", fread($this->handle, 4));
    47      return $val[1];
    48    } 
    49    
    50    /// Nacteni float
    51    public function readFloat()
    52    {
    53      $val = unpack("f*", fread($this->handle, 4));
    54      return $val[1];
    55    }
    56    
    57    /// Nacteni znaku
    58    public function readChar()
    59    {
    60      return fgetc($this->handle);
    61    }   
    62    
    63    public function seekPos($pos, $type = SEEK_SET)
    64    {
    65      fseek($this->handle, $pos, $type);
    66    }
    67  }
     3include('stream.php');
     4
     5define('NOT_DBC_FILE', 'Není DBC soubor.');
     6define('FIELD_COUNT_NOT_MATCH', 'Počet sloupců neodpovídá délce formátu.');
     7define('RECORD_SIZE_NOT_MATCH', 'Velikost řádku neodpovídá zadanému formátu.');
    688 
    69  class DbcReader extends BinaryReader
    70  {
    71    private $offsets; /// Offsety jednotlivych poli
    72    private $format;  /// Format dbc souboru
    73    
    74    private $recSize; /// Velikost jednoho zaznamu
    75    private $recCount;/// Pocet zaznamu
    76    private $strSize; /// Velikost string casti
    77    private $fldCount;/// Pocet poli (v 1 zaznamu)
     9class DBCFile extends FileStream
     10{
     11  private $HeaderSize = 20;
     12  private $Offsets;
     13  private $StringOffset;
     14  private $StringList = array();
     15  private $StringListOffset = array();
     16  private $Format;
     17   
     18  private $RecordSize;
     19  private $RecordCount;
     20  private $StringBlockSize;
     21  private $FieldCount;
    7822     
    79    /// Nacteni dbc souboru
    80    public function loadDbc($file, $format)
    81    {
    82      $this->loadFile($file);
     23  public function OpenFile($FileName, $Format)
     24  {
     25    parent::OpenFile($FileName);
     26   
     27    $this->Format = $Format;
     28    if($this->ReadUint() != 0x43424457) die(NOT_DBC_FILE);
     29       
     30    $this->RecordCount = $this->ReadUint();
     31    $this->FieldCount = $this->ReadUint();
     32    $this->RecordSize = $this->ReadUint();
     33    $this->StringBlockSize = $this->ReadUint();
    8334     
    84      if ($this->readUint() != 0x43424457)
    85        die ("NO DBC!");
     35    if(strlen($this->Format) != $this->FieldCount)
     36      die(FIELD_COUNT_NOT_MATCH);
     37     
     38    $this->GenerateOffsetTable($Format);
     39    if($this->Offsets[count($this->Offsets) - 1] != $this->RecordSize)
     40          die(RECORD_SIZE_NOT_MATCH.$this->Offsets[count($this->Offsets) - 1].' <> '.$this->RecordSize);
     41  }
     42
     43  public function CreateFile($FileName, $Format)
     44  {
     45    parent::CreateFile($FileName);
     46   
     47    $this->WriteUint(0x43424457);
    8648       
    87      $this->recCount = $this->readUint();
    88      $this->fldCount = $this->readUint();
    89      $this->recSize = $this->readUint();
    90      $this->strSize = $this->readUint();
     49        $this->StringList = array();
     50        $this->StringOffset = 1;
     51    $this->Format = $Format;
     52    $this->GenerateOffsetTable($Format);
     53        $this->FieldCount = strlen($Format);
     54        $this->RecordCount = 0;
     55        $this->RecordSize = $this->Offsets[count($this->Offsets) - 1];
     56        $this->StringBlockSize = 0;
     57
     58    $this->WriteUint($this->RecordCount);
     59    $this->WriteUint($this->FieldCount);
     60    $this->WriteUint($this->RecordSize);
     61    $this->WriteUint($this->StringBlockSize);         
     62  }
     63   
     64  private function GenerateOffsetTable($Format)
     65  {
     66    $this->Offsets = array();
     67        $this->Offsets[0] = 0;
     68    for($I = 0; $I < strlen($Format); $I++)
     69    {
     70      $this->Offsets[$I + 1] = $this->Offsets[$I];
     71      switch($Format[$I])
     72      {
     73        case "b":
     74                case "X":
     75                  $this->Offsets[$I + 1] += 1; 
     76                  break;
     77        case "x":
     78                case "u":
     79                case "i":
     80                case "f":
     81                case "s":
     82                  $this->Offsets[$I + 1] += 4; 
     83                  break;
     84      }
     85    }   
     86  }
     87 
     88  private function SeekPosi($Row, $Column)
     89  {
     90    $Position = $this->HeaderSize + $Row * $this->RecordSize + $this->Offsets[$Column];
     91    $this->Seek($Position);
     92  }
     93   
     94  public function GetByte($Row, $Column)
     95  {
     96    $this->SeekPosi($Row, $Column); 
     97    return($this->ReadByte());
     98  }   
     99   
     100  public function GetUint($Row, $Column)
     101  {
     102    $this->SeekPosi($Row, $Column); 
     103    return($this->ReadUint());
     104  }
     105   
     106  public function GetInt($Row, $Column)
     107  {
     108    $this->SeekPosi($Row, $Column); 
     109    return($this->ReadInt());
     110  } 
     111   
     112  public function GetFloat($Row, $Column)
     113  {
     114    $this->SeekPosi($Row, $Column); 
     115    return($this->ReadFloat());
     116  }
     117
     118  public function SetByte($Row, $Column, $Value)
     119  {
     120    $this->SeekPosi($Row, $Column); 
     121    $this->WriteByte($Value);
     122  }   
     123   
     124  public function SetUint($Row, $Column, $Value)
     125  {
     126    $this->SeekPosi($Row, $Column); 
     127    $this->WriteUint($Value);
     128  }
     129   
     130  public function SetInt($Row, $Column, $Value)
     131  {
     132    $this->SeekPosi($Row, $Column); 
     133    $this->WriteInt($Value);
     134  } 
     135   
     136  public function SetFloat($Row, $Column, $Value)
     137  {
     138    $this->SeekPosi($Row, $Column); 
     139    $this->WriteFloat($Value);
     140  }
     141 
     142  public function GetString($Row, $Column)
     143  {
     144        $Offset = $this->GetUint($Row, $Column);
     145   
     146    $Position = $this->HeaderSize + $this->RecordCount * $this->RecordSize + $Offset;
     147        if($Position >= $this->GetSize()) return('');
     148    $this->Seek($Position);
    91149     
    92      //if (strlen($format) != $this->fldCount)
    93      //  die ("Field count error");
    94      
    95      $this->format = $format;
    96      $this->generateOffsetTable($format);
    97    }
    98    
    99    /// Vytvoreni tabulky offsetu
    100    private function generateOffsetTable($format)
    101    {
    102          //echo(strlen($format).' '.$format);
    103      $this->offsets = array();
    104      $this->offsets[0] = 0;
    105      for ($i = 1; $i < strlen($format); $i++)
    106      {
    107        $this->offsets[$i] = $this->offsets[$i-1];
    108        switch ($format[$i-1])
    109        {
    110          case "b": case "X": $this->offsets[$i] += 1;   break;
    111          case "x": case "u": case "i": case "f": case "s": $this->offsets[$i] += 4;     break;
    112        }
    113      }
    114      
    115      $lastOff = $this->offsets[strlen($format) - 1] + ($format[strlen($format)-1] == "b" || $format[strlen($format)-1] == "X" ? 1 : 4);
    116      if($lastOff != $this->recSize)
    117        die ("Record size error! ".$lastOff.' <> '.$this->recSize);
    118    }
    119    
    120    //////////////////////////////////////////////////////////////////////////////
    121  
    122    /// Nastaveni pozice v souboru
    123    private function seekPosi($row, $col)
    124    {
    125      $pos = 20 + $row*$this->recSize + $this->offsets[$col];
    126      //fseek($this->handle, $pos, SEEK_SET);
    127      $this->seekPos($pos);
    128    }
    129    
    130    //////////////////////////////////////////////////////////////////////////////
    131    
    132    public function getByte($row, $col)
    133    {
    134      $this->seekPosi($row, $col); 
    135      return $this->readByte();
    136    }   
    137    
    138    public function getUint($row, $col)
    139    {
    140      $this->seekPosi($row, $col); 
    141      return $this->readUint();
    142    }
    143    
    144    public function getInt($row, $col)
    145    {
    146      $this->seekPosi($row, $col); 
    147      return $this->readInt();
    148    } 
    149    
    150    public function getFloat($row, $col)
    151    {
    152      $this->seekPosi($row, $col); 
    153      return $this->readFloat();
    154    }
    155    
    156    public function getString($row, $col)
    157    {
    158      $offset = $this->getUint($row, $col);
    159      
    160      $pos = 20 + $this->recCount * $this->recSize + $offset;
    161      $this->seekPos($pos);
    162      
    163      $str = "";
    164      while (($char = $this->readChar()) != "\0")
    165        $str .= $char;
    166      
    167      return $str;
    168    }   
    169    
    170    /// Vrati jeden cely radek jako pole
    171    public function getLine($row)
    172    {
    173      $ret = array();
    174      for($i = 0; $i < $this->fldCount; $i++)
    175      {
    176        switch($this->format[$i])
    177        {
    178          case "b": $ret[$i] = $this->getByte($row, $i); break;
    179          case "u": $ret[$i] = $this->getUint($row, $i); break;
    180          case "i": $ret[$i] = $this->getInt($row, $i); break;
    181          case "f": $ret[$i] = $this->getFloat($row, $i); break;
    182          case "s": $ret[$i] = $this->getString($row, $i); break;
    183          case "x": case "X": default: break;
    184        }
    185      }
    186      return $ret;
    187    }
    188    
    189    /// Vrati vybrane sloupecky z jednoho radku
    190    public function getLineCols($row, $cols)
    191    {
    192      $ret = array();
    193      for($i = 0; $i < count($cols); $i++)
    194      {
    195        switch($this->format[$cols[$i]])
    196        {
    197          case "b": $ret[$i] = $this->getByte($row, $cols[$i]); break;
    198          case "u": $ret[$i] = $this->getUint($row, $cols[$i]); break;
    199          case "i": $ret[$i] = $this->getInt($row, $cols[$i]); break;
    200          case "f": $ret[$i] = $this->getFloat($row, $cols[$i]); break;
    201          case "s": $ret[$i] = $this->getString($row, $cols[$i]); break;
    202          case "x": case "X": default: break;
    203        }
    204      }
    205      return $ret; 
    206    }
    207    
    208    /// Pocet zaznamu
    209    public function count() { return $this->recCount; }
    210    /// Pocet poli
    211    public function fieldCount() { return $this->fldCount; }
    212  }
     150    $String = '';
     151    while(($Char = $this->ReadChar()) != "\0")
     152    {
     153      $String .= $Char;
     154    }
     155    return($String);
     156  }   
     157 
     158  public function SetString($Row, $Column, $Value)
     159  {
     160        if(in_array($Value, $this->StringList))
     161        {
     162          $this->SetUint($Row, $Column, $this->StringListOffset[array_search($Value, $this->StringList)]);
     163        } else
     164        {
     165          $this->SetUint($Row, $Column, $this->StringOffset);
     166          $this->StringList[] = $Value;
     167          $this->StringListOffset[] = $this->StringOffset;
     168          $this->StringOffset += strlen($Value) + 1;
     169        }
     170  }
     171
     172  public function Commit()
     173  {
     174        $this->Seek(0);
     175    $this->WriteUint(0x43424457);
     176    $this->WriteUint($this->RecordCount);
     177    $this->WriteUint($this->FieldCount);
     178    $this->WriteUint($this->RecordSize);
     179    $this->WriteUint($this->StringOffset);         
     180        $this->Seek($this->HeaderSize + $this->RecordCount * $this->RecordSize);
     181        $this->WriteByte(0);
     182        foreach($this->StringList as $Index => $Item)
     183        {               
     184      $this->WriteString($Item);
     185        }
     186  }   
     187   
     188  public function GetLine($Row)
     189  {
     190    $Line = array();
     191    for($I = 0; $I < $this->FieldCount; $I++)
     192    {
     193      switch($this->Format[$I])
     194      {
     195        case 'b':
     196                  $Line[$I] = $this->GetByte($Row, $I);
     197                  break;
     198        case 'u':
     199                  $Line[$I] = $this->GetUint($Row, $I);
     200                  break;
     201        case 'i':
     202                  $Line[$I] = $this->GetInt($Row, $I);
     203                  break;
     204        case 'f':
     205                  $Line[$i] = $this->GetFloat($Row, $I);
     206                  break;
     207        case 's':
     208                  $Line[$I] = $this->GetString($Row, $I);
     209                  break;
     210        case 'x':
     211                case 'X':
     212                default:
     213                  break;
     214      }
     215    }
     216    return($Line);
     217  }
     218
     219  public function SetLine($Row, $Line)
     220  {
     221    for($I = 0; $I < $this->FieldCount; $I++)
     222    {
     223      switch($this->Format[$I])
     224      {
     225        case 'b':
     226                  $this->SetByte($Row, $I, $Line[$I]);
     227                  break;
     228        case 'u':
     229                  $this->SetUint($Row, $I, $Line[$I]);
     230                  break;
     231        case 'i':
     232                  $this->SetInt($Row, $I, $Line[$I]);
     233                  break;
     234        case 'f':
     235                  $this->SetFloat($Row, $I, $Line[$i]);
     236                  break;
     237        case 's':
     238                  $this->SetString($Row, $I, $Line[$I]);
     239                  break;
     240        case 'x':
     241                case 'X':
     242                default:
     243                  break;
     244      }
     245    }
     246    return($Line);
     247  }
     248   
     249  public function GetLineCols($Row, $Columns)
     250  {
     251    $Line = array();
     252    for($I = 0; $I < count($Columns); $I++)
     253    {
     254      switch($this->Format[$Columns[$I]])
     255      {
     256        case 'b':
     257                  $Line[$I] = $this->GetByte($Row, $Columns[$I]);
     258                  break;
     259        case 'u':
     260                  $Line[$I] = $this->GetUint($Row, $Columns[$I]);
     261                  break;
     262        case 'i':
     263                  $Line[$I] = $this->GetInt($Row, $Columns[$I]);
     264                  break;
     265        case 'f':
     266                  $Line[$i] = $this->GetFloat($Row, $Columns[$I]);
     267                  break;
     268        case 's':
     269                  $Line[$I] = $this->GetString($Row, $Columns[$I]);
     270                  break;
     271        case 'x':
     272                case 'X':
     273                default:
     274                  break;
     275      }
     276    }
     277    return($Line); 
     278  }
     279   
     280  public function GetRecordCount()
     281  {
     282        return($this->RecordCount);
     283  }
     284
     285  public function SetRecordCount($Value)
     286  {
     287        $this->RecordCount = $Value;
     288  }
     289
     290  public function GetFieldCount()
     291  {
     292        return($this->FieldCount);
     293  }
     294}
    213295 
    214296?>
Note: See TracChangeset for help on using the changeset viewer.