summaryrefslogtreecommitdiff
path: root/src/wincap/file.c
blob: e24f0ec86b782bc8f48d1adc157f2116c643de41 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
/*
 *  file.c
 *
 *  Source file for Device-Independent Bitmap (DIB) API.  Provides
 *  the following functions:
 *
 *  SaveDIB()           - Saves the specified dib in a file
 *  LoadDIB()           - Loads a DIB from a file
 *  DestroyDIB()        - Deletes DIB when finished using it
 *
 * Development Team: Mark Bader
 *                   Patrick Schreiber
 *                   Garrett McAuliffe
 *                   Eric Flo
 *                   Tony Claflin
 *
 * Written by Microsoft Product Support Services, Developer Support.
 * Copyright (c) 1991 Microsoft Corporation. All rights reserved.
 *
 * Modified by Frank J. Lhota to use Win32 CreateFile handles
 * whenever WIN32 is defined.
 */
#include <windows.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <io.h>
/* #include <direct.h> */
#include <stdlib.h>
#include <fcntl.h>
#include "errors.h"
#include "dibutil.h"
#include "dibapi.h"

/*
 * Dib Header Marker - used in writing DIBs to files
 */
#define DIB_HEADER_MARKER   ((WORD) ('M' << 8) | 'B')

#ifdef WIN32
typedef HANDLE MYHFILE;
#else					/* WIN32 */
typedef int MYHFILE;
#endif					/* WIN32 */

/*********************************************************************
 *
 * Local Function Prototypes
 *
 *********************************************************************/


HANDLE ReadDIBFile(MYHFILE);
BOOL MyRead(MYHFILE, LPSTR, DWORD);
BOOL SaveDIBFile(void);
/* BOOL WriteDIB(LPSTR, HANDLE); */
DWORD PASCAL MyWrite(MYHFILE, VOID FAR *, DWORD);

/*************************************************************************
 *
 * LoadDIB()
 *
 * Loads the specified DIB from a file, allocates memory for it,
 * and reads the disk file into the memory.
 *
 * Parameters:
 *
 * LPSTR lpFileName - specifies the file to load a DIB from
 *
 * Returns: A handle to a DIB, or NULL if unsuccessful.
 *
 *************************************************************************/

HDIB LoadDIB(LPSTR lpFileName)
{
   HDIB hDIB;
   MYHFILE hFile;
   OFSTRUCT ofs;

   /*
    * Set the cursor to a hourglass, in case the loading operation
    * takes more than a sec, the user will know what's going on.
    */

   SetCursor(LoadCursor(NULL, IDC_WAIT));
#ifdef WIN32
   hFile = CreateFile(
      lpFileName,	     /* lpFileName            */
      GENERIC_READ,	     /* dwDesiredAccess       */
      FILE_SHARE_READ,	     /* dwShareMode           */
      NULL,		     /* lpSecurityAttributes  */
      OPEN_EXISTING,	     /* dwCreationDisposition */
      FILE_ATTRIBUTE_NORMAL, /* dwFlagsAndAttributes  */
      NULL );		     /* hTemplateFile         */
 
   if (hFile != INVALID_HANDLE_VALUE)
#else					/* WIN32 */
   if ((hFile = OpenFile(lpFileName, &ofs, OF_READ)) != -1)
#endif					/* WIN32 */
   {
      hDIB = ReadDIBFile(hFile);
#ifdef WIN32
      CloseHandle(hFile);
#else					/* WIN32 */
      _lclose(hFile);
#endif					/* WIN32 */
      SetCursor(LoadCursor(NULL, IDC_ARROW));
      return hDIB;
   }
   else
   {
#if 0
      DIBError(ERR_FILENOTFOUND);
#endif
      SetCursor(LoadCursor(NULL, IDC_ARROW));
      return NULL;
   }
}


/*************************************************************************
 *
 * SaveDIB()
 *
 * Saves the specified DIB into the specified file name on disk.  No
 * error checking is done, so if the file already exists, it will be
 * written over.
 *
 * Parameters:
 *
 * HDIB hDib - Handle to the dib to save
 *
 * LPSTR lpFileName - pointer to full pathname to save DIB under
 *
 * Return value: 0 if successful, or one of:
 *        ERR_INVALIDHANDLE
 *        ERR_OPEN
 *        ERR_LOCK
 *
 *************************************************************************/


WORD SaveDIB(HDIB hDib, LPSTR lpFileName)
{
   BITMAPFILEHEADER bmfHdr; // Header for Bitmap file
   LPBITMAPINFOHEADER lpBI;   // Pointer to DIB info structure
   MYHFILE fh;     // file handle for opened file
#ifdef WIN32
   DWORD dwNumberOfBytesWritten;
#else					/* WIN32 */
   OFSTRUCT of;     // OpenFile structure
#endif					/* WIN32 */

   if (!hDib)
      return ERR_INVALIDHANDLE;
#ifdef WIN32
   fh = CreateFile(
      lpFileName,	     /* lpFileName            */
      GENERIC_WRITE,	     /* dwDesiredAccess       */
      0,	     	     /* dwShareMode           */
      NULL,		     /* lpSecurityAttributes  */
      CREATE_ALWAYS,	     /* dwCreationDisposition */
      FILE_ATTRIBUTE_NORMAL, /* dwFlagsAndAttributes  */
      NULL );		     /* hTemplateFile         */
   if (fh == INVALID_HANDLE_VALUE)
#else					/* WIN32 */
   fh = OpenFile(lpFileName, &of, OF_CREATE | OF_READWRITE);
   if (fh == -1)
#endif					/* WIN32 */
      return ERR_OPEN;

   /*
    * Get a pointer to the DIB memory, the first of which contains
    * a BITMAPINFO structure
    */
   lpBI = (LPBITMAPINFOHEADER)GlobalLock(hDib);
   if (!lpBI)
      return ERR_LOCK;

   /*
    * Fill in the fields of the file header
    */

   /* Fill in file type (first 2 bytes must be "BM" for a bitmap) */
   bmfHdr.bfType = DIB_HEADER_MARKER;  // "BM"

   /* Size is size of packed dib in memory plus size of file header */
   bmfHdr.bfSize = GlobalSize(hDib) + sizeof(BITMAPFILEHEADER);
   bmfHdr.bfReserved1 = 0;
   bmfHdr.bfReserved2 = 0;

   /*
    * Now, calculate the offset the actual bitmap bits will be in
    * the file -- It's the Bitmap file header plus the DIB header,
    * plus the size of the color table.
    */
   bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + lpBI->biSize +
                      PaletteSize((LPSTR)lpBI);

   /* Write the file header */
#ifdef WIN32
   WriteFile(fh, (LPCVOID)&bmfHdr, sizeof(BITMAPFILEHEADER),
      &dwNumberOfBytesWritten, NULL);
#else					/* WIN32 */
   _lwrite(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER));
#endif					/* WIN32 */

   /*
    * Write the DIB header and the bits -- use local version of
    * MyWrite, so we can write more than 32767 bytes of data
    */
   MyWrite(fh, (LPSTR)lpBI, GlobalSize(hDib));
   GlobalUnlock(hDib);
#ifdef WIN32
   CloseHandle(fh);
#else					/* WIN32 */
   _lclose(fh);
#endif					/* WIN32 */
   return 0; // Success code
}


/*************************************************************************
 *
 * DestroyDIB ()
 *
 * Purpose:  Frees memory associated with a DIB
 *
 * Returns:  Nothing
 *
 *************************************************************************/


WORD DestroyDIB(HDIB hDib)
{
   GlobalFree(hDib);
   return 0;
}


//************************************************************************
//
// Auxiliary Functions which the above procedures use
//
//************************************************************************


/*************************************************************************

  Function:  ReadDIBFile (MYHFILE)

   Purpose:  Reads in the specified DIB file into a global chunk of
             memory.

   Returns:  A handle to a dib (hDIB) if successful.
             NULL if an error occurs.

  Comments:  BITMAPFILEHEADER is stripped off of the DIB.  Everything
             from the end of the BITMAPFILEHEADER structure on is
             returned in the global memory handle.

*************************************************************************/


HANDLE ReadDIBFile(MYHFILE hFile)
{
   BITMAPFILEHEADER bmfHeader;
   DWORD dwBitsSize;
#ifdef WIN32
   DWORD dwNumberOfBytesRead = 0;
#endif					/* WIN32 */

   HANDLE hDIB;
   LPSTR pDIB;

   /*
    * get length of DIB in bytes for use when reading
    */

#ifdef WIN32
   dwBitsSize = GetFileSize(hFile, NULL);
#else					/* WIN32 */
   dwBitsSize = filelength(hFile);
#endif					/* WIN32 */

   /*
    * Go read the DIB file header and check if it's valid.
    */
#ifdef WIN32
   ReadFile(hFile, (LPVOID)&bmfHeader, sizeof(bmfHeader),
      &dwNumberOfBytesRead, NULL);
   if (dwNumberOfBytesRead != sizeof(bmfHeader)) {
#else					/* WIN32 */
   if ((_lread(hFile, (LPSTR)&bmfHeader, sizeof(bmfHeader)) != sizeof(
       bmfHeader))) {
#endif					/* WIN32 */
       return NULL;
      }
   if (bmfHeader.bfType != DIB_HEADER_MARKER)
   {
      return NULL;
   }
   /*
    * Allocate memory for DIB
    */
   hDIB = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwBitsSize);
   if (hDIB == 0)
   {
      return NULL;
   }
   pDIB = GlobalLock(hDIB);

   /*
    * Go read the bits.
    */
   if (!MyRead(hFile, pDIB, dwBitsSize - sizeof(BITMAPFILEHEADER)))
   {
      GlobalUnlock(hDIB);
      GlobalFree(hDIB);
      return NULL;
   }
   GlobalUnlock(hDIB);
   return hDIB;
}

/*************************************************************************

  Function:  MyRead (MYHFILE, LPSTR, DWORD)

   Purpose:  Routine to read files greater than 64K in size.

   Returns:  TRUE if successful.
             FALSE if an error occurs.

  Comments:

*************************************************************************/


BOOL MyRead(MYHFILE hFile, LPSTR lpBuffer, DWORD dwSize)
{
#ifdef WIN32
   DWORD dwNumberOfBytesRead;

   if(!ReadFile(hFile, (LPVOID)lpBuffer, dwSize, &dwNumberOfBytesRead, NULL))
      return FALSE;
   return (dwNumberOfBytesRead == dwSize);
#else					/* WIN32 */
   char huge *lpInBuf = (char huge *)lpBuffer;
   int nBytes;

   /*
    * Read in the data in 32767 byte chunks (or a smaller amount if it's
    * the last chunk of data read)
    */

   while (dwSize)
   {
      nBytes = (int)(dwSize > (DWORD)32767 ? 32767 : LOWORD (dwSize));
      if (_lread(hFile, (LPSTR)lpInBuf, nBytes) != (WORD)nBytes)
         return FALSE;
      dwSize -= nBytes;
      lpInBuf += nBytes;
   }
   return TRUE;
#endif					/* WIN32 */
}


/****************************************************************************

 FUNCTION   : MyWrite(MYHFILE fh, VOID FAR *pv, DWORD ul)

 PURPOSE    : Writes data in steps of 32k till all the data is written.
              Normal _lwrite uses a WORD as 3rd parameter, so it is
              limited to 32767 bytes, but this procedure is not.

 RETURNS    : 0 - If write did not proceed correctly.
              number of bytes written otherwise.

 ****************************************************************************/


DWORD PASCAL MyWrite(MYHFILE iFileHandle, VOID FAR *lpBuffer, DWORD dwBytes)
{
   DWORD dwBytesTmp = dwBytes;       // Save # of bytes for return value
#ifdef WIN32
   if(!WriteFile(iFileHandle, (LPCVOID)lpBuffer, dwBytes, &dwBytesTmp, NULL))
      return 0;
#else					/* WIN32 */
   BYTE huge *hpBuffer = lpBuffer;   // make a huge pointer to the data

   /*
    * Write out the data in 32767 byte chunks.
    */

   while (dwBytes > 32767)
   {
      if (_lwrite(iFileHandle, (LPSTR)hpBuffer, (WORD)32767) != 32767)
         return 0;
      dwBytes -= 32767;
      hpBuffer += 32767;
   }

   /* Write out the last chunk (which is < 32767 bytes) */
   if (_lwrite(iFileHandle, (LPSTR)hpBuffer, (WORD)dwBytes) != (WORD)dwBytes)
      return 0;
#endif					/* WIN32 */
   return dwBytesTmp;
}