$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 '' }