Use PhysicsFS for making the hoard ham.
[btb/d2x.git] / misc / physfsrwops.c
1 /*
2  * This code provides a glue layer between PhysicsFS and Simple Directmedia
3  *  Layer's (SDL) RWops i/o abstraction.
4  *
5  * License: this code is public domain. I make no warranty that it is useful,
6  *  correct, harmless, or environmentally safe.
7  *
8  * This particular file may be used however you like, including copying it
9  *  verbatim into a closed-source project, exploiting it commercially, and
10  *  removing any trace of my name from the source (although I hope you won't
11  *  do that). I welcome enhancements and corrections to this file, but I do
12  *  not require you to send me patches if you make changes. This code has
13  *  NO WARRANTY.
14  *
15  * Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
16  *  Please see LICENSE in the root of the source tree.
17  *
18  * SDL falls under the LGPL license. You can get SDL at http://www.libsdl.org/
19  *
20  *  This file was written by Ryan C. Gordon. (icculus@clutteredmind.org).
21  */
22
23 #include <stdio.h>  /* used for SEEK_SET, SEEK_CUR, SEEK_END ... */
24 #include "physfsrwops.h"
25
26 static int physfsrwops_seek(SDL_RWops *rw, int offset, int whence)
27 {
28     PHYSFS_file *handle = (PHYSFS_file *) rw->hidden.unknown.data1;
29     int pos = 0;
30
31     if (whence == SEEK_SET)
32     {
33         pos = offset;
34     } /* if */
35
36     else if (whence == SEEK_CUR)
37     {
38         PHYSFS_sint64 current = PHYSFS_tell(handle);
39         if (current == -1)
40         {
41             SDL_SetError("Can't find position in file: %s",
42                           PHYSFS_getLastError());
43             return(-1);
44         } /* if */
45
46         pos = (int) current;
47         if ( ((PHYSFS_sint64) pos) != current )
48         {
49             SDL_SetError("Can't fit current file position in an int!");
50             return(-1);
51         } /* if */
52
53         if (offset == 0)  /* this is a "tell" call. We're done. */
54             return(pos);
55
56         pos += offset;
57     } /* else if */
58
59     else if (whence == SEEK_END)
60     {
61         PHYSFS_sint64 len = PHYSFS_fileLength(handle);
62         if (len == -1)
63         {
64             SDL_SetError("Can't find end of file: %s", PHYSFS_getLastError());
65             return(-1);
66         } /* if */
67
68         pos = (int) len;
69         if ( ((PHYSFS_sint64) pos) != len )
70         {
71             SDL_SetError("Can't fit end-of-file position in an int!");
72             return(-1);
73         } /* if */
74
75         pos += offset;
76     } /* else if */
77
78     else
79     {
80         SDL_SetError("Invalid 'whence' parameter.");
81         return(-1);
82     } /* else */
83
84     if ( pos < 0 )
85     {
86         SDL_SetError("Attempt to seek past start of file.");
87         return(-1);
88     } /* if */
89     
90     if (!PHYSFS_seek(handle, (PHYSFS_uint64) pos))
91     {
92         SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
93         return(-1);
94     } /* if */
95
96     return(pos);
97 } /* physfsrwops_seek */
98
99
100 static int physfsrwops_read(SDL_RWops *rw, void *ptr, int size, int maxnum)
101 {
102     PHYSFS_file *handle = (PHYSFS_file *) rw->hidden.unknown.data1;
103     PHYSFS_sint64 rc = PHYSFS_read(handle, ptr, size, maxnum);
104     if (rc != maxnum)
105     {
106         if (!PHYSFS_eof(handle)) /* not EOF? Must be an error. */
107             SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
108     } /* if */
109
110     return((int) rc);
111 } /* physfsrwops_read */
112
113
114 static int physfsrwops_write(SDL_RWops *rw, const void *ptr, int size, int num)
115 {
116     PHYSFS_file *handle = (PHYSFS_file *) rw->hidden.unknown.data1;
117     PHYSFS_sint64 rc = PHYSFS_write(handle, ptr, size, num);
118     if (rc != num)
119         SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
120
121     return((int) rc);
122 } /* physfsrwops_write */
123
124
125 static int physfsrwops_close(SDL_RWops *rw)
126 {
127     PHYSFS_file *handle = (PHYSFS_file *) rw->hidden.unknown.data1;
128     if (!PHYSFS_close(handle))
129     {
130         SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
131         return(-1);
132     } /* if */
133
134     SDL_FreeRW(rw);
135     return(0);
136 } /* physfsrwops_close */
137
138
139 static SDL_RWops *create_rwops(PHYSFS_file *handle)
140 {
141     SDL_RWops *retval = NULL;
142
143     if (handle == NULL)
144         SDL_SetError("PhysicsFS error: %s", PHYSFS_getLastError());
145     else
146     {
147         retval = SDL_AllocRW();
148         if (retval != NULL)
149         {
150             retval->seek  = physfsrwops_seek;
151             retval->read  = physfsrwops_read;
152             retval->write = physfsrwops_write;
153             retval->close = physfsrwops_close;
154             retval->hidden.unknown.data1 = handle;
155         } /* if */
156     } /* else */
157
158     return(retval);
159 } /* create_rwops */
160
161
162 SDL_RWops *PHYSFSRWOPS_makeRWops(PHYSFS_file *handle)
163 {
164     SDL_RWops *retval = NULL;
165     if (handle == NULL)
166         SDL_SetError("NULL pointer passed to PHYSFSRWOPS_makeRWops().");
167     else
168         retval = create_rwops(handle);
169
170     return(retval);
171 } /* PHYSFSRWOPS_makeRWops */
172
173
174 SDL_RWops *PHYSFSRWOPS_openRead(const char *fname)
175 {
176     return(create_rwops(PHYSFS_openRead(fname)));
177 } /* PHYSFSRWOPS_openRead */
178
179
180 SDL_RWops *PHYSFSRWOPS_openWrite(const char *fname)
181 {
182     return(create_rwops(PHYSFS_openWrite(fname)));
183 } /* PHYSFSRWOPS_openWrite */
184
185
186 SDL_RWops *PHYSFSRWOPS_openAppend(const char *fname)
187 {
188     return(create_rwops(PHYSFS_openAppend(fname)));
189 } /* PHYSFSRWOPS_openAppend */
190
191
192 /* end of physfsrwops.c ... */
193