diff options
Diffstat (limited to 'dviware/dvi2bitmap/InputByteStream.cc')
-rw-r--r-- | dviware/dvi2bitmap/InputByteStream.cc | 871 |
1 files changed, 871 insertions, 0 deletions
diff --git a/dviware/dvi2bitmap/InputByteStream.cc b/dviware/dvi2bitmap/InputByteStream.cc new file mode 100644 index 0000000000..36d57fe80f --- /dev/null +++ b/dviware/dvi2bitmap/InputByteStream.cc @@ -0,0 +1,871 @@ +/* This file is part of dvi2bitmap; see README for copyrights and licence */ + +#include <config.h> + +#include <InputByteStream.h> + +#include <iostream> +#include <fcntl.h> + +#if HAVE_CSTD_INCLUDE +# include <cstdio> +# include <cstdlib> +# include <cassert> +# include <cstring> +#else +# include <stdio.h> +# include <stdlib.h> +# include <assert.h> +# include <string.h> +#endif + +#if HAVE_SYS_ERRNO_H +/* If it's available, explicitly include sys/errno.h as well as + * <cerrno> or <errno.h>. If we're compiling in a strict-ansi mode, + * the compiler may well carefully avoid defining errors which are + * specific to Unix/POSIX; these (specifically EINTR) are precisely + * the ones we're hoping to use. Include <sys/errno.h> _first_: if + * <cerrno> includes it, it will probably define sentinels to prevent + * us re-including it here. + */ +# include <sys/errno.h> +#endif +#if HAVE_CSTD_INCLUDE +# include <cerrno> +#else +# include <errno.h> +#endif + +#include <unistd.h> + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> // for stat +#endif + +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif + +using STD::cerr; // these functions are used many times +using STD::sprintf; +using STD::endl; +using STD::strerror; + +// Static debug switch +verbosities InputByteStream::verbosity_ = normal; +unsigned int InputByteStream::default_buffer_length_ = 0; + +/** + * No-argument constructor creates a new InputByteStream object, but + * does not associate it with any source of bytes. To associate it + * with a source, use {@link #bindToFileDescriptor} or the + * convenience method {@link #openSourceSpec}. + */ +InputByteStream::InputByteStream() + : fd_(-1), mappedfd_(-1), buf_(0), eof_(true) +{ + // empty +} + +/** + * Prepares to read a stream from the specified file descriptor, which + * must be open. + * + * @param fd an open file descriptor + * @throws InputByteStreamError if there is a problem binding to the + * descriptor + */ +InputByteStream::InputByteStream(int fd) + throw (InputByteStreamError) + : fd_(-1), mappedfd_(-1), buf_(0), eof_(true) +{ + bindToFileDescriptor(fd, "", 0, false, false); +} + +/** + * Prepares to read a stream from the specified source. + * + * <p>The source may be + * <ul> + * <li>a file name, which should be readable + * <li>a specifier of the form <code><osfile>filename</code>: + * the specified file is opened + * <li>a specifier of the form <code><osfd>integer</code>: the integer + * specifyies an (open) OS file descriptor; thus + * <code><osfd>0</code> opens the standard input + * </ul> + * + * @param srcspec a source specification as described above + * @throws InputByteStreamError if there is a problem opening or + * binding to the descriptor + */ +InputByteStream::InputByteStream(string srcspec) + throw (InputByteStreamError) + : fd_(-1), mappedfd_(-1), buf_(0), eof_(true) +{ + int fd = openSourceSpec(srcspec); + // Note that, since we don't know that the srcspec isn't a fd or + // a pipe, we cannot say that it's definitely seekable + bindToFileDescriptor(fd, srcspec, 0, false, false); +} + +/** + * Closes the file and reclaims any buffers. + */ +InputByteStream::~InputByteStream () +{ + close(); +} + +/** + * Indicates whether we are at the end of the file. This method does + * not return true until <em>after</em> a failed attempt to read past + * the end of file; that is, it does not return true immediately + * after the last byte has been read from the file. + * + * @return true if we are at the end of the file + */ +bool InputByteStream::eof() +{ + return eof_; +} + +/** + * Binds this stream to a given file descriptor. + * + * <p>If the parameter <code>fillBufferAndClose</code> is true, then + * this method will keep reading from the file descriptor until it + * reaches either the end of the newly-allocated buffer, or + * end-of-file, whichever comes first. It will then close the file + * descriptor. In this case (and in this case alone), the method + * {@link #bufferSeek} becomes useful, and can be used by an extending + * class to implement an efficient <code>seek</code> operation on the file. + * + * @param fileno the file descriptor to be handled by this object + * @param filename the file name associated with this descriptor; this may be + * the empty string + * @param bufsize a size suggested for the input buffer, or zero to + * accept the default + * @param fillBufferAndClose if true, read the entire contents of the + * file into memory + * @param assertIsSeekable if true, the caller is asserting that the + * given file descriptor points to a seekable object (presumably because + * it will depend on it being so). If this is not the case (the + * descriptor refers to a pipe or other non-seekable, and + * non-mappable, object), then throw an exception. If this is false, + * no assertion is being made; it is not being asserted that the + * object is non-seekable. + * + * @throws InputByteStreamError if there is some other problem reading + * the file; or if a negative buffer size is given; or if the + * assertion described for parameter <code>assertIsSeekable</code> + * turns out to be false. + * + * @return true on success + */ +bool InputByteStream::bindToFileDescriptor(int fileno, + string filename, + int bufsize, + bool fillBufferAndClose, + bool assertIsSeekable) + throw (InputByteStreamError) +{ + fd_ = fileno; + if (filename.length() == 0) { + char filenamebuf[20]; // just in case fileno is a _large_ number... + sprintf(filenamebuf, "fd:%d", fileno); + fname_ = filenamebuf; + } else { + fname_ = filename; + } + + eof_ = false; + + if (bufsize < 0) + throw InputByteStreamError("InputByteStream: negative bufsize"); + + buflen_ = 0; + if (buflen_ == 0 && bufsize != 0) + buflen_ = bufsize; + if (buflen_ == 0 && default_buffer_length_ != 0) + buflen_ = default_buffer_length_; + + bool isSeekable; +#ifdef HAVE_SYS_STAT_H + struct stat S; + if (fstat(fd_, &S) == 0) { + if (verbosity_ > normal) + cerr << "File descriptor " << fd_ << " OK:" + << " st_rdev=" << S.st_rdev + << " st_mode=" << S.st_mode + << " pipe=" << (S_ISFIFO(S.st_mode) ? "yes" : "no") + << " st_size=" << S.st_size +#ifndef WIN32 + << " st_blksize=" << S.st_blksize +#endif // WIN32 + << endl; + isSeekable = S_ISREG(S.st_mode); + // This mode can't be S_ISLNK, since this wasn't lstat(). + // The mode could be a FIFO. Anything else is probably a + // user error, which will be caught with normal processing in + // the caller. +#ifndef WIN32 + if (buflen_ == 0) + buflen_ = S.st_blksize; +#endif // WIN32 + } else { + string errmsg = strerror(errno); + throw InputByteStreamError("File descriptor not open: " + errmsg); + } +#else + isSeekable = false; // we don't know it isn't; but we + // can't be sure it is, so be safe +#endif /* HAVE_SYS_STAT_H */ + + if (buflen_ == 0) + buflen_ = 1024; + + if (assertIsSeekable && !isSeekable) + throw InputByteStreamError + ("File " + fname_ + " is not seekable, contrary to assertion"); + +#ifdef HAVE_MMAP + if (isSeekable) { + +# if !defined(HAVE_SYS_STAT_H) + // we shouldn't have got here! + assert(false); +# endif /* !defined(HAVE_SYS_STAT_H) */ + + buflen_ = S.st_size; + errno = 0; + buf_ = reinterpret_cast<Byte*>(mmap(0, buflen_, + PROT_READ, MAP_SHARED, + fd_, 0)); +# if defined(MAP_FAILED) + if (buf_ == static_cast<Byte*>(MAP_FAILED)) +# else + // Some systems have mman.h, but don't declare the MAP_FAILED + // macro variable, though it's mandated by POSIX. In this case, + // just rely on errno being set + if (errno) +# endif + { + string errmsg = strerror(errno); + throw InputByteStreamError + ("Failed to map file " + fname_ + " (" + errmsg + ")"); + } + // Don't ::close(fd_) here: though we don't need it any more, + // leaving it open means that the file won't be reclaimed if + // it's unlinked while we're mapping it (that would be Bad). + // However, we do want fd_ to be negative, as a flag that the + // fd is now inaccessible, both in this class and, via + // getFD(), to extending classes. So save the mapped fd, so + // ::close(mappedfd_) can be closed explicitly within + // InputByteStream::close(). + // + // Now, according to the single-unix spec: ``The mmap() function + // adds an extra reference to the file associated with the + // file descriptor fildes which is not removed by a subsequent + // close() on that file descriptor. This reference is removed + // when there are no more mappings to the file.'' However the + // OS X man page (for example) makes no such guarantee. + // Therefore don't close it now, postponing the close until + // we munmap the file. This may be belt-and-braces, but it + // won't create a problem. + mappedfd_ = fd_; + fd_ = -1; + + p_ = buf_; + eob_ = buf_ + buflen_; + + } + else +#endif /* HAVE_MMAP */ + { + assert(buflen_ > 0); + buf_ = new Byte[buflen_]; + if (fillBufferAndClose) { + size_t real_length = certainly_read_(fd_, buf_, buflen_); + p_ = buf_; + eob_ = buf_ + real_length; + // Do not use close() here, since that also deallocates buf_, + // and sets eof_ true. + ::close(fd_); + fd_ = -1; + if (verbosity_ >= debug) { + cerr << "InputByteStream: read " + << real_length << '/' << buflen_ + << " from fd: buf_ is non zero? " + << (buf_ != 0 ? "yes" : "no") + << "; actual length=" << (eob_-buf_) + << ". Closed: fd=" << fd_ + << endl; + } + } else { + eob_ = p_ = buf_; + assert(p_ == buf_); + } + } + + assert(buf_ <= p_ && p_ <= eob_); + // Since from the client's point of view we haven't read anything yet, + // we can't be at EOF. + assert(!eof_); + + if (verbosity_ >= debug) + cerr << "InputByteStream: reading from fd " << fileno + << ", name=" << fname_ + << ", buffer length=" << buflen_ + << ", seekable=" << (isSeekable ? "yes" : "no") + << ", mapped=" << (mappedfd_ >= 0 ? "yes" : "no") + << (fd_ < 0 ? " (read completed and fd closed)" : "") + << endl; + + return true; +} + + +/** + * Opens a source. The source is specified as in {@link + * #InputByteStream(string)}. Throws an exception on any problems, + * so that if it returns, it has successfully opened the file, or determined + * that the file descriptor is (syntactically) valid. + * + * @param srcspec a source specification + * @return an open file descriptor + * @throws InputByteStreamError if there is any problem opening the file + */ +int InputByteStream::openSourceSpec(string srcspec) + throw (InputByteStreamError) +{ + int fd = -1; + string srcfn; + if (srcspec.substr(0,8).compare("<osfile>") == 0) { + srcfn = srcspec.substr(8); + } else if (srcspec.substr(0,6).compare("<osfd>") == 0) { + string fdstr = srcspec.substr(6); + errno = 0; + fd = STD::strtol(fdstr.c_str(), 0, 10); + if (errno != 0) { + string errmsg = "InputByteStream: Invalid source fd:"; + errmsg += fdstr; + errmsg += " ("; + errmsg += strerror(errno); + errmsg += ")"; + throw InputByteStreamError(errmsg); + } + if (fd < 0) { + throw InputByteStreamError + ("InputByteStream: negative source fd"); + } + } else { + // simple file name + srcfn = srcspec; + } + + if (fd < 0 && srcfn.size() == 0) + throw InputByteStreamError("InputByteStream: no source spec!"); + + assert(!(fd >= 0 && srcfn.size() > 0)); // not _both_ specified + + if (srcfn.size() > 0) { + assert(fd < 0); +#ifdef WIN32 + fd = _open(srcfn.c_str(), _O_RDONLY | _O_BINARY); +#else // WIN32 + fd = open(srcfn.c_str(), O_RDONLY); +#endif // WIN32 + if (verbosity_ > normal) + cerr << "InputByteStream: opening osfile:" << srcfn + << (fd >= 0 ? " OK" : " failed") << endl; + if (fd < 0) { + string errstr = strerror (errno); + throw InputByteStreamError + ("InputByteStream: can't open file " + srcfn + + " to read (" + errstr + ")"); + } + } + assert(fd >= 0); + + return fd; +} + +/** + * Read a given number of bytes, stopping when it has read the + * required number, or at end of file, whichever comes first. + * + * @param fd file descriptor + * @param b pointer to buffer to be filled + * @param len number of bytes to be read + * @return the number of bytes actually read + * + * @throws InputByteStreamError if there was an error reading the file + */ +size_t InputByteStream::certainly_read_(int fd, Byte* b, size_t len) + throw (InputByteStreamError) +{ + size_t totread = 0; + ssize_t thisread = 0; + + assert(fd >= 0); + + while (len > 0 + && (thisread = read(fd, (void*)b, len)) > 0) { + b += thisread; + len -= thisread; + totread += thisread; + } + if (thisread < 0) { + string errmsg = strerror(errno); + throw InputByteStreamError + ("InputByteStream: can't read file " + fname_ + ": " + errmsg); + } + return totread; +} + +/** + * Reads a byte from the stream. Increments the reading pointer. + * This method does not signal an error at end-of-file; if {@link + * #eof} is true or <em>becomes</em> true as a result of this attempt + * to read past the end of the file, then we return zero. That is, + * <code>eof()</code> does not return true immediately the last byte + * in the file has been read. + * + * @return the byte read, or zero if we are at the end of the file + * @throws InputByteStreamError if there is some problem reading the stream + */ +Byte InputByteStream::getByte(void) + throw (InputByteStreamError) +{ + if (eof()) + return 0; + + if (buf_ == 0) + throw InputByteStreamError + ("InputByteStream::getByte: called after stream closed"); + + assert(buf_ != 0 && buf_ <= p_ && p_ <= eob_); + + if (p_ == eob_) + read_buf_(); // alters p_ and eob_, and possibly eof_ + + Byte result; + + if (eof_) + result = 0; + else + result = *p_++; + + assert(buf_ <= p_ && p_ <= eob_); + + return result; +} + +/** + * Retrieves a block from the current position in the stream. Leaves + * the pointer pointing after the block returned. + * + * @param length the size of block desired + * + * @return a pointer to a block of bytes + * @throws InputByteStreamError if the requested number of bytes + * cannot be read, which includes the case of this method being + * called when <code>eof()</code> is true + */ +const Byte *InputByteStream::getBlock(unsigned int length) + throw (InputByteStreamError) +{ + Byte *ret; + + if (eof()) // slightly redundant check, but gives + // distinct report from + // not-enough-space error below + throw InputByteStreamError + ("InputByteStream::getBlock called after EOF"); + + if (buf_ == 0) + throw InputByteStreamError + ("InputByteStream::getBlock: called after stream closed"); + + assert(buf_ != 0 && buf_ <= p_ && p_ <= eob_); + + if (length <= eob_-p_) { + ret = p_; + p_ += length; + //cerr << "small: p_@" << p_-buf_ << endl; + } else { + // it's not all in the buffer: we'll need to read some more + if (fd_ < 0) { + // nothing more to read + char errmsg[100]; + sprintf(errmsg, "InputByteStream::getBlock: requested %d, but that's past EOF", length); + throw InputByteStreamError(errmsg); + } + bool read_ok; + size_t inbufalready = eob_-p_; + size_t mustread = length-inbufalready; // so (p_=(buf_+length)) <= eob_ + if (length <= buflen_) { + // whole block will fit in current buffer + STD::memmove((void*)buf_, (void*)p_, inbufalready); + read_ok = (certainly_read_(fd_, + buf_+inbufalready, + mustread) + == mustread); + //cerr << "medium: read_ok=" << (read_ok?"true":"false"); + } else { + // must expand buffer + int newbuflen = length * 3 / 2; // decent size + Byte* newbuf = new Byte[newbuflen]; + STD::memcpy((void*)newbuf, (void*)p_, inbufalready); + read_ok = (certainly_read_(fd_, + newbuf+inbufalready, + mustread) + == mustread); + if (read_ok) { + delete[] buf_; + buf_ = newbuf; + buflen_ = newbuflen; + } + //cerr << "large: read_ok=" << (read_ok?"true":"false"); + } + if (! read_ok) { + char errmsg[100]; + sprintf(errmsg, "InputByteStream::getBlock: requested %d, but that's past EOF", length); + throw InputByteStreamError(errmsg); + } + ret = buf_; + eob_ = p_ = buf_ + length; + //cerr << "; p=buf+" << p_-buf_ << ", eob=buf+" << eob_-buf_ << endl; + } + + assert(buf_ != 0 && buf_ <= p_ && p_ <= eob_); + + return ret; +} + +void InputByteStream::read_buf_() + throw (InputByteStreamError) +{ + if (fd_ < 0) { + eof_ = true; + return; + } + + assert(fd_ >= 0 && buf_ != 0); + + read_again: + ssize_t bufcontents = read(fd_, buf_, buflen_); + if (bufcontents < 0) + { + if (errno == EINTR) // interrupted system call + goto read_again; + + string errmsg = strerror(errno); + throw InputByteStreamError + ("InputByteStream::read_buf_:"+fname_+": read error (" + +errmsg+")"); + } + eof_ = (bufcontents == 0); + eob_ = buf_ + bufcontents; + if (verbosity_ >= debug) + cerr << "InputByteStream::read_buf_: read " + << bufcontents << '/' << buflen_ << " from fd " << fd_ + << "; eof=" << (eof_ ? "true" : "false") + << ", eob=buf+" << eob_-buf_ + << endl; + p_ = buf_; + + assert(buf_ != 0 && buf_ <= p_ && (eof_ || buf_ < eob_) && p_ <= eob_); +} + +/** + * Skips a given number of bytes forward in the stream. + * + * @param increment the number of bytes to move forward in the stream + * @throws InputByteStreamError if we skip past the end of file + */ +void InputByteStream::skip (unsigned int increment) + throw (InputByteStreamError) +{ + if (eof()) + throw InputByteStreamError("Skip while at EOF"); + + assert(buf_ != 0 && buf_ <= p_ && p_ <= eob_); + + if (fd_ < 0) { + // better be in the buffer already + p_ += increment; + if (p_ >= eob_) { + p_ = eob_; + eof_ = true; + throw InputByteStreamError("skip past end of file"); + } + } else { + if (increment >= eob_-p_) { + increment -= (eob_-p_); + read_buf_(); // changes p_ and eob_ + while (increment >= (eob_-p_)) { + if (eof_) + throw InputByteStreamError("skip past end of file"); + read_buf_(); // changes p_ and eob_ + increment -= (eob_-p_); + } + } + p_ += increment; + } + + assert(buf_ != 0 && buf_ <= p_ && p_ <= eob_); +} + +/** + * Seeks to a specific point in the buffer. This is only useful when + * the buffer holds the complete file, that is, when + * <code>bindToFileDescriptor</code> was called with parameter + * <code>fillBufferAndClose</code> true. + * + * @param offset the offset from the beginning of the buffer, where the + * current position is relocated to + * + * @throws InputByteStreamError if the offset would take the pointer + * outside the buffer, or if the stream has been closed + */ +void InputByteStream::bufferSeek(unsigned int offset) + throw (InputByteStreamError) +{ + if (buf_ == 0) + throw InputByteStreamError + ("Call to bufferSeek when stream has been closed"); + if (offset >= (buflen_)) // unsigned offset can't be negative + throw InputByteStreamError + ("Call to protected bufferSeek too large for buffer"); + + assert(buf_ != 0 && buf_ <= p_ && p_ <= eob_); + + p_ = buf_ + offset; + eof_ = (p_ == eob_); + if (verbosity_ >= debug) + cerr << "bufferSeek to " << offset + << "; eof=" << (eof_ ? "true" : "false") + << ", p=buf+" << p_-buf_ << ", eob=buf+" << eob_-buf_ + << endl; + + assert(buf_ != 0 && buf_ <= p_ && p_ <= eob_); +} + +/** + * Reloads the buffer, presumably after the file descriptor has been + * adjusted by an extending class. + */ +void InputByteStream::reloadBuffer(void) +{ + p_ = eob_; // triggers reading of buffer + eof_ = false; // we guess -- harmless if wrong + assert(fd_ >= 0 && buf_ != 0); // We don't rely on this + // assertion in this method, but + // if it is false, there's a + // programming error somewhere + if (verbosity_ >= debug) + cerr << "InputByteStream::reloadBuffer: p=buf+" << p_-buf_ + << " eob=buf+" << eob_-buf_ + << " eof=" << (eof_ ? "true" : "false") + << endl; + assert(buf_ != 0 && buf_ <= p_ && p_ <= eob_); +} + +/** + * Closes the stream, releasing all resources. + */ +void InputByteStream::close(void) +{ + if (verbosity_ > normal) + cerr << "InputByteStream::close" << endl; + + if (fd_ >= 0) + ::close(fd_); + fd_ = -1; + +#ifdef HAVE_MMAP + if (mappedfd_ >= 0) { + if (buf_ == 0) + cerr << "InputByteStream::close: -- odd, already deallocated" + << endl; + else { + if (munmap(reinterpret_cast<MMAP_TYPE>(buf_), buflen_) == -1) { + string errstr = strerror(errno); + cerr << "InputByteStream: close: can't unmap file: " + << errstr << endl; + } + buf_ = 0; + } + ::close(mappedfd_); + mappedfd_ = -1; + } +#endif + + if (buf_ != 0) { + delete[] buf_; + buf_ = 0; + } + + eof_ = true; + + assert(fd_ < 0 && mappedfd_ < 0 && buf_ == 0); +} + +/** + * Sets the default buffer size to be used for reading files. + * + * @param length the size, in bytes, of the input buffer + */ +void InputByteStream::setDefaultBufferSize(unsigned int length) +{ + default_buffer_length_ = length; +} + +/* +#if (sizeof(unsigned int) != 4) +// The code here is intended to deal with the case where (un)signed +// ints are 4 bytes long. It's actually simpler on machines where +// ints are longer, because we wouldn't have to do the two-stage +// subtraction (below) when n==4. I can't test this, however, so +// simply cause an error here. +#error "InputByteStream.cc assumes sizeof(unsigned int)==4" +#endif +*/ + +// Assumes: DVI file is big-endian - ie, MSB first (I can't find this +// explicitly stated in the spec); DVI integers are 2-complement +// (explicit in the spec). +// I _believe_ that the following code is independent of the host +// machine's bytesex and integer representation (2's-complement or +// not), but.... + +/** + * Obtains an n-byte signed integer from the stream, as a signed + * int. + * + * @param n the number of bytes to read, in the range 1--4 inclusive + * @return the next integer from the input stream, as a signed int + * @throws InputByteStreamError if parameter <code>n</code> was out of range + */ +signed int InputByteStream::getSIS(int n) + throw (InputByteStreamError) +{ + if (n<0 || n>4) + throw InputByteStreamError + ("InputByteStream:"+fname_+": bad argument to getSIS"); + unsigned int t = getByte(); + unsigned int pow2 = 128; // 2^7-1 is largest one-byte signed int + // 2^7=128 is most negative signed int + // 2^8-1 is -1 + for (int i=n-1; i>0; i--) + { + pow2 *= 256; + t *= 256; + t += getByte(); + } + signed int result; + if (t < pow2) + result = t; + else + // pow2 <= t < 2*pow2 + // t is actually a negative number - subtract off 2*pow2 + if (n < 4) + { + // t and 2*pow2 will both fit into a signed int + // so explicitly convert them to that _first_. + // I'm not sure if the result of subtracting an unsigned from + // a smaller unsigned (ie, whether it's a signed negative number, + // or, say, zero) is implementation-dependent or not. + result = static_cast<signed int>(t) + - static_cast<signed int>(2*pow2); + //result -= 2*pow2; + } + else + { + // n==4: t won't fit into a signed int, and 2*pow2 would + // overflow, so do the subtraction in two stages. A + // careless optimiser could mess this up. + t -= pow2; // now it'll fit + // 0 <= t < pow2 + result = pow2 - t; // a positive result in a signed variable + result = -result; + } + return result; +} + +/** + * Obtains an n-byte unsigned integer from the stream, + * as a signed int. + * + * @param n the number of bytes to read, in the range 1--3 inclusive + * (there are no 4-byte unsigned quantities in DVI files) + * @return the next integer from the input stream, as a signed int + * @throws InputByteStreamError if parameter <code>n</code> was out of range + */ +signed int InputByteStream::getSIU(int n) + throw (InputByteStreamError) +{ + // disallow n==4 - there are no unsigned 4-byte quantities in the DVI file + if (n<0 || n>3) + throw InputByteStreamError + ("InputByteStream:"+fname_+": bad argument to getSIU"); + unsigned int t = 0; + for (; n>0; n--) + { + t *= 256; + t += getByte(); + } + return static_cast<signed int>(t); +} + +/** + * Obtains an n-byte unsigned integer from the stream, as an + * unsigned int + * + * @param n the number of bytes to read, in the range 1--4 inclusive + * @return the next integer from the input stream, as an unsigned int + * @throws InputByteStreamError if parameter <code>n</code> was out of range + */ +unsigned int InputByteStream::getUIU(int n) + throw (InputByteStreamError) +{ + if (n<0 || n>4) + throw InputByteStreamError + ("InputByteStream:"+fname_+": bad argument to getUIU"); + unsigned int t = 0; + for (; n>0; n--) + { + t *= 256; + t += getByte(); + } + return t; +} + +/** + * Obtains an n-byte unsigned integer from the beginning of a + * <code>Byte</code> array, as an unsigned int. This has little + * specifically to do with Input streams, and is here as a convenience + * method. + * + * @param n the number of bytes to read, in the range 1--4 inclusive + * @param p a pointer to an array of <code>Byte</code> values + * @return the integer at the beginning of the given array, as an unsigned int + * @throws InputByteStreamError if parameter <code>n</code> was out of range + */ +unsigned int InputByteStream::getUIU(int n, const Byte *p) + throw (InputByteStreamError) +{ + if (n<0 || n>4) + throw InputByteStreamError + ("InputByteStream: bad argument to getUIU(int,Byte*)"); + unsigned int t = 0; + for (const Byte *b=p; n>0; n--, b++) + t = t*256 + static_cast<unsigned int>(*b); + return t; +} |