Schneider / Amstrad CPC Forum

Amstrad / Schneider CPC => Programmierung => Topic started by: oobdoo on 10. June 2020, 14:21:23

Title: Wie Directory eines DSK auslesen
Post by: oobdoo on 10. June 2020, 14:21:23
Im "Das grosse Floppy Buch" von Data Becker wird auf Seite 216/217 die Directory Größe mit 2048 Bytes
angegeben, das Directory (D-Format) soll dabei die Sektoren &C1-&C5 belegen (5x512=2560 Bytes).
Was stimmt denn nun?  :gruebel:

Bisher ist es mir nicht gelungen das Directory vollständig richtig einzulesen.  :(

Title: Re: Wie Directory eines DSK auslesen
Post by: TrebleAlex on 10. June 2020, 15:22:31
Hallo! :-)

Das Directory liegt beim DATA-Format in den ersten 4 Sektoren, d.h. &C1-&C4.
512 Bytes pro Sektor*4=2048 Bytes.
Ab &C5 liegt schon die erste Datei.

Evtl. kommt der Anzeigefehler zu Stande, weil Du auch den Sektor &C5 mit einliest und den Inhalt ausgibst (Steuerzeichen etc.)

Viele Grüsse,

Alex
Title: Re: Wie Directory eines DSK auslesen
Post by: oobdoo on 10. June 2020, 15:57:25
Ok, dann steht im Data Becker Buch was falsches. Trotzdem habe ich weiterhin ein Problem.
Sektor &42 gehört zum Directory. Wenn ich da mit einem Hexmonitor reinschaue dann scheint
da teilweise dummes Zeug zu stehen, z.B. "123456789" oder "@ABCDEFGHI", siehe Bild.
Das DSK wird von anderen Tools aber sauber ausgelesen.
Title: Re: Wie Directory eines DSK auslesen
Post by: TrebleAlex on 10. June 2020, 16:05:07
Hmmm.... Du darfst das DATA-Format (Sektor ID &C0) nicht mit dem SYSTEM-Format verwechseln! (Sektor ID &40)!

Beim System-Format sind die ersten beiden Spuren für CP/M reserviert, d.h. das Directory beginnt dort an Track 2 Sektoren &41-&44 !

Gruß,
Alex
Title: Re: Wie Directory eines DSK auslesen
Post by: oobdoo on 10. June 2020, 16:16:50
Das weiß ich. Dachte ich zumindest. Dank Dir weiß ich jetzt das in meinem Source da tatsächlich noch ein Zahlendreher drin war.  :smiley027:

Nachtrag:

Endlich.  :00008351:

Nun hat auch das Einlesen vom Directory vollständig geklappt.
Nachdem ich den vertikalen Scrollbalken dazu geschaltet hatte,
war auch erkennbar das das Verzeichnis vollständig in der Textbox
vorhanden war. Vorher konnte ich nur die letzten Einträge sehen,
die waren aber ohne Inhalt. Das zu finden hat mich locker 2h gekostet.  :banghead:

Ab morgen kommt endlich das Einlesen einzelner Dateien...  :jubelaola:
Title: Re: Wie Directory eines DSK auslesen
Post by: mv on 12. June 2020, 14:42:32
Mit DSK-Auslesen habe ich mich vor ein paar Tagen auch noch mal beschäftigt.
Dazu eine alte Perl-Version als Vorlage genommen, und in JavaScript umgeschrieben:
https://github.com/benchmarko/CPCBasic/blob/master/DiskImage.js
Im Moment nur für Lesen.
Title: Re: Wie Directory eines DSK auslesen
Post by: oobdoo on 13. June 2020, 01:14:07
Bin kurz davor ein File aus einem DSK raus zu holen. Dazu habe ich mit zwei anderen Tools zusätzlich gearbeitet.
Das blöde dabei, ManageDsk macht es scheinbar richtig  und CPCDiskXP falsch.  :(
AMSDOS1.COM scheint die richtigen Inhalte zu haben, AMSDOS2.COM die falschen. :gruebel
Beide Tools haben natürlich auf das selbe DSK zugegriffen.
Kann das mal einer prüfen?



Title: Re: Wie Directory eines DSK auslesen
Post by: TFM on 14. June 2020, 00:13:52
Und auch hier ist es wieder wichtig zu prüfen, ob eine Datei einen 128 Byte Header hat oder nicht.
Title: Re: Wie Directory eines DSK auslesen
Post by: oobdoo on 14. June 2020, 01:43:09
Ich gehe davon aus das die beiden Tools das machen werden.
Mein Programm ist noch lange nicht so weit. Ich kann aktuell die
richtigen Blöcke raus bekommen, habe es aber noch nicht geschafft
die Formel zur Umrechnung nach Track/Sektor zum Laufen zu bekommen.   :(

Das DSK Auswerten scheint in meinen 35 Jahren als Hobby Programmierer
die härteste Nuss zu sein.  :'(
Title: Re: Wie Directory eines DSK auslesen
Post by: TFM on 14. June 2020, 14:09:36
Diese ganzen Sachen stehen unter FutureOS als Funktionen zur Verfügung, falls da Interesse besteht stehe ich gerne mit Rat und Tat zur Verfügung, steht aber auch alles im Handbuch.

Blocks auf Track, Sektorumrechnung ist an sich linear aufsteigend, beginnend mit dem DIR Blöcken, nummeriert ab 0.
Title: Re: Wie Directory eines DSK auslesen
Post by: oobdoo on 14. June 2020, 16:55:57
Guter Tip mit dem FOS Handbuch. Mal schauen ob ich da Denkanregungen für mich finden kann.  :zunge0020:

Den Hinweis mit dem Header hatte ich nicht sofort verstanden.  :gruebel:

Das passierte erst als ich Nachts im Bett lag.  :D

Ich war fest davon ausgegangen das beide Programme das gleiche Verhalten bei einem Export der Datei zeigen würden.
Title: Re: Wie Directory eines DSK auslesen
Post by: TFM on 14. June 2020, 17:25:05
K.A. wie die beiden Programme funktionieren, aber ich kann mich glaube ich auch an Probleme erinnern.

Eine Text-Datei braucht ja keinen Header, denn es ist ja nur Text.

BASIC und MC Programme (also Binärdateien) brauchen den Header um der Firmware zu sagen, wohin sie geladen werden sollen, wie lange sie sind, und ob / bzw. an welcher Adresse der Autostart Einsprung erfolgen soll. Ja, der Header ist da auch beschrieben.
Title: Re: Wie Directory eines DSK auslesen
Post by: oobdoo on 14. June 2020, 19:00:04
Eben hinbekommen das ich die ersten 128 Bytes einer Datei von einem DSK richtig auslesen konnte.  :00008351:

Der Code war weitgehend richtig, aber wenn man die eigenen Funktionen mit der falschen Sektorgröße und
MaxSektoren füttert dann kann nur dummes Zeug bei raus kommen.  :banghead:
Title: Re: Wie Directory eines DSK auslesen
Post by: oobdoo on 16. June 2020, 01:20:44
Und wieder ein Verständnisproblem.  :(

Die Datei AMSDOS.COM einer CP/M Diskette hat eine Größe von 1024 Byte. DataBlock wird
nur einer benötigt, weil 1 Block = 8 Record (1 Record = 128 Byte), also 8 x 128 = 1024 Byte.

Angegeben wird DataBlock mit 2. Das bedeutet Track 3 und Sektor 4 bzw. 2 und 3 wenn man
von Null zählt. Die Sektor-ID ist &43.

Damit kann ich nur 50% der Datei lesen, weil ein Sektor ja nur 512 Bytes hat.
Woher weiß ich welches den nächste Sektor ist, wo die anderen 50% von der Datei liegen?  :gruebel:
Title: Re: Wie Directory eines DSK auslesen
Post by: oobdoo on 16. June 2020, 02:56:56
Nächste Frage.  :(

Wie kann ich feststellen ob eine Datei einen Header hat oder nicht?
Die Auswertung des Dreizeichen-Filetyps kann es nicht sein, das
kann man ja willkürlich festlegen.
Title: Re: Wie Directory eines DSK auslesen
Post by: TFM on 16. June 2020, 09:41:06
Die Sektornummer einfach hochzählen, wenn es nicht weiter geht, dann mit dem ersten Sektor auf der nächsten Spur weitermachen.
Title: Re: Wie Directory eines DSK auslesen
Post by: Devilmarkus on 16. June 2020, 17:06:44
Im JavaCPC mache ich das so:
(Java Code)

  public static int ChecksumAMSDOS(byte[] pHeader) {
    int Checksum = 0;
    for (int i = 0; i < 67; i++) {
      int CheckSumByte = pHeader[i] & 0xFF;
      Checksum += CheckSumByte;
    }
    return Checksum;
  }
 
  public static boolean CheckAMSDOS(byte[] pHeader) {
    int CalculatedChecksum;
    try {
      CalculatedChecksum = ChecksumAMSDOS(pHeader);
    } catch (Exception e) {
      return false;
    }
    int ChecksumFromHeader = pHeader[67] & 0xFF | (pHeader[68] & 0xFF) << 8;
    if (ChecksumFromHeader == CalculatedChecksum && ChecksumFromHeader != 0) {
      System.out.println("Has AMSDOS header");
      return true;
    }
    System.out.println("Without header");
    return false;
  }
Title: Re: Wie Directory eines DSK auslesen
Post by: drazil on 05. July 2020, 17:25:07
Hi Oobdoo ich hänge mich mal an deinen Thread dran, da ich dazu auch noch ne Frage habe.

Mein Problem ist der Umgang mit NICHT ASCII files die aber keinen Header haben.

Um diese zu exportieren gehe ich momentan folgendermassen vor.
Die FileSize nehme ich aus dem Directoryeintrag, da ja kein Header vorhanden ist. Ist aber nicht die korrekte Grösse.
Anschliessen prüfe ich noch die ersten 100 Bytes auf Character.isAlphabetic. Wenn das nicht so ist wird eine normale Binärdatei gelesen.
Gibts da einen offizielleren Weg, oder wird das tatsächlich so ähnlich geprüft?
Ich habe keine anderen Flags im Directoryeintrag gefunden mit denen ich das steuern könnte.

Beste Grüße
Guido
Title: Re: Wie Directory eines DSK auslesen
Post by: TFM on 05. July 2020, 18:37:35
Da gehst Du schon richtig vor.
- Test auf Header. Wenn ja, dann ist es BIN oder BAS Datei
- Wenn nein, dann ist es Text oder z.B. ein CP/M Kommando (*.COM Dateien)

Zur Bestimmung der Länge kann man die Anzahl der 128 Byte Records aus dem DIRectory ermitteln. Das ist dann auf die nächsten 128 Bytes aufgerundet.

Rekord-Anzahl ermitteln:
------------------------
- Record_Anzahl = (Byte_&0C) * 128 + (Byte_&0F)


Im Data Becker Floppy Buch ist das gut erklärt, ist auch hier im Forum (wImre).
Title: Re: Wie Directory eines DSK auslesen
Post by: drazil on 06. July 2020, 07:46:55
Hi, wo finde ich denn das Floppbuch hier im Forum?

Sorry, schon gefunden.
Title: Re: Wie Directory eines DSK auslesen
Post by: dettus on 24. October 2020, 11:59:44
Vielleicht helfen dir ja meine kleinen Tools weiter.

Erstmal ein dskread.c, damit mache ich aus einem DSK ein CPM file.

/*
Copyright 2020, dettus@dettus.net

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define PARSE_INT32BE(ptr,idx)  (\
        (((unsigned int)((ptr)[((idx)+0)])&0xff)<<24)   |\
        (((unsigned int)((ptr)[((idx)+1)])&0xff)<<16)   |\
        (((unsigned int)((ptr)[((idx)+2)])&0xff)<< 8)   |\
        (((unsigned int)((ptr)[((idx)+3)])&0xff)<< 0)   |\
        0)
#define PARSE_INT16BE(ptr,idx)  (\
        (((unsigned int)((ptr)[((idx)+0)])&0xff)<< 8)   |\
        (((unsigned int)((ptr)[((idx)+1)])&0xff)<< 0)   |\
        0)


#define PARSE_INT32LE(ptr,idx)  (\
        (((unsigned int)((ptr)[((idx)+3)])&0xff)<<24)   |\
        (((unsigned int)((ptr)[((idx)+2)])&0xff)<<16)   |\
        (((unsigned int)((ptr)[((idx)+1)])&0xff)<< 8)   |\
        (((unsigned int)((ptr)[((idx)+0)])&0xff)<< 0)   |\
        0)
#define PARSE_INT16LE(ptr,idx)  (\
        (((unsigned int)((ptr)[((idx)+1)])&0xff)<< 8)   |\
        (((unsigned int)((ptr)[((idx)+0)])&0xff)<< 0)   |\
        0)



unsigned char buf[1<<20];
int main(int argc,char** argv)
{
        FILE *f;
        int dsksize;
        int i,j;
        int tracknum;
        int sidenum;
        int tracksize;
        int idx;

        f=fopen(argv[1],"rb");
        dsksize=fread(buf,sizeof(char),sizeof(buf),f);
        fclose(f);

        f=fopen(argv[2],"wb");

        printf("dsksize:%d\n",dsksize);
        printf("<<magic:");
        for (i=0;i<=0x21;i++)
        {
                printf("%c",buf[i]);
        }
        printf(">>");
        printf("<<name of creator:");
        for (i=0x22;i<=0x2f;i++) printf("%c",buf[i]);
        printf(">>");
        printf("<<number of tracks:%d>>",buf[0x30]);
        printf("<<number of sides:%d>>",buf[0x31]);
        printf("<<size of a track:%d>>",PARSE_INT16LE(buf,0x32));
        printf("\n");
        printf("-------------------------\n");
        tracknum=buf[0x30];
        sidenum=buf[0x31];
        tracksize=PARSE_INT16LE(buf,0x32);

        idx=256;
        for (i=0;i<tracknum*sidenum;i++)
        {
                int idx0;
                int sectorsize;
                int sectornum;
                int sectorids[16]={0};
                int order[16]={0};

                idx0=idx;
                printf("\x1b[0;30;47mtrack:%d side:%d\x1b[0m\n",tracknum/sidenum,tracknum%sidenum);
                printf("magic:      ");
                for (j=0;j<0x0c;j++) printf("%c",buf[idx++]);
                printf("\n");
                idx+=4;         // 0x0c-0x0f: unused
                printf("track:      %d\n",buf[idx++]);
                printf("side:       %d\n",buf[idx++]);
                idx+=2; //0x12-0x13: unused
                sectorsize=buf[idx];
                printf("sector size:%d\n",buf[idx++]);
                sectornum=buf[idx];
                printf("sector num: %d\n",buf[idx++]);
                printf("gap3 length:%d\n",buf[idx++]);
                printf("filler byte:%d\n",buf[idx++]);
                for (j=0;j<sectornum;j++)
                {
                        order[j]=j;
                        printf("   %d> track:      %d\n",j,buf[idx++]);
                        printf("   %d> side:       %d\n",j,buf[idx++]);
                        sectorids[j]=buf[idx];
                        printf("   %d> sectorID:   %d\n",j,buf[idx++]);
                        sectorsize=128<<buf[idx];
                        printf("   %d> sectorsize: %d --> %d bytes\n",j,buf[idx++],sectorsize);
                        printf("   %d> FDC status1:%d\n",j,buf[idx++]);
                        printf("   %d> FDC status2:%d\n",j,buf[idx++]);
                        idx+=2; // 06-07: unused

                }
                for (j=0;j<sectornum-1;j++)
                {
                        int k;
                        for (k=j+1;k<sectornum;k++)
                        {
                                if (sectorids[order[j]]>sectorids[order[k]])
                                {
                                        int x;
                                        x=order[j];
                                        order[j]=order[k];
                                        order[k]=x;
                                }
                        }
                }
                printf("track %2d> order ",i);
                for (j=0;j<sectornum;j++)
                {
                        printf("%d ",order[j]);
                }
                printf("\n");
                idx=idx0+0x100;
                for (j=0;j<sectornum;j++)
                {
                        printf("@%06x   ",idx+order[j]*sectorsize);
                        printf("writing sector %d id=%d\n",order[j],sectorids[order[j]]);
                        fwrite(&buf[idx+order[j]*sectorsize],sizeof(char),sectorsize,f);
                }

                idx=idx0+tracksize;
        }
        fclose(f);
}


Anschliessend verwende ich mein cpmextract.c, um die Dateien aus dem CPM Filesystem zu extrahieren

/*
Copyright 2020, dettus@dettus.net

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// http://www.seasip.info/Cpm/format22.html
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PARSE_INT32BE(ptr,idx)  (\
        (((unsigned int)((ptr)[((idx)+0)])&0xff)<<24)   |\
        (((unsigned int)((ptr)[((idx)+1)])&0xff)<<16)   |\
        (((unsigned int)((ptr)[((idx)+2)])&0xff)<< 8)   |\
        (((unsigned int)((ptr)[((idx)+3)])&0xff)<< 0)   |\
        0)
#define PARSE_INT16BE(ptr,idx)  (\
        (((unsigned int)((ptr)[((idx)+0)])&0xff)<< 8)   |\
        (((unsigned int)((ptr)[((idx)+1)])&0xff)<< 0)   |\
        0)


#define PARSE_INT32LE(ptr,idx)  (\
        (((unsigned int)((ptr)[((idx)+3)])&0xff)<<24)   |\
        (((unsigned int)((ptr)[((idx)+2)])&0xff)<<16)   |\
        (((unsigned int)((ptr)[((idx)+1)])&0xff)<< 8)   |\
        (((unsigned int)((ptr)[((idx)+0)])&0xff)<< 0)   |\
        0)
#define PARSE_INT16LE(ptr,idx)  (\
        (((unsigned int)((ptr)[((idx)+1)])&0xff)<< 8)   |\
        (((unsigned int)((ptr)[((idx)+0)])&0xff)<< 0)   |\
        0)


#define BLOCKSIZE       1024

unsigned char buf[1<<20];
int main(int argc,char** argv)
{
        FILE *f;
        int bufsize;
        int i,j;
        int idx;
        int firstblock;
        int entrycnt;
        int attrs;
        int extent;
        char filename[16]={0};
        char lastfilename[16]={0};


        f=fopen(argv[1],"rb");
        bufsize=fread(buf,sizeof(char),sizeof(buf),f);
        fclose(f);
        f=NULL;
        firstblock=bufsize/BLOCKSIZE;

        idx=0;
        entrycnt=0;


        while (idx<firstblock*BLOCKSIZE)
        {
                if ((buf[idx]&0xf0)==0)
                {
                        printf("%2d> ",entrycnt);
                        for (i=0;i<32;i++) printf("%02x ",buf[idx+i]);
                        printf("user: %x  ",buf[idx]&0xf);
                        idx++;
                        j=0;
                        filename[j++]='_';
                        for (i=0;i<11;i++)
                        {
                                unsigned char c;
                                c=buf[idx++]&0x7f;
                                if (i==8) filename[j++]='.';
                                if (c!=' ') filename[j++]=c;
                                filename[j]=0;
                        }
                        printf("[%s]",filename);
                        if (memcmp(filename,lastfilename,16))
                        {
                                if (f!=NULL) fclose(f);
                                memcpy(lastfilename,filename,16);
                                f=fopen(filename,"wb");
                        }
                        extent=buf[idx++];      // EX
                        idx++;          //      S1=0
                        extent=buf[idx++]<<8;   // S2 little endian
                        extent*=128;
                        extent+=buf[idx++];     // rc
                        printf("extent:%6d ",extent);
                        printf("{");
                        for (i=0;i<16;i++)
                        {
                                int block;
                                block=buf[idx++];
                                if (block && block<firstblock) firstblock=block;
                                printf("%02X ",block);
                                if (block) fwrite(&buf[block*BLOCKSIZE],sizeof(char),BLOCKSIZE,f);
                        }
                        printf("}");
                        printf("\n");

                        entrycnt++;
                } else {
                        idx+=32;
                }
        }
        if (f!=NULL) fclose(f);
}