Logo Search packages:      
Sourcecode: helpdeco version File versions  Download package

splitmrb.c

/*
helpdeco -- utility program to dissect Windows help files
Copyright (C) 1996 Manfred Winterhoff
Copyright (C) 2001 Ben Collver

This file is part of helpdeco; 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
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 or visit:
http://www.gnu.org
*/

/*
SPLITMRB - splits MRB into SHG/BMP/WMF and SHG into BMP/WMF files - Version 1.5
M.Winterhoff <mawin@gmx.net>, Geschw.-Scholl-Ring 17, 38444 Wolfsburg, Germany

usage: SPLITMRB filename[.mrb] ...
       SPLITMRB filename.shg ...

Output files are created in the current directory using resolution-dependent
extensions *.EGA,*.VGA,*.CGA,*.854,*.MAC or *.BMP,*.WMF or *.Snn,*.nnn (where
n is a digit from 0 to 9). Discarded hotspot info will be written to stdout.
*/
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <limits.h>

typedef enum {FALSE,TRUE} BOOL;

typedef struct tagBITMAPFILEHEADER
{
    unsigned short bfType;
    unsigned long bfSize;
    unsigned short bfReserved1;
    unsigned short bfReserved2;
    unsigned long bfOffBits;
}
BITMAPFILEHEADER;

typedef struct tagBITMAPINFOHEADER
{
    unsigned long biSize;
    long biWidth;
    long biHeight;
    unsigned short biPlanes;
    unsigned short biBitCount;
    unsigned long biCompression;
    unsigned long biSizeImage;
    long biXPelsPerMeter;
    long biYPelsPerMeter;
    unsigned long biClrUsed;
    unsigned long biClrImportant;
}
BITMAPINFOHEADER;

typedef struct tagRECT
{
    short left;
    short top;
    short right;
    short bottom;
}
RECT;

typedef struct tagAPMFILEHEADER
{
    unsigned long dwKey;
    unsigned short hMF;
    RECT rcBBox;
    unsigned short wInch;
    unsigned long dwReserved;
    unsigned short wChecksum;
}
APMFILEHEADER;

unsigned short GetCWord(FILE *f)
{
    unsigned char b;

    b=getc(f);
    if(b&1) return (((unsigned short)getc(f)<<8)|(unsigned short)b)>>1;
    return ((unsigned short)b>>1);
}

unsigned long GetCDWord(FILE *f)
{
    unsigned short w;

    w = getw(f);
    if(w&1) return (((unsigned long)getw(f)<<16)|(unsigned long)w)>>1;
    return ((unsigned long)w>>1);
}

unsigned long GetDWord(FILE *f)
{
    unsigned short w;

    w=getw(f);
    return ((unsigned long)getw(f)<<16)|(unsigned long)w;
}

long copy(FILE *f,long bytes,FILE *out)
{
    long length;
    int size;
    static char buffer[1024];

    for(length=0;length<bytes;length+=size)
    {
      size=(int)(bytes-length>sizeof(buffer)?sizeof(buffer):bytes-length);
      fread(buffer,1,size,f);
      fwrite(buffer,size,1,out);
    }
    return length;
}

signed char count; /* for run len decompression */

int derun(int c,FILE *f) /* expand runlen compressed data */
{
    int i;

    if(count&0x7F)
    {
      if(count&0x80)
      {
          putc(c,f);
          count--;
          return 1;
      }
      for(i=0;i<count;i++)
      {
          putc(c,f);
      }
      count=0;
      return i;
    }
    count=(signed char)c;
    return 0;
}

long decompress(int method,FILE *f,long bytes,FILE *fTarget)
{
    static unsigned char lzbuffer[0x1000];
    int (*Emit)(int c,FILE *f);
    unsigned char bits,mask;
    int pos,len,back;
    long n;

    n=0;
    if(method&1)
    {
      Emit=derun;
      count=0;
    }
    else
    {
      Emit=fputc;
    }
    if(method&2)
    {
      mask=0;
      pos=0;
      while(bytes-->0L)
      {
          if(!mask)
          {
            bits=getc(f);
            mask=1;
          }
          else
          {
            if(bits&mask)
            {
                if(bytes--==0) break;
                back=getw(f);
                len=((back>>12)&15)+3;
                back=pos-(back&0xFFF)-1;
                while(len-->0)
                {
                  n+=Emit(lzbuffer[pos++&0xFFF]=lzbuffer[back++&0xFFF],fTarget);
                }
            }
            else
            {
                n+=Emit(lzbuffer[pos++&0xFFF]=getc(f),fTarget);
            }
            mask<<=1;
          }
      }
    }
    else
    {
      while(bytes-->0L) n+=Emit(getc(f),fTarget);
    }
    return n;
}

int GetPackedByte(FILE *f) // RulLen decompression
{
    static unsigned char count,value;

    if(!f) // initialize
    {
      count=value=0;
    }
    else
    {
      if((count&0x7F)==0)
      {
          count=getc(f);
          value=getc(f);
      }
      else if(count&0x80)
      {
          value=getc(f);
      }
      count--;
    }
    return value;
}

#if defined(__GNUC__) && __GNUC__ >= 3
#pragma pack (push, 1)
#endif
typedef struct
{
  u_int8_t c1,c2,c3;
  u_int16_t x,y,w,h;
  u_int32_t hash;
} HOTSPOT
#if defined(__GNUC__) && __GNUC__ < 3
__attribute__((packed))
#endif
     ;
#if defined(__GNUC__) && __GNUC__ >= 3
#pragma pack (pop)
#endif

void PrintHotspotInfo(FILE *f)
{
    int i,l,n;
    HOTSPOT *hotspot;
    char name[80];
    char buffer[128];

    if(getc(f)==1)
    {
      n=getw(f);
      if(n>0)
      {
          hotspot=malloc(n*sizeof(HOTSPOT));
          if(hotspot)
          {
            l=getw(f); // macro data size
            getw(f);   // hiword ignored
            fread(hotspot,sizeof(HOTSPOT),n,f);
            for(i=0;i<l;i++) getc(f);
            for(i=0;i<n;i++)
            {
                for(l=0;l<sizeof(name)&&(name[l]=getc(f))!='\0';l++);
                for(l=0;l<sizeof(buffer)&&(buffer[l]=getc(f))!='\0';l++);
                printf("'%s' ",buffer);
                if((hotspot[i].c1&0xF0)==0xC0)
                {
                  printf("Macro ");
                }
                else if(hotspot[i].c1&1)
                {
                  printf("Jump ");
                }
                else
                {
                  printf("Pop-up ");
                }
                if(hotspot[i].c2)
                {
                  printf("Invisible");
                }
                else
                {
                  printf("Visible ");
                }
                printf(" '%s' %d,%d,%d,%d\n",name,hotspot[i].x,hotspot[i].y,hotspot[i].x+hotspot[i].w,hotspot[i].y+hotspot[i].h);
            }
            free(hotspot);
          }
      }
    }
}

int main(int argc,char *argv[])
{
    FILE *f;
    FILE *fTarget;
    int i,j,k,l,m,n,colors;
    unsigned char byType,byPacked;
    long dwDataSize,dwHotspotOffset,dwHotspotSize,w,h,offset;
    BITMAPFILEHEADER bmfh;
    BITMAPINFOHEADER bmih;
    APMFILEHEADER afh;
    char filename[PATH_MAX];
    BOOL res[7];

    assert(sizeof(HOTSPOT)==15);

    if(argc<2)
    {
      fprintf(stderr,"SPLITMRB - splits MRB into SHG/BMP/WMF and SHG into BMP/WMF files - Version 1.5\n"
                   "M.Winterhoff <mawin@gmx.net>, Geschw.-Scholl-Ring 17, 38444 Wolfsburg, Germany\n"
                   "\n"
                   "usage: SPLITMRB filename[.mrb] ...\n"
                   "       SPLITMRB filename.shg ...\n"
                   "\n"
                   "Output files are created in the current directory using resolution-dependent\n"
                   "extensions *.EGA,*.VGA,*.CGA,*.854,*.MAC or *.BMP,*.WMF or *.Snn,*.nnn (where\n"
                   "n is a digit from 0 to 9). Discarded hotspot info will be written to stdout.\n"
                   "\n");
    }
    else for(i=1;i<argc;i++)
    {
      strcpy(filename,argv[i]);
      l=strlen(filename);
      while(l>0&&filename[l-1]!='\\'&&filename[l-1]!='/'&&filename[l-1]!=':') l--;
      m=l;
      while(filename[l]!='\0'&&filename[l]!='.') l++;
      if(filename[l]=='\0') strcpy(filename+l,".mrb");
      f=fopen(filename,"rb");
      if(!f)
      {
          fprintf(stderr,"Can not open '%s'\n",filename);
      }
      else
      {
          if((getw(f)&0xDFFF)!=0x506C)
          {
            fprintf(stderr,"'%s' is no MRB/SHG bitmap\n",argv[i]);
          }
          else
          {
            n=getw(f);
            res[0]=res[1]=res[2]=res[3]=res[4]=res[5]=res[6]=FALSE;
            for(j=0;j<n;j++)
            {
                fseek(f,4*(j+1),SEEK_SET);
                fread(&offset,sizeof(offset),1,f);
                fseek(f,offset,SEEK_SET);
                byType=getc(f); // type of picture: 5=DDB, 6=DIB, 8=METAFILE
                byPacked=getc(f); // packing method: 0=unpacked, 1=RunLen, 2=LZ77
                if(byType==6||(byType==5&&byPacked<2))
                {
                  memset(&bmfh,0,sizeof(bmfh));
                  memset(&bmih,0,sizeof(bmih));
                  bmfh.bfType=0x4D42; // bitmap magic ("BM")
                  bmih.biSize=sizeof(bmih);
                  w=GetCDWord(f);
                  bmih.biXPelsPerMeter=(w*79L+1)/2;
                  h=GetCDWord(f);
                  bmih.biYPelsPerMeter=(h*79L+1)/2;
                  bmih.biPlanes=GetCWord(f);
                  bmih.biBitCount=GetCWord(f);
                  bmih.biWidth=GetCDWord(f);
                  bmih.biHeight=GetCDWord(f);
                  colors=(int)(bmih.biClrUsed=GetCDWord(f));
                  if(!colors) colors=1<<bmih.biBitCount;
                  bmih.biClrImportant=GetCDWord(f);
                  dwDataSize=GetCDWord(f);
                  dwHotspotSize=GetCDWord(f);
                  GetDWord(f); // dwPictureOffset
                  dwHotspotOffset=GetDWord(f);
                  if(dwHotspotOffset&&n>1) // dwHotspotOffset
                  {
                      // save as SHG
                      sprintf(filename+l,".S%02d",j);
                      fTarget=fopen(filename+m,"wb");
                      if(fTarget)
                      {
                        fprintf(stderr,"Extracting Segmented Hotspot Graphic '%s'...\n",filename+m);
                        putw(0x506C,fTarget);
                        putw(1,fTarget);
                        putw(8,fTarget);
                        putw(0,fTarget);
                        fseek(f,offset,SEEK_SET);
                        copy(f,dwHotspotOffset+dwHotspotSize,fTarget);
                        fclose(fTarget);
                      }
                      else
                      {
                        fprintf(stderr,"Can not create '%s'\n",filename+m);
                      }
                  }
                  else
                  {
                      sprintf(filename+l,".%03d",j);
                      if(w==96&&h==48&&!res[0])
                      {
                        strcpy(filename+l,".cga");
                        res[0]=TRUE;
                      }
                      else if(w==96&&h==72&&!res[1])
                      {
                        strcpy(filename+l,".ega");
                        res[1]=TRUE;
                      }
                      else if(w==96&&h==96&&!res[2])
                      {
                        strcpy(filename+l,".vga");
                        res[2]=TRUE;
                      }
                      else if(w==120&&h==120&&!res[3])
                      {
                        strcpy(filename+l,".854");
                        res[3]=TRUE;
                      }
                      else if(w==72&&h==72&&!res[4])
                      {
                        strcpy(filename+l,".mac");
                        res[4]=TRUE;
                      }
                      else if(!res[6])
                      {
                        strcpy(filename+l,".bmp");
                        res[6]=TRUE;
                      }
                      fTarget=fopen(filename+m,"wb");
                      if(fTarget)
                      {
                        fprintf(stderr,"Extracting %ld x %ld x %u Bitmap '%s' (%ldx%ld dpi)...\n",bmih.biWidth,bmih.biHeight,bmih.biPlanes*bmih.biBitCount,filename+m,w,h);
                        fwrite(&bmfh,1,sizeof(bmfh),fTarget);
                        fwrite(&bmih,1,sizeof(bmih),fTarget);
                        if(byType==6)
                        {
                            copy(f,colors*4L,fTarget);
                        }
                        else
                        {
                            long l;

                            l=0x000000L;
                            fwrite(&l,1,sizeof(l),fTarget);
                            l=0xFFFFFFL;
                            fwrite(&l,1,sizeof(l),fTarget);
                        }
                        bmfh.bfOffBits=sizeof(bmfh)+sizeof(bmih)+colors*4L;
                        bmih.biSizeImage=(((bmih.biWidth*bmih.biBitCount+31)/32)*4)*bmih.biHeight;
                        if(byType==5) // convert 3.0 DDB to 3.1 DIB
                        {
                            long width,length,l;
                            int pad;

                            width=((bmih.biWidth*bmih.biBitCount+15)/16)*2;
                            pad=(int)(((width+3)/4)*4-width);
                            GetPackedByte(NULL);
                            for(l=0;l<bmih.biHeight;l++)
                            {
                              if(byPacked==1)
                              {
                                  for(length=0;length<width;length++) putc(GetPackedByte(f),fTarget);
                              }
                              else
                              {
                                  copy(f,width,fTarget);
                              }
                              if(pad) fwrite("    ",pad,1,fTarget);
                            }
                        }
                        else
                        {
                            decompress(byPacked,f,dwDataSize,fTarget);
                        }
                        // update bitmap headers
                        bmfh.bfSize=ftell(fTarget);
                        fseek(fTarget,0L,SEEK_SET);
                        fwrite(&bmfh,1,sizeof(bmfh),fTarget);
                        fwrite(&bmih,1,sizeof(bmih),fTarget);
                        fclose(fTarget);
                        if(dwHotspotOffset)
                        {
                            fseek(f,offset+dwHotspotOffset,SEEK_SET);
                            PrintHotspotInfo(f);
                        }
                      }
                      else
                      {
                        fprintf(stderr,"Can not create '%s'\n",filename+m);
                      }
                  }
                }
                else if(byType==8) // Windows MetaFile
                {
                  unsigned short *wp;

                  memset(&afh,0,sizeof(afh));
                  afh.dwKey=0x9AC6CDD7L;
                  GetCWord(f); // mapping mode
                  afh.rcBBox.right=getw(f); // width of metafile-picture
                  afh.rcBBox.bottom=getw(f); // height of metafile-picture
                  GetCDWord(f);
                  dwDataSize=GetCDWord(f);
                  dwHotspotSize=GetCDWord(f); // dwHotspotSize
                  GetDWord(f); // dwPictureOffset
                  dwHotspotOffset=GetDWord(f);
                  if(dwHotspotOffset&&n>1) // dwHotspotOffset
                  {
                      sprintf(filename+l,".S%02d",j);
                      fTarget=fopen(filename+m,"wb");
                      if(fTarget)
                      {
                        fprintf(stderr,"Extracting Segmented Hotspot Graphic '%s'...\n",filename+m);
                        putw(0x506C,fTarget);
                        putw(1,fTarget);
                        putw(8,fTarget);
                        putw(0,fTarget);
                        fseek(f,offset,SEEK_SET);
                        copy(f,dwHotspotOffset+dwHotspotSize,fTarget);
                        fclose(fTarget);
                      }
                      else
                      {
                        fprintf(stderr,"Can not create '%s'\n",filename+m);
                      }
                  }
                  else
                  {
                      afh.wInch=2540;
                      wp=(unsigned short *)&afh;
                      for(k=0;k<10;k++) afh.wChecksum^=*wp++;
                      if(!res[5])
                      {
                        strcpy(filename+l,".wmf");
                        res[5]=TRUE;
                      }
                      else
                      {
                        sprintf(filename+l,".%03d",j);
                      }
                      fTarget=fopen(filename+m,"wb");
                      if(fTarget)
                      {
                        fprintf(stderr,"Extracting Metafile '%s'...\n",filename+m);
                        fwrite(&afh,1,sizeof(afh),fTarget);
                        decompress(byPacked,f,dwDataSize,fTarget);
                        fclose(fTarget);
                      }
                      if(dwHotspotOffset)
                      {
                        fseek(f,offset+dwHotspotOffset,SEEK_SET);
                        PrintHotspotInfo(f);
                      }
                  }
                }
                else
                {
                  fprintf(stderr,"Picture %d of '%s' unknown type %02x pack=%02x skipped.\n",j,argv[i],byType,byPacked);
                }
            }
          }
          fclose(f);
      }
    }
    return 0;
}

Generated by  Doxygen 1.6.0   Back to index