Fix a possible memory leak when extracting from an ICO file.
[wine] / dlls / winedos / xms.c
1 /*
2  * XMS v2+ emulation
3  *
4  * Copyright 1998 Ove Kåven
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * Note: This XMS emulation is hooked through the DPMI interrupt.
21  */
22
23 #include "config.h"
24
25 #ifdef HAVE_UNISTD_H
26 # include <unistd.h>
27 #endif
28 #include <string.h>
29 #include "winbase.h"
30 #include "wine/winbase16.h"
31 #include "module.h"
32 #include "miscemu.h"
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(int31);
36
37 typedef struct {
38  WORD Handle;
39  DWORD Offset;
40 } WINE_PACKED MOVEOFS;
41
42 typedef struct {
43  DWORD Length;
44  MOVEOFS Source;
45  MOVEOFS Dest;
46 } WINE_PACKED MOVESTRUCT;
47
48 static BYTE * XMS_Offset( MOVEOFS *ofs )
49 {
50     if (ofs->Handle) return (BYTE*)GlobalLock16(ofs->Handle)+ofs->Offset;
51     else return (BYTE*)PTR_REAL_TO_LIN(SELECTOROF(ofs->Offset),OFFSETOF(ofs->Offset));
52 }
53
54 /**********************************************************************
55  *          XMS_Handler
56  */
57
58 void WINAPI XMS_Handler( CONTEXT86 *context )
59 {
60     switch(AH_reg(context))
61     {
62     case 0x00:   /* Get XMS version number */
63         TRACE("get XMS version number\n");
64         SET_AX( context, 0x0200 ); /* 2.0 */
65         SET_BX( context, 0x0000 ); /* internal revision */
66         SET_DX( context, 0x0001 ); /* HMA exists */
67         break;
68     case 0x08:   /* Query Free Extended Memory */
69     {
70         MEMORYSTATUS status;
71
72         TRACE("query free extended memory\n");
73         GlobalMemoryStatus( &status );
74         SET_DX( context, status.dwAvailVirtual >> 10 );
75         SET_AX( context, status.dwAvailVirtual >> 10 );
76         TRACE("returning largest %dK, total %dK\n", AX_reg(context), DX_reg(context));
77     }
78     break;
79     case 0x09:   /* Allocate Extended Memory Block */
80         TRACE("allocate extended memory block (%dK)\n",
81             DX_reg(context));
82         SET_DX( context, GlobalAlloc16(GMEM_MOVEABLE, (DWORD)DX_reg(context)<<10) );
83         SET_AX( context, DX_reg(context) ? 1 : 0 );
84         if (!DX_reg(context)) SET_BL( context, 0xA0 ); /* out of memory */
85         break;
86     case 0x0a:   /* Free Extended Memory Block */
87         TRACE("free extended memory block %04x\n",DX_reg(context));
88        if(!DX_reg(context) || GlobalFree16(DX_reg(context))) {
89          SET_AX( context, 0 );    /* failure */
90          SET_BL( context, 0xa2 ); /* invalid handle */
91        } else
92          SET_AX( context, 1 );    /* success */
93         break;
94     case 0x0b:   /* Move Extended Memory Block */
95     {
96         MOVESTRUCT*move=CTX_SEG_OFF_TO_LIN(context,
97             context->SegDs,context->Esi);
98         BYTE*src,*dst;
99         TRACE("move extended memory block\n");
100         src=XMS_Offset(&move->Source);
101         dst=XMS_Offset(&move->Dest);
102         memcpy(dst,src,move->Length);
103         if (move->Source.Handle) GlobalUnlock16(move->Source.Handle);
104         if (move->Dest.Handle) GlobalUnlock16(move->Dest.Handle);
105         break;
106     }
107     case 0x88:   /* Query Any Free Extended Memory */
108     {
109         MEMORYSTATUS status;
110         SYSTEM_INFO  info;
111
112         TRACE("query any free extended memory\n");
113
114         GlobalMemoryStatus( &status );
115         GetSystemInfo( &info );
116         context->Eax = status.dwAvailVirtual >> 10;
117         context->Edx = status.dwAvailVirtual >> 10;
118         context->Ecx = (DWORD)info.lpMaximumApplicationAddress;
119         SET_BL( context, 0 ); /* No errors. */
120
121         TRACE("returning largest %ldK, total %ldK, highest 0x%lx\n", 
122               context->Eax, context->Edx, context->Ecx);
123     }
124     break;
125     default:
126         INT_BARF( context, 0x31 );
127         SET_AX( context, 0x0000 ); /* failure */
128         SET_BL( context, 0x80 );   /* function not implemented */
129         break;
130     }
131 }