Windows programming

Moderators: None (Apply to moderate this forum)
Number of threads: 3711
Number of posts: 9173

This Forum Only
Post New Thread
Single Post View       Linear View       Threaded View      f

Report
Obtaining File Sizes... Posted by Sephiroth on 6 Nov 2003 at 10:15 PM
I nee dto obtain the size of a number of files, in bytes. I have been trying to use "GetFileSize()", but it always returns -1. The file does exist and is opened using "fopen()", but for some reason, it won't give me the size! Isn't there an easier more standard function call I can make that works? I seem to remember one or two in DOS C/C++ that returned (I think) a "double" variable. If they work in XP I can use them. Thanks for the info.

-Sephiroth
Report
Re: Obtaining File Sizes... Posted by velius on 7 Nov 2003 at 3:42 AM
The GetFileSize() function needs a handle to the file. fopen() does not return a handle to the file. You need to use CreateFile() to obtain a handle to each file.


Oh my god
I can't deny this
I've been taught just to kill and fight this
To bury it deeper where nobody can find it
Like nobody wanted to know
-- Oh My God - Guns N' Roses

Report
Re: Obtaining File Sizes... Posted by pingpong on 7 Nov 2003 at 5:33 AM
in standard C, you do this:
unsigned long get_file_size(const char* filename)
{
   FILE* fp;
   unsigned long size;

   // open the file
   fp = fopen(filename, "rb");
   if(fp != NULL)
   {
      // seek to the end
      fseek(fp, SEEK_END, 0);
      // get the current position (this is the length of the file)
      size = ftell(fp);
      fclose(fp);
   }
   else
      size = (unsigned long)-1;  // error

   return size;
}

If you already have a FILE* to the file, use this instead:
unsigned long get_file_size_from_handle(FILE* fp)
{
   unsigned long current;
   unsigned long size;

   // save current position
   current = ftell(fp);
   // seek to the end
   fseek(fp, SEEK_END, 0);
   // get the current position (this is the length of the file)
   size = ftell(fp);
   // go back to original position
   fseek(fp, SEEK_SET, current);

   return size;
}

Course, this is C, files that are larger than 4G in size will not work. In Windows, you can use the FindFirstFile API to get the size. First version ignores >4G files:
unsigned long get_file_size(const char* filename)
{
   WIN32_FIND_DATA wfd;
   HANDLE hFind;
   unsigned long size;

   hFind = FindFirstFile(filename, &wfd);
   if(hFind != INVALID_HANDLE_VALUE)
   {
      size = wfd.nFileSizeLow;
      FindClose(hFind);
   }
   else
      size = (unsigned long)-1;

   return size;
}

Next version gets any file size, dont know if you need it and up to you to figure out what to do with the 2 dwords:
bool get_file_size(const char* filename, unsigned long* low, unsigned long* high)
{
   WIN32_FIND_DATA wfd;
   HANDLE hFind;
   bool ret;

   hFind = FindFirstFile(filename, &wfd);
   if(hFind != INVALID_HANDLE_VALUE)
   {
      *low = wfd.nFileSizeLow;
      *high = wfd.nFileSizeHigh;
      FindClose(hFind);
      ret = true;
   }
   else
      ret = false;

   return ret;
}


Report
Re: Obtaining File Sizes... Posted by Sephiroth on 7 Nov 2003 at 7:57 AM
The "fseek" method will work just fine. Thanks, I couldn't remember the way I used to do it to save my life. The files are WAY less than 4gb, so I should be good. And I chose not to use the Win32 API for this in case an X-Win port is ever made. Easier to port fopen() and fseek() than Win32 stuff!

-Sephiroth

Report
Re: Obtaining File Sizes... Posted by Sephiroth on 7 Nov 2003 at 8:15 AM
Actually, ftell() sets my variable to "2". The size of the file in explorer is 25 or 26kb, I forget which. I am thinking that since the cursor location is at "SEEK_END", it's returning the define for that location, which is 2 if I remember correctly. I know there is SEEK_SET and one other.

-Sephiroth

Report
Re: Obtaining File Sizes... Posted by pingpong on 7 Nov 2003 at 9:44 AM
: Actually, ftell() sets my variable to "2". The size of the file in explorer is 25 or 26kb, I forget which. I am thinking that since the cursor location is at "SEEK_END", it's returning the define for that location, which is 2 if I remember correctly. I know there is SEEK_SET and one other.
:

I think explorer shows the file size rounded up to the cluster size of the hard disk. So, even if your file is 1 byte long, it will physically take cluster-size KB in the HD.

Right click the file and do properties, one of the fields should show the exact size in bytes.
Report
Re: Obtaining File Sizes... Posted by pingpong on 7 Nov 2003 at 12:10 PM
This is funny.

I was working on some project at work and I needed to load a file to memory, proceeded with the fopen/fseek/ftell/fclose stuff and what do you know... The size reported back is 2!!!! It looked familiar :)

Course, in both codes I was passing the parameters to fseek in the wrong order, so change fseek(fp, SEEK_XXX, x) to fseek(fp, x, SEEK_XXX).

Thats what you get when you work with C
Report
Re: Obtaining File Sizes... Posted by Sephiroth on 7 Nov 2003 at 11:09 PM
Yeah I figured it out this morning. I opened Wordpad and loaded the source, and it screamed at me. Swapped the parms and it worked fine. And I know explorer rounds. Just have a file-format problem that maybe you can explain.

I am trying to convert Daggerfall IMG files to 24bit bitmaps. The IMG file format is easy enough and consists of a header followed by a linear bitmap. However the bitmap references a palette of RGB data. I know the 24bit bitmap format is BGR, but it isn't comming out right. I want you to see my code and make sure I am going from RGB to BGR properly, or if it's something else. If my bitmap code is correct, then I can concentrate on the old format.
bool ConvertIMG(char *FileName)
  {
  //About 200 lines from start to here, but left out
  //because they deal with reading the old IMG file

  BMFH.bfType = 0x4d42;
  BMFH.bfSize = ((sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)) + (((sizeof(char) * IMGHeader.Width) * IMGHeader.Height) * 3));
  BMFH.bfReserved1 = 0;
  BMFH.bfReserved2 = 0;
  BMFH.bfOffBits = (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER));

  BMIH.biSize = sizeof(BITMAPINFOHEADER);
  BMIH.biWidth = IMGHeader.Width;
  BMIH.biHeight = -IMGHeader.Height;
  BMIH.biPlanes = 1;
  BMIH.biBitCount = 24;
  BMIH.biCompression = BI_RGB;
  BMIH.biSizeImage = 0;
  BMIH.biXPelsPerMeter = IMGHeader.Width;
  BMIH.biYPelsPerMeter = IMGHeader.Height;
  BMIH.biClrUsed = 0;
  BMIH.biClrImportant = 0;

  fwrite(&BMFH, sizeof(BITMAPFILEHEADER), 1, pImageFile);
  fwrite(&BMIH, sizeof(BITMAPINFOHEADER), 1, pImageFile);
  for(int Loop = 0; Loop < (IMGHeader.Width * IMGHeader.Height); Loop++)
    {
    fwrite(&(IMGHeader.Palette[pImage[Loop] + 2]), sizeof(char), 1, pImageFile);
    fwrite(&(IMGHeader.Palette[pImage[Loop] + 1]), sizeof(char), 1, pImageFile);
    fwrite(&(IMGHeader.Palette[pImage[Loop]]), sizeof(char), 1, pImageFile);
    }

  fclose(pImageFile);
  return true;
  }

OK, IMGHeader.Palette is a "char[768]". That is a 256-color palette of RGB data in that order. The pImage is a pointer to a "char" array that was dynamically created with enough storage for the linear bitmap data. The bitmap data ranges 0-255 and references an RGB triplet in the palette. Does it look like I setup the two bitmap headers properly? I know I'm putting the RGB data into the new file as BGR, as you can see, but it isn't comming out right. If the bitmap is good, then I can concentrate on finding the right palette. Daggerfall uses like ten different palette-files, of which four are 768b in size and just contain an array of 256 RGB triplets. The others have an 8bit header, then the 256 RGB triplets.

And on a final note, Daggerfall is a 16bit DOS game, so the files are byte-aligned. I read in the data like this:
//This would read int he first four header vars
short int XOffset, YOffset;
short int Width, Height;
...
fread(&XOffset, sizeof(char[2]), 1, File);
fread(&YOffset, sizeof(char[2]), 1, File);
fread(&Width, sizeof(char[2]), 1, File);
fread(&Height, sizeof(char[2]), 1, File);

Those variables are "short" in DOS, which are 2bytes in size. I assume this is the correct way to read them in. After all, the image comes out nearly-perfect, but off-color. Thanks for the help!

-Sephiroth

Report
Re: Obtaining File Sizes... Posted by Sephiroth on 8 Nov 2003 at 3:44 AM
:     fwrite(&(IMGHeader.Palette[pImage[Loop] + 2]), sizeof(char), 1, pImageFile);
:     fwrite(&(IMGHeader.Palette[pImage[Loop] + 1]), sizeof(char), 1, pImageFile);
:     fwrite(&(IMGHeader.Palette[pImage[Loop]]), sizeof(char), 1, pImageFile);

That was the color problem. The lines shoulda' been this.
    fwrite(&(IMGHeader.Palette[(pImage[Loop] * 3) + 2]), sizeof(char), 1, pImageFile);
    fwrite(&(IMGHeader.Palette[(pImage[Loop] * 3) + 1]), sizeof(char), 1, pImageFile);
    fwrite(&(IMGHeader.Palette[pImage[Loop] * 3]), sizeof(char), 1, pImageFile);

But the image comes out slanted. The first line or two is fine, then it slants. Do I have to pad the bitmap data somehow? I thought I read something about that somewhere.

-Sephiroth

Report
Re: Obtaining File Sizes... Posted by pingpong on 8 Nov 2003 at 1:14 PM
Yup, BMP scan lines are padded to 32-bit boundaries.

this is a function to calculate the bytes/line:
int GetBytesPerLine(int width, int bitsPerPixel)
{
   return ((width * bitsPerPixel + 31) >> 5) << 2;
}

Dont ask!

Now, you might change your code to be liks this:
// get the size of a scanline
int bytesPerLine = GetBytesPerLine(BMIH.biWidth, BMIH.biBitCount);
// get number of extra bytes we need to pad with (*3 since its BGR)
int extra = bytesPerLine - width * 3;

for(int y = 0; y < IMGHeader.Height; y++)
{
   for(int x = 0; x < IMGHeader.Width; x++)
   {
      // write one line as usual
      fwrite(&(IMGHeader.Palette[(pImage[x + y * IMGHeader.Height] * 3) + 2]), sizeof(char), 1, pImageFile);
      fwrite(&(IMGHeader.Palette[(pImage[x + y * IMGHeader.Height] * 3) + 1]), sizeof(char), 1, pImageFile);
      fwrite(&(IMGHeader.Palette[pImage[x + y * IMGHeader.Height] * 3]), sizeof(char), 1, pImageFile);
   }

   // pad
   for(int pad = 0; pad < extra; pad++)
   {
      char dummy = 0;
      fwrite(&dummy, sizeof(char), 1, pImageFile);
   }
}

I havent tested the code but you should get the idea
Report
Re: Obtaining File Sizes... Posted by Sephiroth on 8 Nov 2003 at 1:54 PM
That fixed the color problem. It now displays the proper color, partially. The image is now twisted and it looks like the RGB data isn't right somehow. I'll post the code, but here's a link tot he image to see what I mean.

http://dhta.oesm.org/sephiroth/WOLF00I0.IMG.jpg

  //Setup our bitmap headers
  BMFH.bfType = 0x4d42;
  BMFH.bfSize = ((sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)) + (((sizeof(char) * IMGHeader.Width) * IMGHeader.Height) * 3));
  BMFH.bfReserved1 = 0;
  BMFH.bfReserved2 = 0;
  BMFH.bfOffBits = (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER));

  BMIH.biSize = sizeof(BITMAPINFOHEADER);
  BMIH.biWidth = IMGHeader.Width;
  BMIH.biHeight = -IMGHeader.Height;
  BMIH.biPlanes = 1;
  BMIH.biBitCount = 24;
  BMIH.biCompression = BI_RGB;
  BMIH.biSizeImage = 0;
  BMIH.biXPelsPerMeter = IMGHeader.Width;
  BMIH.biYPelsPerMeter = IMGHeader.Height;
  BMIH.biClrUsed = 0;
  BMIH.biClrImportant = 0;

  //Setup the vars used for padding bitmaps
  Padding = 0;
  ExtraBytes = GetPadding(BMIH.biWidth, BMIH.biBitCount) - BMIH.biWidth * 3;

  //Write the bitmap, with padding
  fwrite(&BMFH, sizeof(BITMAPFILEHEADER), 1, pImageFile);
  fwrite(&BMIH, sizeof(BITMAPINFOHEADER), 1, pImageFile);
  for(int Y_Loop = 0; Y_Loop < IMGHeader.Height; Y_Loop++)
    {
    for(int X_Loop = 0; X_Loop < IMGHeader.Width; X_Loop++)
      {
      FileSize = (X_Loop + (Y_Loop * IMGHeader.Width));
      fwrite(&(IMGHeader.Palette[(pImage[FileSize] * 3) + 2]), sizeof(char), 1, pImageFile);
      fwrite(&(IMGHeader.Palette[(pImage[FileSize] * 3) + 1]), sizeof(char), 1, pImageFile);
      fwrite(&(IMGHeader.Palette[pImage[FileSize] * 3]), sizeof(char), 1, pImageFile);
      }

    for(int PadLoop = 0; PadLoop < ExtraBytes; PadLoop++)
      fwrite(&Padding, sizeof(int), 1, pImageFile);
    }

See anything still wrong? If I can "un-twist" this image and display it properly, My work on the converter will be complete!

-Sephiroth

Report
Re: Obtaining File Sizes... Posted by pingpong on 10 Nov 2003 at 5:33 AM
I cant see how its twisted? Can you post a pic of how its supposed to be as well to?
Report
Re: Obtaining File Sizes... Posted by Sephiroth on 10 Nov 2003 at 7:01 AM
: I cant see how its twisted? Can you post a pic of how its supposed to be as well to?
:
Actually, I think it's the format of the files I am converting, and not the bitmap side. Each of these old 16bit byte-aligned files has a short header containing X and Y offsets, width and height, and the actual image size in bytes. I found out that even though an image may be 320x200 or 40x50, I should read in "sizeof(char) * ImageSize" rather than multiplaying the width and height, because they don't always match! However, quite a few images still come out twisted. I'm on my way to work right now, but when I get home tonight, if I'm not dogged-out, I'll post the info and some bitmaps saved as jpegs for you to see. Thanks for the help with my original bitmap problem, because I'd always gone bitmap->whatever, and never tried to make one before!

-Sephiroth




 

Recent Jobs

Official Programmer's Heaven Blogs
Web Hosting | Browser and Social Games | Gadgets

Popular resources on Programmersheaven.com
Assembly | Basic | C | C# | C++ | Delphi | Flash | Java | JavaScript | Pascal | Perl | PHP | Python | Ruby | Visual Basic
© Copyright 2011 Programmersheaven.com - All rights reserved.
Reproduction in whole or in part, in any form or medium without express written permission is prohibited.
Violators of this policy may be subject to legal action. Please read our Terms Of Use and Privacy Statement for more information.
Operated by CommunityHeaven, a BootstrapLabs company.