$F_NONE = 0x00 # 何も行わない
$F_NOSEL = 0x01 # 選択できない
$DISP_S16 = [System.BitConverter]::ToInt16
$DISP_S32 = [System.BitConverter]::ToInt32
$DISP_S64 = [System.BitConverter]::ToInt64
$DISP_U16 = [System.BitConverter]::ToSInt16
$DISP_U32 = [System.BitConverter]::ToSInt32
$DISP_U64 = [System.BitConverter]::ToSInt64
$DISP_F32 = [System.BitConverter]::ToSingle
$DISP_F64 = [System.BitConverter]::ToDouble
Class Utility
{
static [Int32] ToInt8( [byte[]] $buffer, $bufferIndex )
{
return ($buffer[$bufferIndex] -bor 0xffffff00)
}
static [UInt32] ToUInt8( [byte[]] $buffer, $bufferIndex )
{
return ($buffer[$bufferIndex] -band 0x000000ff)
}
}
$DISP_S8 = [Utility]::ToInt8
$DISP_U8 = [Utility]::ToUInt8
Class CMemberStackFactor
{
[Object[]] $memberArray
[int] $nIndex
CMemberStackFactor( [Object[]] $memberArray )
{
$this.memberArray =$memberArray
$this.nIndex = 0
}
[Boolean] IsNext()
{
if( $this.nIndex -ge $this.memberArray.Count )
{
return $False
}
return $True
}
[Object] GetCurrent()
{
return $this.memberArray[ $this.nIndex ]
}
[void] Next()
{
++ $this.nIndex
}
}
Class CMemberStack
{
[System.Collections.ArrayList] $stack = [System.Collections.ArrayList]::new( 10 )
CMemberStack()
{
}
[void] Push( [CMemberStackFactor] $v )
{
$this.stack.Add( $v )
}
[void] Pop()
{
$this.stack.RemoveAt( $this.stack.Count - 1 )
}
[CMemberStackFactor] Current()
{
return $this.stack[ $this.stack.Count - 1 ]
}
[CMemberStackFactor] GetValue( [int] $nIndex )
{
return $this.stack[ $nIndex ]
}
[int] GetLevel()
{
return $this.stack.Count - 1
}
[void] Clear()
{
$this.stack.Clear()
}
}
Class CMemberParser
{
[CMemberStack] $_stack1 = [CMemberStack]::new()
[CMemberStack] $_stack2 = [CMemberStack]::new()
[int] $_nFindIndex
[int] $_nOffset
Hidden $nLoopCount = @( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 )
hidden [Boolean] _CalcPosition()
{
[CMemberStackFactor] $stackFactor = $this._stack1.Current()
while( $stackFactor.IsNext() )
{
$member = $stackFactor.GetCurrent()
if( $False )
{
}
elseif( $member.size -gt 0 )
{
if( ($member.bitFlag -band $script:F_NOSEL) -eq 0 )
{
if( -- $this._nFindIndex -eq 0 )
{
return $True
}
}
}
elseif( $member.loop -gt 0 )
{
$this._stack1.Push( [CMemberStackFactor]::new($member.subMember) )
[Boolean] $r = $this._CalcPosition()
if( $r )
{
return $True
}
$this._stack1.Pop()
}
$stackFactor.Next()
}
return $False
}
hidden [void] _CalcOffsetNoTargetLoop( [Object[]] $subMember, [int] $nLoop )
{
[int] $nBackupOffset = $this._nOffset
$this._nOffset = 0
$this._stack2.Push( [CMemberStackFactor]::new($subMember) )
$this._CalcOffsetNoTarget()
$this._stack2.Pop()
$this._nOffset = $nBackupOffset + $this._nOffset * $nLoop
}
hidden [Boolean] _CalcOffsetNoTarget()
{
[CMemberStackFactor] $stackFactor = $this._stack2.Current()
while( $stackFactor.IsNext() )
{
$member = $stackFactor.GetCurrent()
if( $False )
{
}
elseif( $member.size -gt 0 )
{
$loop = $member.loop
if( $loop -le 0 )
{
$loop = 1
}
$this._nOffset += $member.size * $loop
}
elseif( $member.loop -ge 2 )
{
$this._CalcOffsetNoTargetLoop( $member.subMember, $member.loop )
}
elseif( $member.subMember -ne $Null )
{
$this._CalcOffsetNoTargetLoop( $member.subMember, 1 )
}
$stackFactor.Next()
}
return $False
}
hidden [Boolean] _CalcOffsetTarget()
{
[CMemberStackFactor] $stackFactor = $this._stack2.Current()
while( $stackFactor.IsNext() )
{
$member = $stackFactor.GetCurrent()
if( $False )
{
}
elseif( $member.size -gt 0 )
{
$loop = $member.loop
if( $loop -le 0 )
{
$loop = 1
}
[CMemberStackFactor] $stack1Factor = $this._stack1.GetValue( $this._stack2.GetLevel() )
if( $stack1Factor.memberArray[$stack1Factor.nIndex] -eq $member )
{
if( $loop -ge 2 )
{
$loop = $this.nLoopCount[ $this._stack2.GetLevel() ]
}
$loop --
$this._nOffset += $member.size * $loop
return $True
}
$this._nOffset += $member.size * $loop
}
elseif( $member.loop -gt 0 )
{
[CMemberStackFactor] $stack1Factor = $this._stack1.GetValue( $this._stack2.GetLevel() )
if( $stack1Factor.memberArray[$stack1Factor.nIndex] -eq $member )
{
$nLoop = $this.nLoopCount[ $this._stack2.GetLevel() ]
if( $nLoop -ge 2 )
{
$this._CalcOffsetNoTargetLoop( $member.subMember, $nLoop - 1 )
}
$this._stack2.Push( [CMemberStackFactor]::new($member.subMember) )
[Boolean] $r = $this._CalcOffsetTarget()
if( $r )
{
return $True
}
$this._stack2.Pop()
}
else
{
$this._CalcOffsetNoTargetLoop( $member.subMember, $member.loop )
}
}
$stackFactor.Next()
}
return $False
}
[Boolean] CalcPosition( [int] $nFindIndex, [Object[]] $memberArray )
{
$this._nFindIndex = $nFindIndex
$this._stack1.Clear()
$this._stack1.Push( [CMemberStackFactor]::new($memberArray) )
return $this._CalcPosition()
}
[int] GetLoopNum()
{
$level = $this._stack1.GetLevel()
if( $level -le 0 )
{
if( $level -eq 0 )
{
[CMemberStackFactor] $stackFactor = $this._stack1.GetValue( 0 )
$member = $stackFactor.GetCurrent()
if( $member.loop -ge 2 )
{
return 1
}
}
return 0
}
return $level + 1
}
[void] SetLoopCount( [int] $nIndex, [int] $nLoopCount )
{
$this.nLoopCount[ $nIndex ] = $nLoopCount
}
[int] CalcOffset( [Object[]] $memberArray )
{
$this._nOffset = 0
$this._stack2.Clear()
$this._stack2.Push( [CMemberStackFactor]::new($memberArray) )
[Boolean] $r = $this._CalcOffsetTarget()
if( $r -lt $False )
{
return -1
}
return $this._nOffset
}
[int] CalcMemberSize( [Object[]] $memberArray )
{
$this._nOffset = 0
$this._stack2.Clear()
$this._stack2.Push( [CMemberStackFactor]::new($memberArray) )
$this._CalcOffsetNoTarget()
$this._stack2.Pop()
return $this._nOffset
}
}
# Display-Member との違いは番号が付くこと
Function Display-Member-IX
{
Param( [Object[]] $memberArray )
$ctx = @{ index = 0 }
Function _Core( [Object[]] $memberArray, [String] $Indent )
{
for( $i = 0; $i -lt $memberArray.Length; $i ++ )
{
$member = $memberArray[ $i ]
if( $False )
{
}
elseif( $member.size -gt 0 )
{
$ctx.index ++
if( $member.loop -ge 2 )
{
'[{3,3}] {0}{1}[{4}] ... {2}' -f `
$Indent, $member.name, $member.size, $ctx.index, $member.loop
}
else
{
'[{3,3}] {0}{1} ... {2}' -f `
$Indent, $member.name, $member.size, $ctx.index
}
}
elseif( $member.loop -gt 0 )
{
'[ ] {0}{1}[{2}]' -f $Indent, $member.name, $member.loop
_Core $member.subMember ($Indent + ' ')
}
}
}
_Core $memberArray ''
}
Function Display-Member
{
Param( [Object[]] $memberArray )
Function _Core( [Object[]] $memberArray, [String] $Indent )
{
for( $i = 0; $i -lt $memberArray.Length; $i ++ )
{
$member = $memberArray[ $i ]
if( $False )
{
}
elseif( $member.size -gt 0 )
{
if( $member.loop -ge 2 )
{
'{0}{1}[{3}] ... {2}' -f $Indent, $member.name, $member.size, $member.loop
}
else
{
'{0}{1} ... {2}' -f $Indent, $member.name, $member.size
}
}
elseif( $member.loop -ge 2 )
{
'{0}{1}[{2}]' -f $Indent, $member.name, $member.loop
_Core $member.subMember ($Indent + ' ')
}
elseif( $member.subMember -ne $Null )
{
'{0}{1}' -f $Indent, $member.name
_Core $member.subMember ($Indent + ' ')
}
}
}
_Core $memberArray ''
}
Function Dump-Member
{
Param( [Object[]] $memberArray, [byte[]] $buffer, [Long] $nDisplayAddress )
$pm_ = @{ buffer = $buffer; bufferPointer = 0; displayAddress = $nDisplayAddress; }
Function _Hex( $pm, [int] $bufferSize )
{
[String] $blank = ''
[String] $r = ''
for( $i = 0; $i -lt $bufferSize; $i ++ )
{
$r += $blank + $pm.buffer[$pm.bufferPointer + $i].ToString( 'X2' )
$blank = ' '
}
return $r
}
Function _Val( $pm, $member )
{
if( $member.fnDisp -ne $Null )
{
return $member.fnDisp.Invoke( $pm.buffer, $pm.bufferPointer )
}
else
{
return _Hex $pm $member.size
}
}
Function _Core( $pm, [Object[]] $memberArray, [String] $Indent )
{
for( $i = 0; $i -lt $memberArray.Length; $i ++ )
{
$member = $memberArray[ $i ]
if( $False )
{
}
elseif( $member.size -gt 0 )
{
$loop = $member.loop
if( $loop -ge 2 )
{
for( $nLoopIndex = 0; $nLoopIndex -lt $loop; $nLoopIndex ++ )
{
$val = _Val $pm $member
$nAddress = $pm.bufferPointer + $pm.displayAddress
'{0:X8} {1}{2}[{4}] = {3}' -f $nAddress, $Indent, $member.name, $val, $nLoopIndex
$pm.bufferPointer += $member.size
}
}
else
{
$val = _Val $pm $member
$nAddress = $pm.bufferPointer + $pm.displayAddress
'{0:X8} {1}{2} = {3}' -f $nAddress, $Indent, $member.name, $val
$pm.bufferPointer += $member.size
}
}
elseif( $member.loop -ge 2 )
{
for( $nLoopIndex = 0; $nLoopIndex -lt $member.loop; $nLoopIndex ++ )
{
'{0} {1}{2}[{3}]' -f ' ', $Indent, $member.name, $nLoopIndex
_Core $pm $member.subMember ($Indent + ' ')
}
}
elseif( $member.subMember -ne $Null )
{
'{0} {1}{2}' -f ' ', $Indent, $member.name
_Core $pm $member.subMember ($Indent + ' ')
}
}
}
_Core $pm_ $memberArray ''
}
Class CDumpX
{
[System.IO.FileStream] $_fs
[System.IO.BinaryReader] $_br
[CMemberParser] $_parse = [CMemberParser]::new()
[Boolean] BeginDumpX( [String] $szPath )
{
try
{
$this._fs = [System.IO.File]::Open( $szPath, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read )
$this._br = [System.IO.BinaryReader]::new( $this._fs )
return $True
}
catch
{
return $False
}
}
[void] EndDumpX()
{
[CDumpX]::_SafeClose( ([ref]$this._br) )
[CDumpX]::_SafeClose( ([ref]$this._fs) )
}
[Long] Read( [Byte[]] $buffer, [Int] $nOffset, [Int] $nLength )
{
$nPosition = $this._fs.Position
[void] $this._br.Read( $buffer, $nOffset, $nLength )
return $nPosition
}
[void] DumpMember( [Object[]] $memberArray, [Byte[]] $buffer, [Long] $nDisplayAddress )
{
#------------------------------------------------------------
# ファイル構造のサイズとバッファのサイズを確認
$r = $this._parse.CalcMemberSize( $memberArray )
if( $r -gt $buffer.Length )
{
Write-Host ('ファイルから読み込んだサイズ({0})がファイル構造のサイズ({1})より小さいためダンプを中止しました。' -f $buffer.Length, $r)
return
}
#------------------------------------------------------------
# ファイル構造を表示
Write-Host ('□ファイル構造 ... {0} byte(s)' -f $r)
Display-Member-IX $memberArray | Out-Host
''
#------------------------------------------------------------
# ファイルをダンプ
Write-Host ('□ファイルダンプ')
Dump-Member $memberArray $buffer $nDisplayAddress | Out-Host
''
}
hidden static [void] _SafeClose( [ref] $handle )
{
if( $handle.Value -ne $Null )
{
$handle.Value.Close()
$handle.Value = $Null
}
}
}
# ファイルの読み込み
#
# 戻り値
# 読み込んだデータを格納するバイト配列
# 失敗すると $Null を返す
Function Read-File
{
Param( $szPath, $nOffset, $nLength )
try
{
[System.IO.FileStream] $fs = [System.IO.File]::Open( $szPath, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read )
[System.IO.BinaryReader] $br = [System.IO.BinaryReader]::new( $fs )
if( ($nOffset -eq $Null) -bor ($nOffset -ge $fs.Length) -bor ($nOffset -lt 0) )
{
$nOffset = 0
}
if( ($nLength -eq $Null) -bor ($nLength -gt $fs.Length) -bor ($nLength -le 0) )
{
$nLength = $fs.Length
}
$n = ($nOffset + $nLength) - $fs.Length
if( $n -gt 0 )
{
$nLength -= $n
if( $nLength -lt 0 )
{
$nLength = 0
}
}
[System.Byte[]] $buffer = [System.Byte[]]::new( $nLength )
[void] $br.Read( $buffer, $nOffset, $nLength )
$br.Close()
$fs.Close()
return $buffer
}
catch
{
return $Null
}
}
Function Dump-X-Core( [Object[]] $memberArray, [System.IO.FileInfo] $File, [int] $nOffset )
{
#------------------------------------------------------------
# ファイル構造パーサを生成
$parse = [CMemberParser]::new()
#------------------------------------------------------------
# ファイルの読み込み
[System.Byte[]] $buffer = Read-File $File.FullName $nOffset
if( $buffer -eq $Null )
{
'ファイルの読み込みに失敗しました。'
return
}
#------------------------------------------------------------
# ファイル構造のサイズとバッファのサイズを確認
$r = $parse.CalcMemberSize( $memberArray )
if( $r -gt $buffer.Length )
{
'ファイルから読み込んだサイズ({0})がファイル構造のサイズ({1})より小さいためダンプを中止しました。' -f $buffer.Length, $r
return
}
#------------------------------------------------------------
# ファイル構造を表示
"□ファイル構造 ... {0} byte(s)" -f $r
Display-Member $memberArray
''
#------------------------------------------------------------
# ファイルをダンプ
"□ファイルダンプ"
Dump-Member $memberArray $buffer
''
}