Compare commits
No commits in common. "b3c3ce482163ccb57c03d547c9492bca1cca2a8d" and "f49754928ea5b334e494c8121eb4382818449040" have entirely different histories.
b3c3ce4821
...
f49754928e
@ -37,4 +37,19 @@ pre {
|
|||||||
color: #c0c0c0;
|
color: #c0c0c0;
|
||||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:deep(ul) {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(ul ul) {
|
||||||
|
padding: 0 0 0 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(li) {
|
||||||
|
list-style: none;
|
||||||
|
line-height: 1.5rem;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -41,29 +41,25 @@ export interface IAttributes {
|
|||||||
|
|
||||||
export interface IStandardDirEntry {
|
export interface IStandardDirEntry {
|
||||||
type: 'standard-entry'
|
type: 'standard-entry'
|
||||||
id: string
|
|
||||||
name: string
|
name: string
|
||||||
basename: string
|
|
||||||
extension: string
|
extension: string
|
||||||
attributes: IAttributes
|
attributes: IAttributes
|
||||||
size: number
|
size: number
|
||||||
firstCluster: number
|
firstCluster: number
|
||||||
|
clusterChain: number[]
|
||||||
subDirEntries: TDirEntry[]
|
subDirEntries: TDirEntry[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ILongFileNameDirEntry {
|
export interface ILongFileNameDirEntry {
|
||||||
type: 'long-filename-entry'
|
type: 'long-filename-entry'
|
||||||
id: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IFinalDirEntry {
|
export interface IFinalDirEntry {
|
||||||
type: 'final-entry'
|
type: 'final-entry'
|
||||||
id: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IUnusedDirEntry {
|
export interface IUnusedDirEntry {
|
||||||
type: 'unused-entry'
|
type: 'unused-entry'
|
||||||
id: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TDirEntry = IStandardDirEntry | ILongFileNameDirEntry | IFinalDirEntry | IUnusedDirEntry
|
export type TDirEntry = IStandardDirEntry | ILongFileNameDirEntry | IFinalDirEntry | IUnusedDirEntry
|
||||||
@ -192,35 +188,36 @@ export class FloppyDisk {
|
|||||||
return chain
|
return chain
|
||||||
}
|
}
|
||||||
|
|
||||||
addDirectory(listing: string, path: string[], entries: TDirEntry[]) {
|
addDirectory(listing: string, entries: TDirEntry[]) {
|
||||||
|
listing += '\n<ul>'
|
||||||
|
|
||||||
for (let i = 0; i < entries.length; i++) {
|
for (let i = 0; i < entries.length; i++) {
|
||||||
const entry = entries[i]
|
const entry = entries[i]
|
||||||
if (
|
if (entry.type !== 'standard-entry') {
|
||||||
entry.type !== 'standard-entry' ||
|
|
||||||
entry.attributes.volumeId ||
|
|
||||||
entry.name === '..' ||
|
|
||||||
entry.name === '.'
|
|
||||||
) {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
listing += `${path.join('\\') + '\\'}${entry.name}`
|
const fullName = `${entry.name}${entry.extension ? '.' + entry.extension : ''}`
|
||||||
|
|
||||||
if (entry.attributes.directory) {
|
if (entry.name === '.' || entry.name === '..' || entry.attributes.volumeId) {
|
||||||
listing += '\\<br/>'
|
// do nothing
|
||||||
listing = this.addDirectory(listing, [...path, entry.name], entry.subDirEntries)
|
} else if (entry.attributes.directory) {
|
||||||
|
listing += `\n<li>${fullName}\\`
|
||||||
|
listing = this.addDirectory(listing, entry.subDirEntries)
|
||||||
|
listing += '</li>\n'
|
||||||
} else {
|
} else {
|
||||||
listing += '<br/>'
|
listing += `\n<li>${fullName}</li>\n`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
listing += '\n</ul>'
|
||||||
return listing
|
return listing
|
||||||
}
|
}
|
||||||
|
|
||||||
buildFileListing(): string {
|
buildFileListing(): string {
|
||||||
let listing = '<p>\\<br/>'
|
let listing = '<ul>A:\\'
|
||||||
listing += this.addDirectory('', [''], this.rootDirEntries ?? [])
|
listing += this.addDirectory('', this.rootDirEntries ?? [])
|
||||||
listing += '</p>'
|
listing += '</ul>'
|
||||||
return listing
|
return listing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -308,25 +305,20 @@ function decodeDirectoryEntry(data: DataView, fd: FloppyDisk): TDirEntry | null
|
|||||||
|
|
||||||
const firstByte = data.getUint8(0)
|
const firstByte = data.getUint8(0)
|
||||||
const attributeByte = data.getUint8(11)
|
const attributeByte = data.getUint8(11)
|
||||||
const id = crypto.randomUUID()
|
|
||||||
|
|
||||||
if (firstByte === 0) {
|
if (firstByte === 0) {
|
||||||
return { type: 'final-entry', id }
|
return { type: 'final-entry' }
|
||||||
} else if (firstByte === 0xe5) {
|
} else if (firstByte === 0xe5) {
|
||||||
return { type: 'unused-entry', id }
|
return { type: 'unused-entry' }
|
||||||
} else if (attributeByte === 0x0f) {
|
} else if (attributeByte === 0x0f) {
|
||||||
return { type: 'long-filename-entry', id }
|
return { type: 'long-filename-entry' }
|
||||||
} else {
|
} else {
|
||||||
const asciiDecoder = new TextDecoder('ascii')
|
const asciiDecoder = new TextDecoder('ascii')
|
||||||
const basename = asciiDecoder
|
const name = asciiDecoder.decode(data.buffer.slice(data.byteOffset, data.byteOffset + 8)).trim()
|
||||||
.decode(data.buffer.slice(data.byteOffset, data.byteOffset + 8))
|
|
||||||
.trim()
|
|
||||||
const extension = asciiDecoder
|
const extension = asciiDecoder
|
||||||
.decode(data.buffer.slice(data.byteOffset + 8, data.byteOffset + 11))
|
.decode(data.buffer.slice(data.byteOffset + 8, data.byteOffset + 11))
|
||||||
.trim()
|
.trim()
|
||||||
|
|
||||||
const name = basename + (extension ? '.' + extension : '')
|
|
||||||
|
|
||||||
const attributeByte = data.getUint8(11)
|
const attributeByte = data.getUint8(11)
|
||||||
|
|
||||||
const attributes: IAttributes = {
|
const attributes: IAttributes = {
|
||||||
@ -343,25 +335,24 @@ function decodeDirectoryEntry(data: DataView, fd: FloppyDisk): TDirEntry | null
|
|||||||
|
|
||||||
const entry: IStandardDirEntry = {
|
const entry: IStandardDirEntry = {
|
||||||
type: 'standard-entry',
|
type: 'standard-entry',
|
||||||
id,
|
|
||||||
name,
|
name,
|
||||||
basename,
|
|
||||||
extension,
|
extension,
|
||||||
attributes,
|
attributes,
|
||||||
firstCluster,
|
firstCluster,
|
||||||
|
clusterChain: [],
|
||||||
size,
|
size,
|
||||||
subDirEntries: [],
|
subDirEntries: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry.attributes.directory && entry.name !== '.' && entry.name !== '..') {
|
if (entry.attributes.directory && entry.name !== '.' && entry.name !== '..') {
|
||||||
const clusterChain = fd.clusterChain(entry.firstCluster)
|
entry.clusterChain = fd.clusterChain(entry.firstCluster)
|
||||||
|
|
||||||
const dataSize = clusterChain.length * fd.bytesPerCluster
|
const dataSize = entry.clusterChain.length * fd.bytesPerCluster
|
||||||
|
|
||||||
if (dataSize !== 0) {
|
if (dataSize !== 0) {
|
||||||
const entryData = new Uint8Array(dataSize)
|
const entryData = new Uint8Array(dataSize)
|
||||||
for (let i = 0; i < clusterChain.length; i++) {
|
for (let i = 0; i < entry.clusterChain.length; i++) {
|
||||||
const offset = (clusterChain[i] - 2) * fd.bytesPerCluster
|
const offset = (entry.clusterChain[i] - 2) * fd.bytesPerCluster
|
||||||
const view = new Uint8Array(fd.buffer, fd.dataOffset + offset, fd.bytesPerCluster)
|
const view = new Uint8Array(fd.buffer, fd.dataOffset + offset, fd.bytesPerCluster)
|
||||||
entryData.set(view, i * fd.bytesPerCluster)
|
entryData.set(view, i * fd.bytesPerCluster)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user