Source file: /~heha/basteln/PC/Programmiergeräte/PEPS-III/peps4win32.zip/src/hexload.c

/*──────────────────────────────────────────────────────────────┐
│HexLoad: HEX-Dateien (auch nicht-zusammenhängend) laden	│
│Codepage: UTF-8 ohne BOM, Zeilenenden: LF, Tabweite: 8		│
└──────────────────────────────────────────────────────────────*/

#include "peps.h"
/* GLOBAL */
MEMAREA *areas;	// sortierte (!) Speicherbereiche
long LoadOffset;
FILE *InFile;
bool Verbose;
BYTE buffer[0x200000];	// maximal können 2 MiB verarbeitet werden

// Kann mehrfach aufgerufen werden.
// Das Initialisieren des PEPS muss voraus gehen,
// außer bei FileToFile-Operationen
//void InitBuffer(long size) {
// if (buffer) return;
// TargetSize=size;
// buffer = malloc(TargetSize);
//}

// Vorgefundenen Speicherblock hinzufügen,
// dabei versuchen die Anzahl der tatsächlichen Blöcke zu minimieren.
// Kommt auch mit Überlappungen zurecht!
// Es muss a < e gelten! Null-Blöcke sind nicht erlaubt.
void AddArea(long a, long e) {
 MEMAREA *p,*q,**pp=&areas;
 if (a<e) for(;;) {		// EVL durchgehen
  p=*pp;
  if (!p || e < p->a) {		// Kein Block ODER Bereich liegt davor?
   q = malloc(sizeof(MEMAREA));	// Neuer Block
   *pp = q;			// fontal einfügen
   q->next = p;
   q->a = a;			// abspeichern
   q->e = e;
   break;			// Schleife beenden
  }
  if (e >= p->a && a <=	p->e) {	// Überlappt oder schmiegt sich an?
   if (p->a > a) p->a = a;	// Anfang ausdehnen (kann Vorgänger nicht berühren)
   if (p->e < e) {
    p->e = e;			// Ende ausdehnen
    while ((q = p->next)) {	// Folgeblöcke abtesten
     if (q->a <= e) {		// Berührt oder überlappt nächsten Block?
      if (q->e > e) p->e = q->e;	// ja, anhängen (je nachdem was länger ist)
      p->next = q->next;	// <q> auskoppeln
      free(q);			// Folgeblock verschlingen (Okklusion)
     }else break;		// nein, Suche abbrechen
    }
   }
   break;			// Schleife beenden
  }
  pp=&p->next;			// Zeiger auf vorhergehenden Anker setzen
 }
}

// EVL löschen
void ClearAreas() {
 MEMAREA *p;
 while ((p=areas)) {
  areas=p->next;
  free(p);
 }
}

// Bytes aus Speicherbereich hinzufügen, bei <p>==NULL aus globalem InFile
// a = Zieladresse, LoadOffset wird zusätzlich berücksichtigt
void AddBytes(const BYTE*p, long a, long len) {
 long e;
 a += LoadOffset;	// kann negativ werden
 e = a + len;
// Clipping
 if (e<0) return;	// komplett außerhalb (davor)
 if (a>sizeof(buffer)) return;	// komplett außerhalb (dahinter)
 if (a<0) {	// kann passieren bei negativem LoadOffset
  a=-a;		// Überhang (Betrag)
  if (p) p+=a;
  else fseek(InFile,a,SEEK_CUR);	// vorspulen
  a=0;
 }
 if ((unsigned long)e>sizeof(buffer)) e=sizeof(buffer);
// Daten schaufeln
 len = e-a;	// Länge nach dem Clipping
 if (len<=0) return;	// nichts! (sollte nicht vorkommen)
 if (p) memcpy(buffer+a,p,len);
 else fread(buffer+a,1,len,InFile);
// Bereich hinzufügen
 AddArea(a,e);
}

void LoadObjModule() {
 rprintf(4);
}

// Hexziffer in Nibble umwandeln; <c> muss gültiges Hexzeichen sein
static BYTE nibble(char c) {
 if (!isxdigit(c)) DoExit(6);
 c&=0x1F;		// '0'..'9' -> 0x10..0x19, 'A'..'F', 'a'..'f' --> 0x01..0x06 (erschlägt Kleinbuchstaben)
 c-=0x10;
 if (c<0) c+=0x10+10-1;
 return c;
}

// Hex-Zahl (2 Zeichen) einlesen
static BYTE htoi(const char *str) {
 return nibble(str[0])<<4|nibble(str[1]);
}

void LoadIntel() {
 long Segment=0, UpperLBA=0;
 char buf[600];		// Textzeile

 rprintf(5);
 buf[sizeof buf-1]=0;	// Muss da stehen bleiben
 while (fgets(buf,sizeof(buf)-1,InFile)) {	// 1 Zeile lesen
  char *start;
  BYTE CheckSum;
  int i;
  BYTE Data[260];	// 4 Byte Header, max. 255 Datenbytes, 1 Byte Prüfsumme
#define Length (Data[0])			// … der Daten (ab Data+4)
#define RecordAdr ((Data[1]<<8)|Data[2])	// tatsächlich Big-Endian
#define RecordType (Data[3])
  if (buf[sizeof(buf)-1]) DoExit(11);		// Zeile zu lang
  start=strchr(buf,':');
  if (!start) continue;	// ungültige, eher leere Zeile ignorieren
  start++;
  CheckSum = 0;
  Length = 0;		// Optimizer ruhig stellen
  for (i=0; i<(int)Length+5; i++) {
   CheckSum += Data[i] = htoi(start);
   start+=2;
  }
  if (CheckSum) DoExit(9);

  switch (RecordType) {
   case 4:	//ELADRRECORD, Extended Linear Address Record
      /* 18.12.1997 (aMay) */
    UpperLBA = (long)(Data[4]<<8 | Data[5])<<16;// bis 4 GiByte
    break;

   case 3:	//STARTRECORD
   case 2:	//EADRRECORD
    Segment = (long)(Data[4]<<8 | Data[5])<<4;	// bis 1 MiByte
    break;

   case 0:	//DATARECORD
      /* 18.12.97 aMay */
      /* Extended Linear Address Record berücksichtigen! */
    AddBytes(Data+4,RecordAdr+Segment+UpperLBA,Length);
    break;
  }
#undef Length
#undef RecordAdr
#undef RecordType
 }
}


void LoadMotorola() {
 char buf[600];		// Textzeile

 rprintf(10);
 buf[sizeof(buf)-1]=0;	// darf nicht überschrieben werden, sonst Zeile zu lang!
 while (fgets(buf,sizeof(buf)-1,InFile)) {
  char *start;
  int i;
  BYTE CheckSum;
  BYTE Data[258];	// RecordType, Länge, max. 255 Datenbytes, Prüfsumme = 258 Bytes
#define RecordType (Data[0])
#define Length (Data[1])	// inklusive Adresse, exklusive Prüfsumme
  if (buf[sizeof(buf)-1]) DoExit(11);
  start=strchr(buf,'S');
  if (!start) continue;	// ungültige, eher leere Zeile ignorieren
  *start = '0';		// Zweistellige Hexzahl draus machen
  CheckSum = 0xFF;
  Length = 0;		// Optimizer ruhig stellen
  for (i=0; i<(int)Length+3; i++) {
   CheckSum += Data[i] = htoi(start);
   start+=2;
  }
  if (CheckSum!=RecordType) DoExit(12);
  
  switch (RecordType) {
/*
   case 0:	//MFIRSTRECORD
    Data[Length+1] = 0;
    printf(" %s ", Data+2);	// wozu das??
    break;
*/
   case 1:	//MDATA16RECORD, 16-bit-Adresse
    AddBytes(Data+4,Data[2]<<8|Data[3],Length-3);
    break;
   case 2:	//MDATA24RECORD, 24-bit-Adresse (reicht bis 16 MiByte)
    AddBytes(Data+5,(long)Data[2]<<16|Data[3]<<8|Data[4],Length-4);
    break;
  }
 }
}

void LoadBinary() {
 long Size;
 fseek(InFile,0,SEEK_END);	// Hoppla, unter Linux kommt da keine Dateilänge 'raus!
 Size=ftell(InFile);		// Deshalb eher umständlich
 rprintf(41, Size, Size);
 fseek(InFile,0,SEEK_SET);
 AddBytes(NULL,0,Size);
}
Detected encoding: UTF-80