Compare commits
3 Commits
85e07598d4
...
e6bdde292d
| Author | SHA1 | Date | |
|---|---|---|---|
| e6bdde292d | |||
| 6d79a35ce5 | |||
| 98ad0d4dfe |
@ -1,20 +1,18 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { getBiosParameterBlock } from '@/floppy/disk.ts'
|
import { FloppyDisk } from '@/floppy/disk.ts'
|
||||||
import PropertyList from '@/components/PropertyList.vue'
|
|
||||||
|
|
||||||
const { data = new ArrayBuffer(0) } = defineProps<{ data: ArrayBuffer }>()
|
const { data = new ArrayBuffer(0) } = defineProps<{ data: ArrayBuffer }>()
|
||||||
|
|
||||||
const biosParameterBlock = computed(() => {
|
const floppyDisk = computed(() => {
|
||||||
return getBiosParameterBlock(data)
|
return new FloppyDisk(data)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<section v-if="biosParameterBlock">
|
<section v-if="floppyDisk.bootSectorInfo">
|
||||||
<h3>BIOS Parameter Block (BPB)</h3>
|
<h3>Boot Sector</h3>
|
||||||
<PropertyList :obj="biosParameterBlock" />
|
<pre>{{ floppyDisk.bootSectorInfo }}</pre>
|
||||||
<pre>{{ biosParameterBlock }}</pre>
|
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@ -14,8 +14,12 @@ const hexDump = computed(() => {
|
|||||||
return ''.padEnd(80, ' ')
|
return ''.padEnd(80, ' ')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let lastLine = ''
|
||||||
|
let repeat = false
|
||||||
|
|
||||||
while (offset < total) {
|
while (offset < total) {
|
||||||
const values = [offset.toString(16).padStart(8, '0')]
|
const offsetStr = offset.toString(16).padStart(8, '0')
|
||||||
|
const values = []
|
||||||
const asciiValues: string[] = []
|
const asciiValues: string[] = []
|
||||||
let cnt = 0
|
let cnt = 0
|
||||||
while (offset < total && cnt < 16) {
|
while (offset < total && cnt < 16) {
|
||||||
@ -31,7 +35,7 @@ const hexDump = computed(() => {
|
|||||||
values.push(byte.toString(16).padStart(2, '0'))
|
values.push(byte.toString(16).padStart(2, '0'))
|
||||||
|
|
||||||
const char = String.fromCharCode(byte)
|
const char = String.fromCharCode(byte)
|
||||||
if (char > ' ' && char <= 'a') {
|
if (char >= ' ' && char <= '~') {
|
||||||
asciiValues.push(char)
|
asciiValues.push(char)
|
||||||
} else {
|
} else {
|
||||||
asciiValues.push('.')
|
asciiValues.push('.')
|
||||||
@ -60,7 +64,21 @@ const hexDump = computed(() => {
|
|||||||
asciiValues.push('|')
|
asciiValues.push('|')
|
||||||
}
|
}
|
||||||
|
|
||||||
lines.push(values.join(' ') + asciiValues.join(''))
|
const line = values.join(' ')
|
||||||
|
if (line !== lastLine) {
|
||||||
|
if (repeat) {
|
||||||
|
lines.push('*'.padEnd(80, ' '))
|
||||||
|
}
|
||||||
|
repeat = false
|
||||||
|
|
||||||
|
lines.push([offsetStr, line].join(' ') + asciiValues.join(''))
|
||||||
|
lastLine = line
|
||||||
|
} else {
|
||||||
|
repeat = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (repeat) {
|
||||||
|
lines.push('*'.padEnd(80, ' '))
|
||||||
}
|
}
|
||||||
lines.push(offset.toString(16).padStart(8, '0').padEnd(80, ' '))
|
lines.push(offset.toString(16).padStart(8, '0').padEnd(80, ' '))
|
||||||
return lines.join('\n')
|
return lines.join('\n')
|
||||||
@ -76,7 +94,7 @@ pre {
|
|||||||
width: fit-content;
|
width: fit-content;
|
||||||
padding: 0.5em 1em 10em;
|
padding: 0.5em 1em 10em;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
overflow: scroll;
|
overflow-y: scroll;
|
||||||
min-height: 10rem;
|
min-height: 10rem;
|
||||||
height: 20rem;
|
height: 20rem;
|
||||||
max-height: 20rem;
|
max-height: 20rem;
|
||||||
|
|||||||
@ -1,61 +1,121 @@
|
|||||||
export interface BiosParameterBlock {
|
export interface IBootSectorInfo {
|
||||||
oemId: string
|
jumpInstruction: [number, number, number]
|
||||||
bytesPerSector: number
|
oemName: string
|
||||||
sectorsPerCluster: number
|
biosParameterBlock: IBiosParameterBlock
|
||||||
numReservedSectors: number
|
extendedBootSector: IExtendedBootSectorSmall
|
||||||
numFATs: number
|
bootPartitionSignature: number
|
||||||
numRootDirEntries: number
|
|
||||||
totalSectors: number
|
|
||||||
mediaTypeDescriptor: number
|
|
||||||
sectorsPerFAT: number
|
|
||||||
sectorsPerTrack: number
|
|
||||||
numHeads: number
|
|
||||||
bootSignature: number
|
|
||||||
volumeId: number
|
|
||||||
volumeLabel: string
|
|
||||||
fileSystemId: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getBiosParameterBlock(buffer: ArrayBuffer): BiosParameterBlock | null {
|
export interface IExtendedBootSectorSmall {
|
||||||
if (buffer.byteLength < 64) {
|
driveNumber: number
|
||||||
|
reserved: number
|
||||||
|
bootSignature: number
|
||||||
|
volumeId?: number
|
||||||
|
volumeLabel?: string
|
||||||
|
fileSystemType?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IBiosParameterBlock {
|
||||||
|
bytesPerSector: number
|
||||||
|
sectorsPerCluster: number
|
||||||
|
reservedSectorCount: number
|
||||||
|
tableCount: number
|
||||||
|
rootEntryCount: number
|
||||||
|
totalSectorsSmall: number
|
||||||
|
mediaDescriptorType: number
|
||||||
|
sectorsPerTableSmall: number
|
||||||
|
sectorsPerTrack: number
|
||||||
|
headCount: number
|
||||||
|
hiddenSectorCount: number
|
||||||
|
totalSectorsLarge: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FloppyDisk {
|
||||||
|
private readonly _buffer = new ArrayBuffer(0)
|
||||||
|
private _bootSector: IBootSectorInfo | null = null
|
||||||
|
|
||||||
|
constructor(buffer: ArrayBuffer) {
|
||||||
|
this._buffer = buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
get bootSectorInfo() {
|
||||||
|
return (this._bootSector = this._bootSector ?? decodeBootSector(this._buffer))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeBootSector(buffer: ArrayBuffer): IBootSectorInfo | null {
|
||||||
|
if (buffer.byteLength < 512) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const asciiDecoder = new TextDecoder('ascii')
|
||||||
const data = new DataView(buffer)
|
const data = new DataView(buffer)
|
||||||
|
|
||||||
const asciiDecoder = new TextDecoder('ascii')
|
const jumpInstruction: [number, number, number] = [
|
||||||
|
data.getUint8(0),
|
||||||
|
data.getUint8(1),
|
||||||
|
data.getUint8(2),
|
||||||
|
]
|
||||||
|
|
||||||
const oemId = asciiDecoder.decode(buffer.slice(3, 11))
|
const oemName = asciiDecoder.decode(buffer.slice(3, 11))
|
||||||
const bytesPerSector = data.getUint16(11, true)
|
const bytesPerSector = data.getUint16(11, true)
|
||||||
const sectorsPerCluster = data.getUint8(13)
|
const sectorsPerCluster = data.getUint8(13)
|
||||||
const numReservedSectors = data.getUint16(14, true)
|
const reservedSectorCount = data.getUint16(14, true)
|
||||||
const numFATs = data.getUint8(16)
|
const tableCount = data.getUint8(16)
|
||||||
const numRootDirEntries = data.getUint16(17, true)
|
const rootEntryCount = data.getUint16(17, true)
|
||||||
const totalSectors = data.getUint16(19, true)
|
const totalSectorsSmall = data.getUint16(19, true)
|
||||||
const mediaTypeDescriptor = data.getUint8(21)
|
const mediaDescriptorType = data.getUint8(21)
|
||||||
const sectorsPerFAT = data.getUint16(22, true)
|
const sectorsPerTableSmall = data.getUint16(22, true)
|
||||||
const sectorsPerTrack = data.getUint16(24, true)
|
const sectorsPerTrack = data.getUint16(24, true)
|
||||||
const numHeads = data.getUint16(26, true)
|
const headCount = data.getUint16(26, true)
|
||||||
|
const hiddenSectorCount = data.getUint32(28, true)
|
||||||
|
const totalSectorsLarge = data.getUint32(32, true)
|
||||||
|
const driveNumber = data.getUint8(36)
|
||||||
|
const reserved = data.getUint8(37)
|
||||||
const bootSignature = data.getUint8(38)
|
const bootSignature = data.getUint8(38)
|
||||||
const volumeId = data.getUint32(39, true)
|
|
||||||
const volumeLabel = asciiDecoder.decode(buffer.slice(43, 54))
|
let volumeId
|
||||||
const fileSystemId = asciiDecoder.decode(buffer.slice(54, 62))
|
if (bootSignature === 0x28 || bootSignature === 0x29) {
|
||||||
|
volumeId = data.getUint32(39, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
let volumeLabel
|
||||||
|
if (bootSignature === 0x29) {
|
||||||
|
volumeLabel = asciiDecoder.decode(buffer.slice(43, 54))
|
||||||
|
}
|
||||||
|
|
||||||
|
let fileSystemType
|
||||||
|
if (bootSignature === 0x29) {
|
||||||
|
fileSystemType = asciiDecoder.decode(buffer.slice(54, 62))
|
||||||
|
}
|
||||||
|
|
||||||
|
const bootPartitionSignature = data.getUint16(510, true)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
oemId,
|
jumpInstruction,
|
||||||
bytesPerSector,
|
oemName,
|
||||||
sectorsPerCluster,
|
bootPartitionSignature,
|
||||||
numReservedSectors,
|
biosParameterBlock: {
|
||||||
numFATs,
|
bytesPerSector,
|
||||||
numRootDirEntries,
|
sectorsPerCluster,
|
||||||
totalSectors,
|
reservedSectorCount,
|
||||||
mediaTypeDescriptor,
|
tableCount,
|
||||||
sectorsPerFAT,
|
rootEntryCount,
|
||||||
sectorsPerTrack,
|
totalSectorsSmall,
|
||||||
numHeads,
|
mediaDescriptorType,
|
||||||
bootSignature,
|
sectorsPerTableSmall,
|
||||||
volumeId,
|
sectorsPerTrack,
|
||||||
volumeLabel,
|
headCount,
|
||||||
fileSystemId,
|
hiddenSectorCount,
|
||||||
|
totalSectorsLarge,
|
||||||
|
},
|
||||||
|
extendedBootSector: {
|
||||||
|
driveNumber,
|
||||||
|
reserved,
|
||||||
|
bootSignature,
|
||||||
|
volumeId,
|
||||||
|
volumeLabel,
|
||||||
|
fileSystemType,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user