From 8954b5b2d38238f7a8a2f702523523a6d2b7172d Mon Sep 17 00:00:00 2001 From: Rob Greene Date: Sun, 27 Jul 2025 20:27:09 -0500 Subject: [PATCH 1/6] This corrects for a naming issue if the file is given on the command line; a full directory path causes issues. --- .../acx/command/ImportCommand.java | 26 +++++++------------ .../acx/fileutil/FileUtils.java | 2 +- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/app/cli-acx/src/main/java/io/github/applecommander/acx/command/ImportCommand.java b/app/cli-acx/src/main/java/io/github/applecommander/acx/command/ImportCommand.java index b2e2fb53..2390c1eb 100644 --- a/app/cli-acx/src/main/java/io/github/applecommander/acx/command/ImportCommand.java +++ b/app/cli-acx/src/main/java/io/github/applecommander/acx/command/ImportCommand.java @@ -19,18 +19,6 @@ */ package io.github.applecommander.acx.command; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.*; -import java.util.function.Function; -import java.util.logging.Logger; - import com.webcodepro.applecommander.storage.DirectoryEntry; import com.webcodepro.applecommander.storage.FileEntry; import com.webcodepro.applecommander.storage.os.prodos.ProdosFormatDisk; @@ -42,7 +30,6 @@ import com.webcodepro.applecommander.util.readerwriter.OverrideFileEntryReader; import com.webcodepro.shrinkit.HeaderBlock; import com.webcodepro.shrinkit.NuFileArchive; import com.webcodepro.shrinkit.ThreadRecord; - import io.github.applecommander.acx.base.ReadWriteDiskCommandOptions; import io.github.applecommander.acx.converter.IntegerTypeConverter; import io.github.applecommander.acx.fileutil.FileUtils; @@ -60,6 +47,13 @@ import picocli.CommandLine.Command; import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.function.Function; +import java.util.logging.Logger; + @Command(name = "import", description = "Import file onto disk.", aliases = { "put" }) public class ImportCommand extends ReadWriteDiskCommandOptions { @@ -116,7 +110,7 @@ public class ImportCommand extends ReadWriteDiskCommandOptions { new IOException(String.format("Directory '%s' not found.", dir))); } } - + FileUtils copier = new FileUtils(overwriteFlag); FileEntryReader inputReader = inputData.get(); for (FileEntryReader processorReader : processor.apply(inputReader)) { @@ -161,7 +155,7 @@ public class ImportCommand extends ReadWriteDiskCommandOptions { byte[] data = Files.readAllBytes(path); fileEntryReader = OverrideFileEntryReader.builder() .fileData(data) - .filename(filename) + .filename(path.getFileName().toString()) .prodosFiletype("BIN") .build(); } catch (IOException e) { @@ -365,7 +359,7 @@ public class ImportCommand extends ReadWriteDiskCommandOptions { } public static class Overrides { - @Option(names = { "-t", "--type" }, description = "ProDOS File type. " + @Option(names = { "-t", "--type" }, description = "ProDOS or native file type. " + "(Each filesystem translates between it's native types and ProDOS.)") private Optional fileType; diff --git a/app/cli-acx/src/main/java/io/github/applecommander/acx/fileutil/FileUtils.java b/app/cli-acx/src/main/java/io/github/applecommander/acx/fileutil/FileUtils.java index 35729ffb..8647c977 100644 --- a/app/cli-acx/src/main/java/io/github/applecommander/acx/fileutil/FileUtils.java +++ b/app/cli-acx/src/main/java/io/github/applecommander/acx/fileutil/FileUtils.java @@ -85,7 +85,7 @@ public class FileUtils { } public void copyFile(DirectoryEntry directory, FileEntryReader source) throws DiskException { - String sourceName = source.getFilename().get(); + String sourceName = source.getFilename().orElseThrow(); String sanitizedName = directory.getFormattedDisk().getSuggestedFilename(sourceName); final Optional fileEntry = directory.getFiles().stream() .filter(entry -> entry.getFilename().equals(sanitizedName)) From 3353d971ca2468c38794f3abce5f8ef24fb05b98 Mon Sep 17 00:00:00 2001 From: Rob Greene Date: Mon, 28 Jul 2025 10:04:38 -0500 Subject: [PATCH 2/6] Change FormattedDisk#fromProdosFiletype to be FormattedDisk#toNativeFiletype and updated operations to allow native file types and pass them through. --- .../applecommander/storage/FormattedDisk.java | 6 ++++-- .../storage/os/cpm/CpmFormatDisk.java | 2 +- .../storage/os/dos33/DosFormatDisk.java | 6 +++++- .../os/gutenberg/GutenbergFormatDisk.java | 2 +- .../storage/os/nakedos/NakedosFormatDisk.java | 2 +- .../storage/os/pascal/PascalFormatDisk.java | 19 ++++++++++++------- .../storage/os/prodos/ProdosFormatDisk.java | 2 +- .../storage/os/rdos/RdosFormatDisk.java | 4 ++-- .../DosFileEntryReaderWriter.java | 2 +- .../PascalFileEntryReaderWriter.java | 2 +- .../ImportSelectFilesWizardPane.java | 2 +- 11 files changed, 30 insertions(+), 19 deletions(-) diff --git a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/FormattedDisk.java b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/FormattedDisk.java index aeafbefc..6d9adaa3 100644 --- a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/FormattedDisk.java +++ b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/FormattedDisk.java @@ -415,9 +415,11 @@ public abstract class FormattedDisk extends Disk implements DirectoryEntry { /** * Provides conversation from a given ProDOS file type since as it is common across - * many archiving tools. + * many archiving tools. This should also allow "native" filetypes to just pass-through. + * (For example, a "B" in a DOS disk should just return a "B" while a "BAS" would be + * transformed to a "B" filetype.) */ - public abstract String fromProdosFiletype(String prodosFiletype); + public abstract String toNativeFiletype(String prodosFiletype); /** * Provides conversation to a given ProDOS file type since as it is common across * many archiving tools. diff --git a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/cpm/CpmFormatDisk.java b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/cpm/CpmFormatDisk.java index c1a03ba5..35bc7726 100644 --- a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/cpm/CpmFormatDisk.java +++ b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/cpm/CpmFormatDisk.java @@ -562,7 +562,7 @@ public class CpmFormatDisk extends FormattedDisk { * many archiving tools. */ @Override - public String fromProdosFiletype(String prodosFiletype) { + public String toNativeFiletype(String prodosFiletype) { if ("TXT".equalsIgnoreCase(prodosFiletype)) { return "TXT"; } diff --git a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/dos33/DosFormatDisk.java b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/dos33/DosFormatDisk.java index e5322d6c..a181de32 100644 --- a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/dos33/DosFormatDisk.java +++ b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/dos33/DosFormatDisk.java @@ -788,7 +788,11 @@ public class DosFormatDisk extends FormattedDisk { * many archiving tools. */ @Override - public String fromProdosFiletype(String prodosFiletype) { + public String toNativeFiletype(String prodosFiletype) { + if (FILE_TYPE_MAPPING.containsKey(prodosFiletype)) { + // This is really a DOS file type. Pass it back. + return prodosFiletype; + } return FILE_TYPE_MAPPING.entrySet() .stream() .filter(e -> e.getValue().equals(prodosFiletype)) diff --git a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/gutenberg/GutenbergFormatDisk.java b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/gutenberg/GutenbergFormatDisk.java index f30836cd..dc34fc50 100644 --- a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/gutenberg/GutenbergFormatDisk.java +++ b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/gutenberg/GutenbergFormatDisk.java @@ -708,7 +708,7 @@ public class GutenbergFormatDisk extends FormattedDisk { * many archiving tools. */ @Override - public String fromProdosFiletype(String prodosFiletype) { + public String toNativeFiletype(String prodosFiletype) { return "T"; } /** diff --git a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/nakedos/NakedosFormatDisk.java b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/nakedos/NakedosFormatDisk.java index 642fd1ae..f6f55acf 100644 --- a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/nakedos/NakedosFormatDisk.java +++ b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/nakedos/NakedosFormatDisk.java @@ -546,7 +546,7 @@ public class NakedosFormatDisk extends FormattedDisk { * many archiving tools. */ @Override - public String fromProdosFiletype(String prodosFiletype) { + public String toNativeFiletype(String prodosFiletype) { return "B"; } /** diff --git a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/pascal/PascalFormatDisk.java b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/pascal/PascalFormatDisk.java index ec90a2d9..d86f3638 100644 --- a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/pascal/PascalFormatDisk.java +++ b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/pascal/PascalFormatDisk.java @@ -69,11 +69,7 @@ public class PascalFormatDisk extends FormattedDisk { DATAFILE, "BIN", "GRAF", "BIN", "FOTO", "BIN", - "securedir", "BIN", - - // Prodos => Pascal - "BIN", DATAFILE, - "TXT", TEXTFILE + "securedir", "BIN" ); /** @@ -689,8 +685,17 @@ public class PascalFormatDisk extends FormattedDisk { * many archiving tools. */ @Override - public String fromProdosFiletype(String prodosFiletype) { - return FILE_TYPE_MAP.getOrDefault(prodosFiletype, DATAFILE); + public String toNativeFiletype(String prodosFiletype) { + // Note: Can't use the map due to the 1:N relationship, so this is somewhat manual. + for (String pascalFiletype : FILE_TYPES) { + if (prodosFiletype.equalsIgnoreCase(pascalFiletype)) { + return pascalFiletype; + } + } + if ("TXT".equalsIgnoreCase(prodosFiletype)) { + return TEXTFILE; + } + return DATAFILE; } /** * Provides conversation to a given ProDOS file type since as it is common across diff --git a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/prodos/ProdosFormatDisk.java b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/prodos/ProdosFormatDisk.java index dbbb997f..ea585ec9 100644 --- a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/prodos/ProdosFormatDisk.java +++ b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/prodos/ProdosFormatDisk.java @@ -1463,7 +1463,7 @@ public class ProdosFormatDisk extends FormattedDisk { * many archiving tools. */ @Override - public String fromProdosFiletype(String prodosFiletype) { + public String toNativeFiletype(String prodosFiletype) { return prodosFiletype; }; /** diff --git a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/rdos/RdosFormatDisk.java b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/rdos/RdosFormatDisk.java index ba09bb19..d87cde7a 100644 --- a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/rdos/RdosFormatDisk.java +++ b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/rdos/RdosFormatDisk.java @@ -577,10 +577,10 @@ public class RdosFormatDisk extends FormattedDisk { * many archiving tools. */ @Override - public String fromProdosFiletype(String prodosFiletype) { + public String toNativeFiletype(String prodosFiletype) { return FILE_TYPE_MAPPING.entrySet() .stream() - .filter(e -> e.getValue().equals(prodosFiletype)) + .filter(e -> prodosFiletype.equalsIgnoreCase(e.getKey()) || prodosFiletype.equalsIgnoreCase(e.getValue())) .map(Map.Entry::getKey) .findFirst() .orElse("B"); diff --git a/lib/ac-api/src/main/java/com/webcodepro/applecommander/util/readerwriter/DosFileEntryReaderWriter.java b/lib/ac-api/src/main/java/com/webcodepro/applecommander/util/readerwriter/DosFileEntryReaderWriter.java index cdc1b13c..d09d5d61 100644 --- a/lib/ac-api/src/main/java/com/webcodepro/applecommander/util/readerwriter/DosFileEntryReaderWriter.java +++ b/lib/ac-api/src/main/java/com/webcodepro/applecommander/util/readerwriter/DosFileEntryReaderWriter.java @@ -52,7 +52,7 @@ public class DosFileEntryReaderWriter implements FileEntryReader, FileEntryWrite } @Override public void setProdosFiletype(String filetype) { - String dosFiletype = fileEntry.getFormattedDisk().fromProdosFiletype(filetype); + String dosFiletype = fileEntry.getFormattedDisk().toNativeFiletype(filetype); fileEntry.setFiletype(dosFiletype); } diff --git a/lib/ac-api/src/main/java/com/webcodepro/applecommander/util/readerwriter/PascalFileEntryReaderWriter.java b/lib/ac-api/src/main/java/com/webcodepro/applecommander/util/readerwriter/PascalFileEntryReaderWriter.java index 6b3fe0fc..249ccf6f 100644 --- a/lib/ac-api/src/main/java/com/webcodepro/applecommander/util/readerwriter/PascalFileEntryReaderWriter.java +++ b/lib/ac-api/src/main/java/com/webcodepro/applecommander/util/readerwriter/PascalFileEntryReaderWriter.java @@ -50,7 +50,7 @@ public class PascalFileEntryReaderWriter implements FileEntryReader, FileEntryWr } @Override public void setProdosFiletype(String filetype) { - fileEntry.setFiletype(fileEntry.getFormattedDisk().fromProdosFiletype(filetype)); + fileEntry.setFiletype(fileEntry.getFormattedDisk().toNativeFiletype(filetype)); } @Override diff --git a/lib/ac-swt-common/src/main/java/com/webcodepro/applecommander/ui/swt/wizard/importfile/ImportSelectFilesWizardPane.java b/lib/ac-swt-common/src/main/java/com/webcodepro/applecommander/ui/swt/wizard/importfile/ImportSelectFilesWizardPane.java index 8146af20..ba30caaa 100644 --- a/lib/ac-swt-common/src/main/java/com/webcodepro/applecommander/ui/swt/wizard/importfile/ImportSelectFilesWizardPane.java +++ b/lib/ac-swt-common/src/main/java/com/webcodepro/applecommander/ui/swt/wizard/importfile/ImportSelectFilesWizardPane.java @@ -211,7 +211,7 @@ public class ImportSelectFilesWizardPane extends WizardPane { AppleSingle as = AppleSingle.read(data); suggestedFilename = Optional.ofNullable(as.getRealName()) .orElse(suggestedFilename); - suggestedFiletype = wizard.getDisk().fromProdosFiletype( + suggestedFiletype = wizard.getDisk().toNativeFiletype( ProdosFormatDisk.getFiletype(as.getProdosFileInfo().getFileType())); suggestedAddress = Optional.ofNullable(as.getProdosFileInfo()) .map(ProdosFileInfo::getAuxType) From 7109d42ad4338b69a1e9692bcd47484d8b744475 Mon Sep 17 00:00:00 2001 From: Rob Greene Date: Mon, 28 Jul 2025 11:36:08 -0500 Subject: [PATCH 3/6] PascalFileEntry now implicitly writes the entry back to disk with every "set" method. Should close #144. --- .../storage/os/pascal/PascalFileEntry.java | 50 ++++++++++++------- .../storage/os/pascal/PascalFormatDisk.java | 12 ++--- .../storage/StorageBundle.properties | 1 + 3 files changed, 38 insertions(+), 25 deletions(-) diff --git a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/pascal/PascalFileEntry.java b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/pascal/PascalFileEntry.java index 24031263..5e787ddc 100644 --- a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/pascal/PascalFileEntry.java +++ b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/pascal/PascalFileEntry.java @@ -59,12 +59,35 @@ public class PascalFileEntry implements FileEntry { /** * Constructor for PascalFileEntry. */ - public PascalFileEntry(byte[] fileEntry, PascalFormatDisk disk) { + public PascalFileEntry(byte[] fileEntry, int index, PascalFormatDisk disk) { super(); this.fileEntry = fileEntry; + this.index = index; this.disk = disk; } + /** + * Write the fileEntry data to the disk image. + */ + protected void writeFileEntry() { + if (this.deleted) { + return; // prevents trying to save a deleted file (not a reality in Pascal filesystem) + } + List dir = disk.getDirectory(); + if (this.index < dir.size()) { + dir.set(this.index, this); + } + else if (this.index == dir.size()) { + dir.add(this.index, this); + } + else { + throw new RuntimeException(textBundle.format("PascalFormatDisk.UnexpectedDirectoryIndex", this.index, dir.size())); + } + // Since every "set" triggers a write, the file count tends to get whacked; this makes it sane. + dir.get(0).setFileCount(dir.size()-1); + disk.putDirectory(dir); + } + /** * Get the block number of the file's 1st block. */ @@ -77,6 +100,7 @@ public class PascalFileEntry implements FileEntry { */ public void setFirstBlock(int first) { AppleUtil.setWordValue(fileEntry, 0, first); + writeFileEntry(); } /** @@ -91,6 +115,7 @@ public class PascalFileEntry implements FileEntry { */ public void setLastBlock(int last) { AppleUtil.setWordValue(fileEntry, 2, last); + writeFileEntry(); } /** @@ -105,6 +130,7 @@ public class PascalFileEntry implements FileEntry { */ public void setFilename(String filename) { AppleUtil.setPascalString(fileEntry, 6, filename.toUpperCase(), 15); + writeFileEntry(); } /** @@ -147,6 +173,7 @@ public class PascalFileEntry implements FileEntry { } else { AppleUtil.setWordValue(fileEntry, 4, 0); } + writeFileEntry(); } /** @@ -175,6 +202,7 @@ public class PascalFileEntry implements FileEntry { */ public void setBytesUsedInLastBlock(int value) { AppleUtil.setWordValue(fileEntry, 22, value); + writeFileEntry(); } /** @@ -235,7 +263,7 @@ public class PascalFileEntry implements FileEntry { if (index != 0) { dir.remove(index); PascalFileEntry volEntry = (PascalFileEntry) dir.get(0); - volEntry.setFileCount(count - 2); // inlcudes the volume entry + volEntry.setFileCount(count - 2); // includes the volume entry dir.set(0, volEntry); disk.putDirectory(dir); deleted = true; @@ -254,6 +282,7 @@ public class PascalFileEntry implements FileEntry { */ public void setModificationDate(Date date) { AppleUtil.setPascalDate(fileEntry, 24, date); + writeFileEntry(); } /** @@ -375,7 +404,6 @@ public class PascalFileEntry implements FileEntry { * Set file data for this file entry. Because the directory entry may * have been changed, use this.index to determine which entry to update. * author John B. Matthews. - * @see #setEntryIndex * @see PascalFormatDisk#createFile */ public void setFileData(byte[] data) throws DiskFullException { @@ -448,11 +476,7 @@ public class PascalFileEntry implements FileEntry { } } // update this directory entry - if (this.index > 0) { - List dir = disk.getDirectory(); - dir.set(this.index, this); - disk.putDirectory(dir); - } + writeFileEntry(); } /** @@ -522,16 +546,6 @@ public class PascalFileEntry implements FileEntry { return false; } - /** - * Remember the index of a newly created file entry. - * Required to update the entry after setFileData, - * which may change any or all of the new entry's fields. - * author John B. Matthews - */ - public void setEntryIndex(int index) { - this.index = index; - } - /** * Set the file count in a volume entry. * Use only on the volume entry: dir.get(0). diff --git a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/pascal/PascalFormatDisk.java b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/pascal/PascalFormatDisk.java index d86f3638..0d732fc5 100644 --- a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/pascal/PascalFormatDisk.java +++ b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/pascal/PascalFormatDisk.java @@ -152,7 +152,8 @@ public class PascalFormatDisk extends FormattedDisk { for (int i=0; i Date: Mon, 28 Jul 2025 14:13:20 -0500 Subject: [PATCH 4/6] Changing how files are written for PascalFileEntry. This unifies the writing logic for TEXT and all other types and expands the file size if it grew. Should close #146. --- .../storage/os/pascal/PascalFileEntry.java | 145 +++++++++--------- 1 file changed, 71 insertions(+), 74 deletions(-) diff --git a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/pascal/PascalFileEntry.java b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/pascal/PascalFileEntry.java index 5e787ddc..1e0370f0 100644 --- a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/pascal/PascalFileEntry.java +++ b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/pascal/PascalFileEntry.java @@ -22,6 +22,8 @@ package com.webcodepro.applecommander.storage.os.pascal; import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UncheckedIOException; import java.text.NumberFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -385,19 +387,41 @@ public class PascalFileEntry implements FileEntry { } /** - * Find index of last CR < 1023 bytes from offset. - * @author John B. Matthews + * Convert the given text file to conform to the expected Pascal text file format. + *

+ * Initial header page of 1024 bytes (left as zeros), followed by 1024-byte chunks + * that terminate on CR, with all remaining bytes being zero. */ - private int findEOL(byte[] data, int offset) throws DiskFullException { - int i = offset + 1022; - while (i > offset) { - if (data[i] == 13) { - return i; + private byte[] convertTextToBlocks(byte[] text) throws DiskFullException { + try { + byte[] chunk = new byte[1024]; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(chunk); + int offset = 0; + while (offset < text.length) { + Arrays.fill(chunk, (byte) 0); + int size = 0; + for (int i=0; i= 1024) { + storageError(textBundle.get("PascalFileEntry.LineLengthError")); + } + } + System.out.printf("OFFSET=%d, SIZE=%d\n", offset, size); + System.arraycopy(text, offset, chunk, 0, size); + System.out.println("DONE"); + out.write(chunk); + offset += size; } - i--; + return out.toByteArray(); + } catch (IOException ex) { + throw new UncheckedIOException(ex); } - storageError(textBundle.get("PascalFileEntry.LineLengthError")); //$NON-NLS-1$ - return 0; } /** @@ -407,76 +431,49 @@ public class PascalFileEntry implements FileEntry { * @see PascalFormatDisk#createFile */ public void setFileData(byte[] data) throws DiskFullException { - int first = getFirstBlock(); - int last = getLastBlock(); + // Prepare a text file for writing since it has a special format if (fileEntry[4] == 3) { // text data = filterText(data); - byte[] buf1 = new byte[512]; - byte[] buf2 = new byte[512]; - int offset = 0; - int pages = 0; - disk.writeBlock(first, buf1); // First two blocks (first page) is ignored by Pascal text - disk.writeBlock(first+1,buf2); // ...so write a page of zeroes - pages++; - while (offset + 1023 < data.length) { // We have at least one full page of data (1024 bytes) - if ((pages * 2) > (last - first - 2)) { - storageError(textBundle.get("PascalFileEntry.NotEnoughRoom")); //$NON-NLS-1$ - } - int crPtr = findEOL(data, offset); // Copy to last CR & we'll zero-pad to end of page - System.arraycopy(data, offset, buf1, 0, 512); - System.arraycopy(data, offset+512, buf2, 0, crPtr - offset + 1 - 512); - disk.writeBlock(first + (pages * 2), buf1); - disk.writeBlock(first + (pages * 2) + 1, buf2); - pages++; - Arrays.fill(buf1, (byte) 0); - Arrays.fill(buf2, (byte) 0); - offset = crPtr + 1; - } - if (offset < data.length) { // We have less than a full page of data left over - int len1 = data.length - offset; - int len2 = 0; - if (len1 > 512) { // That final page spans both blocks - len2 = len1 - 512; // Second block gets the remainder of the partial page length minus 512 bytes - len1 = 512; // The first block will write the first 512 bytes - } - System.arraycopy(data, offset, buf1, 0, len1); - disk.writeBlock(first + (pages * 2), buf1); // Copy out the first block - if (len2 > 0) { - System.arraycopy(data, offset+512, buf2, 0, len2); - } - len2 = 512; // TEXT files always pad out to 1KB - disk.writeBlock(first + (pages * 2) + 1, buf2); // Copy out second block - setBytesUsedInLastBlock(len2); // The second block holds the last byte - setLastBlock(first + (pages * 2) + 2); // Final block +1... i.e. pages++ - } else { // The last page was completely full, so the last byte used in the last block is 512 - setLastBlock(first + pages * 2); - setBytesUsedInLastBlock(512); - } + data = convertTextToBlocks(data); + } - } else { // data or code - if (data.length > (last - first) * 512) { + // Write file data + int first = getFirstBlock(); + int last = getLastBlock(); + int requiredBlocks = (data.length + 511) / 512; + if (data.length > (last - first) * 512) { + // we won't fit into the existing allocated space, time to recompute + first = 0; + for (PascalFileEntry fe : disk.getDirectory()) { + if (fe.getFirstBlock() != this.getFirstBlock()) { // ignore this file + first = Math.max(first, fe.getLastBlock()); + } + } + last = first+requiredBlocks; + if (first == 0 || last >= disk.getBlocksOnDisk()) { + // this throws an exception storageError(textBundle.get("PascalFileEntry.NotEnoughRoom")); //$NON-NLS-1$ } - byte[] buf = new byte[512]; - int blocks = data.length / 512; - int bytes = data.length % 512; - for (int i = 0; i < blocks; i++) { - System.arraycopy(data, i * 512, buf, 0, 512); - disk.writeBlock(first + i, buf); - } - if (bytes > 0) { - Arrays.fill(buf, (byte) 0); - System.arraycopy(data, blocks * 512, buf, 0, bytes); - disk.writeBlock(first + blocks, buf); - setLastBlock(first + blocks + 1); - setBytesUsedInLastBlock(bytes); - } else { - setLastBlock(first + blocks); - setBytesUsedInLastBlock(512); - } } - // update this directory entry - writeFileEntry(); + byte[] buf = new byte[512]; + int blocks = data.length / 512; + int bytes = data.length % 512; + for (int i = 0; i < blocks; i++) { + System.arraycopy(data, i * 512, buf, 0, 512); + disk.writeBlock(first + i, buf); + } + if (bytes > 0) { + Arrays.fill(buf, (byte) 0); + System.arraycopy(data, blocks * 512, buf, 0, bytes); + disk.writeBlock(first + blocks, buf); + setFirstBlock(first); + setLastBlock(first + blocks + 1); + setBytesUsedInLastBlock(bytes); + } else { + setFirstBlock(first); + setLastBlock(first + blocks); + setBytesUsedInLastBlock(512); + } } /** From 68e2c2b68271e5f092f68e5ce3df7d2f0f01edbc Mon Sep 17 00:00:00 2001 From: Rob Greene Date: Mon, 28 Jul 2025 14:26:07 -0500 Subject: [PATCH 5/6] Oops. Removing some debugging code. --- .../applecommander/storage/os/pascal/PascalFileEntry.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/pascal/PascalFileEntry.java b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/pascal/PascalFileEntry.java index 1e0370f0..072bcd09 100644 --- a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/pascal/PascalFileEntry.java +++ b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/pascal/PascalFileEntry.java @@ -412,9 +412,7 @@ public class PascalFileEntry implements FileEntry { storageError(textBundle.get("PascalFileEntry.LineLengthError")); } } - System.out.printf("OFFSET=%d, SIZE=%d\n", offset, size); System.arraycopy(text, offset, chunk, 0, size); - System.out.println("DONE"); out.write(chunk); offset += size; } From 6e5cd6679447d37316546134c3950a5a9bbf7229 Mon Sep 17 00:00:00 2001 From: Rob Greene Date: Mon, 28 Jul 2025 14:46:54 -0500 Subject: [PATCH 6/6] Adjusting text file build out. --- .../applecommander/storage/os/pascal/PascalFileEntry.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/pascal/PascalFileEntry.java b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/pascal/PascalFileEntry.java index 072bcd09..aa372aa1 100644 --- a/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/pascal/PascalFileEntry.java +++ b/lib/ac-api/src/main/java/com/webcodepro/applecommander/storage/os/pascal/PascalFileEntry.java @@ -402,8 +402,8 @@ public class PascalFileEntry implements FileEntry { Arrays.fill(chunk, (byte) 0); int size = 0; for (int i=0; i