HGLOBAL stos_pp(char *fileName, char *errorText, char *compressionText)
{
   /*
   ** STOS pp, Packed screen without MBK header
   */
   FILE* f;
   picsize_t len;
   byte *file;
   HGLOBAL h=NULL;
   file=malloc(40000L);
   if(file==NULL)
   {
      sprintf(errorText, "Out of memory.");
      return h;
   }
   f=fopen(fileName, "rb");
   if(f==NULL)
   {
      sprintf(errorText, "Can not open file!");
   }
   else
   {
      len=packed_fread(file, 40000L, f);
      if(get_long(file)!=STOS_HD)
      {
         sprintf(errorText, "This is not valid PP file!");
      }
      else
      {
         /* patch resolution into the file, as all are set to medium */
         byte res=fileName[strlen(fileName)-1]-'1';
         h=stos_compressed(file, len, errorText, compressionText, res);
      }
      fclose(f);
   }
   free(file);
   return h;
}

HGLOBAL stos_compressed(byte* file, picsize_t size, char *errorText, char *compressionText, int forceres)
{ /* compressed picture */
   /* forceres: use this to force a different resolution, else: -1 */
   HGLOBAL h=NULL;
   if(get_long(file)!=STOS_HD)
   {
      sprintf(errorText, "This is not valid STOS compressed screen!");
   }
   else
   {
      byte* screen;
      screen=malloc(32000);
      if(screen==NULL)
      {
         sprintf(errorText, "Out of memory!");
         return h;
      }
      else
      {
         stcolor_t colors[16];
         unsigned int res;
         dword literal;
         dword pointer0;
         dword pointer1;
         word bytes_per_line_tab[]={160, 160, 80};
         word bytes_per_plane_tab[]={8, 4, 2};
         word planes_tab[]={4, 2, 1};
         word lines_tab[]={200, 200, 400};
         coord_t line_size;
         coord_t plane_size;
         coord_t planes;
         coord_t y_size;
         coord_t x_res;
         coord_t blocks;
         coord_t block_size;
         coord_t block_line;
         byte byte1;
         byte cmd0;
         byte cmd1;
         byte mask0;
         byte mask1;
         word plane_offset=0;
         memset(screen, 0, 32000); /* clear screen */
         res=get_word(file+4);
         if(res>2)
         {
            sprintf(errorText, "This is not valid STOS compressed screen!");
            free(screen);
            return h;
         }
         line_size=bytes_per_line_tab[res];
         plane_size=bytes_per_plane_tab[res];
         planes=planes_tab[res];
         y_size=lines_tab[res];
         x_res=get_word(file+10);
         if(((x_res*plane_size)>line_size) || (x_res==0))
         {
            sprintf(errorText, "This is not valid STOS compressed screen!");
            free(screen);
            return h;
         }
         blocks=get_word(file+12);
         block_size=get_word(file+16);
         if(((blocks*block_size)>y_size) || ((blocks*block_size)==0))
         {
            sprintf(errorText, "This is not valid STOS compressed screen!");
            free(screen);
            return h;
         }
         block_line=block_size*line_size;
         literal=70;
         pointer0=get_long(file+20);
         pointer1=get_long(file+24);
         if((literal>size) || (pointer0>size) || (pointer1>size))
         {
            sprintf(errorText, "STOS decompression error!");
            free(screen);
            return h;
         }
         get_colors(file+38, colors, 16);
         mask0=0x80;
         mask1=0x80;
         byte1=file[literal++];
         cmd0=file[pointer0++];
         cmd1=file[pointer1++];
         if(mask1&cmd1)
         {
            cmd0=file[pointer0++];
         }
         mask1>>=1;
         do
         {
            coord_t block_line_offset=plane_offset;
            coord_t j=blocks;
            do
            {
               coord_t line_offset=block_line_offset;
               coord_t k=x_res;
               do
               {
                  int m;
                  for(m=0; m<2; m++)
                  {
                     coord_t line=line_offset+m;
                     coord_t l=block_size;
                     do
                     {
                        if(mask0&cmd0)
                        {
                           byte1=file[literal++];
                        }
                        if(line>32000)
                        {
                           sprintf(errorText, "STOS decompression error!");
                           free(screen);
                           return h;
                        }
                        screen[line]=byte1;
                        line+=line_size;
                        mask0>>=1;
                        if(mask0==0)
                        {
                           mask0=0x80;
                           if(mask1&cmd1)
                           {
                              cmd0=file[pointer0++];
                           }
                           mask1>>=1;
                           if(mask1==0)
                           {
                              mask1=0x80;
                              cmd1=file[pointer1++];
                              if((literal>size) || (pointer0>size) || (pointer1>size))
                              {
                                 sprintf(errorText, "STOS decompression error!");
                                 free(screen);
                                 return h;
                              }
                           }
                        }
                     }
                     while(--l);
                  }
                  line_offset+=plane_size;
               }
               while(--k);
               block_line_offset+=block_line;
            }
            while(--j);
            plane_offset+=2;
         }
         while(--planes);
         if(forceres>=0)
         {
            res=forceres;
         }
         if(res==0)
         {
            h=convert_4bit(320, 200, screen, colors, NULL);
            sprintf(compressionText, "STOS compressed screen");
         }
         else if(res==1)
         {
            h=convert_2bit(640, 200, screen, colors, NULL);
            sprintf(compressionText, "STOS compressed screen");
         }
         else if(res==2)
         {
            h=convert_1bit(640, 400, screen, colors, NULL);
            sprintf(compressionText, "STOS compressed screen");
         }
         else
         {
            sprintf(errorText, "This is not valid STOS compressed screen!");
         }
         free(screen);
      }
   }
   return h;
}

void get_colors(const void *p, stcolor_t *colors, int cnt)
{
   int i;
   const byte* q=p;
   for(i=0;i<cnt;i++)
   {
      colors[i]=get_word(q+2*i);
   }
}