CppUnit TDD之探索swf文件头(中)

 
这一篇,我们来看一下代码。
 
using System;
using System.IO;
 
namespace SwfHeaderReader
{
    /// <summary>
    /// Summary description for FlashHeaderReader.
    /// </summary>
    public class FlashHeaderReader
    {
        internal int FrameRate
        {
            get { return mFrameRate; }
        }
        internal int FrameCount
        {
            get { return mFrameCount; }
        }
 
    internal int Width
    {
      get { return mWidth; }
    }
  
    internal int Height
    {
      get { return mHeight; }
    }
 
    internal bool Error
    {
      get {return mbErrorSignature;}    
    }
 
        private int mFrameRate=0;
        private int mFrameCount=0;
        private int mVersion=0;
        private bool mIsCompressed=false;
    private int mWidth=0;
    private int mHeight=0;
    private bool mbErrorSignature;
 
    // To Parse Header
    private byte[] data;
    private int currentIndex;
  
 
        public FlashHeaderReader(String filename)
        {
      currentIndex=0;
      mbErrorSignature=false;
            FileStream fs = File.OpenRead(filename);
            data = new byte[fs.Length];          
            fs.Read (data, 0, data.Length);
            fs.Close();      
      ParseHeader();          
        }
 
    /*
     * Parse the header of the swf format
     * Format http://www.half-serious.com/swf/format/index.html#header
     * convert from php : http://www.zend.com/codex.php?id=1382&single=1  
     */
    private void ParseHeader()
    {    
      ReadSignature();    
      mVersion=GetNextByte();
      ReadFileLength();
      ReadFrameSize();                  
      ReadFrameRate();
      ReadFrameCount();
    }
 
    /*
     * Read first caractere FWS or CWS
     * File compressed are not supported
     */
    private void ReadSignature()
    {
      Byte readingByte=GetNextByte();
      if (readingByte=='C')
      {
        mIsCompressed=true;
        // Not supported
      }
      if (readingByte!='F' && readingByte!='C')
      {
        mbErrorSignature=true;
      }
    
      if (GetNextByte()!='W') mbErrorSignature=true;
      if (GetNextByte()!='S') mbErrorSignature=true;
    }
    /*
     * Read the RECT Structure : Frame size in twips  
     * This retrieve from byte the size.
     * the source php is difficult to translate I have made
     * something working...
     */
    private void ReadFrameSize()
    {
      int cByte = GetNextByte();
      int NbBits=cByte>>3;
          
      cByte&=7;
      cByte<<=5;
 
      int currentBit=2;
 
      int currentValue;
 
      // Must get all 4 values in the RECT
      for (int numField=0;numField<4;numField++)
      {
        currentValue=0;
        int bitcount = 0 ;
        while (bitcount<NbBits)
        {
          if ((cByte&128)==128)
          {
            currentValue =currentValue + (1<<(NbBits-bitcount-1)) ;
          }         
          cByte<<=1 ;
          cByte &= 255 ;
          currentBit-- ;
          bitcount++ ;
          // We will be needing a new byte if we run out of bits
          if (currentBit<0)
          {
            cByte    = GetNextByte() ;
            currentBit = 7 ;
          }
        }      
      
        // TWIPS to PIXELS
      currentValue/=20;
      switch (numField)
      {
        case 0:
        mWidth = currentValue ;
        break ;
        case 1:
        mWidth = currentValue - mWidth ;
        break ;
        case 2:
        mHeight = currentValue ;
        break ;
        case 3:
        mHeight = currentValue - mHeight ;
        break;
       }
      }      
    }
 
    /*
     * Read Frame delay in 8.8 fixed number of frames per second 
     */
    private void ReadFrameRate()
    {
      // Frame rate
      byte fps_decimal,fps_int ;
      fps_decimal = GetNextByte();      
      fps_int     =GetNextByte();
      mFrameRate=fps_int+(fps_decimal)/100;
    }
 
    private void ReadFrameCount()
    {
      for (int i=0;i<2;i++)
      {
        mFrameCount+= (GetNextByte()<<(8*i)) ;
      }
    }
    /*
     * Read FileLength : Length of entire file in bytes  
     * Not implemented
     */
    private void ReadFileLength()
    {
      //Read Size
      GetNextByte();
      GetNextByte();
      GetNextByte();
      GetNextByte();
    }
 
    /*
     * Retrieve one caractere of the buffer.
     */
    private byte GetNextByte()
    {
      Byte result;
      result=data[currentIndex];
      currentIndex++;
      return(result);
    }
    }
}
 
哇塞。怎么这么写啊。
    private void ParseHeader()
    {    
      ReadSignature();    
      mVersion=GetNextByte();
      ReadFileLength();
      ReadFrameSize();                  
      ReadFrameRate();
      ReadFrameCount();
    }
 
在C++里面,我一个File的open一下就读完所有的结构了啊。
还好我前两年看了设计模式,要不还不被人笑死。这个应该算是builder模式吧。
从重构的角度讲,小函数更具灵活性,而且更容易被重用。这点上,最后一个函数GetNextByte()也是深得重构理论真传。
 
好了,先写个测试读取文件大小的用例吧。
写个读取swf文件的类。
 
//SwfReader.h
#pragma once
typedef struct SwfHeader {
DWORD mfType; // CWS , Signature 0x46, 0x57, 0x53 (“FWS”)
BYTE version;
DWORD fileLength;
 
WORD frameRate;
WORD frameCount;
 
} SWFHEADER, *PSWFHEADER;
 
class CSwfReader
{
public:
CSwfReader(void){};
~CSwfReader(void)
{
if (NULL != m_byData)
{
delete[] m_byData;
}
}
 
void ParseHeader(void)
{
ReadSignature();    
swfHeader.version = GetNextByte();
m_bHeader = TRUE;
ReadFileLength();
ReadFrameSize();
ReadFrameRate();
ReadFrameCount();
}
 
SWFHEADER swfHeader;
BOOL m_bOpen;
BOOL m_bHeader;
 
private:
BYTE* m_byData;
CFile m_file;
int currentIndex;
 
void ReadSignature()
{
GetNextByte();
GetNextByte();
GetNextByte();
}
void ReadFileLength()
{
swfHeader.fileLength = GetNextDWord();
}
void ReadFrameSize()
{
 
}
void ReadFrameRate()
{
 
}
void ReadFrameCount()
{
 
}
BYTE GetNextByte()
{
BYTE result;
result=m_byData[currentIndex];
currentIndex++;
return(result);
}
WORD GetNextWord()
{
WORD result;
result=m_byData[currentIndex];
currentIndex+=2;
return(result);
}
DWORD GetNextDWord()
{
DWORD result;
int temp = 0;
result = m_byData[currentIndex];                
temp = m_byData[currentIndex+1];
result += temp<<8;
temp = m_byData[currentIndex+2];
result += temp<<16;
temp = m_byData[currentIndex+3];
result += temp<<24;
currentIndex+=4;
return(result);
}
 
public:
 
CSwfReader(CString aszName)
:currentIndex(0)
,m_bOpen(FALSE)
,m_bHeader(FALSE)
{
 
if(!m_file.Open(aszName, CFile::modeRead))
{
m_bOpen = FALSE;
return ;
}
 
int dwFileSize = m_file.GetLength();
m_byData = new BYTE[dwFileSize];
memset(m_byData, 0x00, dwFileSize);
m_file.Read(m_byData, dwFileSize);
m_bOpen = TRUE;
 
}
};
 
不是吧,怎么都写在h里面啊。(会写c++程序吗?)
 
Visual Assist 10.4里面集成了函数挪移的重构方法。所以写在哪里不重要哦。关键是,这不是发布容易嘛!
 
过会儿,我就(乾坤)挪移一下。(真想挪点儿面包过来。)
 
在CSwfReaderTest类里面添加TestSwfReader测试方法。引用需要测试的头文件过来。
 
void TestSwfReader(void)
{        
CSwfReader swfR(_T("g:/worksource/Robot/Twins02.swf"));
swfR.ParseHeader();
BYTE version = swfR.swfHeader.version;
int length = swfR.swfHeader.fileLength;
 
CPPUNIT_ASSERT_EQUAL((int)version, 5);        
CPPUNIT_ASSERT_EQUAL(length, 81125);
}
 
好了。泡一下测试吧。是不是又通过了。
这就像上学的时候,每次到大考的时候,都不慌张。为什么?
因为每月一次的模拟考试,已经让你了解了,你的考试水平。正常情况是不会有太大偏差的。
cppunit也是这样一个东西吧。可以让我们每个部分都自测一下。然后发布的时候,就不用着急了。基本上,主要的,核心的功能,都有测试代码,每次都运行着,不会出现太大偏差。
 
上传一下源码。让一些比较懒的朋友,舒服一下。
 
更多精彩部分,请看下篇。

你可能感兴趣的:(CppUnit TDD之探索swf文件头(中))