|
| 1 | +Imports System.IO |
| 2 | +Imports System.IO.Compression |
| 3 | +Imports System.Text |
| 4 | + |
| 5 | +Module DebugScript |
| 6 | + Public Structure DebugSegment |
| 7 | + Dim Offset As UInteger |
| 8 | + Dim Data() As Byte |
| 9 | + End Structure |
| 10 | + |
| 11 | + Private Function ConvertUintegerToByteArray(Value As UInteger) As Byte() |
| 12 | + Return BitConverter.GetBytes(Value) |
| 13 | + End Function |
| 14 | + Private Function ConvertUShortToByteArray(Value As UShort) As Byte() |
| 15 | + Return BitConverter.GetBytes(Value) |
| 16 | + End Function |
| 17 | + Private Function ConvertByteToByteArray(Value As Byte) As Byte() |
| 18 | + Dim Data(0) As Byte |
| 19 | + Data(0) = Value |
| 20 | + Return Data |
| 21 | + End Function |
| 22 | + |
| 23 | + Private Function DebugDump(Address As UInteger, Length As UInteger) As String |
| 24 | + Dim Response As String |
| 25 | + |
| 26 | + Response = "D " & Address.ToString("X4") & " " & (Address + Length - 1).ToString("X4") |
| 27 | + |
| 28 | + Return Response |
| 29 | + End Function |
| 30 | + |
| 31 | + Private Function DebugEnter(Address As UInteger, Data() As Byte) As String |
| 32 | + Dim Response As String |
| 33 | + |
| 34 | + Response = "E " & Address.ToString("X4") & " " & BitConverter.ToString(Data).Replace("-", " ") |
| 35 | + |
| 36 | + Return Response |
| 37 | + End Function |
| 38 | + |
| 39 | + Private Function DebugLoad(Address As UInteger, Drive As Byte, FirstSector As UInteger, Number As UShort) As String |
| 40 | + Dim Response As String |
| 41 | + |
| 42 | + Response = "L " & Address.ToString("X4") & " " & Drive & " " & FirstSector.ToString("X") & " " & Number.ToString("X") |
| 43 | + |
| 44 | + Return Response |
| 45 | + End Function |
| 46 | + |
| 47 | + Private Function DebugWrite(Address As UInteger, Drive As Byte, FirstSector As UInteger, Number As UShort) As String |
| 48 | + Dim Response As String |
| 49 | + |
| 50 | + Response = "W " & Address.ToString("X4") & " " & Drive & " " & FirstSector.ToString("X") & " " & Number.ToString("X") |
| 51 | + |
| 52 | + Return Response |
| 53 | + End Function |
| 54 | + |
| 55 | + Private Function GetSegment(Offset As UInteger, Value As Object) As DebugSegment |
| 56 | + Dim Segment As DebugSegment |
| 57 | + |
| 58 | + Segment.Offset = Offset |
| 59 | + If TypeOf Value Is System.UInt16 Then |
| 60 | + Segment.Data = ConvertUShortToByteArray(Value) |
| 61 | + ElseIf TypeOf Value Is System.UInt32 Then |
| 62 | + Segment.Data = ConvertUintegerToByteArray(Value) |
| 63 | + ElseIf TypeOf Value Is System.Byte Then |
| 64 | + Segment.Data = ConvertByteToByteArray(Value) |
| 65 | + Else |
| 66 | + Segment.Data = Value |
| 67 | + End If |
| 68 | + |
| 69 | + Return Segment |
| 70 | + End Function |
| 71 | + |
| 72 | + Public Sub GenerateDebugPackage(Disk As DiskImage.Disk, ImageData As LoadedImageData) |
| 73 | + Dim TempPath As String = Path.GetTempPath() & Guid.NewGuid().ToString() |
| 74 | + Dim ContentPath As String = Path.Combine(TempPath, "CONTENT") |
| 75 | + Dim ToolsPath As String = Path.Combine(ContentPath, "TOOLS") |
| 76 | + Dim DataPath As String = Path.Combine(ContentPath, "DATA") |
| 77 | + Dim ZipPath As String = Path.Combine(TempPath, "PATCH.ZIP") |
| 78 | + |
| 79 | + Directory.CreateDirectory(DataPath) |
| 80 | + Directory.CreateDirectory(ToolsPath) |
| 81 | + |
| 82 | + GenerateDebugScripts(DataPath, Disk, ImageData.SessionModifications) |
| 83 | + GenerateDirectoryDump(DataPath, Disk, ImageData.CachedRootDir) |
| 84 | + |
| 85 | + WriteResourceToFile("CHOICE.COM", Path.Combine(ToolsPath, "CHOICE.COM")) |
| 86 | + WriteResourceToFile("CRC32.COM", Path.Combine(ToolsPath, "CRC32.COM")) |
| 87 | + WriteResourceToFile("PATCH.BAT", Path.Combine(ContentPath, "PATCH.BAT")) |
| 88 | + |
| 89 | + ZipContent(ZipPath, ContentPath) |
| 90 | + |
| 91 | + Dim Dialog = New SaveFileDialog With { |
| 92 | + .FileName = Path.GetFileName(ZipPath), |
| 93 | + .Filter = "Zip Archive (*.zip)|*.zip" |
| 94 | + } |
| 95 | + If Dialog.ShowDialog = DialogResult.OK Then |
| 96 | + File.Copy(ZipPath, Dialog.FileName, True) |
| 97 | + End If |
| 98 | + |
| 99 | + Directory.Delete(TempPath, True) |
| 100 | + End Sub |
| 101 | + |
| 102 | + Public Sub GenerateDirectoryDump(DataPath As String, Disk As DiskImage.Disk, CachedRootDir() As Byte) |
| 103 | + Dim FileName As String |
| 104 | + |
| 105 | + Dim SectorStart = Disk.BootSector.RootDirectoryRegionStart |
| 106 | + Dim SectorEnd = Disk.BootSector.DataRegionStart |
| 107 | + Dim Length = (SectorEnd - SectorStart) * Disk.BootSector.BytesPerSector |
| 108 | + Dim Offset As UInteger = 256 |
| 109 | + |
| 110 | + For Index = 0 To 1 |
| 111 | + FileName = Path.Combine(DataPath, "DIRDUMP" & Index & ".TXT") |
| 112 | + Dim SB = New StringBuilder() |
| 113 | + |
| 114 | + SB.AppendLine("N ROOTDIR.TMP") |
| 115 | + SB.AppendLine(DebugLoad(Offset, Index, SectorStart, SectorEnd - SectorStart)) |
| 116 | + SB.AppendLine("RCX") |
| 117 | + SB.AppendLine(Length.ToString("X4")) |
| 118 | + SB.AppendLine("RBX") |
| 119 | + SB.AppendLine("0") |
| 120 | + SB.AppendLine("W " & Offset.ToString("X4")) |
| 121 | + SB.AppendLine("Q") |
| 122 | + |
| 123 | + File.WriteAllText(FileName, SB.ToString) |
| 124 | + Next Index |
| 125 | + |
| 126 | + FileName = Path.Combine(DataPath, "ROOTDIR.CRC") |
| 127 | + File.WriteAllText(FileName, "ROOTDIR.TMP " & Crc32.ComputeChecksum(Disk.Directory.GetContent()).ToString("X8")) |
| 128 | + End Sub |
| 129 | + |
| 130 | + Public Sub GenerateDebugScripts(DataPath As String, Disk As DiskImage.Disk, Modifications As Hashtable) |
| 131 | + Dim ScriptModifications As New Hashtable |
| 132 | + Dim SectorDict As New Dictionary(Of UInteger, List(Of DebugSegment)) |
| 133 | + Dim SegmentList As List(Of DebugSegment) |
| 134 | + Dim ByteLenPerLine As Byte = 16 |
| 135 | + |
| 136 | + Dim DriveAFile As String = Path.Combine(DataPath, "DRIVE0.TXT") |
| 137 | + Dim DriveBFile As String = Path.Combine(DataPath, "DRIVE1.TXT") |
| 138 | + |
| 139 | + Dim SB_A = New StringBuilder() |
| 140 | + Dim SB_B = New StringBuilder() |
| 141 | + |
| 142 | + For Each Offset As UInteger In Modifications.Keys |
| 143 | + ScriptModifications.Item(Offset) = Modifications.Item(Offset) |
| 144 | + Next |
| 145 | + For Each Offset As UInteger In Disk.Modifications.Keys |
| 146 | + ScriptModifications.Item(Offset) = Disk.Modifications.Item(Offset) |
| 147 | + Next |
| 148 | + |
| 149 | + Dim OffsetArray(ScriptModifications.Keys.Count - 1) As UInteger |
| 150 | + ScriptModifications.Keys.CopyTo(OffsetArray, 0) |
| 151 | + Array.Sort(OffsetArray) |
| 152 | + |
| 153 | + For Each Offset As UInteger In OffsetArray |
| 154 | + Dim Sector As UInteger = Disk.OffsetToSector(Offset) |
| 155 | + |
| 156 | + If SectorDict.ContainsKey(Sector) Then |
| 157 | + SegmentList = SectorDict.Item(Sector) |
| 158 | + Else |
| 159 | + SegmentList = New List(Of DebugSegment) |
| 160 | + SectorDict.Add(Sector, SegmentList) |
| 161 | + End If |
| 162 | + |
| 163 | + Dim SectorOffset As UInteger = Disk.SectorToOffset(Sector) |
| 164 | + Dim Value = ScriptModifications.Item(Offset) |
| 165 | + SegmentList.Add(GetSegment(Offset - SectorOffset, Value)) |
| 166 | + Next |
| 167 | + |
| 168 | + For Each Sector In SectorDict.Keys |
| 169 | + SB_A.AppendLine(DebugLoad(0, 0, Sector, 1)) |
| 170 | + SB_B.AppendLine(DebugLoad(0, 1, Sector, 1)) |
| 171 | + SegmentList = SectorDict.Item(Sector) |
| 172 | + For Each Segment In SegmentList |
| 173 | + For I = 0 To Math.Ceiling(Segment.Data.Length / ByteLenPerLine) - 1 |
| 174 | + Dim SourceIndex As Integer = I * ByteLenPerLine |
| 175 | + Dim SegmentOffset As Integer = Segment.Offset + SourceIndex |
| 176 | + Dim Length As Integer = Math.Min(ByteLenPerLine, Segment.Data.Length - SourceIndex) |
| 177 | + Dim Block(Length - 1) As Byte |
| 178 | + Array.Copy(Segment.Data, SourceIndex, Block, 0, Length) |
| 179 | + SB_A.AppendLine(DebugEnter(SegmentOffset, Block)) |
| 180 | + SB_B.AppendLine(DebugEnter(SegmentOffset, Block)) |
| 181 | + Next |
| 182 | + Next |
| 183 | + SB_A.AppendLine(DebugWrite(0, 0, Sector, 1)) |
| 184 | + SB_B.AppendLine(DebugWrite(0, 1, Sector, 1)) |
| 185 | + Next |
| 186 | + SB_A.AppendLine("Q") |
| 187 | + SB_B.AppendLine("Q") |
| 188 | + |
| 189 | + File.WriteAllText(DriveAFile, SB_A.ToString) |
| 190 | + File.WriteAllText(DriveBFile, SB_B.ToString) |
| 191 | + End Sub |
| 192 | + |
| 193 | + Private Sub WriteResourceToFile(ResourceName As String, FileName As String) |
| 194 | + Dim AppName = System.Diagnostics.Process.GetCurrentProcess().ProcessName |
| 195 | + Using Resource = Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(AppName & "." & ResourceName) |
| 196 | + Using File = New FileStream(FileName, FileMode.Create, FileAccess.Write) |
| 197 | + Resource.CopyTo(File) |
| 198 | + End Using |
| 199 | + End Using |
| 200 | + End Sub |
| 201 | + |
| 202 | + Private Sub ZipContent(ZipPath As String, ContentPath As String) |
| 203 | + Using ZipStream As Stream = New FileStream(ZipPath, FileMode.Create, FileAccess.Write) |
| 204 | + Using Archive As New ZipArchive(ZipStream, ZipArchiveMode.Create) |
| 205 | + For Each FilePath In Directory.GetFiles(ContentPath, "*.*", SearchOption.AllDirectories) |
| 206 | + Dim RelativePath = FilePath.Replace(ContentPath & "\", String.Empty) |
| 207 | + Using FileStream As Stream = New FileStream(FilePath, FileMode.Open, FileAccess.Read) |
| 208 | + Using FileStreamInZip As Stream = Archive.CreateEntry(RelativePath).Open() |
| 209 | + FileStream.CopyTo(FileStreamInZip) |
| 210 | + End Using |
| 211 | + End Using |
| 212 | + Next |
| 213 | + End Using |
| 214 | + End Using |
| 215 | + End Sub |
| 216 | +End Module |
0 commit comments