#include <Includes/Main_Global.h>
/* All Support And Routines For The LHA Compression Type */
#define boolean BOOL
#define DELIM   ('/')
#define DELIM2  (0xff)
#define DELIMSTR "/"
#define bcopy(s,d,n) memmove((d),(s),(n))
#define UNIX_FILE_TYPEMASK      0170000
#define UNIX_FILE_REGULAR       0100000
#define UNIX_FILE_DIRECTORY     0040000
#define UNIX_SETUID             0004000
#define UNIX_SETGID             0002000
#define UNIX_STYCKYBIT          0001000
#define UNIX_OWNER_READ_PERM    0000400
#define UNIX_OWNER_WRITE_PERM   0000200
#define UNIX_OWNER_EXEC_PERM    0000100
#define UNIX_GROUP_READ_PERM    0000040
#define UNIX_GROUP_WRITE_PERM   0000020
#define UNIX_GROUP_EXEC_PERM    0000010
#define UNIX_OTHER_READ_PERM    0000004
#define UNIX_OTHER_WRITE_PERM   0000002
#define UNIX_OTHER_EXEC_PERM    0000001
#define UNIX_RW_RW_RW           0000666

#define LZHEADER_STRAGE         4096   
                      

typedef struct LzHeader 
{
  unsigned char   header_size;
  char            method[5];
  long            packed_size;
  long            original_size;
  long            last_modified_stamp;
  unsigned char   attribute;
  unsigned char   header_level;
  char            name[256];
  unsigned short  crc;
  boolean         has_crc;
  unsigned char   extend_type;
  unsigned char   minor_version;
  /*  extend_type == EXTEND_UNIX  and convert from other type. */
  time_t          unix_last_modified_stamp;
  unsigned short  unix_mode;
  unsigned short  unix_uid;
  unsigned short  unix_gid;
} LzHeader;
             


LHA_Describe( char *FileName)
{
  char buffer[200];
  sprintf(buffer,"LHEX -faw=T: e %s FILE_ID.DIZ file_id.diz >NIL: ",FileName);    
  Execute(buffer,0,0);
  return(Read_FILEID());
}

char * File_Part_Unix( char *FileName)
{
 char *NewFile;
 char  current;
 int length=0;
 
 length = strlen(FileName);
 while(length!=0)
 {
    current = FileName[length];
    if(current==0x5C) 
     {
     NewFile = FileName+length+1;
//     printf("Returning Early!");
     return(NewFile);
    }
    length--;
 }
    
 return(FileName);
}

LHA_Find( char *FileName, char *SearchString)
{
 FILE                   *Archive_File;
 struct LzHeader        *Header;
 char *Buffer;
 
    int i=0;
   
 Archive_File = fopen(FileName,"r");
 Header = Allocate_Memory(sizeof(struct LzHeader));
 if(!Archive_File)
   return(FALSE);
   
 while (get_header (Archive_File, Header))
    {
         DoMethod(App->App,MUIM_Application_InputBuffered);
        Buffer = File_Part_Unix(Header->name);
       // printf("Comparing %s with %s\n",strupr(Buffer ) ,strupr(SearchString));
        if(!strcmp( strupr(Buffer ) ,strupr(SearchString)))
         {
          DoMethod(App->Found_Lister,MUIM_List_InsertSingle,FileName,MUIV_List_Insert_Bottom);
          set(App->FoundLister_Window,MUIA_Window_Open,TRUE);
          //printf("File %s is in %s\n",SearchString,FilePart(FileName));
         }
        
        if (Archive_File != stdin)
            fseek (Archive_File, Header->packed_size, SEEK_CUR);
        else  
          {
            i = Header->packed_size;
            while(i--) fgetc(Archive_File);
        }
    }     
fclose(Archive_File);
 
}
static char *get_ptr;

#define setup_get(PTR)  (get_ptr = (PTR))
#define get_byte()      (*get_ptr++ & 0xff)
#define put_ptr         get_ptr
#define setup_put(PTR)  (put_ptr = (PTR))
#define put_byte(c)     (*put_ptr++ = (char)(c))

static unsigned short get_word ()
{
    int b0, b1;

    b0 = get_byte ();
    b1 = get_byte ();
    return (b1 << 8) + b0;
}

static void put_word (unsigned int v)
{
    put_byte (v);
    put_byte (v >> 8);
}

unsigned char * convdelim(unsigned char *path,unsigned char  delim)
{
    unsigned char c;
    unsigned char *p;
#ifdef MULTIBYTE_CHAR
    int kflg;

    kflg = 0;
#endif
    for (p = path; (c = *p) != 0; p++) {
#ifdef MULTIBYTE_CHAR
        if (kflg) {
            kflg = 0;
        } 
        else if (iskanji(c)) {
            kflg = 1;
        } 
        else
#endif
            if (c == '\\' || c == DELIM || c == DELIM2)
            {
                *p = delim;
                path = p + 1;
            }
    }
    return path;
}
      


static long get_longword ()
{
    long b0, b1, b2, b3;

    b0 = get_byte ();
    b1 = get_byte ();
    b2 = get_byte ();
    b3 = get_byte ();
    return (b3 << 24) + (b2 << 16) + (b1 << 8) + b0;
}
#define I_GENERIC_HEADER_BOTTOM I_EXTEND_TYPE



#define EXTEND_GENERIC      0
#define EXTEND_UNIX         'U'
#define EXTEND_MSDOS        'M'
#define EXTEND_MACOS        'm'
#define EXTEND_OS9          '9'
#define EXTEND_OS2          '2'
#define EXTEND_OS68K        'K'
#define EXTEND_OS386        '3'        /* OS-9000??? */
#define EXTEND_HUMAN        'H'
#define EXTEND_CPM          'C'
#define EXTEND_FLEX         'F'
#define EXTEND_RUNSER       'R'
/*    this OS type is not official */
#define EXTEND_TOWNSOS      'T'
#define EXTEND_XOSK         'X'
/*------------------------------*/

#define GENERIC_ATTRIBUTE           0x20
#define GENERIC_DIRECTORY_ATTRIBUTE 0x10
#define HEADER_LEVEL0               0x00
#define HEADER_LEVEL1               0x01
#define HEADER_LEVEL2               0x02

#define CURRENT_UNIX_MINOR_VERSION  0x00    
                          

BOOL get_header( FILE *Archive_Handle, struct LzHeader *Header)
{
    int header_size;
    int name_length;
    char data[4096];
    char dirname[1024];
    int dir_length = 0;
    int checksum;
    int i;
    char *ptr;
    
    if (((header_size = getc (Archive_Handle)) == EOF) || (header_size == 0))
    {
        return FALSE;
    }
    if (fread(data + 1, sizeof (char), header_size + 1, Archive_Handle)  < header_size + 1)

    {
        printf("Invalid header (LHarc file ?)\n");
        return FALSE;        /* finish */
    }

    setup_get (data + 1);
    checksum = get_byte();

    Header->header_size = header_size;
    bcopy (data + 2, Header->method, 5);

    setup_get (data + 7);
    Header->packed_size         = get_longword ();
    Header->original_size       = get_longword ();
    Header->last_modified_stamp = get_longword ();
    Header->attribute           = get_byte ();

    if ((Header->header_level   = get_byte ()) != 2) 
        {
        
        name_length          = get_byte ();
        for (i = 0; i < name_length; i ++)
             {
             Header->name[i] = (char)get_byte ();
            }
           Header->name[name_length] = '\0';
   
        } 
      else 
        {
         Header->unix_last_modified_stamp = Header->last_modified_stamp;
        }
         name_length = 0;

    /* defaults for other type */

    Header->unix_mode    = UNIX_FILE_REGULAR | UNIX_RW_RW_RW;

    Header->unix_gid     = 0;
    Header->unix_uid     = 0;

    if (header_size - name_length >= 24)
    {                /* EXTEND FORMAT */
        Header->crc            = get_word ();
        Header->extend_type    = get_byte ();
        Header->has_crc        = TRUE;
    }
    else if (header_size - name_length == 22)
    {                /* Generic with CRC */
        Header->crc            = get_word ();
        Header->extend_type    = EXTEND_GENERIC;
        Header->has_crc        = TRUE;
    }
    else if (header_size - name_length == 20)
    {                /* Generic no CRC */
        Header->extend_type    = EXTEND_GENERIC;
        Header->has_crc        = FALSE;
    }
    else
    {
        printf("Do Not Know Header Format!\n");
        return FALSE;
    }
    
    

    if (Header->extend_type == EXTEND_GENERIC && Header->header_level != 2);
    else 
     if (Header->header_level > 0) 
           {
            if (Header->header_level != 2) setup_get(data + Header->header_size);
            ptr = get_ptr;
            while((header_size = get_word()) != 0)
            {
                  if (Header->header_level != 2 && 
                      ((data + 1024 - get_ptr < header_size) ||
                      fread(get_ptr, sizeof(char), header_size, Archive_Handle) < header_size))   
                      {
                       return(FALSE);
                      }
            switch (get_byte()) 
            {
            case 0:
                /*
                 * header crc
                 */
                setup_get(get_ptr + header_size - 3);
                break;
            case 1:
                /*
                 * filename
                 */
                for (i = 0; i < header_size - 3; i++)
                    Header->name[i] =(char)get_byte ();
                Header->name[header_size - 3] = '\0';
                break;
            case 2:
                /*
                 * directory
                 */
                for (i = 0; i < header_size - 3; i++)
                    dirname[i] = (char)get_byte ();
                dirname[header_size - 3] = '\0';
                convdelim(dirname, DELIM);
                dir_length = header_size-3;
                break;
            
            
            default:
                /*
                 * other headers
                 */
                setup_get(get_ptr + header_size - 3);
                break;
            }
        }
        if (Header->header_level != 2 && get_ptr - ptr != 2) 
        {
            Header->packed_size -= get_ptr - ptr - 2;
            Header->header_size += get_ptr - ptr - 2;
        }
    }
    if (dir_length)
    {
        strcat(dirname, Header->name);
        strcpy(Header->name, dirname);
        name_length += dir_length;
    }

    return(TRUE);
 
}
 

LHA_Information( void)
{
    
    FILE                        *Archive_Name;
    char                        *Archive_Buffer;
    char                        *Primary_Buffer;
    char                        *FileName = "work:Test.lha";
    struct      FileInfoBlock   *FileInfo;
    int                         Index=0;
    int                         Delta=0;
    long                        UnCompSize=0;
    long                        CompSize=0;
    int                         CompressionType=0;
    int                         NameSize=0;
    int                         Incidental_Lock;
    
    FileInfo = malloc(sizeof(struct FileInfoBlock));
    Primary_Buffer = malloc(200);
    Incidental_Lock = Lock(FileName,ACCESS_READ);
    if(Incidental_Lock)
     {
        Examine(Incidental_Lock,FileInfo);
     }
     else
      printf("Unable To Examine %s\n",FileName);
      
     UnLock(Incidental_Lock); 
     Archive_Name = fopen(FileName,"r");
     if(Archive_Name)
      {
        printf("Opened The LHA.\n\n");
        Archive_Buffer = malloc(FileInfo->fib_Size);
        if(Archive_Buffer)
           {
             fread(Archive_Buffer,FileInfo->fib_Size,1,Archive_Name);   
             if(Archive_Buffer[2]==0x2D&&Archive_Buffer[3]==0x6C&&Archive_Buffer[4]==0x68&&Archive_Buffer[6]==0x2D)
                 { 
                  while(Index!=FileInfo->fib_Size)
                        {
                          if(Archive_Buffer[Index]==0x2D&&Archive_Buffer[Index+1]==0x6C&&Archive_Buffer[Index+2]==0x68&&Archive_Buffer[Index+4]==0x2D)
                             {
                               Delta=0;
                               NameSize = Archive_Buffer[Index+19];
                               while(NameSize!=0)
                                    {
                                      Primary_Buffer[Delta]=Archive_Buffer[Index+20+Delta];
                                      Delta++;
                                      NameSize--;
                                    }
                               Primary_Buffer[Delta]=0000;
                           
                               if(!strcmp(strupr(Primary_Buffer),"FILE_ID.DIZ"))
                                  {
                                    sprintf(Primary_Buffer,"%x%x%x%x",Archive_Buffer[Index+8],Archive_Buffer[Index+7],Archive_Buffer[Index+6],Archive_Buffer[Index+5]);
                                    stch_l(Primary_Buffer,&UnCompSize);
                                    printf("%d/",UnCompSize);
                                    sprintf(Primary_Buffer,"%x%x%x%x" ,Archive_Buffer[Index+12],Archive_Buffer[Index+11],Archive_Buffer[Index+10],Archive_Buffer[Index+9]);
                                    stch_l(Primary_Buffer,&CompSize);
                                    printf("%d\n",CompSize);
                                                                        
                                    Primary_Buffer[0]=Archive_Buffer[Index+3];
                                    Primary_Buffer[1]=0000;
                                    CompressionType = atoi(Primary_Buffer);
                                    
                                    switch(CompressionType)
                                             {
                                                case   0:
                                                  printf("No Compression Found\n");
                                                break;
                                                
                                                case   5:
                                                  printf("File Is Compressed\n");
                                                break;
                                            }
                                    
                                      
                                  }                   
                             }
                          Index++;  
                        }                             
                  printf("\nLHA File Is Valid.\n");
                 }
               else
                printf("Invalid LHA File.\n");
                   
             free(Archive_Buffer);  
             free(Primary_Buffer);
           }
           else
             printf("Unable To Allocate %d Bytes For Archive\n",FileInfo->fib_Size);
         
        fclose(Archive_Name);
      }
      else
        printf("Couldn't Open The Archive File\n");
        
      free(FileInfo);

}
