Compare commits
4 Commits
f49754928e
...
b3c3ce4821
| Author | SHA1 | Date | |
|---|---|---|---|
| b3c3ce4821 | |||
| 1497ee2df6 | |||
| 9ff9642f65 | |||
| 18c5554211 |
@ -37,19 +37,4 @@ 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,25 +41,29 @@ 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
|
||||||
@ -188,36 +192,35 @@ export class FloppyDisk {
|
|||||||
return chain
|
return chain
|
||||||
}
|
}
|
||||||
|
|
||||||
addDirectory(listing: string, entries: TDirEntry[]) {
|
addDirectory(listing: string, path: 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 (entry.type !== 'standard-entry') {
|
if (
|
||||||
|
entry.type !== 'standard-entry' ||
|
||||||
|
entry.attributes.volumeId ||
|
||||||
|
entry.name === '..' ||
|
||||||
|
entry.name === '.'
|
||||||
|
) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
const fullName = `${entry.name}${entry.extension ? '.' + entry.extension : ''}`
|
listing += `${path.join('\\') + '\\'}${entry.name}`
|
||||||
|
|
||||||
if (entry.name === '.' || entry.name === '..' || entry.attributes.volumeId) {
|
if (entry.attributes.directory) {
|
||||||
// do nothing
|
listing += '\\<br/>'
|
||||||
} else if (entry.attributes.directory) {
|
listing = this.addDirectory(listing, [...path, entry.name], entry.subDirEntries)
|
||||||
listing += `\n<li>${fullName}\\`
|
|
||||||
listing = this.addDirectory(listing, entry.subDirEntries)
|
|
||||||
listing += '</li>\n'
|
|
||||||
} else {
|
} else {
|
||||||
listing += `\n<li>${fullName}</li>\n`
|
listing += '<br/>'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
listing += '\n</ul>'
|
|
||||||
return listing
|
return listing
|
||||||
}
|
}
|
||||||
|
|
||||||
buildFileListing(): string {
|
buildFileListing(): string {
|
||||||
let listing = '<ul>A:\\'
|
let listing = '<p>\\<br/>'
|
||||||
listing += this.addDirectory('', this.rootDirEntries ?? [])
|
listing += this.addDirectory('', [''], this.rootDirEntries ?? [])
|
||||||
listing += '</ul>'
|
listing += '</p>'
|
||||||
return listing
|
return listing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -305,20 +308,25 @@ 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' }
|
return { type: 'final-entry', id }
|
||||||
} else if (firstByte === 0xe5) {
|
} else if (firstByte === 0xe5) {
|
||||||
return { type: 'unused-entry' }
|
return { type: 'unused-entry', id }
|
||||||
} else if (attributeByte === 0x0f) {
|
} else if (attributeByte === 0x0f) {
|
||||||
return { type: 'long-filename-entry' }
|
return { type: 'long-filename-entry', id }
|
||||||
} else {
|
} else {
|
||||||
const asciiDecoder = new TextDecoder('ascii')
|
const asciiDecoder = new TextDecoder('ascii')
|
||||||
const name = asciiDecoder.decode(data.buffer.slice(data.byteOffset, data.byteOffset + 8)).trim()
|
const basename = asciiDecoder
|
||||||
|
.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 = {
|
||||||
@ -335,24 +343,25 @@ 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 !== '..') {
|
||||||
entry.clusterChain = fd.clusterChain(entry.firstCluster)
|
const clusterChain = fd.clusterChain(entry.firstCluster)
|
||||||
|
|
||||||
const dataSize = entry.clusterChain.length * fd.bytesPerCluster
|
const dataSize = 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 < entry.clusterChain.length; i++) {
|
for (let i = 0; i < clusterChain.length; i++) {
|
||||||
const offset = (entry.clusterChain[i] - 2) * fd.bytesPerCluster
|
const offset = (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