summaryrefslogtreecommitdiff
path: root/dviware/dvi2bitmap/FileByteStream.cc
blob: 121de93206167ed1538410ddb2d2dfb57fe70887 (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
/* This file is part of dvi2bitmap; see README for copyrights and licence */

#include <config.h>

#include <FileByteStream.h>

#include <iostream>
//#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#ifdef HAVE_CSTD_INCLUDE
#include <cstdio>
#include <cerrno>
#include <cassert>
#include <cstring>		// for strerror
#else
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include <string.h>
#endif

using STD::cerr;
using STD::endl;


/**
 * Opens the requested file.  If preload is true, then open the file
 * and read it entire into memory (possibly helpful if the client will
 * be seeking a lot).  If the file can't be opened, then try adding
 * <code>tryext</code> to the end of it.
 *
 * <p>The file to be opened must be a seekable object -- that is, it
 * must be a regular file, rather than a named pipe or a socket.  The
 * constructor checks this, and throws an exception if this is not the
 * case. If you wish to open a named pipe, you can do so using {@link
 * InputByteStream#InputByteStream(string)}.
 *
 * @param filename the file to be opened
 * @param tryext a file extension, including any dot, which should be
 * added to the end of <code>filename</code> if that cannot be opened;
 * default <code>""</code> suppresses this
 * @param preload if true, then the file is read entirely into memory
 *
 * @throws InputByteStreamError if there is a problem opening the
 * file, including the discovery that it is not a seekable object
 */
FileByteStream::FileByteStream(string& filename,
			       string tryext,
			       bool preload)
    throw (InputByteStreamError)
{
    if (getVerbosity() > normal)
	cerr << "FileByteStream(name=" << filename
	     << ",ext=" << tryext
	     << ",preload=" << (preload?"yes":"no") << ")" << endl;
    int newfd = -1;
    try {
	newfd = openSourceSpec("<osfile>" + filename);
    } catch (InputByteStreamError& e) {
	newfd = -1;
    }
    if (newfd < 0) {
	newfd = openSourceSpec("<osfile>" + filename + tryext);
	// Let it throw the exception, this time
	// If it succeeds, modify the argument
	filename += tryext;
    }
    assert(newfd >= 0);

    // ermm, we should test for HAVE_SYS_STAT_H, here, but (a) are
    // there really any platforms which don't have stat?, and (b) we
    // need the filesize information, and I don't know how else to
    // get it.  Deal with this if we really do find such a wierd
    // platform.
#ifndef HAVE_SYS_STAT_H
#error "Come on -- you _must_ have stat(2)!"
#endif
    struct stat S;
    if (fstat (newfd, &S))
    {
	string errstr = STD::strerror (errno);
	throw InputByteStreamError ("Can't stat open file (" + errstr + ")");
    }
    filesize_ = S.st_size;

    bindToFileDescriptor(newfd,
			 filename,
			 (preload ? filesize_ : 0),
			 preload,
			 true);	// assert is seekable
}

FileByteStream::~FileByteStream()
{
    // nothing
}

/**
 * Sets the position of the file pointer.
 *
 * @param pos if positive, the offset from the beginning of the file;
 * if negative, the offset from the end of the file
 *
 * @throws InputByteStreamError if the offset is larger
 * than the size of the file
 */
void FileByteStream::seek(int pos)
    throw (InputByteStreamError)
{
    int fd = getFD();
    int offset = (pos >= 0 ? pos : filesize_ + pos);
    if (offset < 0 || offset > filesize_)
	throw InputByteStreamError("FileByteStream: seek out of bounds");

    if (fd < 0) {
	// preloaded
	bufferSeek(offset);
	// no need to reload buffer
    } else {
	if (lseek(fd, offset, SEEK_SET) < 0) {
	    string errmsg = STD::strerror(errno);
	    throw InputByteStreamError("Can't seek (" + errmsg + ")");
	}
	if (getVerbosity() > normal)
	    cerr << "FileByteStream::seek(" << pos << "=>" << offset
		 << ") ok" << endl;
	reloadBuffer();
    }
}