fltk/src/Fl_Image_Reader.cxx
Albrecht Schlosser 4075a14715 Clarify return values and fix a minor issue (#271)
Fix: Fl_Image_Reader::seek() would not clear the error flag when
reading from memory.
2021-09-25 20:19:51 +02:00

162 lines
4.0 KiB
C++

//
// Internal (Image) Reader class for the Fast Light Tool Kit (FLTK).
//
// Copyright 2020-2021 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
// file is missing or damaged, see the license at:
//
// https://www.fltk.org/COPYING.php
//
// Please see the following page on how to report bugs and issues:
//
// https://www.fltk.org/bugs.php
//
//
// Include necessary header files...
//
#include "Fl_Image_Reader.h"
#include <FL/fl_utf8.h>
#include <FL/fl_string.h>
#include <stdlib.h>
#include <string.h>
/*
This internal (undocumented) class reads data chunks from a file or from
memory in LSB-first byte order.
This class is used in Fl_GIF_Image and Fl_BMP_Image to avoid code
duplication and may be extended to be used in similar cases. Future
options might be to read data in MSB-first byte order or to add more
methods.
*/
// Initialize the reader to access the file system, filename is copied
// and stored.
int Fl_Image_Reader::open(const char *filename) {
if (!filename)
return -1;
pName = fl_strdup(filename);
if ( (pFile = fl_fopen(filename, "rb")) == NULL ) {
return -1;
}
pIsFile = 1;
return 0;
}
// Initialize the reader for memory access, name is copied and stored
int Fl_Image_Reader::open(const char *imagename, const unsigned char *data, const long datasize) {
if (imagename)
pName = fl_strdup(imagename);
if (data) {
pStart = pData = data;
pIsData = 1;
if (datasize > 0) {
pEnd = pStart + datasize;
}
return 0;
} else {
return -1;
}
}
// Close and destroy the reader
Fl_Image_Reader::~Fl_Image_Reader() {
if (pIsFile && pFile) {
fclose(pFile);
}
if (pName)
::free(pName);
}
// Read a single byte from memory or a file
uchar Fl_Image_Reader::read_byte() {
if (error()) // don't read after read error or EOF
return 0;
if (pIsFile) {
int ret = getc(pFile);
if (ret < 0) {
if (feof(pFile))
pError = 1;
else if (ferror(pFile))
pError = 2;
else
pError = 3; // unknown error
return 0;
}
return ret;
} else if (pIsData) {
if (pData < pEnd)
return *pData++;
pError = 1; // EOF
return 0;
}
pError = 3; // undefined mode
return 0;
}
// Read a 16-bit unsigned integer, LSB-first
unsigned short Fl_Image_Reader::read_word() {
unsigned char b0, b1; // Bytes from file or memory
b0 = read_byte();
b1 = read_byte();
if (error())
return 0;
return ((b1 << 8) | b0);
}
// Read a 32-bit unsigned integer, LSB-first
unsigned int Fl_Image_Reader::read_dword() {
unsigned char b0, b1, b2, b3; // Bytes from file or memory
b0 = read_byte();
b1 = read_byte();
b2 = read_byte();
b3 = read_byte();
if (error())
return 0;
return ((((((b3 << 8) | b2) << 8) | b1) << 8) | b0);
}
// Move the current read position to a byte offset from the beginning
// of the file or the original start address in memory.
// This method clears the error flag if the position is valid.
// If reading from memory and (pStart + n) overflows, then the result is undefined.
void Fl_Image_Reader::seek(unsigned int n) {
pError = 0;
if (pIsFile) {
int ret = fseek(pFile, n , SEEK_SET);
if (ret < 0)
pError = 2; // read / position error
return;
} else if (pIsData) {
if (pStart + n <= pEnd)
pData = pStart + n;
else
pError = 2; // read / position error
return;
}
// unknown mode (not initialized ?)
pError = 3;
}
// Get the current read position as a byte offset from the
// beginning of the file or the original start address in memory.
// This method does neither affect the error flag nor is it affected
// by the current error status. If reading from a file, this may
// return -1 or any error code from ftell().
long Fl_Image_Reader::tell() const {
if (pIsFile) {
return ftell(pFile);
} else if (pIsData) {
return long(pData - pStart);
}
return 0;
}