/* Michael Christoph Software */
/* myDumpCatalog - Catalog Texte ausgeben */

/*
  g++ myDumpCatalog.c -o myDumpCatalog -l auto

  myDumpCatalog C-Work:AmigaMag/af_173_CatalogEdit/prefs.catalog 

  catcomp prefs.cd prefs.ct catalog prefs-neu.catalog nooptim
*/

/************************** PROGRAMM-PARAMETER ********************************/

#define PROGNAME "myDumpCatalog"
#define VERSIONR "1.00"
#define PROGDATE "29.11.2024"
#define COPYRIGT "Copyright © Nov.2024"
#define AUTORNAM "by Meicky-Soft"

volatile const char __attribute__((unused)) *version = "\0$VER: " PROGNAME " " VERSIONR " (" PROGDATE ") - " COPYRIGT " " AUTORNAM "\0\n";

/******************************* INCLUDES *************************************/

#include <exec/execbase.h>
//#include <dos/stdio.h>
//#include <classes/requester.h>
//#include <workbench/startup.h>
#include <libraries/iffparse.h>

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/utility.h>
//#include <proto/intuition.h>
//#include <proto/requester.h>
#include <proto/locale.h>
//#include <proto/icon.h>

/***************************** PROTOTYPEN *************************************/

/************************ VARIABLEN DEKLARATIONEN *****************************/

struct Catalog *gb_Catalog;

const TEXT *gb_ArgTemplate = "CATALOG,ID/K,DEBUG/K";
enum { ARG_catalog, ARG_id, ARG_debug, ARG_MAXI };
uint32 gb_Args[ARG_MAXI] = { (uint32)NULL,(uint32)NULL,(uint32)NULL };

#define CATSTR(id)        ILocale->GetCatalogStr(gb_Catalog,id,(STRPTR)STR_ ## id)
#define CATSTRSTR(id,str) ILocale->GetCatalogStr(gb_Catalog,id,(STRPTR)str)

USED CONST TEXT stacksize[] = "$STACK:80000";

/***************************** DEFINES *****************************************/

struct IFFHeader
{
  uint32 form;
  uint32 len;
  uint32 id;
};

#define PRINT_ID(id) (id&0xFF000000)>>24,(id&0xFF0000)>>16,(id&0xFF00)>>8,(id&0xFF)

#define ID_CTLG MAKE_ID('C','T','L','G')
#define ID_LANG MAKE_ID('L','A','N','G')
#define ID_CSET MAKE_ID('C','S','E','T')
#define ID_STRS MAKE_ID('S','T','R','S')
#define ID_FVER MAKE_ID('F','V','E','R')

/******************************************************************************/

CONST_STRPTR ReplaceNL(CONST_STRPTR str)
{
  static TEXT sout[1000];
  uint32 i, j=0;

  if(IUtility->Strlen(str) < 970)
  {
    IUtility->SetMem(sout,'\0',sizeof(sout));
    for(i=0; i<IUtility->Strlen(str); ++i)
    {
      if(str[i] == '\n') { IUtility->Strlcat(sout,"\\n",sizeof(sout)); j+=2; } 
      else if(str[i] == '\\') { IUtility->Strlcat(sout,"\\",sizeof(sout)); j+=1; } 
      else if(str[i] == '\"') { IUtility->Strlcat(sout,"\\\"",sizeof(sout)); j+=2; } 
      else sout[j++] = str[i];
    }
  }
  else return str;  // Text ist zu lange, unverändert zurück geben
  return sout;
}

/******************************************************************************/

CONST_STRPTR ReplaceNULL(CONST_STRPTR str, int32 len)
{
  static TEXT sout[1000];
  uint32 i, j=0;

  if(len < 970)
  {
    IUtility->SetMem(sout,'\0',sizeof(sout));
    for(i=0; i<len; ++i)
    {
      if(str[i] == '\0') { IUtility->Strlcat(sout,"\\0",sizeof(sout)); j+=2; } 
      else sout[j++] = str[i];
    }
  }
  else return str;  // Text ist zu lange, unverändert zurück geben
  return sout;
}

/******************************************************************************/
/******************************************************************************/

int main(int argc, char *argv[])
{
  int res = RETURN_ERROR;
  TEXT gb_ProgName[50];  // Programmname alleine
  TEXT progname[120];    // Programmname evtl. mit Pfad
  struct RDArgs *rda = NULL;
  BPTR cat;
  TEXT str[5]; str[4] = '\0';
  TEXT buffer[1000];

  IDOS->GetCliProgramName(progname,sizeof(progname));
  IUtility->Strlcpy(gb_ProgName,IDOS->FilePart(progname),sizeof(gb_ProgName));  // evtl. Pfadangabe entfernen

  // ins Programmverzeichnis wechseln und Programmnamen ermitteln
  BPTR olddir = IDOS->SetCurrentDir(IDOS->GetProgramDir());

  if((rda = IDOS->ReadArgs((STRPTR)gb_ArgTemplate,(LONG*)gb_Args,NULL)))
  {
    if ((cat = IDOS->Open((STRPTR)gb_Args[ARG_catalog],MODE_OLDFILE)))
    {
/*
IFF Struktur:
FORM....CTLG
FVER....xxxxxxxxxxx
CSET....nnnn
STRS....
 vier Byte für die ID
 vier Bytes für die echte Textlänge
 und dann der Text mit Nullbyte und ggf. mehr zum auffüllen.
*/
      uint32 id, len, lenr, num=0;
      IFFHeader header;
      CONST_STRPTR sw;
      TEXT namecd[250], namect[250];
      BPTR cd, ct;

      IDOS->Read(cat,&header,sizeof(IFFHeader));
      if (header.form == ID_FORM && header.id == ID_CTLG)
      {
        IUtility->Strlcpy(namecd,(STRPTR)gb_Args[ARG_catalog],sizeof(namecd));
        id = IUtility->Strlen(namecd);
        namecd[id-6] = 'd'; namecd[id-5] = '\0';
        IUtility->Strlcpy(namect,namecd,sizeof(namect));
        id = IUtility->Strlen(namect);
        namect[id-1] = 't';

        if((cd = IDOS->FOpen(namecd,MODE_NEWFILE,0)))
        {
          if((ct = IDOS->FOpen(namect,MODE_NEWFILE,0)))
          {
            while(true)  // Kopfdaten überlesen bis wir die Texte finden
            {
              buffer[0] = '\0';
              IDOS->Read(cat,&id,4);  // 4 Bytes für den Chunk-Typ
              IDOS->Read(cat,&len,4);  // 4 Byte für die Länge des Chunks
              lenr = len + len%2;
IDOS->Printf("id=%ld len=%ld (%ld)\n",id,len,lenr);
              // die Typen Version, Sprache und Charset interessieren uns nicht
              if(id == ID_FVER || id == ID_LANG || id == ID_CSET) { IDOS->Read(cat,buffer,lenr); buffer[len] = '\0'; }
IDOS->Printf("gelesen %lc%lc%lc%lc : <%.50s>\n",PRINT_ID(id),buffer);
              if(id == ID_STRS) break;  // wir haben den Chunk mit den Texten gefunden
            }

            if(id == ID_STRS)
            {
IDOS->Printf("STRS gefunden, %ld bytes Textdaten\n",len);
              while(true)  // Endlosschleife bis Dateieinde erreicht ist
              {
                buffer[0] = '\0';
                if((IDOS->Read(cat,&id,4)) == 0) break;  // ID für den Text lesen
                IDOS->Read(cat,&len,4);  // Wie lange ist der Text selber
                lenr = len + 4-(len%4);  // ggf. aufrunden auf Langwort
                IDOS->Read(cat,buffer,lenr);  // Text mit evtl. Füllbytes am Ende einlesen
                ++num;
                // sind Null-Bytes im Text vorhanden, dann maskieren sonst Text direkt übernehmen
                if(len != IUtility->Strlen(buffer)) sw = ReplaceNULL(buffer,len); else sw = buffer;
                sw = ReplaceNL(sw); // Zeilenumbruch maskieren
IDOS->Printf("ID %ld len=%ld [%ld] <%.20s>\n",id,len,lenr,sw);

                // ermittelten Texte in die cd und ct Datei shreiben
                IDOS->FPrintf(cd,"MSG_%ld (%ld//)\n; %s\n",id,id,sw);
                IDOS->FPrintf(ct,"MSG_%ld\n%s\n",id,sw);
              }
            }
            IDOS->Printf("\r%ld Texte gefunden.\n",num);

            res = RETURN_OK;

            IDOS->FClose(ct);
          }
          else IDOS->Printf("FEHLER %ld: beim öffnen der Ausgabedatei ct <%s>.\n",IDOS->IoErr(),namect);

          IDOS->FClose(cd);
        }
        else IDOS->Printf("FEHLER %ld: beim öffnen der Ausgabedatei cd <%s>.\n",IDOS->IoErr(),namecd);
      }
      else IDOS->Printf("FEHLER: Datei <%s> ist kein Catalog\n",(STRPTR)gb_Args[ARG_catalog]);

      IDOS->Close(cat);
    }
    else IDOS->Printf("FEHLER: beim öffnen des Catalogs <%s>.\n",(STRPTR)gb_Args[ARG_catalog]);

    IDOS->FreeArgs(rda);
  }
  else { IDOS->PrintFault(IDOS->IoErr(),gb_ProgName); res = RETURN_ERROR; }


  // zurück ins Aufrufverzeichnis
  IDOS->SetCurrentDir(olddir);

  return( res );
}

/******************************************************************************/


