hitcounter
dpointer
Monday, July 12, 2004
 
ziplist

This small program ziplist I have mentioned before in my other blog entry (April 20, 2004). After reading the specification, I was interested in making short utility to show the content of a zip file, thus ziplist was born. It was pure C, portable, self-contained (no need for zlib), and already tested in Linux, Windows, and AIX. Ziplist is neither perfect (probably it can't handle few variants of zip files out there) or highly optimized for performance, it serves only as an example. So enjoy!

/* ziplist: small program to list files inside a .zip 
 * Copyright (C) 2004 Ariya Hidayat <ariya.hidayat@gmail.com>
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

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

#define readu16(ptr) ((ptr)[0]+((ptr)[1]<<8))
#define readu32(ptr) ((ptr)[0]+((ptr)[1]<<8)+((ptr)[2]<<16)+((ptr)[3]<<24))

void panic( char* msg )
{
  printf( "Fatal error: %s\n", msg );
  exit( -1 );
}

char* method( int n )
{
  char* s;
  switch( n )
  {
    case 0:  s = "Stored"; break;
    case 1:  s = "Shrunk"; break;
    case 2:  s = "Reduced1"; break;
    case 3:  s = "Reduced2"; break;
    case 4:  s = "Reduced3"; break;
    case 5:  s = "Reduced4"; break;
    case 6:  s = "Imploded"; break;
    case 8:  s = "Deflated"; break;
    default: s = "Unknown"; break;
  }  
  return s;
}

void ziplist( char* filename )
{
  FILE* f;
  int count = 0, i;
  unsigned char buffer[32];
  int comp_size, uncomp_size;
  int mod_date, mod_time;
  int name_length;
  int skip;
  
  /* open and check first few bytes for zip ide */  
  f = fopen( filename, "rb" );
  if( !f ) panic( "can't open input file" );  
  if( fread( buffer, 1, 30, f ) != 30 )
   panic( "not a zip file" );
   
  while( !feof( f ) )
  {
  
    /* magic id for file header file is: 0x50,0x4b,0x03,0x04 */
   if( ( buffer[0] != 0x50 ) || ( buffer[1] != 0x4b ) ||  
      ( buffer[2] != 0x03 ) || ( buffer[3] != 0x04 ) )
      {
        if( !count )  
          panic( "not a zip file" );
        else
          break;
      }
   
    /* pretty column header */    
    if( !count )
    {
      printf(" Length    Method    Size    Ratio   Date & Time     CRC-32    Name\n");
      printf("--------  -------- --------  ----- ----------------  --------  ------\n");
    }
  
    count++;
                    
    /* get necessary stuff */
    comp_size = readu32( buffer+18 );
    uncomp_size = readu32( buffer+22 );
    name_length = readu16( buffer+26 );
    mod_time = readu16( buffer+10 );
    mod_date = readu16( buffer+12 );
    skip = readu16( buffer+28 );
    if( buffer[7] & 0x40 )
      skip += 12;  
  
    /* print information */        
    printf("%8d  %-8s %8d  %3d%%  %02d-%02d-%04d %02d:%02d  %02X%02X%02X%02X  ", 
      uncomp_size, method( buffer[8] ), comp_size, !uncomp_size ? 0 : 100-comp_size*100/uncomp_size,
      (mod_date>>5)&15, mod_date&31, 1980+(mod_date>>9),
      (mod_time>>5)&63, (mod_time>>11),
      (unsigned char)buffer[17], (unsigned char)buffer[16], 
      (unsigned char)buffer[15], (unsigned char)buffer[14] );
      
    /* get filename */
    while( name_length > 0 )
    {
      i = fread( buffer, 1, ( name_length < 30 ) ? name_length : 30, f );
      if( i < 0 )
      {
        fclose( f );
        panic( "can't read input file" );
      }
      buffer[ i ] = '\0';
      if( name_length < i ) buffer[ name_length ] = '\0';
      printf("%s", buffer );
      name_length -= i;
    }
    printf( "\n" );
  
    /* skip = number of bytes to skip, including data descriptor (if any) */
    /* skip extra field + compressed data */
    fseek( f, skip + comp_size, SEEK_CUR );
  
    /* load another header */
    if( !feof( f ) )
      if( fread( buffer, 1, 30, f ) != 30 )
        panic( "can't read input file" );
  }
  
  /* that's all, folks */
  fclose( f );
}

int main(int argc, char *argv[])
{
  if( argc < 2 )
  {
    printf("usage: %s filename\n", argv[0] );
    return 0;
  }
  
  ziplist( argv[1] );

  return 0;
}

Comments: Post a Comment

<< Home

Powered by Blogger