~ubuntu-branches/ubuntu/wily/gargoyle-free/wily-proposed

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
/* $Header: d:/cvsroot/tads/tads3/VMFILE.H,v 1.2 1999/05/17 02:52:28 MJRoberts Exp $ */

/* 
 *   Copyright (c) 1998, 2002 Michael J. Roberts.  All Rights Reserved.
 *   
 *   Please see the accompanying license file, LICENSE.TXT, for information
 *   on using and copying this software.  
 */
/*
Name
  vmfile.h - VM external file interface
Function
  
Notes
  
Modified
  10/28/98 MJRoberts  - Creation
*/

#ifndef VMFILE_H
#define VMFILE_H

#include "t3std.h"
#include "vmerr.h"

/* ------------------------------------------------------------------------ */
/*
 *   VM external file interface.  The VM uses this interface for
 *   manipulating files that contain program images and saved state. 
 */

class CVmFile
{
public:
    /* create a new file object */
    CVmFile()
    {
        /* no file yet */
        fp_ = 0;

        /* presume the base seek position is at the start of the file */
        seek_base_ = 0;
    }

    /* delete the file */
    ~CVmFile();

    /*
     *   Set the file to use an existing underlying OS file handle.  The
     *   seek_base value gives the byte offset within the OS file handle
     *   of our virtual byte stream; this is useful if the file object is
     *   handling a byte stream embedded within a larger OS file (such as
     *   a resource within a file containing multiple resources).  If
     *   we're simply providing access to the entire underlying file, the
     *   seek_base value should be zero.  
     */
    void set_file(osfildef *fp, long seek_base)
    {
        /* remember the file handle and seek position */
        fp_ = fp;
        seek_base_ = seek_base;
    }

    /*
     *   Detach from the underlying OS file handle.  Normally, when we are
     *   deleted, we'll close our underlying OS file handle.  If the
     *   caller has a separate reference to the OS file handle and wants
     *   to keep the handle open after deleting us, the caller should use
     *   this function to detach us from the OS file handle before
     *   deleting us.
     *   
     *   After calling this routine, no operations can be performed on the
     *   underlying file through this object, since we will have forgotten
     *   the file handle.  
     */
    void detach_file()
    {
        /* forget our file handle */
        fp_ = 0;
    }

    /* 
     *   Open an existing file for reading.  Throws an error if the file
     *   does not exist.  
     */
    void open_read(const char *fname, os_filetype_t typ);

    /* 
     *   Create a file for writing, replacing any existing file.  Throws
     *   an error if the file cannot be created. 
     */
    void open_write(const char *fname, os_filetype_t typ);

    /* close the underlying file */
    void close()
    {
        osfcls(fp_);
        fp_ = 0;
    }

    /*
     *   Read various types from the file.  These routines throw an error
     *   if the data cannot be read. 
     */
    uchar read_byte() { char b; read_bytes(&b, 1); return (uchar)b; }
    uint read_uint2() { char b[2]; read_bytes(b, 2); return osrp2(b); }
    int  read_int2()  { char b[2]; read_bytes(b, 2); return osrp2s(b); }
    long read_int4()  { char b[4]; read_bytes(b, 4); return osrp4(b); }
    ulong read_uint4() { char b[4]; read_bytes(b, 4); return t3rp4u(b); }

    /* read bytes - throws an error if the bytes cannot be read */
    void read_bytes(char *buf, size_t buflen)
    {
        if (buflen != 0 && osfrb(fp_, buf, buflen))
            err_throw(VMERR_READ_FILE);
    }

    /*
     *   Write various types to the file.  These routines throw an error
     *   if the data cannot be written. 
     */
    void write_int2(uint v) { char b[2]; oswp2(b, v); write_bytes(b, 2); }
    void write_int4(uint v) { char b[4]; oswp4(b, v); write_bytes(b, 4); }

    /* write bytes - throws an error if the bytes cannot be written */
    void write_bytes(const char *buf, size_t buflen)
    {
        if (buflen != 0 && osfwb(fp_, buf, buflen))
            err_throw(VMERR_WRITE_FILE);
    }

    /* get the current seek position */
    long get_pos() const { return osfpos(fp_) - seek_base_; }

    /* seek to a new position */
    void set_pos(long seekpos)
    {
        /* seek relative to the base seek position */
        osfseek(fp_, seekpos + seek_base_, OSFSK_SET);
    }

    /* seek to a position relative to the end of the file */
    void set_pos_from_eof(long pos) { osfseek(fp_, pos, OSFSK_END); }

    /* seek to a position relative to the current file position */
    void set_pos_from_cur(long pos) { osfseek(fp_, pos, OSFSK_CUR); }

protected:
    /* our underlying OS file handle */
    osfildef *fp_;

    /* 
     *   Base seek position - this is useful for virtual byte streams that
     *   are embedded in larger files (resource files, for example).
     *   set_pos() is always relative to this position.  Note that
     *   set_pos_from_eof() is *not* relative to this position, so
     *   embedded byte streams must not use set_pos_from_eof() unless the
     *   embedded stream ends at the end of the enclosing file. 
     */
    long seek_base_;
};

/* ------------------------------------------------------------------------ */
/*
 *   Generic stream interface.  This is a higher-level type of file interface
 *   than CVmFile: this interface can be implemented on different kinds of
 *   underlying storage formats to provide generic stream access independent
 *   of the actual storage implementation.
 *   
 *   We provide default implementations of the type readers in terms of the
 *   low-level byte reader virtual method, which must be implemented by each
 *   concrete subclass.  However, all of the type readers are virtual, so
 *   subclasses can override these if they can be implemented more
 *   efficiently on the underlying stream (for example, some implementations
 *   might have ready access to the data in a buffer already, in which case
 *   it might be faster to avoid the extra buffer copy of the default
 *   implementations of the type readers).  
 */
class CVmStream
{
public:
    /* read/write a byte */
    virtual uchar read_byte() { char b; read_bytes(&b, 1); return (uchar)b; }
    virtual void write_byte(uchar b) { write_bytes((char *)&b, 1); }

    /* 
     *   read various integer types (signed 2-byte, unsigned 2-byte, signed
     *   4-byte, unsigned 4-byte) 
     */
    virtual int read_int2() { char b[2]; read_bytes(b, 2); return osrp2s(b); }
    virtual uint read_uint2()
        { char b[2]; read_bytes(b, 2); return osrp2(b); }
    virtual long read_int4() { char b[4]; read_bytes(b, 4); return osrp4(b); }
    virtual ulong read_uint4()
        { char b[4]; read_bytes(b, 4); return t3rp4u(b); }

    /* write an integer value */
    virtual void write_int2(int i)
        { char b[2]; oswp2(b, i); write_bytes(b, 2); }
    virtual void write_int4(long l)
        { char b[4]; oswp4(b, l); write_bytes(b, 4); }

    /* read bytes - this must be provided by the implementation */
    virtual void read_bytes(char *buf, size_t len) = 0;

    /* write byte */
    virtual void write_bytes(const char *buf, size_t len) = 0;

    /* get the current seek offset */
    virtual long get_seek_pos() const = 0;

    /* 
     *   set the seek offset - this is only valid with offsets previously
     *   obtained with get_seek_pos() 
     */
    virtual void set_seek_pos(long pos) = 0;
};

/*
 *   Implementation of the generic stream with an underlying CVmFile object 
 */
class CVmFileStream: public CVmStream
{
public:
    /* create based on the underlying file object */
    CVmFileStream(CVmFile *fp) { fp_ = fp; }

    /* read bytes */
    void read_bytes(char *buf, size_t len) { fp_->read_bytes(buf, len); }

    /* write bytes */
    void write_bytes(const char *buf, size_t len)
        { fp_->write_bytes(buf, len); }

    /* get/set the seek position */
    long get_seek_pos() const { return fp_->get_pos(); }
    void set_seek_pos(long pos) { fp_->set_pos(pos); }

private:
    /* our underlying file stream */
    CVmFile *fp_;
};

/*
 *   Implementation of the generic stream reader for reading from memory 
 */
class CVmMemoryStream: public CVmStream
{
public:
    /* create given the underlying memory buffer */
    CVmMemoryStream(char *buf, size_t len)
    {
        /* remember the buffer */
        buf_ = buf;
        buflen_ = len;

        /* start at the start of the buffer */
        p_ = buf;
    }

    /* read bytes */
    void read_bytes(char *buf, size_t len)
    {
        /* if we don't have enough bytes left, throw an error */
        if (len > (size_t)((buf_ + buflen_) - p_))
            err_throw(VMERR_READ_FILE);

        /* copy the data */
        memcpy(buf, p_, len);

        /* advance past the data we just read */
        p_ += len;
    }

    /* write bytes */
    void write_bytes(const char *buf, size_t len)
    {
        /* if we don't have space, throw an error */
        if (len > (size_t)((buf_ + buflen_) - p_))
            err_throw(VMERR_WRITE_FILE);

        /* copy the data */
        memcpy(p_, buf, len);

        /* advance past the data */
        p_ += len;
    }

    /* get the position - return an offset from the start of our buffer */
    long get_seek_pos() const { return p_ - buf_; }

    /* set the position, as an offset from the start of our buffer */
    void set_seek_pos(long pos)
    {
        /* limit it to the available space */
        if (pos < 0)
            pos = 0;
        else if (pos > (long)buflen_)
            pos = buflen_;

        /* set the position */
        p_ = buf_ + pos;
    }

protected:
    /* our buffer */
    char *buf_;

    /* size of our buffer */
    size_t buflen_;

    /* current read/write pointer */
    char *p_;
};

/*
 *   Read-only memory stream 
 */
class CVmReadOnlyMemoryStream: public CVmMemoryStream
{
public:
    CVmReadOnlyMemoryStream(const char *buf, size_t len)
        : CVmMemoryStream((char *)buf, len)
    {
    }

    /* disallow writing */
    void write_bytes(const char *, size_t) { err_throw(VMERR_WRITE_FILE); }
};

#endif /* VMFILE_H */