rpms/clonekeen/F-8 clonekeen-clonekeen2x-fixes.patch, NONE, 1.1 clonekeen-extract-sounds.c, NONE, 1.1 clonekeen-fixes.patch, NONE, 1.1 clonekeen-options.patch, NONE, 1.1 clonekeen.autodlrc, NONE, 1.1 clonekeen.desktop, NONE, 1.1 clonekeen.png, NONE, 1.1 clonekeen.sh, NONE, 1.1 clonekeen.spec, NONE, 1.1 extract.c, NONE, 1.1 .cvsignore, 1.1, 1.2 sources, 1.1, 1.2

Hans de Goede (jwrdegoede) fedora-extras-commits at redhat.com
Sun Nov 4 20:18:50 UTC 2007


Author: jwrdegoede

Update of /cvs/extras/rpms/clonekeen/F-8
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv18069

Modified Files:
	.cvsignore sources 
Added Files:
	clonekeen-clonekeen2x-fixes.patch clonekeen-extract-sounds.c 
	clonekeen-fixes.patch clonekeen-options.patch 
	clonekeen.autodlrc clonekeen.desktop clonekeen.png 
	clonekeen.sh clonekeen.spec extract.c 
Log Message:
* Thu Oct 25 2007 Hans de Goede <j.w.r.degoede at hhs.nl> 0.8.3-1
- Initial Fedora package


clonekeen-clonekeen2x-fixes.patch:

--- NEW FILE clonekeen-clonekeen2x-fixes.patch ---
Only in src.fixed/ai: .#walker.c
diff -ur src.fixed/ai/baby.c src/ai/baby.c
--- src.fixed/ai/baby.c	2005-11-09 22:12:46.000000000 +0100
+++ src/ai/baby.c	2007-10-24 19:26:26.000000000 +0200
@@ -212,7 +212,7 @@
 #define BABY_SMALLJUMP_MAX_DEC_RATE    20
 void baby_jump(int o, int big)
 {
-    if (rand()&2==0) big = 1-big;
+    if ((rand()&2)==0) big = 1-big;
     if (big==BABY_JUMP_BIG)
     {
       objects[o].ai.baby.inertia_y = -BABY_BIGJUMP;
diff -ur src.fixed/ai/fireball.c src/ai/fireball.c
--- src.fixed/ai/fireball.c	2005-11-09 22:13:08.000000000 +0100
+++ src/ai/fireball.c	2007-10-24 19:26:26.000000000 +0200
@@ -14,8 +14,7 @@
 
 void fireball_ai(int o)
 {
-int i;
-int newobject;
+	int i;
   if (objects[o].needinit)
   {
     objects[o].ai.ray.animframe = 0;
@@ -26,6 +25,26 @@
     objects[o].needinit = 0;
   }
 
+  // test if it hit a baddie
+   for(i=1;i<MAX_OBJECTS;i++)
+   {
+     if (!objects[i].exists || i==o) continue;
+     if (objects[o].ai.ray.dontHitEnable)
+     {
+       if (objects[i].type==objects[o].ai.ray.dontHit) continue;
+     }
+
+     if (objects[i].canbezapped)
+     {
+        if (hitdetect(i, o))
+        {
+	     objects[o].type = OBJ_RAY;
+		 objects[o].ai.ray.state = RAY_STATE_SETZAPZOT;
+          objects[i].zapped++;
+        }
+     }
+   }
+
   // check if it hit keen
   if (objects[o].touchPlayer)
   {
diff -ur src.fixed/ai/meep.c src/ai/meep.c
--- src.fixed/ai/meep.c	2005-11-09 22:13:32.000000000 +0100
+++ src/ai/meep.c	2007-10-24 19:26:26.000000000 +0200
@@ -43,10 +43,25 @@
   }
   if (objects[o].ai.meep.state==MEEP_DEAD) return;
 
-  if (objects[o].touchPlayer && objects[o].ai.meep.state!=MEEP_DYING)
-  {
-     killplayer(objects[o].touchedBy);
-  }
+   if (objects[o].touchPlayer && !player[objects[o].touchedBy].pdie)
+   {
+      /* don't push the player as he's walking through the exit door */
+      if (!levelcontrol.level_done || levelcontrol.level_finished_by != objects[o].touchedBy)
+      {
+         if (player[objects[o].touchedBy].x < objects[o].x)
+         {
+            player[objects[o].touchedBy].playpushed_x = -MEEP_WALK_SPD;
+            if (player[objects[o].touchedBy].pinertia_x > 0) player[objects[o].touchedBy].pinertia_x = 0;
+            player[objects[o].touchedBy].playpushed_decreasetimer = 0;
+         }
+         else
+         {
+            player[objects[o].touchedBy].playpushed_x = MEEP_WALK_SPD;
+            if (player[objects[o].touchedBy].pinertia_x < 0) player[objects[o].touchedBy].pinertia_x = 0;
+            player[objects[o].touchedBy].playpushed_decreasetimer = 0;
+         }
+      }
+   } 
 
   if (objects[o].zapped)
   {
diff -ur src.fixed/ai/mother.c src/ai/mother.c
--- src.fixed/ai/mother.c	2005-11-09 22:13:34.000000000 +0100
+++ src/ai/mother.c	2007-10-24 19:26:26.000000000 +0200
@@ -10,7 +10,7 @@
 #define MOTHER_WALK_ANIM_RATE     70
 #define MOTHER_WALK_SPD           1
 
-#define MOTHER_SPIT_PROB          1000
+#define MOTHER_SPIT_PROB          2000
 #define MOTHER_SPIT_SHOW_TIME     100
 
 #define MOTHER_HP      4
@@ -48,10 +48,26 @@
   }
   if (objects[o].ai.mother.state==MOTHER_DEAD) return;
 
-  if (objects[o].touchPlayer)
-  {
-     killplayer(objects[o].touchedBy);
-  }
+   if (objects[o].touchPlayer && !player[objects[o].touchedBy].pdie)
+   {
+      /* don't push the player as he's walking through the exit door */
+      if (!levelcontrol.level_done || levelcontrol.level_finished_by != objects[o].touchedBy)
+      {
+         if (player[objects[o].touchedBy].x < objects[o].x)
+         {
+            player[objects[o].touchedBy].playpushed_x = -MOTHER_WALK_SPD;
+            if (player[objects[o].touchedBy].pinertia_x > 0) player[objects[o].touchedBy].pinertia_x = 0;
+            player[objects[o].touchedBy].playpushed_decreasetimer = 0;
+         }
+         else
+         {
+            player[objects[o].touchedBy].playpushed_x = MOTHER_WALK_SPD;
+            if (player[objects[o].touchedBy].pinertia_x < 0) player[objects[o].touchedBy].pinertia_x = 0;
+            player[objects[o].touchedBy].playpushed_decreasetimer = 0;
+         }
+      }
+   } 
+
 
   if (objects[o].zapped)
   {
@@ -70,27 +86,20 @@
    case MOTHER_WALK:
      if (rand()%MOTHER_SPIT_PROB==(MOTHER_SPIT_PROB/2))
      {
-       if (objects[o].onscreen)
-       {
-         objects[o].ai.mother.state = MOTHER_SPIT;
-         objects[o].ai.mother.timer = 0;
-       }
-       else
-       {
-          // try to get onscreen by heading towards the player
-          if (player[primaryplayer].x > objects[o].x)
-            objects[o].ai.mother.dir = RIGHT;
-          else
-            objects[o].ai.mother.dir = LEFT;
-       }
+	   if (objects[o].ai.mother.dir == RIGHT) // turn around before spitting
+			objects[o].ai.mother.dir = LEFT;
+	   else
+			objects[o].ai.mother.dir = RIGHT;
+
+	   objects[o].ai.mother.state = MOTHER_SPIT;
+       objects[o].ai.mother.timer = 0;
      }
 
      if (objects[o].ai.mother.dir==RIGHT)
      {
        objects[o].sprite = MOTHER_WALK_RIGHT_FRAME + objects[o].ai.mother.animframe;
-//       not_about_to_fall = tiles[getmaptileat((objects[o].x>>CSF)+sprites[MOTHER_WALK_RIGHT_FRAME].xsize, (objects[o].y>>CSF)+sprites[MOTHER_WALK_RIGHT_FRAME].ysize)].solidfall;
 
-       if (objects[o].blockedr)// || !not_about_to_fall)
+       if (objects[o].blockedr)
        {
          objects[o].ai.mother.dir = LEFT;
        }
diff -ur src.fixed/ai/ninja.c src/ai/ninja.c
--- src.fixed/ai/ninja.c	2005-11-09 22:13:42.000000000 +0100
+++ src/ai/ninja.c	2007-10-24 19:26:26.000000000 +0200
@@ -156,7 +156,9 @@
      else objects[o].ai.ninja.animtimer++;
      break;
    case NINJA_KICK:
-     if (!objects[o].ai.ninja.isdying)
+       if (objects[o].blockedu && objects[o].ai.ninja.YInertia < 0) objects[o].ai.ninja.YInertia *= 0.5;
+
+	   if (!objects[o].ai.ninja.isdying)
      {
        if (objects[o].ai.ninja.dir==LEFT)
          { objects[o].sprite = NINJA_KICK_LEFT_FRAME; }
diff -ur src.fixed/ai/se.c src/ai/se.c
--- src.fixed/ai/se.c	2005-11-09 22:14:30.000000000 +0100
+++ src/ai/se.c	2007-10-24 19:26:26.000000000 +0200
@@ -946,6 +946,10 @@
 void se_mortimer_leg_right(int o)
 {
 int mx,my;
+  if (objects[o].touchPlayer)
+  {
+     killplayer(objects[o].touchedBy);
+  }
    if (objects[o].needinit)
    {
      objects[o].ai.se.dir = UP;
diff -ur src.fixed/ai/tank.c src/ai/tank.c
--- src.fixed/ai/tank.c	2005-11-09 22:14:22.000000000 +0100
+++ src/ai/tank.c	2007-10-18 22:34:25.000000000 +0200
@@ -57,8 +57,10 @@
    // stop keen from walking through our sprite
      if (objects[o].touchPlayer && !player[objects[o].touchedBy].pdie)
      {
-          sound_play(SOUND_YORP_BUMP, PLAY_NORESTART);
+        sound_play(SOUND_YORP_BUMP, PLAY_NORESTART);
 
+        if (!((player[objects[o].touchedBy].y) < (objects[o].y - 300))) // give the player a little jump-over room
+        {
           if (player[objects[o].touchedBy].x < objects[o].x)
           {
              player[objects[o].touchedBy].playpushed_x = -TANKPUSHAMOUNT;
@@ -71,6 +73,7 @@
              player[objects[o].touchedBy].playpushed_decreasetimer = 0;
              player[objects[o].touchedBy].pdir = player[objects[o].touchedBy].pshowdir = RIGHT;
           }
+        }
      }
 
    switch(objects[o].ai.tank.state)
@@ -95,7 +98,7 @@
                { objects[o].ai.tank.movedir = LEFT; }
              else if (!tank_CanMoveLeft(o))
                { objects[o].ai.tank.movedir = RIGHT; }
-             else if (rand()&1)
+             else if (player[objects[o].ai.tank.detectedPlayerIndex].x < objects[o].x) // turn towards player
                { objects[o].ai.tank.movedir = LEFT; }
              else
                { objects[o].ai.tank.movedir = RIGHT; }
@@ -143,9 +146,8 @@
          if (objects[o].ai.tank.detectedPlayer)
          {
            objects[o].ai.tank.ponsameleveltime++;
-           if ((objects[o].ai.tank.ponsameleveltime > TANK_SAME_LEVEL_TIME) || \
-               (objects[o].ai.tank.ponsameleveltime > TANK_SAME_LEVEL_TIME_FAST && options[OPT_MEAN].value))
-           {   // keen would be a good target now.
+           if (objects[o].ai.tank.ponsameleveltime > TANK_SAME_LEVEL_TIME_FAST && options[OPT_MEAN].value)
+           {   // keen would be a good target now. (hard mode)
               if (!objects[o].ai.tank.alreadyfiredcauseonsamelevel ||\
                   objects[o].ai.tank.ponsameleveltime > TANK_REPEAT_FIRE_TIME || \
                   (objects[o].ai.tank.ponsameleveltime > TANK_REPEAT_FIRE_TIME_FAST && options[OPT_MEAN].value))
@@ -178,20 +180,10 @@
        if (objects[o].ai.tank.dist_traveled > TANK_MINTRAVELDIST && objects[o].onscreen)
        {
           if (rand()%TANK_LOOKFIRE_PROB==(TANK_LOOKFIRE_PROB/2))
-          {  // we're either going to look or fire
-              if (rand()&1)
-              { // look
-                 objects[o].ai.tank.timer = 0;
-                 objects[o].ai.tank.frame = 0;
-                 objects[o].ai.tank.state = TANK_LOOK;
-              }
-              else
-              { // FIRE!
-                 objects[o].ai.tank.timer = 0;
-                 objects[o].ai.tank.state = TANK_FIRE;
-              }
-              break;
-          }
+	  {
+		  objects[o].ai.tank.timer = 0;
+		  objects[o].ai.tank.state = TANK_FIRE;
+	  }
        }
 
        if (objects[o].ai.tank.movedir==LEFT)
@@ -252,7 +244,10 @@
          objects[newobject].sprite = ENEMYRAY;
          objects[newobject].ai.ray.dontHitEnable = 0;
 
-         objects[o].ai.tank.state = TANK_WALK;
+	 objects[o].ai.tank.timer = 0;
+         objects[o].ai.tank.frame = 0;
+         objects[o].ai.tank.animtimer = 0;
+         objects[o].ai.tank.state = TANK_LOOK; // must look after fire
       } else objects[o].ai.tank.timer++;
      break;
 
diff -ur src.fixed/ai/tankep2.c src/ai/tankep2.c
--- src.fixed/ai/tankep2.c	2005-11-09 22:14:06.000000000 +0100
+++ src/ai/tankep2.c	2007-10-24 19:26:26.000000000 +0200
@@ -15,8 +15,8 @@
 
 #define TANK_WALK_SPEED         4
 #define TANK_WALK_ANIM_TIME     60
-#define TANK_LOOK_ANIM_TIME     70
-#define TANK_LOOK_TOTALTIME     180
+#define TANK_LOOK_ANIM_TIME     110
+#define TANK_LOOK_TOTALTIME     250
 #define TANK2_PREPAREFIRE_TIME  80
 
 // frames
@@ -30,6 +30,7 @@
 #define TANK2_SHOTS_PER_VOLLEY    4
 #define TANK2_MIN_TIME_TILL_CAN_FIRE  600
 #define TANK2_MAX_TIME_TILL_CAN_FIRE  1000
+#define TANK2_PAUSE_BEFORE_FIRST_SHOT 150
 #define TANK2_TIME_BETWEEN_SHOTS  50
 #define TANK2_TIME_BEFORE_FIRE_WHEN_SEE      100
 #define TANK2_TIME_BETWEEN_FIRE_CAUSE_LEVEL  400
@@ -126,7 +127,7 @@
                    if (!objects[o].ai.tank.timetillcanfirecauseonsamelevel)
                    {
                      objects[o].ai.tank.firetimes = TANK2_SHOTS_PER_VOLLEY;
-                     objects[o].ai.tank.timetillnextshot = 0;
+                     objects[o].ai.tank.timetillnextshot = TANK2_PAUSE_BEFORE_FIRST_SHOT;
                      objects[o].ai.tank.timetillcanfire = (rand()%(TANK2_MAX_TIME_TILL_CAN_FIRE-TANK2_MIN_TIME_TILL_CAN_FIRE))+TANK2_MIN_TIME_TILL_CAN_FIRE;
                      objects[o].ai.tank.timetillcanfirecauseonsamelevel = TANK2_TIME_BETWEEN_FIRE_CAUSE_LEVEL;
                    }
@@ -183,7 +184,7 @@
           if (!objects[o].ai.tank.timetillcanfire)
           {
             objects[o].ai.tank.firetimes = TANK2_SHOTS_PER_VOLLEY;
-            objects[o].ai.tank.timetillnextshot = 0;
+            objects[o].ai.tank.timetillnextshot = TANK2_PAUSE_BEFORE_FIRST_SHOT;
             objects[o].ai.tank.timetillcanfire = (rand()%(TANK2_MAX_TIME_TILL_CAN_FIRE-TANK2_MIN_TIME_TILL_CAN_FIRE))+TANK2_MIN_TIME_TILL_CAN_FIRE;
           }
           else
@@ -192,47 +193,49 @@
           }
        }
 
-       if (objects[o].ai.tank.movedir==LEFT)
-       {  // move left
-//         not_about_to_fall = tiles[getmaptileat((objects[o].x>>CSF)-1, (objects[o].y>>CSF)+sprites[TANK2_WALK_LEFT_FRAME].ysize+16)].solidfall;
-         objects[o].sprite = TANK2_WALK_LEFT_FRAME + objects[o].ai.tank.frame;
-         if (!objects[o].blockedl)
-         {
-           objects[o].x -= TANK_WALK_SPEED;
-           objects[o].ai.tank.dist_traveled++;
-         }
-         else
-         {
-           objects[o].ai.tank.frame = 0;
-           objects[o].ai.tank.timer = 0;
-           objects[o].ai.tank.animtimer = 0;
-           objects[o].ai.tank.state = TANK_LOOK;
-         }
-       }
-       else
-       {  // move right
-//         not_about_to_fall = tiles[getmaptileat((objects[o].x>>CSF)+sprites[TANK2_WALK_RIGHT_FRAME].xsize+1, (objects[o].y>>CSF)+sprites[TANK2_WALK_RIGHT_FRAME].ysize+16)].solidfall;
-         objects[o].sprite = TANK2_WALK_RIGHT_FRAME + objects[o].ai.tank.frame;
-         if (!objects[o].blockedr)
-         {
-           objects[o].x += TANK_WALK_SPEED;
-           objects[o].ai.tank.dist_traveled++;
-         }
-         else
-         {
-           objects[o].ai.tank.frame = 0;
-           objects[o].ai.tank.timer = 0;
-           objects[o].ai.tank.animtimer = 0;
-           objects[o].ai.tank.state = TANK_LOOK;
-         }
-       }
-       // hover animation
-       if (objects[o].ai.tank.animtimer > TANK_WALK_ANIM_TIME)
-       {
-         if (objects[o].ai.tank.frame>=3) objects[o].ai.tank.frame=0;
-                                     else objects[o].ai.tank.frame++;
-         objects[o].ai.tank.animtimer = 0;
-       } else objects[o].ai.tank.animtimer++;
+	  if (!objects[o].ai.tank.firetimes) // can't walk while firing
+	  {
+		  if (objects[o].ai.tank.movedir==LEFT)
+		  {  // move left
+			  objects[o].sprite = TANK2_WALK_LEFT_FRAME + objects[o].ai.tank.frame;
+			  if (!objects[o].blockedl)
+			  {
+				  objects[o].x -= TANK_WALK_SPEED;
+				  objects[o].ai.tank.dist_traveled++;
+			  }
+			  else
+			  {
+				  objects[o].ai.tank.frame = 0;
+				  objects[o].ai.tank.timer = 0;
+				  objects[o].ai.tank.animtimer = 0;
+				  objects[o].ai.tank.state = TANK_LOOK;
+			  }
+		  }
+		  else
+		  {  // move right
+			  objects[o].sprite = TANK2_WALK_RIGHT_FRAME + objects[o].ai.tank.frame;
+			  if (!objects[o].blockedr)
+			  {
+				  objects[o].x += TANK_WALK_SPEED;
+				  objects[o].ai.tank.dist_traveled++;
+			  }
+			  else
+			  {
+				  objects[o].ai.tank.frame = 0;
+				  objects[o].ai.tank.timer = 0;
+				  objects[o].ai.tank.animtimer = 0;
+				  objects[o].ai.tank.state = TANK_LOOK;
+			  }
+		  }
+	  }
+
+      // hover animation
+      if (objects[o].ai.tank.animtimer > TANK_WALK_ANIM_TIME)
+      {
+        if (objects[o].ai.tank.frame>=3) objects[o].ai.tank.frame=0;
+                                    else objects[o].ai.tank.frame++;
+        objects[o].ai.tank.animtimer = 0;
+      } else objects[o].ai.tank.animtimer++;
     break;
 
    }
diff -ur src.fixed/ai/walker.c src/ai/walker.c
--- src.fixed/ai/walker.c	2005-11-09 22:14:18.000000000 +0100
+++ src/ai/walker.c	2007-10-18 22:22:07.000000000 +0200
@@ -107,7 +107,7 @@
          if (player[objects[o].touchedBy].x < objects[o].x)
          {
             player[objects[o].touchedBy].playpushed_x = -WALKERPUSHAMOUNT;
-//            if (player[objects[o].touchedBy].pinertia_x > 0) player[objects[o].touchedBy].pinertia_x = 0;
+            if (player[objects[o].touchedBy].pinertia_x > 0) player[objects[o].touchedBy].pinertia_x = 0;
             player[objects[o].touchedBy].playpushed_decreasetimer = 0;
          }
          else
Only in src: fileio.c


--- NEW FILE clonekeen-extract-sounds.c ---
/*  Utility to extract the embedded sounds from Commander Keen
    Episode 2 (keen2.exe) and Episode 3 (keen3.exe)

    Copyright (C) 2007 Hans de Goede  <j.w.r.degoede at hhs.nl>
    
    Many thanks to Mitugu(Kou) Kurizono for the decompression algorithm.

    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 <string.h>

int bit_count;
FILE *fin;

int get_bit(void)
{
  static unsigned short bits;
  int bit;
  
  bit = bits & 1;
  bit_count--;

  if (bit_count <= 0)
  {
    bits = getc(fin) | getc(fin) << 8;

    if (bit_count == -1) /* special case for first bit word */
    {
      bit = bits & 1;
      bits >>= 1;
    }

    bit_count += 16;
  }
  else
    bits >>= 1;
  
  return bit;
}

int main(int argc, char *argv[])
{
  unsigned char buf[131072];
  short offset;
  const char *output_filename;
  int pos, repeat, sounds_start, sounds_end, ret = 0;
  FILE *fout;

  pos = 0;
  bit_count = 0;
  
  if (argc != 2)
  {
    fprintf(stderr, "%s: Usage: %s keen?.exe\n", argv[0], argv[0]);
    return 1;
  }
  
  if (!strcmp(argv[1], "keen2.exe"))
  {
    output_filename = "sounds.ck2";
    sounds_start  = 0x12730;
    sounds_end    = 0x14BDA;
  }
  else if (!strcmp(argv[1], "keen3.exe"))
  {
    output_filename = "sounds.ck3";
    sounds_start  = 0x13A70;
    sounds_end    = 0x164D4;
  }
  else
  {
    fprintf(stderr, "%s: Error: Unknown keen executable name: %s\n",
      argv[0], argv[1]);
    return 1;
  }
  
  fin = fopen(argv[1], "r");
  if (!fin)
  {
    fprintf(stderr, "%s: Error opening input file %s: ", argv[0], argv[1]);
    perror(NULL);
  }

  fout = fopen(output_filename, "w");
  if (!fout)
  {
    fprintf(stderr, "%s: Error opening output file %s: ", argv[0],
      output_filename);
    perror(NULL);
    fclose(fin);
    return 1;
  }

  /* skip header */
  fseek(fin, 32, SEEK_SET);

  while (1)
  {
    if (ferror(fin))
    {
      fprintf(stderr, "%s: Error reading from input file %s: ", argv[0],
        argv[1]);
      perror(NULL);
      fclose(fin);
      fclose(fout);
      return 1;
    }
    
    if (get_bit())
    {
      buf[pos++] = getc(fin);
    }
    else
    {
      if (get_bit())
      {
        unsigned char tmp[2];
        fread(tmp, 1, 2, fin);
        repeat = (tmp[1] & 0x07);
        offset = ((tmp[1] & ~0x07) << 5) | tmp[0] | 0xE000;

        if (repeat == 0)
        {
          repeat = getc (fin);

          if (repeat == 0)
            break;
          else if (repeat == 1)
            continue;
          else
            repeat++;
        }
        else
          repeat += 2;
      }
      else
      {
        repeat = ((get_bit() << 1) | get_bit()) + 2;
        offset = getc(fin) | 0xFF00;
      }

      while (repeat > 0)
      {
        buf[pos] = buf[pos + offset];
        pos++;
        repeat--;
      }
    }
  }
  
  printf("%s: Decompression (unlzexe) of %s done\n", argv[0], argv[1]);
  
  if (strcmp(&buf[sounds_start], "SND"))
  {
    fprintf(stderr, "%s: Error: Beginning of sound data not found at expected offset\n",
      argv[0]);
    ret = 1;
  }
  else if (fwrite(&buf[sounds_start], 1, sounds_end - sounds_start, fout) !=
      (sounds_end - sounds_start))
  {
    fprintf(stderr, "%s: error writing to output file %s: ", argv[0],
      output_filename);
    perror(NULL);
    ret = 1;
  }
  printf("%s: %s has been successfully written\n", argv[0], output_filename);
  
  fclose(fin);
  fclose(fout);

  return ret;
}

clonekeen-fixes.patch:

--- NEW FILE clonekeen-fixes.patch ---
--- keen/src.orig/latch.c	2005-11-10 19:51:48.000000000 +0100
+++ keen/src/latch.c	2007-10-15 16:30:54.000000000 +0200
@@ -71,7 +71,7 @@
 char buf[12];
 int i,j,k;
 
-    sprintf(fname, "data/EGAHEAD.CK%c", episode + '0');
+    sprintf(fname, "data/egahead.ck%c", episode + '0');
  
     headfile = fopen(fname, "rb");
     if (!headfile)
@@ -201,7 +201,7 @@
 unsigned long RawDataSize;
 unsigned char ch;
 
-    sprintf(fname, "data/EGALATCH.CK%c", episode + '0');
+    sprintf(fname, "data/egalatch.ck%c", episode + '0');
  
     VidDrv_printf("latch_loadlatch(): Opening file '%s'.\n", fname);
 
@@ -390,7 +390,7 @@
 int i;
 unsigned char ch;
 
-    sprintf(fname, "data/EGASPRIT.CK%c", episode + '0');
+    sprintf(fname, "data/egasprit.ck%c", episode + '0');
  
     VidDrv_printf("latch_loadsprites(): Opening file '%s'.\n", fname);
 
--- keen/src.orig/main.c	2005-11-09 23:35:10.000000000 +0100
+++ keen/src/main.c	2007-10-15 16:52:40.000000000 +0200
@@ -316,7 +316,7 @@
   if (argc>1 && *argv[1] != '-')
   {   // command to start at a specific level ("keen 4 -ep1", etc)
     playgame_levelmanager(argc, argv, 0);
-    goto exitt;
+    goto ok;
   }
   #endif
 
@@ -325,10 +325,10 @@
   if (eseq)
   {
     endsequence();
-    goto exitt;
+    goto ok;
   }
 
-  if (intro()) goto exitt;
+  if (intro()) goto ok;
 
   defaultopt = 0;
   do   
@@ -409,13 +409,13 @@
     VidDrv_printf("bottom of game control loop opt=%d crashflag=%d\n", opt, crashflag);
   } while(opt != MAINMNU_QUIT && !crashflag);
 
-VidDrv_printf("WARNING! WARNING! dropped out of game control loop!!!!\n");
-exitt: ;
-  Graphics_Stop();
+  if (crashflag)
+    VidDrv_printf("WARNING! WARNING! dropped out of game control loop!!!!\n");
+
 ok: ;
+  cleanup();
   banner();
   VidDrv_printf("\nThanks for playing!\n\n");
-  cleanup();
   if (crashflag)
   {
     if (crashflag != QUIT_NONFATAL) VidDrv_printf("\a");
@@ -484,7 +485,7 @@
         else if (newlevel==9)
            newlevel = 5;
     }
-    sprintf(levelname, "LEVEL%02d.CK%d", newlevel, levelcontrol.episode);
+    sprintf(levelname, "level%02d.ck%d", newlevel, levelcontrol.episode);
 
     if (levelcontrol.chglevelto==WORLD_MAP)
     {
--- keen/src.orig/sdl/snddrv.c	2005-11-09 22:48:24.000000000 +0100
+++ keen/src/sdl/snddrv.c	2007-10-15 16:32:30.000000000 +0200
@@ -121,7 +121,7 @@
 
   VidDrv_printf("sound_load_all(): loading all sounds...\n");
 
-  sprintf(soundfile, "data/SOUNDS.CK%d", levelcontrol.episode);
+  sprintf(soundfile, "data/sounds.ck%d", levelcontrol.episode);
 
   ok  = sound_load(soundfile, "KEENWALKSND", SOUND_KEEN_WALK);
   ok |= sound_load(soundfile, "KEENWLK2SND", SOUND_KEEN_WALK2);

clonekeen-options.patch:

--- NEW FILE clonekeen-options.patch ---
diff -up keen/src/main.c~ keen/src/main.c
--- keen/src/main.c~	2007-10-25 21:47:38.000000000 +0200
+++ keen/src/main.c	2007-10-25 21:47:38.000000000 +0200
@@ -126,6 +126,48 @@ void SetDefaultOptions(void)
   setoption(OPT_CHEATS, "Enable all cheats", 0);
 }
 
+void LoadConfig(void)
+{
+  FILE *f;
+  char *colon, buf[512];
+  int i;
+  
+  f = fopen("clonekeen.cfg", "r");
+  if (!f)
+    return;
+    
+  /* skip leading comment line */
+  fgets(buf, sizeof(buf), f);
+  
+  for (i = 1; i < NUM_OPTIONS; i++)
+  {
+    if (!fgets(buf, sizeof(buf), f))
+      break;
+    colon = strrchr(buf, ':');
+    if (colon)
+      options[i].value = strtol(colon + 1, NULL, 10); 
+  }
+
+  fclose(f);
+}
+
+void SaveConfig(void)
+{
+  int i;
+  FILE *f = fopen("clonekeen.cfg", "w");
+
+  if (!f)
+    return;
+
+  fprintf(f,
+    "# Do not change the order of the settings below, nor remove this line!\n");
+  
+  for (i = 1; i < NUM_OPTIONS; i++)
+    fprintf(f, "%s: %d\n", options[i].name, (int)options[i].value);
+
+  fclose(f);
+}
+
 int main(int argc, char **argv)
 {
   int i,c;
@@ -159,9 +201,10 @@ int main(int argc, char **argv)
 
   // set default config-menu options
   SetDefaultOptions();
-  setoption(OPT_FULLSCREEN, "SDL Fullscreen Mode", 0);
-  setoption(OPT_ZOOM, "Image Zoom", 1);
+  setoption(OPT_FULLSCREEN, "SDL Fullscreen Mode", 1);
+  setoption(OPT_ZOOM, "Image Zoom", 2);
   setoption(OPT_FRAMESKIP, "Frameskip", 2);
+  LoadConfig();
 
   /* process command line options */
   VidDrv_printf("Processing command-line options.\n");
@@ -414,6 +457,7 @@ directtomap: ;
 
 ok: ;
   cleanup();
+  SaveConfig();
   banner();
   VidDrv_printf("\nThanks for playing!\n\n");
   if (crashflag)


--- NEW FILE clonekeen.autodlrc ---
[MESSAGELIST]
[MESSAGE]
	[TITLE]Please click 'Accept' to allow internet access.[/TITLE]
	[TEXT]In order to play "Commander Keen: Invasion of the Vorticons", An Apogee Game, the original datafiles are needed.

Click Accept, to download the shareware version "Commander Keen: Marooned on Mars" (Episode 1), which can be freely downloaded from the internet.

If you posess the full version you can use that instead: Put the files from the full version in ~/.clonekeen/data and run clonekeen again.

Please click Accept to allow access to the internet to download the necessary datafiles.[/TEXT]
[/MESSAGE]
[MESSAGE]
	[TITLE]License Information[/TITLE]
	[TEXT]"Commander Keen: Marooned on Mars"
(Episode 1 of the "Invasion of the Vorticons Trilogy")

Copyright 1990 id Software
Licensed for Distribution by Apogee Software, Ltd.
P.O. Box 496389, Garland, TX 75049, TEL: 972-271-1765 ("Apogee")

BY COPYING, USING OR DISTRIBUTING THIS SHAREWARE PROGRAM, YOU INDICATE YOUR AGREEMENT TO THE TERMS OF THIS vendor.doc.

=====================
KEY POINTS
=====================

[*] Everyone can -- and is encouraged! -- to copy, upload and generally pass around this Program without charging for it.

[*] If you want to distribute it in a retail location (such as on a rack), or as part of a hardware or software bundle, or on CD-ROM you must get PRIOR signed written permission from Apogee.  Apogee reserves its right to withhold permission.

[*] If you want to distribute it as provided in this Vendor.doc by catalog, advertisement, BBS, on-line service, or direct mail, no written permission is needed.  Apogee highly recommends, however, that distribution be made from a copy from Apogee or from one of its authorized sources, such as our web site (http://www.apogee1.com) to prevent the sale of older versions.

[*] All advertising of the Program must include "Apogee" in the description.

[*] The Program is marked "Shareware" and contains "episode #1". No right is given by this Vendor.Doc to copy, use or distribute any other version, including any version that is registered, or not marked shareware, or that contains any episode other than #1.

======================
LICENSE
======================

[1] DEFINITIONS:  "Program" means Commander Keen and its related files, including this one.  The "Trademarks" consists of "Apogee", the Apogee "comet logo", and "Commander Keen".

[2] OWNERSHIP: Except to the extent expressly licensed, Apogee owns and reserves the exclusive right to distribute the Program, and to use the Trademarks in connection with it.  Its content, layout and format are the property of Apogee to the extent permitted by law.

[3] GRANT AND CONDITIONS:  Apogee grants a non-exclusive license to distribute the Program on IBM compatible media under the Trademarks subject to the following conditions:

 [A] CONDITIONS FOR ALL DISTRIBUTION

  [1] All of the Program's files, including this one, as released by us must be included without modification. The following files must always be included to constitute a legal version for shareware distribution:

      â–  egahead  ck1        15,568 01-23-90   1:31p
      â–  egalatch ck1        57,065 01-23-90   1:31p
      â–  egasprit ck1        17,633 01-23-90   1:31p
      â–  endtext  ck1           942 01-23-90   1:31p
      â–  finale   ck1         8,565 01-23-90   1:31p
      â–  helptext ck1         1,859 01-23-90   1:31p
      â–  keen1    exe        51,190 01-23-90   1:31p
      â–  level01  ck1         1,368 01-23-90   1:31p
      â–  level02  ck1           724 01-23-90   1:31p
      â–  level03  ck1         3,474 01-23-90   1:31p
      â–  level04  ck1         1,720 01-23-90   1:31p
      â–  level05  ck1           810 01-23-90   1:31p
      â–  level06  ck1           928 01-23-90   1:31p
      â–  level07  ck1         5,650 01-23-90   1:31p
      â–  level08  ck1         3,416 01-23-90   1:31p
      â–  level09  ck1         1,638 01-23-90   1:31p
      â–  level10  ck1         2,086 01-23-90   1:31p
      â–  level11  ck1         1,636 01-23-90   1:31p
      â–  level12  ck1         2,178 01-23-90   1:31p
      â–  level13  ck1         9,908 01-23-90   1:31p
      â–  level14  ck1         7,024 01-23-90   1:31p
      â–  level15  ck1         2,234 01-23-90   1:31p
      â–  level16  ck1         5,818 01-23-90   1:31p
      â–  level80  ck1         5,638 01-23-90   1:31p
      â–  level81  ck1           758 01-23-90   1:31p
      â–  level90  ck1         1,262 01-23-90   1:31p
      â–  preview2 ck1        27,886 01-23-90   1:31p
      â–  preview3 ck1        25,429 01-23-90   1:31p
      â–  previews ck1         2,160 01-23-90   1:31p
      â–  sounds   ck1         8,898 01-23-90   1:31p
      â–  storytxt ck1         3,504 01-23-90   1:31p

  [2] No copyright or trademark information may be removed.

  [3] You must not [a] distribute any version of the Program with unauthorized changes, such as additional or different levels, or changed characters or mazes; or [b] characterize such versions as an "add-on" or "extension" of any Apogee product; or [c] distribute any unauthorized third party utility designed to alter any Apogee game, game level, game episode or saved game.

 [B] ADDITIONAL CONDITIONS IF YOU CHARGE:  If your distribution involves a disk or other physical medium, you must also:

  [1] Clearly market the Program as shareware, which requires (among other things) using "try before you buy" or similar words on packaging for the Programs.

  [2] Include "Apogee" and the "comet" logo (we encourage use of the 4 color version) on the front cover of the package.

  [3] Include the your name, address and phone number on the packaging and in any added documentation.  This can be imprinted on the package or may be in the form of a label affixed to the box, carton or folder. 

  [4] Any description of the Program included in a re-sellers catalog, sales brochure, on special packaging or handouts, must include "An Apogee Game", "Released by Apogee" or "Published by Apogee" if the word count of the description is more than 14 words in length.

  [5] Distribute copies only after the programs on newly created master diskettes have been thoroughly tested.  Always use high quality media and duplication technology.

  [6] Try to sell only the most current version of the Program.

  [7] Although Apogee discourages the practice, you may add an installation routine if it does not interfere with the proper operation or installation of the Program.

  [8] Program updates, recommended descriptions and "screenshots" will be provided upon request, and are available in the re-seller / dealer conference of Apogee's main BBS.

 [C] ADDITIONAL CONDITIONS FOR BUNDLES, CD-ROMS, AND RACKS: If you wish to distribute in a retail location (such as on a rack), or as part of a hardware or software bundle, or on CD-ROM, you must get PRIOR signed written permission from Apogee, which is in Apogee's discretion and may be subject to royalty or other conditions.

[4] TERM:  Unless terminated for cause, your grants under this VENDOR.DOC terminate 30 days after you receive written notice, or such longer period as the notice may provide.  Following such termination, you may distribute the Program only until the earlier of 60 days after the termination date in the notice, or distribution of the copies you have in stock.  Sections [2], [5], and [6] survive termination.

[5] LIMITED WARRANTY AND LIMITATION OF REMEDIES: If Apogee provides a physically defective copy of the Program, Apogee will replace it upon submission of the defective one.  Aside from this, the Program IS PROVIDED "AS-IS", AND NO WARRANTIES OF ANY KIND (INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE), EXPRESS OR IMPLIED, ARE MADE AS TO IT OR ANY MEDIUM IT MAY BE ON.  OUR ENTIRE LIABILITY AND YOUR EXCLUSIVE REMEDY IS SUCH REPLACEMENT, AND UNDER NO CIRCUMSTANCES WILL WE PROVIDE ANY OTHER REMEDY FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, PUNITIVE, INCIDENTAL OR OTHER DAMAGES ARISING FROM IT, INCLUDING SUCH FROM NEGLIGENCE, STRICT LIABILITY, OR BREACH OF WARRANTY OR CONTRACT, EVEN AFTER NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.

[6] MISCELLANY

 [A] Since we would be irreparably damaged if Section [3], [4] or [6][D] were not specifically enforced, we will be entitled without bond, other security or proof of damages, to appropriate equitable remedies with respect to breaches of such sections, in addition to such other remedies as we may have.

 [B] You will hold us, our partners, contractors, employees and agents harmless from damage, loss and expense arising directly or indirectly from your acts and omissions in copying and distributing the Program, including from any installation routine that you may add.

 [C] With respect to every matter arising under this, you consent to the exclusive jurisdiction and venue of the state and federal courts sitting in Dallas, Texas, and to service by certified mail, return receipt requested, or as otherwise permitted by law.

 [D] You will not modify, reverse compile, disassemble, or reverse engineer the Program, or use or disclose any confidential information that it contains.

[V.07.15.94][/TEXT]
[/MESSAGE]
[/MESSAGELIST]

[FILELIST]
[FILE]
	[FILENAME]1keen.zip[/FILENAME]
	[MD5]7375d0452276388d52c35d0b3ad6ab82[/MD5]
	[PATH]$HOME/.clonekeen/data[/PATH]
	[MIRRORS]
		[URL]ftp://ftp.3drealms.com/share/1keen.zip[/URL]
	[/MIRRORS]
[/FILE]
[/FILELIST]


--- NEW FILE clonekeen.desktop ---
[Desktop Entry]
Name=CloneKeen
Comment=Clone of the classic Keen platform game, will automatically download the needed shareware data-files
Exec=clonekeen
Icon=clonekeen
StartupNotify=false
Terminal=false
Type=Application
Categories=Game;ActionGame;


--- NEW FILE clonekeen.sh ---
#!/bin/bash

set -e

if [ ! -d ~/.clonekeen ]; then
  mkdir ~/.clonekeen
  cp -p /usr/share/clonekeen/*.dat ~/.clonekeen
  cp -a /usr/share/clonekeen/data ~/.clonekeen
fi

if [ ! -f ~/.clonekeen/data/storytxt.ck1 ]; then
  set +e
  /usr/share/autodl/AutoDL.py /usr/share/clonekeen/clonekeen.autodlrc
  STATUS=$?
  set -e
  # status 2 means download was ok, but the user choose not to start the game
  if [ "$STATUS" = "0" -o  "$STATUS" = "2" ]; then
    cd ~/.clonekeen/data
    unzip -qq 1keen.zip CK1SW131.SHR
    /usr/libexec/clonekeen-extract CK1SW131.SHR > /dev/null
    rm 1keen.zip CK1SW131.SHR keen1.exe
  fi

  if [ "$STATUS" != "0" ]; then
    exit $STATUS
  fi
fi

if [ -f ~/.clonekeen/data/keen2.exe -a ! -f ~/.clonekeen/data/sounds.ck2 ]; then
  cd ~/.clonekeen/data
  /usr/libexec/clonekeen-extract-sounds keen2.exe > /dev/null
fi  

if [ -f ~/.clonekeen/data/keen3.exe -a ! -f ~/.clonekeen/data/sounds.ck3 ]; then
  cd ~/.clonekeen/data
  /usr/libexec/clonekeen-extract-sounds keen3.exe > /dev/null
fi  

cd ~/.clonekeen
exec /usr/libexec/clonekeen "$@"


--- NEW FILE clonekeen.spec ---
Name:           clonekeen
Version:        0.8.3
Release:        1%{?dist}
Summary:        "Commander Keen: Invasion of the Vorticons" clone
Group:          Amusements/Games
License:        GPLv2+
URL:            http://clonekeen.sourceforge.net/
Source0:        http://downloads.sourceforge.net/%{name}/CKBeta83_Src.zip
# This are the .dat files and the extra (GPL) levels from 
# http://downloads.sourceforge.net/%{name}/CKBeta83_Bin_W32.zip
# ep1attr.dat and ep3attr.dat are replaced with improved versions from
# http://jonathannielsen.com/mw/CloneKeen2X-1.0-src.zip
# The pristine upstream .zip's aren't used because the included sounds.ck?
# files are property of ID software
Source1:        %{name}-%{version}-data.tar.gz
Source2:        extract.c
Source3:        clonekeen-extract-sounds.c
Source4:        %{name}.sh
Source5:        %{name}.autodlrc
Source6:        %{name}.desktop
Source7:        %{name}.png
Patch0:         %{name}-fixes.patch
Patch1:         %{name}-clonekeen2x-fixes.patch
Patch2:         %{name}-options.patch
BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildRequires:  SDL_mixer-devel dynamite-devel desktop-file-utils
Requires:       hicolor-icon-theme autodownloader

%description
CloneKeen is an almost complete clone of the old classic DOS game,
Commander Keen: Invasion of the Vorticons by by ID Software.
CloneKeen requires the original gamedata files to work.

If you posess the original DOS games. You can play all three episodes of the
game. If you don't, you can can still play the shareware episode one. Which can
be freely downloaded from Apogee, but cannot be distributed as a part of
Fedora. When you start CloneKeen for the first time it will offer to download
the shareware datafiles for you.


%prep
%setup -q -a 1 -n keen
%patch0 -p1
%patch1 -p0
%patch2 -p1
cp -a %{SOURCE2} %{SOURCE3} .
rm src/scale2x/*.o
sed -i 's/\r//g' readme.txt src/changelog.txt


%build
make %{?_smp_mflags} -C src -f Makefile.lnx CFLAGS="$RPM_OPT_FLAGS"
gcc -o %{name}-extract $RPM_OPT_FLAGS extract.c -ldynamite
gcc -o %{name}-extract-sounds $RPM_OPT_FLAGS %{name}-extract-sounds.c


%install
rm -rf $RPM_BUILD_ROOT
mkdir -p $RPM_BUILD_ROOT%{_bindir}
mkdir -p $RPM_BUILD_ROOT%{_libexecdir}
mkdir -p $RPM_BUILD_ROOT%{_datadir}/%{name}/data

install -m 755 src/keen $RPM_BUILD_ROOT%{_libexecdir}/%{name}
install -m 755 %{name}-extract $RPM_BUILD_ROOT%{_libexecdir}
install -m 755 %{name}-extract-sounds $RPM_BUILD_ROOT%{_libexecdir}
install -p -m 755 %{SOURCE4} $RPM_BUILD_ROOT%{_bindir}/%{name}
install -p -m 644 %{SOURCE5} $RPM_BUILD_ROOT%{_datadir}/%{name}
install -p -m 644 bin/*.dat  $RPM_BUILD_ROOT%{_datadir}/%{name}
install -p -m 644 bin/data/* $RPM_BUILD_ROOT%{_datadir}/%{name}/data

# below is the desktop file and icon stuff.
mkdir -p $RPM_BUILD_ROOT%{_datadir}/applications
desktop-file-install --vendor fedora            \
  --dir $RPM_BUILD_ROOT%{_datadir}/applications \
  %{SOURCE6}

mkdir -p $RPM_BUILD_ROOT%{_datadir}/icons/hicolor/24x24/apps
install -p -m 644 %{SOURCE7} \
  $RPM_BUILD_ROOT%{_datadir}/icons/hicolor/24x24/apps


%clean
rm -rf $RPM_BUILD_ROOT


%post
touch --no-create %{_datadir}/icons/hicolor || :
if [ -x %{_bindir}/gtk-update-icon-cache ]; then
   %{_bindir}/gtk-update-icon-cache --quiet %{_datadir}/icons/hicolor || :
fi

%postun
touch --no-create %{_datadir}/icons/hicolor || :
if [ -x %{_bindir}/gtk-update-icon-cache ]; then
   %{_bindir}/gtk-update-icon-cache --quiet %{_datadir}/icons/hicolor || :
fi


%files
%defattr(-,root,root,-)
%doc readme.txt src/changelog.txt
%{_bindir}/%{name}
%{_libexecdir}/%{name}*
%{_datadir}/%{name}
%{_datadir}/applications/fedora-%{name}.desktop
%{_datadir}/icons/hicolor/24x24/apps/%{name}.png


%changelog
* Thu Oct 25 2007 Hans de Goede <j.w.r.degoede at hhs.nl> 0.8.3-1
- Initial Fedora package


--- NEW FILE extract.c ---
/* utility to extract the .SHR installer data files of early ID software
   shareware games
   
    Copyright (C) 2007 Hans de Goede  <j.w.r.degoede at hhs.nl>

    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>
#include <string.h>
#include <ctype.h>
#include <libdynamite.h>

struct cookie_s {
  char *in_buffer;
  int in_buffer_remaining;
  int in_buffer_index;
  int in_buffer_size;
  FILE* out_file;
};   

size_t reader(void* buffer, size_t size, void* cookie)
{
  struct cookie_s *c = cookie;
  if (size > c->in_buffer_remaining)
    size = c->in_buffer_remaining;
    
  memcpy (buffer, c->in_buffer + c->in_buffer_index, size);
  
  c->in_buffer_index += size;
  c->in_buffer_remaining -= size;
  
  return size;
}

size_t writer(void* buffer, size_t size, void* cookie)
{
  struct cookie_s *c = cookie;
  return fwrite(buffer, 1, size, c->out_file);
}

int main(int argc, char *argv[])
{
  struct cookie_s cookie;
  FILE *in_file;
  char filename[16];
  unsigned char buf[4];
  int i, compressed_size;
    
  if (argc != 2) {
    fprintf(stderr, "%s: Usage: %s <filename.CHR> %d\n", argv[0], argv[0], argc);
    return 1;
  }
  
  in_file = fopen(argv[1], "r");
  if (!in_file) {
    fprintf(stderr, "error opening: %s", argv[1]);
    perror(NULL);
    return 1;
  } 

  /* skip first 0x3A bytes header */
  if (fseek(in_file, 0x3A, SEEK_CUR)) {
    perror("error skipping initial file header");
    return 1;
  }
  
  cookie.in_buffer = malloc(65536);
  if (!cookie.in_buffer) {
    fprintf(stderr, "Error: out of memory\n");
    return 1;
  }
  cookie.in_buffer_size = 65536;
  
  while (1)
  {
    /* get the name of the file */
    if (fread(filename, 1, sizeof(filename), in_file) != sizeof(filename)) {
      if (feof(in_file)) {
        free(cookie.in_buffer);
        fclose(in_file);
        return 0; /* done */
      }
      perror("error getting output filename from file");
      return 1;
    }

    /* verify the filename and convert to lower case */
    for (i = 0 ; i < sizeof(filename); i++) {
      if (filename[i] == 0)
        break; /* done */
      if (!isprint(filename[i])) {
        fprintf(stderr, "error invalid output filename\n");
        return 1;
      }
      filename[i] = tolower(filename[i]);
    }
    if (i == sizeof(filename)) {
      fprintf(stderr, "error too long output filename\n");
      return 1;
    }
    
    /* seek to compressed size */
    if (fseek(in_file, 0x88 - sizeof(filename), SEEK_CUR)) {
      perror("error skipping file header before file size");
      return 1;
    }

    if (fread(buf, 1, 4, in_file) != 4) {
      perror("error reading file size");
      return 1;
    }
    compressed_size = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
    if (compressed_size > cookie.in_buffer_size) {
      cookie.in_buffer = realloc(cookie.in_buffer, compressed_size);
      if (!cookie.in_buffer) {
        fprintf(stderr, "Error: out of memory\n");
        return 1;
      }
      cookie.in_buffer_size = compressed_size;
    }

    /* seek to begin of compressed data */
    if (fseek(in_file, 0x1C, SEEK_CUR)) {
      perror("error skipping file header before file size");
      return 1;
    }
    
    /* read compressed data */
    if (fread(cookie.in_buffer, 1, compressed_size, in_file) !=
          compressed_size) {
      perror("error reading compressed data");
      return 1;
    }
    
    cookie.in_buffer_index = 0;
    cookie.in_buffer_remaining = compressed_size;
    
    cookie.out_file = fopen(filename, "w");
    if (!cookie.out_file) {
      fprintf(stderr, "Error creating: %s for writing", filename);
      perror(NULL);
      return 1;
    }

    printf("decompressing: %s, compressed size: %d\n", filename,
            compressed_size);
    
    if ((i = dynamite_explode(reader, writer, &cookie))) {
      fprintf(stderr, "Error: %d while decompressing\n", i);
      return i;
    }
    
    fclose(cookie.out_file);
  }
  
  /* never reached */
  return 0;
}


Index: .cvsignore
===================================================================
RCS file: /cvs/extras/rpms/clonekeen/F-8/.cvsignore,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- .cvsignore	4 Nov 2007 19:10:28 -0000	1.1
+++ .cvsignore	4 Nov 2007 20:18:17 -0000	1.2
@@ -0,0 +1,2 @@
+CKBeta83_Src.zip
+clonekeen-0.8.3-data.tar.gz


Index: sources
===================================================================
RCS file: /cvs/extras/rpms/clonekeen/F-8/sources,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- sources	4 Nov 2007 19:10:28 -0000	1.1
+++ sources	4 Nov 2007 20:18:17 -0000	1.2
@@ -0,0 +1,2 @@
+9aa11b4793bad38bde2eb45597adb54e  CKBeta83_Src.zip
+76b38e7819d8bc90399789acfbc5a5dc  clonekeen-0.8.3-data.tar.gz




More information about the fedora-extras-commits mailing list