/*
 * Obj2Src 3.0
 *
 * Copyright 2000 Matteo Baccan <mbaccan@planetisa.com>
 * www - http://www.infomedia.it/artic/Baccan
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA (or visit
 * their web site at http://www.gnu.org/).
 *
 */

/* ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±

   ___,/|   Rivisto e corretto by     IAN     il 17/08/94  9:06am ___,/|
   \ o_O|   Rivisto e corretto by     TEO     il 21/08/94 10:52pm \ o_O|
   =(_|_)=  þ-           Ora funziona senza include           -þ  =(_|_)=
      U     Rivisto e corretto by     TEO     il 05/11/94  1:38pm    U
            þ-            Inizio riscrittura in C             -þ
            Rivisto e corretto by     TEO     il 11/05/00  1:38pm
            þ-              Open Source version               -þ
   ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±± */

// Uncomment this line if you use Borland Dos Compiler
//#define DOS_VERSION

#define WIN32_VERSION

#include <conio.h>
#include <dir.h>
#include <dos.h>
#include <process.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include <fcntl.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <io.h>

#ifdef WIN32_VERSION
#include <windows.h>
#endif

#define CFILE    1
#define CDEST    2
#define CFUNC    3
#define COUTPUT  4

#define OUT_CLIPPER   1
#define OUT_ASM       2
#define OUT_C         3

void dfConvFL( int hFileSource, int hFileDest, char * fpfunc, int iOut );

void dfWrite( char * fpString, int hFileDest );

char * _dfByte2Hex( unsigned char ucReg );

void _dfPro( unsigned int usTop,     // Top
             unsigned int usLeft,    // Left
             unsigned int usRight,   // Right
             long    lEle,     // Elemento attuale sul
             long    lTot  );   // totale

void _setblink( void );


void main(int argc, char *argv[] )
{
    struct text_info acttext;
    struct ffblk     flblock;
    int fsource;
    int fdest;
    char scanstart, scanend;
    int iOut = OUT_CLIPPER;

    gettextinfo( &acttext );
    _setblink();

    textcolor( 15 );
    cprintf( "\r\n ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿\r\n");
    cprintf( " ³²±° " );
    textcolor( 11 );
    cprintf( "   þObj2Src V3.0þ  Generates ASM/C Sources from any binary file!" );
    textcolor( 15 );
    cprintf( "    °±²³\r\n" );
    cprintf( " ³²±° " );
    textcolor( 13 );
    cprintf( "Clipper SwapWare(tm) Copyright (C)1995-2000 by" );
    textcolor( 14 );
    cprintf( " TEO+IAN of T</\\>T" );
    textcolor( 15 );
    cprintf( "    °±²³\r\n" );
    cprintf( " ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ\r\n" );
    textcolor( acttext.normattr );
    cprintf( "\r\n" );

    if( argc<4 ){
       textcolor( 12 );
       cprintf( "Command line:\r\n\r\n" );
       textcolor( 14 );
       cprintf( "Obj2Src" );
       textcolor( 15 );
       cprintf( " InputFile OutputFile FunctionName [/CLP|/ASM|/C]\r\n\r\n" );

       textcolor( acttext.normattr );
       cprintf( "The output file can be compiled with MASM or TASM to generate a Clipper\r\n" );
       cprintf( "The output file can be also compiled with a C Compiler\r\n" );
       cprintf( "Callable Function that returns a string containing the inputfile itself!\r\n" );
    }else{
       if( findfirst( argv[CFILE], &flblock, FA_ARCH )!=0 ){
          cprintf( "%s not found\r\n", argv[CFILE] );
          exit(1);
       }
       if( argc>4 && stricmp( argv[COUTPUT], "/ASM" )==0 )
          iOut=OUT_ASM;
       if( argc>4 && stricmp( argv[COUTPUT], "/C" )==0 )
          iOut=OUT_C;

       if( stricmp( argv[CFILE], argv[CDEST] )==0 ){
          textcolor( 15 );
          cprintf( "InputFile same as OutputFile! Do you want a Recursive loop ?" );
          textcolor( 14 );
          if( (getch()&223)!='Y' ){
             cprintf( "\r\nThat's right." );
          }else{
             cprintf( "\r\nARE YOU NUTS? Nah, I'd better quit now..." );
          }
          cprintf( " Re-enter the correct parameters" );
          textcolor( acttext.normattr );
          cprintf( "\r\n" );
          exit(2);
       }

       if( findfirst( argv[CDEST], &flblock, FA_ARCH )==0 ){
          textcolor( 15 );
          cprintf( "%s already exists... Overwrite(Y/n)", argv[CDEST] );
          textcolor( 14 );
          if( (getch()&223)!='Y' ){
             cprintf( " Aborted." );
             textcolor( acttext.normattr );
             cprintf( "\r\n" );
             exit(3);
          }else{
             cprintf( " Yes." );
          }
          textcolor( acttext.normattr );
          cprintf( "\r\n\r\n" );
          #ifdef WIN32_VERSION
          DeleteFile( argv[CDEST] );
          #endif
       }

       cprintf( "Opening source      file : %s\r\n", argv[CFILE] );
       #ifdef DOS_VERSION
       fsource=open( argv[CFILE], O_RDONLY );
       #endif
       #ifdef WIN32_VERSION
       fsource=open( argv[CFILE], O_BINARY|O_RDONLY );
       #endif
                                       //(unsigned)(256*256-16)
       if( lseek( fsource, 0, SEEK_END )>65520 ){
          cprintf( "\r\n" );
          textcolor( 147 );
          cprintf( "Û" );
          textcolor( 177 );
          cprintf( "Û" );
          textcolor( 147 );
          cprintf( "Û" );
          textcolor( 177 );
          cprintf( "Û" );
          textcolor( 147 );
          cprintf( "Û" );
          textcolor( 177 );
          cprintf( "Û" );
          textcolor( 13 );
          cprintf( " W A R N I N G : The Inputfile exceeds 64k! " );
          textcolor( 177 );
          cprintf( "Û" );
          textcolor( 147 );
          cprintf( "Û" );
          textcolor( 177 );
          cprintf( "Û" );
          textcolor( 147 );
          cprintf( "Û" );
          textcolor( 177 );
          cprintf( "Û" );
          textcolor( 147 );
          cprintf( "Û" );
          textcolor( acttext.normattr );
          cprintf( "\r\n\r\n" );
       }
       lseek( fsource, 0, SEEK_SET );

       cprintf( "Opening destination file : %s\r\n\r\n", argv[CDEST] );
       fdest=open( argv[CDEST], O_CREAT|O_TRUNC|O_BINARY|O_WRONLY );
       if( fdest>-1 ){
          textcolor( 15 );
          cprintf( "Working... " );
          textcolor( 15 );
          #ifdef DOS_VERSION
          asm{
             xor ax, ax
             mov ah, 0x03
             mov bx, 0x00
             int 0x10
             mov scanstart,ch
             mov scanend,cl
             xor ax,ax
             mov ah,0x01
             mov ch,0x01
             mov cl,0x00
             int 0x10
          }
          #endif
          dfConvFL( fsource, fdest, argv[CFUNC], iOut );
          #ifdef DOS_VERSION
          asm{
             xor ax,ax
             mov ah,0x01
             mov ch,scanstart
             mov cl,scanend
             int 0x10
          }
          #endif

          textcolor( 11 );
          cprintf( " Äþ[DONE]þÄ" );
          textcolor( 7 );
          cprintf( "\r\n" );
          close( fdest );
          #ifdef WIN32_VERSION
          SetFileAttributes( argv[CDEST], FA_NORMAL|FA_ARCH );
          #endif
       }

       close( fsource );
    }
}

void dfConvFL( int hFileSource, int hFileDest, char * fpfunc, int iOut ){
    char fpRead[16];                   /* Read Buffer  */
    char fpWrite[200];                 /* Write Buffer */
    int uiLen;                         /* Byte read    */
    unsigned short uiStart;                    /* Start Row    */
    unsigned short uiActual;                   /* Byte actual  */

    struct text_info acttext;

    unsigned long lEle, lTot;                  /* Actual and total element */

    uiStart=0;

    if(iOut==OUT_C){
       dfWrite( "//------- Generated by Obj2Src 3.0 (C)1995-2000 T</\\>T ---------\r\n", hFileDest );
    } else {
       dfWrite( ";-------- Generated by Obj2Src 3.0 (C)1995-2000 T</\\>T ---------\r\n", hFileDest );
       dfWrite( ".286\r\n"                                                        , hFileDest );
       dfWrite( ".MODEL LARGE\r\n\r\n"                                            , hFileDest );
       if(iOut==OUT_CLIPPER)
          dfWrite( "extrn    __retclen:far\r\n\r\n"                                  , hFileDest );

       dfWrite( "PUBLIC    "                                                    , hFileDest );
       dfWrite( fpfunc                                                          , hFileDest );
       dfWrite( "   ;* Function declaration\r\n\r\n"                            , hFileDest );
       dfWrite( "FAR_DATA  SEGMENT  PARA  'FAR_DATA'\r\n"                       , hFileDest );
    }

    gettextinfo( &acttext );
    _setblink();
    textcolor( 31 );

    lTot=lseek( hFileSource, 0, SEEK_END );
    if( lTot>0xFFFF-16 ) lTot=0xFFFF-16;
    lseek( hFileSource, 0, SEEK_SET );
    lEle=0;

    while( (uiLen=_read( hFileSource, fpRead, 16 ))>0 && lEle<=0xFFFF-16 ){

       if( uiStart==0 ){
          if(iOut==OUT_C){
             strcpy( fpWrite, "char *" );
             strcat( fpWrite, fpfunc   );
             strcat( fpWrite, "(){"    );
             strcat( fpWrite, "\r\n" );
             strcat( fpWrite, "   return" );
          } else if(iOut==OUT_CLIPPER)
             strcpy( fpWrite, "Buffer  " );
          else{
              strcpy( fpWrite, fpfunc );
              strcat( fpWrite, " "    );
          }
          uiStart=1;
       } else {
          if(iOut==OUT_C){
             strcpy( fpWrite, "         " );
          } else {
             strcpy( fpWrite, "	" );
          }
       }

       if(iOut==OUT_C){
          strcat( fpWrite, " \"\\0x" );
          strcat( fpWrite, _dfByte2Hex( fpRead[0] ) );
       } else {
          strcat( fpWrite, "DB 0" );
          strcat( fpWrite, _dfByte2Hex( fpRead[0] ) );
          strcat( fpWrite, "h" );
       }

       uiActual=1;
       while( uiActual<uiLen){
          if(iOut==OUT_C){
             strcat( fpWrite, "\\0x" );
             strcat( fpWrite, _dfByte2Hex( fpRead[uiActual++]) );
          } else {
             strcat( fpWrite, ", 0" );
             strcat( fpWrite, _dfByte2Hex( fpRead[uiActual++]) );
             strcat( fpWrite, "h" );
          }
       }

       if(iOut==OUT_C)
          strcat( fpWrite, "\"\r\n" );
       else
          strcat( fpWrite, "\r\n\0" );

       write( hFileDest, fpWrite, strlen(fpWrite) );

       _dfPro( acttext.cury, acttext.curx, 68, (long) (lEle+=uiLen), lTot );
    }

    if(iOut==OUT_C){
       dfWrite( ";\r\n"                                                                                  , hFileDest );
       dfWrite( "}\r\n"                                                                                  , hFileDest );
    } else {
       if(iOut==OUT_CLIPPER)
          dfWrite( "LenBuffer DW $-Buffer\r\n"                                                              , hFileDest );
       dfWrite( "FAR_DATA  ENDS\r\n\r\n"                                                                 , hFileDest );
       if(iOut==OUT_CLIPPER){
          dfWrite( "CSEG   SEGMENT 'CODE'      ;* Type of the segment\r\n"                                  , hFileDest );
          dfWrite( "       ASSUME cs:CSEG, ds:DGROUP\r\n\r\n"                                               , hFileDest );
          dfWrite( "   "                                                                                    , hFileDest );
          dfWrite( fpfunc                                                                                   , hFileDest );
          dfWrite( "   PROC    FAR      ;* Start Routine\r\n\r\n"                                           , hFileDest );
          dfWrite( "      pusha                         ;* Save the Register\r\n"                           , hFileDest );
          dfWrite( "      mov   bp,sp\r\n\r\n"                                                              , hFileDest );
          dfWrite( "      push  ds                      ;* Save DS\r\n"                                     , hFileDest );
          dfWrite( "      mov   ax, SEG LenBuffer       ;* FAR data\r\n"                                    , hFileDest );
          dfWrite( "      mov   ds, ax                  ;* Change DS\r\n"                                   , hFileDest );
          dfWrite( "      mov   bx, OFFSET LenBuffer    ;* Get pos of LenBuffer\r\n"                        , hFileDest );
          dfWrite( "      mov   cx, word ptr ds:[bx]    ;* Get LenBuffer\r\n"                               , hFileDest );
          dfWrite( "      pop   ds                      ;* Restore DS\r\n\r\n"                              , hFileDest );
          dfWrite( "      push  cx                      ;* Save the length\r\n"                             , hFileDest );
          dfWrite( "      push  SEG    Buffer           ;* Save the segment\r\n"                            , hFileDest );
          dfWrite( "      push  OFFSET Buffer           ;* Save the offset\r\n"                             , hFileDest );
          dfWrite( "      call  __retclen               ;* Call the __retclen to restore Clipper Buffer\r\n", hFileDest );
          dfWrite( "      add   sp, 6                   ;* Reset the stack pointer\r\n\r\n"                 , hFileDest );
          dfWrite( "      popa                          ;* Restore the register\r\n"                        , hFileDest );
          dfWrite( "      ret                           ;* Return\r\n\r\n"                                  , hFileDest );
          dfWrite( "   "                                                                                    , hFileDest );
          dfWrite( fpfunc                                                                                   , hFileDest );
          dfWrite( "   ENDP             ;* End of Routine\r\n\r\n"                                          , hFileDest );
          dfWrite( "CSEG   ENDS                       ;* End of Segment Code\r\n\r\n"                       , hFileDest );
       }
       dfWrite( "END                               ;* End of Program\r\n"                                , hFileDest );
    }
}

void dfWrite( char * fpString, int hFileDest ){
    write( hFileDest, fpString, strlen(fpString) );
}

void _dfPro( unsigned int usTop,     // Top
             unsigned int usLeft,    // Left
             unsigned int usRight,   // Right
             long    lEle,     // Elemento attuale sul
             long    lTot)     // totale
{
   unsigned int  uiNum;
   unsigned int  uiActual;
   unsigned long uiChar;
   char fpStr[80];

   uiNum=(usRight-usLeft+1);
   uiChar=uiNum*lEle/lTot;
   uiActual=0;

   while( uiActual<uiChar ) fpStr[uiActual++]='Û';
   while( uiActual<uiNum  ) fpStr[uiActual++]='±';
   fpStr[uiActual]=NULL;

   gotoxy( usLeft, usTop );
   cprintf( fpStr );
}

char * _dfByte2Hex( unsigned char ucReg ){
  static char fpHexBuf[3];
  static char * fpChar ="0123456789ABCDEF";

  fpHexBuf[0] = fpChar[ucReg/(16)       & 0x0f ];
  fpHexBuf[1] = fpChar[ucReg            & 0x0f ];
  fpHexBuf[2] = '\0';

  return fpHexBuf;
}

void _setblink( void ){
    #ifdef DOS_VERSION
    asm{ // Rimetto a posto il blink
       mov ax,0x1003
       mov bx,0x0001
       int 0x10
    }
    #endif
}