diff options
Diffstat (limited to 'src/io/stream')
-rw-r--r-- | src/io/stream/Makefile.tst | 48 | ||||
-rw-r--r-- | src/io/stream/README | 13 | ||||
-rw-r--r-- | src/io/stream/bufferstream.cpp | 144 | ||||
-rw-r--r-- | src/io/stream/bufferstream.h | 98 | ||||
-rw-r--r-- | src/io/stream/gzipstream.cpp | 459 | ||||
-rw-r--r-- | src/io/stream/gzipstream.h | 124 | ||||
-rw-r--r-- | src/io/stream/inkscapestream.cpp | 800 | ||||
-rw-r--r-- | src/io/stream/inkscapestream.h | 668 | ||||
-rw-r--r-- | src/io/stream/streamtest.cpp | 256 | ||||
-rw-r--r-- | src/io/stream/stringstream.cpp | 125 | ||||
-rw-r--r-- | src/io/stream/stringstream.h | 105 | ||||
-rw-r--r-- | src/io/stream/uristream.cpp | 231 | ||||
-rw-r--r-- | src/io/stream/uristream.h | 101 | ||||
-rw-r--r-- | src/io/stream/xsltstream.cpp | 248 | ||||
-rw-r--r-- | src/io/stream/xsltstream.h | 140 |
15 files changed, 3560 insertions, 0 deletions
diff --git a/src/io/stream/Makefile.tst b/src/io/stream/Makefile.tst new file mode 100644 index 0000000..2e3142d --- /dev/null +++ b/src/io/stream/Makefile.tst @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +############################################## +# +# Test makefile for InkscapeStreams +# +############################################## + + +CC = gcc +CXX = g++ + + +INC = -I. -I.. + +XSLT_CFLAGS = `pkg-config --cflags libxslt` +XSLT_LIBS = `pkg-config --libs libxslt` + +GLIBMM_CFLAGS = `pkg-config --cflags glibmm-2.4` +GLIBMM_LIBS = `pkg-config --libs glibmm-2.4` + +CFLAGS = -g $(GLIBMM_CFLAGS) $(XSLT_CFLAGS) +LIBS = $(GLIBMM_LIBS) $(XSLT_LIBS) ../uri.o -lz + +OBJ = \ +inkscapestream.o \ +base64stream.o \ +gzipstream.o \ +stringstream.o \ +uristream.o \ +xsltstream.o \ +ftos.o + +all: streamtest + +streamtest: inkscapestream.h libstream.a streamtest.o + $(CXX) -o streamtest streamtest.o libstream.a $(LIBS) + +libstream.a: $(OBJ) + ar crv libstream.a $(OBJ) + + +.cpp.o: + $(CXX) $(CFLAGS) $(INC) -c -o $@ $< + +clean: + -$(RM) *.o *.a + -$(RM) streamtest + diff --git a/src/io/stream/README b/src/io/stream/README new file mode 100644 index 0000000..67d8721 --- /dev/null +++ b/src/io/stream/README @@ -0,0 +1,13 @@ + +This directory contains code related to streams. + +Base class: + inkscapestream.h Used by other stream handling code and odf, filter-file + +Derived classes: + bufferstream.h Used by odf + gzipstream.h Used by repr-io.cpp + stringstream.h Used by rerp-io.cpp and ui/clipboard.cpp + Note file with same name in src/svg + uristream.h Used by repr-io.cpp + xsltstream.h Used by none one (except testfile) diff --git a/src/io/stream/bufferstream.cpp b/src/io/stream/bufferstream.cpp new file mode 100644 index 0000000..1723ee1 --- /dev/null +++ b/src/io/stream/bufferstream.cpp @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/** + * @file + * Phoebe DOM Implementation. + * + * This is a C++ approximation of the W3C DOM model, which follows + * fairly closely the specifications in the various .idl files, copies of + * which are provided for reference. Most important is this one: + * + * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/idl-definitions.html + *//* + * Authors: + * see git history + * Bob Jamison + * + * Copyright (C) 2018 Authors + * Released under GNU LGPL v2.1+, read the file 'COPYING' for more information. + */ + +/** + * This class provided buffered endpoints for input and output. + */ + +#include "bufferstream.h" + +namespace Inkscape +{ +namespace IO +{ + +//######################################################################### +//# B U F F E R I N P U T S T R E A M +//######################################################################### +/** + * + */ +BufferInputStream::BufferInputStream( + const std::vector<unsigned char> &sourceBuffer) + : buffer(sourceBuffer) +{ + position = 0; + closed = false; +} + +/** + * + */ +BufferInputStream::~BufferInputStream() += default; + +/** + * Returns the number of bytes that can be read (or skipped over) from + * this input stream without blocking by the next caller of a method for + * this input stream. + */ +int BufferInputStream::available() +{ + if (closed) + return -1; + return buffer.size() - position; +} + + +/** + * Closes this input stream and releases any system resources + * associated with the stream. + */ +void BufferInputStream::close() +{ + closed = true; +} + +/** + * Reads the next byte of data from the input stream. -1 if EOF + */ +int BufferInputStream::get() +{ + if (closed) + return -1; + if (position >= (int)buffer.size()) + return -1; + int ch = (int) buffer[position++]; + return ch; +} + + + + +//######################################################################### +//# B U F F E R O U T P U T S T R E A M +//######################################################################### + +/** + * + */ +BufferOutputStream::BufferOutputStream() +{ + closed = false; +} + +/** + * + */ +BufferOutputStream::~BufferOutputStream() += default; + +/** + * Closes this output stream and releases any system resources + * associated with this stream. + */ +void BufferOutputStream::close() +{ + closed = true; +} + +/** + * Flushes this output stream and forces any buffered output + * bytes to be written out. + */ +void BufferOutputStream::flush() +{ + //nothing to do +} + +/** + * Writes the specified byte to this output stream. + */ +int BufferOutputStream::put(char ch) +{ + if (closed) + return -1; + buffer.push_back(ch); + return 1; +} + + + + +} //namespace IO +} //namespace Inkscape + +//######################################################################### +//# E N D O F F I L E +//######################################################################### diff --git a/src/io/stream/bufferstream.h b/src/io/stream/bufferstream.h new file mode 100644 index 0000000..811ab0d --- /dev/null +++ b/src/io/stream/bufferstream.h @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/** + * @file + * Phoebe DOM Implementation. + * + * This is a C++ approximation of the W3C DOM model, which follows + * fairly closely the specifications in the various .idl files, copies of + * which are provided for reference. Most important is this one: + * + * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/idl-definitions.html + *//* + * Authors: + * see git history + * Bob Jamison + * + * Copyright (C) 2018 Authors + * Released under GNU LGPL v2.1+, read the file 'COPYING' for more information. + */ +#ifndef SEEN_BUFFERSTREAM_H +#define SEEN_BUFFERSTREAM_H + + +#include <vector> +#include "inkscapestream.h" + + +namespace Inkscape +{ +namespace IO +{ + +//######################################################################### +//# S T R I N G I N P U T S T R E A M +//######################################################################### + +/** + * This class is for reading character from a DOMString + * + */ +class BufferInputStream : public InputStream +{ + +public: + + BufferInputStream(const std::vector<unsigned char> &sourceBuffer); + ~BufferInputStream() override; + int available() override; + void close() override; + int get() override; + +private: + const std::vector<unsigned char> &buffer; + long position; + bool closed; + +}; // class BufferInputStream + + + + +//######################################################################### +//# B U F F E R O U T P U T S T R E A M +//######################################################################### + +/** + * This class is for sending a stream to a character buffer + * + */ +class BufferOutputStream : public OutputStream +{ + +public: + + BufferOutputStream(); + ~BufferOutputStream() override; + void close() override; + void flush() override; + int put(char ch) override; + virtual std::vector<unsigned char> &getBuffer() + { return buffer; } + + virtual void clear() + { buffer.clear(); } + +private: + std::vector<unsigned char> buffer; + bool closed; + +}; // class BufferOutputStream + + + +} //namespace IO +} //namespace Inkscape + + + +#endif // SEEN_BUFFERSTREAM_H diff --git a/src/io/stream/gzipstream.cpp b/src/io/stream/gzipstream.cpp new file mode 100644 index 0000000..03960b0 --- /dev/null +++ b/src/io/stream/gzipstream.cpp @@ -0,0 +1,459 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/** @file + * Zlib-enabled input and output streams + *//* + * Authors: + * see git history + * Bob Jamison <rjamison@titan.com> + * + * + * Copyright (C) 2018 Authors + * Released under GNU LGPL v2.1+, read the file 'COPYING' for more information. + */ +/* + * This is a thin wrapper of libz calls, in order + * to provide a simple interface to our developers + * for gzip input and output. + */ + +#include "gzipstream.h" +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <string> + +namespace Inkscape +{ +namespace IO +{ + +//######################################################################### +//# G Z I P I N P U T S T R E A M +//######################################################################### + +#define OUT_SIZE 4000 + +/** + * + */ +GzipInputStream::GzipInputStream(InputStream &sourceStream) + : BasicInputStream(sourceStream), + loaded(false), + totalIn(0), + totalOut(0), + outputBuf(nullptr), + srcBuf(nullptr), + crc(0), + srcCrc(0), + srcSiz(0), + srcConsumed(0), + srcLen(0), + outputBufPos(0), + outputBufLen(0) +{ + memset( &d_stream, 0, sizeof(d_stream) ); +} + +/** + * + */ +GzipInputStream::~GzipInputStream() +{ + close(); + if ( srcBuf ) { + delete[] srcBuf; + srcBuf = nullptr; + } + if ( outputBuf ) { + delete[] outputBuf; + outputBuf = nullptr; + } +} + +/** + * Returns the number of bytes that can be read (or skipped over) from + * this input stream without blocking by the next caller of a method for + * this input stream. + */ +int GzipInputStream::available() +{ + if (closed || !outputBuf) + return 0; + return outputBufLen - outputBufPos; +} + + +/** + * Closes this input stream and releases any system resources + * associated with the stream. + */ +void GzipInputStream::close() +{ + if (closed) + return; + + int zerr = inflateEnd(&d_stream); + if (zerr != Z_OK) { + printf("inflateEnd: Some kind of problem: %d\n", zerr); + } + + if ( srcBuf ) { + delete[] srcBuf; + srcBuf = nullptr; + } + if ( outputBuf ) { + delete[] outputBuf; + outputBuf = nullptr; + } + closed = true; +} + +/** + * Reads the next byte of data from the input stream. -1 if EOF + */ +int GzipInputStream::get() +{ + int ch = -1; + if (closed) { + // leave return value -1 + } + else if (!loaded && !load()) { + closed=true; + } else { + loaded = true; + + if ( outputBufPos >= outputBufLen ) { + // time to read more, if we can + fetchMore(); + } + + if ( outputBufPos < outputBufLen ) { + ch = (int)outputBuf[outputBufPos++]; + } + } + + return ch; +} + +#define FTEXT 0x01 +#define FHCRC 0x02 +#define FEXTRA 0x04 +#define FNAME 0x08 +#define FCOMMENT 0x10 + +bool GzipInputStream::load() +{ + crc = crc32(0L, Z_NULL, 0); + + std::vector<Byte> inputBuf; + while (true) + { + int ch = source.get(); + if (ch<0) + break; + inputBuf.push_back(static_cast<Byte>(ch & 0xff)); + } + long inputBufLen = inputBuf.size(); + + if (inputBufLen < 19) //header + tail + 1 + { + return false; + } + + srcLen = inputBuf.size(); + srcBuf = new (std::nothrow) Byte [srcLen]; + if (!srcBuf) { + return false; + } + + outputBuf = new (std::nothrow) unsigned char [OUT_SIZE]; + if ( !outputBuf ) { + delete[] srcBuf; + srcBuf = nullptr; + return false; + } + outputBufLen = 0; // Not filled in yet + + std::vector<unsigned char>::iterator iter; + Bytef *p = srcBuf; + for (iter=inputBuf.begin() ; iter != inputBuf.end() ; ++iter) + { + *p++ = *iter; + } + + int headerLen = 10; + + //Magic + //int val = (int)srcBuf[0]; + ////printf("val:%x\n", val); + //val = (int)srcBuf[1]; + ////printf("val:%x\n", val); + + ////Method + //val = (int)srcBuf[2]; + ////printf("val:%x\n", val); + + //flags + int flags = static_cast<int>(srcBuf[3]); + + ////time + //val = (int)srcBuf[4]; + //val = (int)srcBuf[5]; + //val = (int)srcBuf[6]; + //val = (int)srcBuf[7]; + + ////xflags + //val = (int)srcBuf[8]; + ////OS + //val = (int)srcBuf[9]; + +// if ( flags & FEXTRA ) { +// headerLen += 2; +// int xlen = +// TODO deal with optional header parts +// } + if ( flags & FNAME ) { + int cur = 10; + while ( srcBuf[cur] ) + { + cur++; + headerLen++; + } + headerLen++; + } + + + srcCrc = ((0x0ff & srcBuf[srcLen - 5]) << 24) + | ((0x0ff & srcBuf[srcLen - 6]) << 16) + | ((0x0ff & srcBuf[srcLen - 7]) << 8) + | ((0x0ff & srcBuf[srcLen - 8]) << 0); + //printf("srcCrc:%lx\n", srcCrc); + + srcSiz = ((0x0ff & srcBuf[srcLen - 1]) << 24) + | ((0x0ff & srcBuf[srcLen - 2]) << 16) + | ((0x0ff & srcBuf[srcLen - 3]) << 8) + | ((0x0ff & srcBuf[srcLen - 4]) << 0); + //printf("srcSiz:%lx/%ld\n", srcSiz, srcSiz); + + //outputBufLen = srcSiz + srcSiz/100 + 14; + + unsigned char *data = srcBuf + headerLen; + unsigned long dataLen = srcLen - (headerLen + 8); + //printf("%x %x\n", data[0], data[dataLen-1]); + + d_stream.zalloc = (alloc_func)nullptr; + d_stream.zfree = (free_func)nullptr; + d_stream.opaque = (voidpf)nullptr; + d_stream.next_in = data; + d_stream.avail_in = dataLen; + d_stream.next_out = outputBuf; + d_stream.avail_out = OUT_SIZE; + + int zerr = inflateInit2(&d_stream, -MAX_WBITS); + if ( zerr == Z_OK ) + { + zerr = fetchMore(); + } else { + printf("inflateInit2: Some kind of problem: %d\n", zerr); + } + + + return (zerr == Z_OK) || (zerr == Z_STREAM_END); +} + + +int GzipInputStream::fetchMore() +{ + // TODO assumes we aren't called till the buffer is empty + d_stream.next_out = outputBuf; + d_stream.avail_out = OUT_SIZE; + outputBufLen = 0; + outputBufPos = 0; + + int zerr = inflate( &d_stream, Z_SYNC_FLUSH ); + if ( zerr == Z_OK || zerr == Z_STREAM_END ) { + outputBufLen = OUT_SIZE - d_stream.avail_out; + if ( outputBufLen ) { + crc = crc32(crc, const_cast<const Bytef *>(outputBuf), outputBufLen); + } + //printf("crc:%lx\n", crc); +// } else if ( zerr != Z_STREAM_END ) { +// // TODO check to be sure this won't happen for partial end reads +// printf("inflate: Some kind of problem: %d\n", zerr); + } + + return zerr; +} + +//######################################################################### +//# G Z I P O U T P U T S T R E A M +//######################################################################### + +/** + * + */ +GzipOutputStream::GzipOutputStream(OutputStream &destinationStream) + : BasicOutputStream(destinationStream) +{ + + totalIn = 0; + totalOut = 0; + crc = crc32(0L, Z_NULL, 0); + + //Gzip header + destination.put(0x1f); + destination.put(0x8b); + + //Say it is compressed + destination.put(Z_DEFLATED); + + //flags + destination.put(0); + + //time + destination.put(0); + destination.put(0); + destination.put(0); + destination.put(0); + + //xflags + destination.put(0); + + //OS code - from zutil.h + //destination.put(OS_CODE); + //apparently, we should not explicitly include zutil.h + destination.put(0); + +} + +/** + * + */ +GzipOutputStream::~GzipOutputStream() +{ + close(); +} + +/** + * Closes this output stream and releases any system resources + * associated with this stream. + */ +void GzipOutputStream::close() +{ + if (closed) + return; + + flush(); + + //# Send the CRC + uLong outlong = crc; + for (int n = 0; n < 4; n++) + { + destination.put(static_cast<char>(outlong & 0xff)); + outlong >>= 8; + } + //# send the file length + outlong = totalIn & 0xffffffffL; + for (int n = 0; n < 4; n++) + { + destination.put(static_cast<char>(outlong & 0xff)); + outlong >>= 8; + } + + destination.close(); + closed = true; +} + +/** + * Flushes this output stream and forces any buffered output + * bytes to be written out. + */ +void GzipOutputStream::flush() +{ + if (closed || inputBuf.empty()) + { + return; + } + + uLong srclen = inputBuf.size(); + Bytef *srcbuf = new (std::nothrow) Bytef [srclen]; + if (!srcbuf) + { + return; + } + + uLong destlen = srclen; + Bytef *destbuf = new (std::nothrow) Bytef [(destlen + (srclen/100) + 13)]; + if (!destbuf) + { + delete[] srcbuf; + return; + } + + std::vector<unsigned char>::iterator iter; + Bytef *p = srcbuf; + for (iter=inputBuf.begin() ; iter != inputBuf.end() ; ++iter) + *p++ = *iter; + + crc = crc32(crc, const_cast<const Bytef *>(srcbuf), srclen); + + int zerr = compress(destbuf, static_cast<uLongf *>(&destlen), srcbuf, srclen); + if (zerr != Z_OK) + { + printf("Some kind of problem\n"); + } + + totalOut += destlen; + //skip the redundant zlib header and checksum + for (uLong i=2; i<destlen-4 ; i++) + { + destination.put((int)destbuf[i]); + } + + destination.flush(); + + inputBuf.clear(); + delete[] srcbuf; + delete[] destbuf; +} + + + +/** + * Writes the specified byte to this output stream. + */ +int GzipOutputStream::put(char ch) +{ + if (closed) + { + //probably throw an exception here + return -1; + } + + + //Add char to buffer + inputBuf.push_back(ch); + totalIn++; + return 1; +} + + + +} // namespace IO +} // namespace Inkscape + + +//######################################################################### +//# E N D O F F I L E +//######################################################################### + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/io/stream/gzipstream.h b/src/io/stream/gzipstream.h new file mode 100644 index 0000000..fc80f97 --- /dev/null +++ b/src/io/stream/gzipstream.h @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#ifndef SEEN_INKSCAPE_IO_GZIPSTREAM_H +#define SEEN_INKSCAPE_IO_GZIPSTREAM_H +/** + * @file + * Zlib-enabled input and output streams. + * + * This is a thin wrapper of libz calls, in order + * to provide a simple interface to our developers + * for gzip input and output. + */ +/* + * Authors: + * Bob Jamison <rjamison@titan.com> + * + * Copyright (C) 2004 Inkscape.org + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include <vector> +#include "inkscapestream.h" +#include <zlib.h> + +namespace Inkscape +{ +namespace IO +{ + +//######################################################################### +//# G Z I P I N P U T S T R E A M +//######################################################################### + +/** + * This class is for deflating a gzip-compressed InputStream source + * + */ +class GzipInputStream : public BasicInputStream +{ + +public: + + GzipInputStream(InputStream &sourceStream); + + ~GzipInputStream() override; + + int available() override; + + void close() override; + + int get() override; + +private: + + bool load(); + int fetchMore(); + + bool loaded; + + long totalIn; + long totalOut; + + unsigned char *outputBuf; + unsigned char *srcBuf; + + unsigned long crc; + unsigned long srcCrc; + unsigned long srcSiz; + unsigned long srcConsumed; + unsigned long srcLen; + long outputBufPos; + long outputBufLen; + + z_stream d_stream; +}; // class GzipInputStream + + + + +//######################################################################### +//# G Z I P O U T P U T S T R E A M +//######################################################################### + +/** + * This class is for gzip-compressing data going to the + * destination OutputStream + * + */ +class GzipOutputStream : public BasicOutputStream +{ + +public: + + GzipOutputStream(OutputStream &destinationStream); + + ~GzipOutputStream() override; + + void close() override; + + void flush() override; + + int put(char ch) override; + +private: + + std::vector<unsigned char> inputBuf; + + long totalIn; + long totalOut; + unsigned long crc; + +}; // class GzipOutputStream + + + + + + + +} // namespace IO +} // namespace Inkscape + + +#endif /* __INKSCAPE_IO_GZIPSTREAM_H__ */ diff --git a/src/io/stream/inkscapestream.cpp b/src/io/stream/inkscapestream.cpp new file mode 100644 index 0000000..bc6dc1d --- /dev/null +++ b/src/io/stream/inkscapestream.cpp @@ -0,0 +1,800 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Our base input/output stream classes. These are is directly + * inherited from iostreams, and includes any extra + * functionality that we might need. + * + * Authors: + * Bob Jamison <rjamison@titan.com> + * + * Copyright (C) 2004 Inkscape.org + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include <cstdlib> +#include "inkscapestream.h" + +namespace Inkscape +{ +namespace IO +{ + +//######################################################################### +//# U T I L I T Y +//######################################################################### + +void pipeStream(InputStream &source, OutputStream &dest) +{ + for (;;) + { + int ch = source.get(); + if (ch<0) + break; + dest.put(ch); + } + dest.flush(); +} + +//######################################################################### +//# B A S I C I N P U T S T R E A M +//######################################################################### + + +/** + * + */ +BasicInputStream::BasicInputStream(InputStream &sourceStream) + : source(sourceStream) +{ + closed = false; +} + +/** + * Returns the number of bytes that can be read (or skipped over) from + * this input stream without blocking by the next caller of a method for + * this input stream. + */ +int BasicInputStream::available() +{ + if (closed) + return 0; + return source.available(); +} + + +/** + * Closes this input stream and releases any system resources + * associated with the stream. + */ +void BasicInputStream::close() +{ + if (closed) + return; + source.close(); + closed = true; +} + +/** + * Reads the next byte of data from the input stream. -1 if EOF + */ +int BasicInputStream::get() +{ + if (closed) + return -1; + return source.get(); +} + + + +//######################################################################### +//# B A S I C O U T P U T S T R E A M +//######################################################################### + +/** + * + */ +BasicOutputStream::BasicOutputStream(OutputStream &destinationStream) + : destination(destinationStream) +{ + closed = false; +} + +/** + * Closes this output stream and releases any system resources + * associated with this stream. + */ +void BasicOutputStream::close() +{ + if (closed) + return; + destination.close(); + closed = true; +} + +/** + * Flushes this output stream and forces any buffered output + * bytes to be written out. + */ +void BasicOutputStream::flush() +{ + if (closed) + return; + destination.flush(); +} + +/** + * Writes the specified byte to this output stream. + */ +int BasicOutputStream::put(char ch) +{ + if (closed) + return -1; + destination.put(ch); + return 1; +} + + + +//######################################################################### +//# B A S I C R E A D E R +//######################################################################### +/** + * + */ +BasicReader::BasicReader(Reader &sourceReader) +{ + source = &sourceReader; +} + +/** + * Returns the number of bytes that can be read (or skipped over) from + * this reader without blocking by the next caller of a method for + * this reader. + */ +int BasicReader::available() +{ + if (source) + return source->available(); + else + return 0; +} + + +/** + * Closes this reader and releases any system resources + * associated with the reader. + */ +void BasicReader::close() +{ + if (source) + source->close(); +} + +/** + * Reads the next byte of data from the reader. + */ +char BasicReader::get() +{ + if (source) + return source->get(); + else + return (char)-1; +} + + +/** + * Reads a line of data from the reader. + */ +Glib::ustring BasicReader::readLine() +{ + Glib::ustring str; + while (available() > 0) + { + char ch = get(); + if (ch == '\n') + break; + str.push_back(ch); + } + return str; +} + +/** + * Reads a line of data from the reader. + */ +Glib::ustring BasicReader::readWord() +{ + Glib::ustring str; + while (available() > 0) + { + char ch = get(); + if (!std::isprint(ch)) + break; + str.push_back(ch); + } + return str; +} + + +static bool getLong(Glib::ustring &str, long *val) +{ + const char *begin = str.raw().c_str(); + char *end; + long ival = strtol(begin, &end, 10); + if (str == end) + return false; + *val = ival; + return true; +} + +static bool getULong(Glib::ustring &str, unsigned long *val) +{ + const char *begin = str.raw().c_str(); + char *end; + unsigned long ival = strtoul(begin, &end, 10); + if (str == end) + return false; + *val = ival; + return true; +} + +static bool getDouble(Glib::ustring &str, double *val) +{ + const char *begin = str.raw().c_str(); + char *end; + double ival = strtod(begin, &end); + if (str == end) + return false; + *val = ival; + return true; +} + + + +const Reader &BasicReader::readBool (bool& val ) +{ + Glib::ustring buf = readWord(); + if (buf == "true") + val = true; + else + val = false; + return *this; +} + +const Reader &BasicReader::readShort (short& val ) +{ + Glib::ustring buf = readWord(); + long ival; + if (getLong(buf, &ival)) + val = (short) ival; + return *this; +} + +const Reader &BasicReader::readUnsignedShort (unsigned short& val ) +{ + Glib::ustring buf = readWord(); + unsigned long ival; + if (getULong(buf, &ival)) + val = (unsigned short) ival; + return *this; +} + +const Reader &BasicReader::readInt (int& val ) +{ + Glib::ustring buf = readWord(); + long ival; + if (getLong(buf, &ival)) + val = (int) ival; + return *this; +} + +const Reader &BasicReader::readUnsignedInt (unsigned int& val ) +{ + Glib::ustring buf = readWord(); + unsigned long ival; + if (getULong(buf, &ival)) + val = (unsigned int) ival; + return *this; +} + +const Reader &BasicReader::readLong (long& val ) +{ + Glib::ustring buf = readWord(); + long ival; + if (getLong(buf, &ival)) + val = ival; + return *this; +} + +const Reader &BasicReader::readUnsignedLong (unsigned long& val ) +{ + Glib::ustring buf = readWord(); + unsigned long ival; + if (getULong(buf, &ival)) + val = ival; + return *this; +} + +const Reader &BasicReader::readFloat (float& val ) +{ + Glib::ustring buf = readWord(); + double ival; + if (getDouble(buf, &ival)) + val = (float)ival; + return *this; +} + +const Reader &BasicReader::readDouble (double& val ) +{ + Glib::ustring buf = readWord(); + double ival; + if (getDouble(buf, &ival)) + val = ival; + return *this; +} + + + +//######################################################################### +//# I N P U T S T R E A M R E A D E R +//######################################################################### + + +InputStreamReader::InputStreamReader(InputStream &inputStreamSource) + : inputStream(inputStreamSource) +{ +} + + + +/** + * Close the underlying OutputStream + */ +void InputStreamReader::close() +{ + inputStream.close(); +} + +/** + * Flush the underlying OutputStream + */ +int InputStreamReader::available() +{ + return inputStream.available(); +} + +/** + * Overloaded to receive its bytes from an InputStream + * rather than a Reader + */ +char InputStreamReader::get() +{ + char ch = inputStream.get(); + return ch; +} + + + +//######################################################################### +//# S T D R E A D E R +//######################################################################### + + +/** + * + */ +StdReader::StdReader() +{ + inputStream = new StdInputStream(); +} + +/** + * + */ +StdReader::~StdReader() +{ + delete inputStream; +} + + + +/** + * Close the underlying OutputStream + */ +void StdReader::close() +{ + inputStream->close(); +} + +/** + * Flush the underlying OutputStream + */ +int StdReader::available() +{ + return inputStream->available(); +} + +/** + * Overloaded to receive its bytes from an InputStream + * rather than a Reader + */ +char StdReader::get() +{ + char ch = inputStream->get(); + return ch; +} + + + + + +//######################################################################### +//# B A S I C W R I T E R +//######################################################################### + +/** + * + */ +BasicWriter::BasicWriter(Writer &destinationWriter) +{ + destination = &destinationWriter; +} + +/** + * Closes this writer and releases any system resources + * associated with this writer. + */ +void BasicWriter::close() +{ + if (destination) + destination->close(); +} + +/** + * Flushes this output stream and forces any buffered output + * bytes to be written out. + */ +void BasicWriter::flush() +{ + if (destination) + destination->flush(); +} + +/** + * Writes the specified byte to this output writer. + */ +void BasicWriter::put(char ch) +{ + if (destination) + destination->put(ch); +} + +/** + * Provide printf()-like formatting + */ +Writer &BasicWriter::printf(char const *fmt, ...) +{ + va_list args; + va_start(args, fmt); + gchar *buf = g_strdup_vprintf(fmt, args); + va_end(args); + if (buf) { + writeString(buf); + g_free(buf); + } + return *this; +} +/** + * Writes the specified character to this output writer. + */ +Writer &BasicWriter::writeChar(char ch) +{ + put(ch); + return *this; +} + + +/** + * Writes the specified unicode string to this output writer. + */ +Writer &BasicWriter::writeUString(const Glib::ustring &str) +{ + writeStdString(str.raw()); + return *this; +} + +/** + * Writes the specified standard string to this output writer. + */ +Writer &BasicWriter::writeStdString(const std::string &str) +{ + for (char it : str) { + put(it); + } + return *this; +} + +/** + * Writes the specified character string to this output writer. + */ +Writer &BasicWriter::writeString(const char *str) +{ + std::string tmp; + if (str) + tmp = str; + else + tmp = "null"; + writeStdString(tmp); + return *this; +} + + + + +/** + * + */ +Writer &BasicWriter::writeBool (bool val ) +{ + if (val) + writeString("true"); + else + writeString("false"); + return *this; +} + + +/** + * + */ +Writer &BasicWriter::writeShort (short val ) +{ + gchar *buf = g_strdup_printf("%d", val); + if (buf) { + writeString(buf); + g_free(buf); + } + return *this; +} + + + +/** + * + */ +Writer &BasicWriter::writeUnsignedShort (unsigned short val ) +{ + gchar *buf = g_strdup_printf("%u", val); + if (buf) { + writeString(buf); + g_free(buf); + } + return *this; +} + +/** + * + */ +Writer &BasicWriter::writeInt (int val) +{ + gchar *buf = g_strdup_printf("%d", val); + if (buf) { + writeString(buf); + g_free(buf); + } + return *this; +} + +/** + * + */ +Writer &BasicWriter::writeUnsignedInt (unsigned int val) +{ + gchar *buf = g_strdup_printf("%u", val); + if (buf) { + writeString(buf); + g_free(buf); + } + return *this; +} + +/** + * + */ +Writer &BasicWriter::writeLong (long val) +{ + gchar *buf = g_strdup_printf("%ld", val); + if (buf) { + writeString(buf); + g_free(buf); + } + return *this; +} + +/** + * + */ +Writer &BasicWriter::writeUnsignedLong(unsigned long val) +{ + gchar *buf = g_strdup_printf("%lu", val); + if (buf) { + writeString(buf); + g_free(buf); + } + return *this; +} + +/** + * + */ +Writer &BasicWriter::writeFloat(float val) +{ +#if 1 + gchar *buf = g_strdup_printf("%8.3f", val); + if (buf) { + writeString(buf); + g_free(buf); + } +#else + std::string tmp = ftos(val, 'g', 8, 3, 0); + writeStdString(tmp); +#endif + return *this; +} + +/** + * + */ +Writer &BasicWriter::writeDouble(double val) +{ +#if 1 + gchar *buf = g_strdup_printf("%8.3f", val); + if (buf) { + writeString(buf); + g_free(buf); + } +#else + std::string tmp = ftos(val, 'g', 8, 3, 0); + writeStdString(tmp); +#endif + return *this; +} + + +Writer& operator<< (Writer &writer, char val) + { return writer.writeChar(val); } + +Writer& operator<< (Writer &writer, Glib::ustring &val) + { return writer.writeUString(val); } + +Writer& operator<< (Writer &writer, std::string &val) + { return writer.writeStdString(val); } + +Writer& operator<< (Writer &writer, char const *val) + { return writer.writeString(val); } + +Writer& operator<< (Writer &writer, bool val) + { return writer.writeBool(val); } + +Writer& operator<< (Writer &writer, short val) + { return writer.writeShort(val); } + +Writer& operator<< (Writer &writer, unsigned short val) + { return writer.writeUnsignedShort(val); } + +Writer& operator<< (Writer &writer, int val) + { return writer.writeInt(val); } + +Writer& operator<< (Writer &writer, unsigned int val) + { return writer.writeUnsignedInt(val); } + +Writer& operator<< (Writer &writer, long val) + { return writer.writeLong(val); } + +Writer& operator<< (Writer &writer, unsigned long val) + { return writer.writeUnsignedLong(val); } + +Writer& operator<< (Writer &writer, float val) + { return writer.writeFloat(val); } + +Writer& operator<< (Writer &writer, double val) + { return writer.writeDouble(val); } + + + +//######################################################################### +//# O U T P U T S T R E A M W R I T E R +//######################################################################### + + +OutputStreamWriter::OutputStreamWriter(OutputStream &outputStreamDest) + : outputStream(outputStreamDest) +{ +} + + + +/** + * Close the underlying OutputStream + */ +void OutputStreamWriter::close() +{ + flush(); + outputStream.close(); +} + +/** + * Flush the underlying OutputStream + */ +void OutputStreamWriter::flush() +{ + outputStream.flush(); +} + +/** + * Overloaded to redirect the output chars from the next Writer + * in the chain to an OutputStream instead. + */ +void OutputStreamWriter::put(char ch) +{ + outputStream.put(ch); +} + +//######################################################################### +//# S T D W R I T E R +//######################################################################### + + +/** + * + */ +StdWriter::StdWriter() +{ + outputStream = new StdOutputStream(); +} + + +/** + * + */ +StdWriter::~StdWriter() +{ + delete outputStream; +} + + + +/** + * Close the underlying OutputStream + */ +void StdWriter::close() +{ + flush(); + outputStream->close(); +} + +/** + * Flush the underlying OutputStream + */ +void StdWriter::flush() +{ + outputStream->flush(); +} + +/** + * Overloaded to redirect the output chars from the next Writer + * in the chain to an OutputStream instead. + */ +void StdWriter::put(char ch) +{ + outputStream->put(ch); +} + + +} // namespace IO +} // namespace Inkscape + + +//######################################################################### +//# E N D O F F I L E +//######################################################################### diff --git a/src/io/stream/inkscapestream.h b/src/io/stream/inkscapestream.h new file mode 100644 index 0000000..68c28ba --- /dev/null +++ b/src/io/stream/inkscapestream.h @@ -0,0 +1,668 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#ifndef SEEN_INKSCAPE_IO_INKSCAPESTREAM_H +#define SEEN_INKSCAPE_IO_INKSCAPESTREAM_H +/* + * Authors: + * Bob Jamison <rjamison@titan.com> + * + * Copyright (C) 2004 Inkscape.org + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include <cstdio> +#include <glibmm/ustring.h> + +namespace Inkscape +{ +namespace IO +{ + +class StreamException : public std::exception +{ +public: + + StreamException(const char *theReason) noexcept + { reason = theReason; } + StreamException(Glib::ustring &theReason) noexcept + { reason = theReason; } + ~StreamException() noexcept override + = default; + char const *what() const noexcept override + { return reason.c_str(); } + +private: + Glib::ustring reason; + +}; + +//######################################################################### +//# I N P U T S T R E A M +//######################################################################### + +/** + * This interface is the base of all input stream classes. Users who wish + * to make an InputStream that is part of a chain should inherit from + * BasicInputStream. Inherit from this class to make a source endpoint, + * such as a URI or buffer. + * + */ +class InputStream +{ + +public: + + /** + * Constructor. + */ + InputStream() = default; + + /** + * Destructor + */ + virtual ~InputStream() = default; + + /** + * Return the number of bytes that are currently available + * to be read + */ + virtual int available() = 0; + + /** + * Do whatever it takes to 'close' this input stream + * The most likely implementation of this method will be + * for endpoints that use a resource for their data. + */ + virtual void close() = 0; + + /** + * Read one byte from this input stream. This is a blocking + * call. If no data is currently available, this call will + * not return until it exists. If the user does not want + * their code to block, then the usual solution is: + * if (available() > 0) + * myChar = get(); + * This call returns -1 on end-of-file. + */ + virtual int get() = 0; + +}; // class InputStream + + + + +/** + * This is the class that most users should inherit, to provide + * their own streams. + * + */ +class BasicInputStream : public InputStream +{ + +public: + + BasicInputStream(InputStream &sourceStream); + + ~BasicInputStream() override = default; + + int available() override; + + void close() override; + + int get() override; + +protected: + + bool closed; + + InputStream &source; + +private: + + +}; // class BasicInputStream + + + +/** + * Convenience class for reading from standard input + */ +class StdInputStream : public InputStream +{ +public: + + int available() override + { return 0; } + + void close() override + { /* do nothing */ } + + int get() override + { return getchar(); } + +}; + + + + + + +//######################################################################### +//# O U T P U T S T R E A M +//######################################################################### + +/** + * This interface is the base of all input stream classes. Users who wish + * to make an OutputStream that is part of a chain should inherit from + * BasicOutputStream. Inherit from this class to make a destination endpoint, + * such as a URI or buffer. + */ +class OutputStream +{ + +public: + + /** + * Constructor. + */ + OutputStream() = default; + + /** + * Destructor + */ + virtual ~OutputStream() = default; + + /** + * This call should + * 1. flush itself + * 2. close itself + * 3. close the destination stream + */ + virtual void close() = 0; + + /** + * This call should push any pending data it might have to + * the destination stream. It should NOT call flush() on + * the destination stream. + */ + virtual void flush() = 0; + + /** + * Send one byte to the destination stream. + */ + virtual int put(char ch) = 0; + + +}; // class OutputStream + + +/** + * This is the class that most users should inherit, to provide + * their own output streams. + */ +class BasicOutputStream : public OutputStream +{ + +public: + + BasicOutputStream(OutputStream &destinationStream); + + ~BasicOutputStream() override = default; + + void close() override; + + void flush() override; + + int put(char ch) override; + +protected: + + bool closed; + + OutputStream &destination; + + +}; // class BasicOutputStream + + + +/** + * Convenience class for writing to standard output + */ +class StdOutputStream : public OutputStream +{ +public: + + void close() override + { } + + void flush() override + { } + + int put(char ch) override + {return putchar(ch); } + +}; + + + + +//######################################################################### +//# R E A D E R +//######################################################################### + + +/** + * This interface and its descendants are for unicode character-oriented input + * + */ +class Reader +{ + +public: + + /** + * Constructor. + */ + Reader() = default; + + /** + * Destructor + */ + virtual ~Reader() = default; + + + virtual int available() = 0; + + virtual void close() = 0; + + virtual char get() = 0; + + virtual Glib::ustring readLine() = 0; + + virtual Glib::ustring readWord() = 0; + + /* Input formatting */ + virtual const Reader& readBool (bool& val ) = 0; + virtual const Reader& operator>> (bool& val ) = 0; + + virtual const Reader& readShort (short &val) = 0; + virtual const Reader& operator>> (short &val) = 0; + + virtual const Reader& readUnsignedShort (unsigned short &val) = 0; + virtual const Reader& operator>> (unsigned short &val) = 0; + + virtual const Reader& readInt (int &val) = 0; + virtual const Reader& operator>> (int &val) = 0; + + virtual const Reader& readUnsignedInt (unsigned int &val) = 0; + virtual const Reader& operator>> (unsigned int &val) = 0; + + virtual const Reader& readLong (long &val) = 0; + virtual const Reader& operator>> (long &val) = 0; + + virtual const Reader& readUnsignedLong (unsigned long &val) = 0; + virtual const Reader& operator>> (unsigned long &val) = 0; + + virtual const Reader& readFloat (float &val) = 0; + virtual const Reader& operator>> (float &val) = 0; + + virtual const Reader& readDouble (double &val) = 0; + virtual const Reader& operator>> (double &val) = 0; + +}; // interface Reader + + + +/** + * This class and its descendants are for unicode character-oriented input + * + */ +class BasicReader : public Reader +{ + +public: + + BasicReader(Reader &sourceStream); + + ~BasicReader() override = default; + + int available() override; + + void close() override; + + char get() override; + + Glib::ustring readLine() override; + + Glib::ustring readWord() override; + + /* Input formatting */ + const Reader& readBool (bool& val ) override; + const Reader& operator>> (bool& val ) override + { return readBool(val); } + + const Reader& readShort (short &val) override; + const Reader& operator>> (short &val) override + { return readShort(val); } + + const Reader& readUnsignedShort (unsigned short &val) override; + const Reader& operator>> (unsigned short &val) override + { return readUnsignedShort(val); } + + const Reader& readInt (int &val) override; + const Reader& operator>> (int &val) override + { return readInt(val); } + + const Reader& readUnsignedInt (unsigned int &val) override; + const Reader& operator>> (unsigned int &val) override + { return readUnsignedInt(val); } + + const Reader& readLong (long &val) override; + const Reader& operator>> (long &val) override + { return readLong(val); } + + const Reader& readUnsignedLong (unsigned long &val) override; + const Reader& operator>> (unsigned long &val) override + { return readUnsignedLong(val); } + + const Reader& readFloat (float &val) override; + const Reader& operator>> (float &val) override + { return readFloat(val); } + + const Reader& readDouble (double &val) override; + const Reader& operator>> (double &val) override + { return readDouble(val); } + + +protected: + + Reader *source; + + BasicReader() + { source = nullptr; } + +private: + +}; // class BasicReader + + + +/** + * Class for placing a Reader on an open InputStream + * + */ +class InputStreamReader : public BasicReader +{ +public: + + InputStreamReader(InputStream &inputStreamSource); + + /*Overload these 3 for your implementation*/ + int available() override; + + void close() override; + + char get() override; + + +private: + + InputStream &inputStream; + + +}; + +/** + * Convenience class for reading formatted from standard input + * + */ +class StdReader : public BasicReader +{ +public: + + StdReader(); + + ~StdReader() override; + + /*Overload these 3 for your implementation*/ + int available() override; + + void close() override; + + char get() override; + + +private: + + InputStream *inputStream; + + +}; + + + + + +//######################################################################### +//# W R I T E R +//######################################################################### + +/** + * This interface and its descendants are for unicode character-oriented output + * + */ +class Writer +{ + +public: + + /** + * Constructor. + */ + Writer() = default; + + /** + * Destructor + */ + virtual ~Writer() = default; + + virtual void close() = 0; + + virtual void flush() = 0; + + virtual void put(char ch) = 0; + + /* Formatted output */ + virtual Writer& printf(char const *fmt, ...) G_GNUC_PRINTF(2,3) = 0; + + virtual Writer& writeChar(char val) = 0; + + virtual Writer& writeUString(const Glib::ustring &val) = 0; + + virtual Writer& writeStdString(const std::string &val) = 0; + + virtual Writer& writeString(const char *str) = 0; + + virtual Writer& writeBool (bool val ) = 0; + + virtual Writer& writeShort (short val ) = 0; + + virtual Writer& writeUnsignedShort (unsigned short val ) = 0; + + virtual Writer& writeInt (int val ) = 0; + + virtual Writer& writeUnsignedInt (unsigned int val ) = 0; + + virtual Writer& writeLong (long val ) = 0; + + virtual Writer& writeUnsignedLong (unsigned long val ) = 0; + + virtual Writer& writeFloat (float val ) = 0; + + virtual Writer& writeDouble (double val ) = 0; + + + +}; // interface Writer + + +/** + * This class and its descendants are for unicode character-oriented output + * + */ +class BasicWriter : public Writer +{ + +public: + + BasicWriter(Writer &destinationWriter); + + ~BasicWriter() override = default; + + /*Overload these 3 for your implementation*/ + void close() override; + + void flush() override; + + void put(char ch) override; + + + + /* Formatted output */ + Writer &printf(char const *fmt, ...) override G_GNUC_PRINTF(2,3); + + Writer& writeChar(char val) override; + + Writer& writeUString(const Glib::ustring &val) override; + + Writer& writeStdString(const std::string &val) override; + + Writer& writeString(const char *str) override; + + Writer& writeBool (bool val ) override; + + Writer& writeShort (short val ) override; + + Writer& writeUnsignedShort (unsigned short val ) override; + + Writer& writeInt (int val ) override; + + Writer& writeUnsignedInt (unsigned int val ) override; + + Writer& writeLong (long val ) override; + + Writer& writeUnsignedLong (unsigned long val ) override; + + Writer& writeFloat (float val ) override; + + Writer& writeDouble (double val ) override; + + +protected: + + Writer *destination; + + BasicWriter() + { destination = nullptr; } + +private: + +}; // class BasicWriter + + + +Writer& operator<< (Writer &writer, char val); + +Writer& operator<< (Writer &writer, Glib::ustring &val); + +Writer& operator<< (Writer &writer, std::string &val); + +Writer& operator<< (Writer &writer, char const *val); + +Writer& operator<< (Writer &writer, bool val); + +Writer& operator<< (Writer &writer, short val); + +Writer& operator<< (Writer &writer, unsigned short val); + +Writer& operator<< (Writer &writer, int val); + +Writer& operator<< (Writer &writer, unsigned int val); + +Writer& operator<< (Writer &writer, long val); + +Writer& operator<< (Writer &writer, unsigned long val); + +Writer& operator<< (Writer &writer, float val); + +Writer& operator<< (Writer &writer, double val); + + + + +/** + * Class for placing a Writer on an open OutputStream + * + */ +class OutputStreamWriter : public BasicWriter +{ +public: + + OutputStreamWriter(OutputStream &outputStreamDest); + + /*Overload these 3 for your implementation*/ + void close() override; + + void flush() override; + + void put(char ch) override; + + +private: + + OutputStream &outputStream; + + +}; + + +/** + * Convenience class for writing to standard output + */ +class StdWriter : public BasicWriter +{ +public: + StdWriter(); + + ~StdWriter() override; + + + void close() override; + + + void flush() override; + + + void put(char ch) override; + + +private: + + OutputStream *outputStream; + +}; + +//######################################################################### +//# U T I L I T Y +//######################################################################### + +void pipeStream(InputStream &source, OutputStream &dest); + + + +} // namespace IO +} // namespace Inkscape + + +#endif // SEEN_INKSCAPE_IO_INKSCAPESTREAM_H diff --git a/src/io/stream/streamtest.cpp b/src/io/stream/streamtest.cpp new file mode 100644 index 0000000..5d27058 --- /dev/null +++ b/src/io/stream/streamtest.cpp @@ -0,0 +1,256 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * TODO: insert short description here + *//* + * Authors: see git history + * + * Copyright (C) 2015 Authors + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + + +#include <stdio.h> +#include <limits.h> // realpath +#include <stdlib.h> // mkdtemp, realpath +#include <unistd.h> // chdir +#include <string.h> // strlen, strncpy, strrchr + +#include "inkscapestream.h" +#include "base64stream.h" +#include "gzipstream.h" +#include "stringstream.h" +#include "uristream.h" +#include "xsltstream.h" + +// quick way to pass the name of the executable into the test +char myself[PATH_MAX]; + +// names and path storage for other tests +char *xmlname = "crystalegg.xml"; +char xmlpath[PATH_MAX]; +char *xslname = "doc2html.xsl"; +char xslpath[PATH_MAX]; + +bool testUriStream() +{ + printf("######### UriStream copy ############\n"); + Inkscape::URI inUri(myself); + Inkscape::IO::UriInputStream ins(inUri); + Inkscape::URI outUri("streamtest.copy"); + Inkscape::IO::UriOutputStream outs(outUri); + + pipeStream(ins, outs); + + ins.close(); + outs.close(); + + return true; +} + +bool testWriter() +{ + printf("######### OutputStreamWriter ############\n"); + Inkscape::IO::StdOutputStream outs; + Inkscape::IO::OutputStreamWriter writer(outs); + + writer << "Hello, world! " << 123.45 << " times\n"; + + writer.printf("There are %f quick brown foxes in %d states\n", 123.45, 88); + + return true; +} + +bool testStdWriter() +{ + printf("######### StdWriter ############\n"); + Inkscape::IO::StdWriter writer; + + writer << "Hello, world! " << 123.45 << " times\n"; + + writer.printf("There are %f quick brown foxes in %d states\n", 123.45, 88); + + return true; +} + +bool testBase64() +{ + printf("######### Base64 Out ############\n"); + Inkscape::URI plainInUri(xmlpath); + Inkscape::IO::UriInputStream ins1(plainInUri); + + Inkscape::URI b64OutUri("crystalegg.xml.b64"); + Inkscape::IO::UriOutputStream outs1(b64OutUri); + Inkscape::IO::Base64OutputStream b64Outs(outs1); + + pipeStream(ins1, b64Outs); + + ins1.close(); + b64Outs.close(); + + printf("######### Base64 In ############\n"); + Inkscape::URI b64InUri("crystalegg.xml.b64"); + Inkscape::IO::UriInputStream ins2(b64InUri); + Inkscape::IO::Base64InputStream b64Ins(ins2); + + Inkscape::URI plainOutUri("crystalegg.xml.b64dec"); + Inkscape::IO::UriOutputStream outs2(plainOutUri); + + pipeStream(b64Ins, outs2); + + outs2.close(); + b64Ins.close(); + + return true; +} + +bool testXslt() +{ + printf("######### XSLT Sheet ############\n"); + Inkscape::URI xsltSheetUri(xslpath); + Inkscape::IO::UriInputStream xsltSheetIns(xsltSheetUri); + Inkscape::IO::XsltStyleSheet stylesheet(xsltSheetIns); + xsltSheetIns.close(); + + Inkscape::URI sourceUri(xmlpath); + Inkscape::IO::UriInputStream xmlIns(sourceUri); + + printf("######### XSLT Input ############\n"); + Inkscape::URI destUri("test.html"); + Inkscape::IO::UriOutputStream xmlOuts(destUri); + + Inkscape::IO::XsltInputStream xsltIns(xmlIns, stylesheet); + pipeStream(xsltIns, xmlOuts); + xsltIns.close(); + xmlOuts.close(); + + + printf("######### XSLT Output ############\n"); + + Inkscape::IO::UriInputStream xmlIns2(sourceUri); + + Inkscape::URI destUri2("test2.html"); + Inkscape::IO::UriOutputStream xmlOuts2(destUri2); + + Inkscape::IO::XsltOutputStream xsltOuts(xmlOuts2, stylesheet); + pipeStream(xmlIns2, xsltOuts); + xmlIns2.close(); + xsltOuts.close(); + + return true; +} + +bool testGzip() +{ + + printf("######### Gzip Output ############\n"); + Inkscape::URI gzUri("test.gz"); + Inkscape::URI sourceUri(xmlpath); + Inkscape::IO::UriInputStream sourceIns(sourceUri); + Inkscape::IO::UriOutputStream gzOuts(gzUri); + + Inkscape::IO::GzipOutputStream gzipOuts(gzOuts); + pipeStream(sourceIns, gzipOuts); + sourceIns.close(); + gzipOuts.close(); + + printf("######### Gzip Input ############\n"); + + Inkscape::IO::UriInputStream gzIns(gzUri); + Inkscape::URI destUri("crystalegg2.xml"); + Inkscape::IO::UriOutputStream destOuts(destUri); + + Inkscape::IO::GzipInputStream gzipIns(gzIns); + pipeStream(gzipIns, destOuts); + gzipIns.close(); + destOuts.close(); + + return true; +} + +bool doTest() +{ + if (!testUriStream()) + { + return false; + } + if (!testWriter()) + { + return false; + } + if (!testStdWriter()) + { + return false; + } + if (!testBase64()) + { + return false; + } + if (!testXslt()) + { + return false; + } + if (!testGzip()) + { + return false; + } + return true; +} + +void path_init(char *path, char *name) +{ + if (strlen(name)>PATH_MAX-strlen(myself)) + { + printf("merging paths would be too long\n"); + exit(1); + } + strncpy(path,myself,PATH_MAX); + char * ptr = strrchr(path,'/'); + if (!ptr) + { + printf("path '%s' is missing any slashes\n",path); + exit(1); + } + strncpy(ptr+1,name,strlen(name)+1); + path[PATH_MAX-1] = '\0'; + printf("'%s'\n",path); +} + + +int main(int argc, char **argv) +{ + if (!realpath(argv[0],myself)) + { + perror("realpath"); + return 1; + } + path_init(xmlpath,xmlname); + path_init(xslpath,xslname); + + // create temp files somewhere else instead of current dir + // TODO: clean them up too + char * testpath = strdup("/tmp/streamtest-XXXXXX"); + char * testpath2; + testpath2 = mkdtemp(testpath); + free(testpath); + if (!testpath2) + { + perror("mkdtemp"); + return 1; + } + if (chdir(testpath2)) + { + perror("chdir"); + return 1; + } + + if (!doTest()) + { + printf("#### Test failed\n"); + return 1; + } + else + { + printf("##### Test succeeded\n"); + } + return 0; +} diff --git a/src/io/stream/stringstream.cpp b/src/io/stream/stringstream.cpp new file mode 100644 index 0000000..0259869 --- /dev/null +++ b/src/io/stream/stringstream.cpp @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Our base String stream classes. We implement these to + * be based on Glib::ustring + * + * Authors: + * Bob Jamison <rjamison@titan.com> + * + * Copyright (C) 2004 Inkscape.org + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + + +#include "stringstream.h" + +namespace Inkscape +{ +namespace IO +{ + + +//######################################################################### +//# S T R I N G I N P U T S T R E A M +//######################################################################### + + +/** + * + */ +StringInputStream::StringInputStream(Glib::ustring &sourceString) + : buffer(sourceString) +{ + position = 0; +} + +/** + * + */ +StringInputStream::~StringInputStream() += default; + +/** + * Returns the number of bytes that can be read (or skipped over) from + * this input stream without blocking by the next caller of a method for + * this input stream. + */ +int StringInputStream::available() +{ + return buffer.size() - position; +} + + +/** + * Closes this input stream and releases any system resources + * associated with the stream. + */ +void StringInputStream::close() +{ +} + +/** + * Reads the next byte of data from the input stream. -1 if EOF + */ +int StringInputStream::get() +{ + if (position >= (int)buffer.size()) + return -1; + int ch = (int) buffer[position++]; + return ch; +} + + + + +//######################################################################### +//# S T R I N G O U T P U T S T R E A M +//######################################################################### + +/** + * + */ +StringOutputStream::StringOutputStream() += default; + +/** + * + */ +StringOutputStream::~StringOutputStream() += default; + +/** + * Closes this output stream and releases any system resources + * associated with this stream. + */ +void StringOutputStream::close() +{ +} + +/** + * Flushes this output stream and forces any buffered output + * bytes to be written out. + */ +void StringOutputStream::flush() +{ + //nothing to do +} + +/** + * Writes the specified byte to this output stream. + */ +int StringOutputStream::put(char ch) +{ + buffer.push_back(ch); + return 1; +} + + +} // namespace IO +} // namespace Inkscape + + +//######################################################################### +//# E N D O F F I L E +//######################################################################### diff --git a/src/io/stream/stringstream.h b/src/io/stream/stringstream.h new file mode 100644 index 0000000..3afb9a8 --- /dev/null +++ b/src/io/stream/stringstream.h @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * TODO: insert short description here + *//* + * Authors: see git history + * + * Copyright (C) 2018 Authors + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ +#ifndef __INKSCAPE_IO_STRINGSTREAM_H__ +#define __INKSCAPE_IO_STRINGSTREAM_H__ + +#include <glibmm/ustring.h> + +#include "inkscapestream.h" + + +namespace Inkscape +{ +namespace IO +{ + + +//######################################################################### +//# S T R I N G I N P U T S T R E A M +//######################################################################### + +/** + * This class is for reading character from a Glib::ustring + * + */ +class StringInputStream : public InputStream +{ + +public: + + StringInputStream(Glib::ustring &sourceString); + + ~StringInputStream() override; + + int available() override; + + void close() override; + + int get() override; + +private: + + Glib::ustring &buffer; + + long position; + +}; // class StringInputStream + + + + +//######################################################################### +//# S T R I N G O U T P U T S T R E A M +//######################################################################### + +/** + * This class is for sending a stream to a Glib::ustring + * + */ +class StringOutputStream : public OutputStream +{ + +public: + + StringOutputStream(); + + ~StringOutputStream() override; + + void close() override; + + void flush() override; + + int put(char ch) override; + + virtual Glib::ustring &getString() + { return buffer; } + + virtual void clear() + { buffer = ""; } + +private: + + Glib::ustring buffer; + + +}; // class StringOutputStream + + + + + + + +} // namespace IO +} // namespace Inkscape + + + +#endif /* __INKSCAPE_IO_STRINGSTREAM_H__ */ diff --git a/src/io/stream/uristream.cpp b/src/io/stream/uristream.cpp new file mode 100644 index 0000000..1596919 --- /dev/null +++ b/src/io/stream/uristream.cpp @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Our base String stream classes. We implement these to + * be based on Glib::ustring + * + * Authors: + * Bob Jamison <rjamison@titan.com> + * + * Copyright (C) 2004 Inkscape.org + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + + +#include "uristream.h" +#include "io/sys.h" +#include <string> +#include <cstring> + + +namespace Inkscape +{ +namespace IO +{ + +/* + * URI scheme types + */ +#define SCHEME_NONE 0 +#define SCHEME_FILE 1 +#define SCHEME_DATA 2 + +/* + * A temporary modification of Jon Cruz's portable fopen(). + * Simplified a bit, since we will always use binary +*/ + +#define FILE_READ 1 +#define FILE_WRITE 2 + +static FILE *fopen_utf8name( char const *utf8name, int mode ) +{ + FILE *fp = nullptr; + if (!utf8name) + { + return nullptr; + } + if (mode!=FILE_READ && mode!=FILE_WRITE) + { + return nullptr; + } + +#ifndef _WIN32 + gchar *filename = g_filename_from_utf8( utf8name, -1, nullptr, nullptr, nullptr ); + if ( filename ) { + if (mode == FILE_READ) + fp = std::fopen(filename, "rb"); + else + fp = std::fopen(filename, "wb"); + g_free(filename); + } +#else + { + gunichar2 *wideName = g_utf8_to_utf16( utf8name, -1, NULL, NULL, NULL ); + if ( wideName ) { + if (mode == FILE_READ) + fp = _wfopen( (wchar_t*)wideName, L"rb" ); + else + fp = _wfopen( (wchar_t*)wideName, L"wb" ); + g_free( wideName ); + } else { + gchar *safe = Inkscape::IO::sanitizeString(utf8name); + g_message("Unable to convert filename from UTF-8 to UTF-16 [%s]", safe); + g_free(safe); + } + } +#endif + + return fp; +} + + + +//######################################################################### +//# F I L E I N P U T S T R E A M +//######################################################################### + + +/** + * + */ +FileInputStream::FileInputStream(FILE *source) + : inf(source) +{ + if (!inf) { + Glib::ustring err = "FileInputStream passed NULL"; + throw StreamException(err); + } +} + +/** + * + */ +FileInputStream::~FileInputStream() +{ + close(); +} + +/** + * Returns the number of bytes that can be read (or skipped over) from + * this input stream without blocking by the next caller of a method for + * this input stream. + */ +int FileInputStream::available() +{ + return 0; +} + + +/** + * Closes this input stream and releases any system resources + * associated with the stream. + */ +void FileInputStream::close() +{ + if (!inf) + return; + fflush(inf); + fclose(inf); + inf=nullptr; +} + +/** + * Reads the next byte of data from the input stream. -1 if EOF + */ +int FileInputStream::get() +{ + int retVal = -1; + if (!inf || feof(inf)) + { + retVal = -1; + } + else + { + retVal = fgetc(inf); + } + + return retVal; +} + + + + +//######################################################################### +//# F I L E O U T P U T S T R E A M +//######################################################################### + +FileOutputStream::FileOutputStream(FILE *fp) + : ownsFile(false) + , outf(fp) +{ + if (!outf) { + Glib::ustring err = "FileOutputStream given null file "; + throw StreamException(err); + } +} + +/** + * + */ +FileOutputStream::~FileOutputStream() +{ + close(); +} + +/** + * Closes this output stream and releases any system resources + * associated with this stream. + */ +void FileOutputStream::close() +{ + if (!outf) + return; + fflush(outf); + if ( ownsFile ) + fclose(outf); + outf=nullptr; +} + +/** + * Flushes this output stream and forces any buffered output + * bytes to be written out. + */ +void FileOutputStream::flush() +{ + if (!outf) + return; + fflush(outf); +} + +/** + * Writes the specified byte to this output stream. + */ +int FileOutputStream::put(char ch) +{ + unsigned char uch; + + if (!outf) + return -1; + uch = (unsigned char)(ch & 0xff); + if (fputc(uch, outf) == EOF) { + Glib::ustring err = "ERROR writing to file "; + throw StreamException(err); + } + + return 1; +} + + + + + +} // namespace IO +} // namespace Inkscape + + +//######################################################################### +//# E N D O F F I L E +//######################################################################### + +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/io/stream/uristream.h b/src/io/stream/uristream.h new file mode 100644 index 0000000..f0544d8 --- /dev/null +++ b/src/io/stream/uristream.h @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#ifndef SEEN_INKSCAPE_IO_URISTREAM_H +#define SEEN_INKSCAPE_IO_URISTREAM_H +/** + * @file + * This should be the only way that we provide sources/sinks + * to any input/output stream. + */ +/* + * Authors: + * Bob Jamison <rjamison@titan.com> + * + * Copyright (C) 2004 Inkscape.org + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + + +#include "object/uri.h" + +#include "inkscapestream.h" + + +namespace Inkscape +{ + +class URI; + +namespace IO +{ + +//######################################################################### +//# F I L E I N P U T S T R E A M +//######################################################################### + +/** + * This class is for receiving a stream of data from a file + */ +class FileInputStream : public InputStream +{ + +public: + FileInputStream(FILE *source); + + ~FileInputStream() override; + + int available() override; + + void close() override; + + int get() override; + +private: + FILE *inf; //for file: uris + +}; // class FileInputStream + + + + +//######################################################################### +//# F I L E O U T P U T S T R E A M +//######################################################################### + +/** + * This class is for sending a stream to a destination file + */ +class FileOutputStream : public OutputStream +{ + +public: + + FileOutputStream(FILE *fp); + + ~FileOutputStream() override; + + void close() override; + + void flush() override; + + int put(char ch) override; + +private: + + bool ownsFile; + + FILE *outf; //for file: uris + +}; // class FileOutputStream + + + + + +} // namespace IO +} // namespace Inkscape + + +#endif // SEEN_INKSCAPE_IO_URISTREAM_H + +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/io/stream/xsltstream.cpp b/src/io/stream/xsltstream.cpp new file mode 100644 index 0000000..882db30 --- /dev/null +++ b/src/io/stream/xsltstream.cpp @@ -0,0 +1,248 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * XSL Transforming input and output classes + * + * Authors: + * Bob Jamison <ishmalius@gmail.com> + * + * Copyright (C) 2004-2008 Inkscape.org + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + + +#include "xsltstream.h" +#include "stringstream.h" +#include <libxslt/transform.h> + + + + +namespace Inkscape +{ +namespace IO +{ + +//######################################################################### +//# X S L T S T Y L E S H E E T +//######################################################################### + +/** + * + */ +XsltStyleSheet::XsltStyleSheet(InputStream &xsltSource) + + : stylesheet(nullptr) +{ + if (!read(xsltSource)) { + throw StreamException("read failed"); + } +} + +/** + * + */ +XsltStyleSheet::XsltStyleSheet() + : stylesheet(nullptr) +{ +} + + + +/** + * + */ +bool XsltStyleSheet::read(InputStream &xsltSource) +{ + StringOutputStream outs; + pipeStream(xsltSource, outs); + std::string strBuf = outs.getString().raw(); + xmlDocPtr doc = xmlParseMemory(strBuf.c_str(), strBuf.size()); + stylesheet = xsltParseStylesheetDoc(doc); + //following not necessary. handled by xsltFreeStylesheet(stylesheet); + //xmlFreeDoc(doc); + if (!stylesheet) + return false; + return true; +} + + +/** + * + */ +XsltStyleSheet::~XsltStyleSheet() +{ + if (stylesheet) + xsltFreeStylesheet(stylesheet); +} + + + +//######################################################################### +//# X S L T I N P U T S T R E A M +//######################################################################### + + +/** + * + */ +XsltInputStream::XsltInputStream(InputStream &xmlSource, XsltStyleSheet &sheet) + : BasicInputStream(xmlSource), stylesheet(sheet) +{ + //Load the data + StringOutputStream outs; + pipeStream(source, outs); + std::string strBuf = outs.getString().raw(); + + //Do the processing + const char *params[1]; + params[0] = nullptr; + xmlDocPtr srcDoc = xmlParseMemory(strBuf.c_str(), strBuf.size()); + xmlDocPtr resDoc = xsltApplyStylesheet(stylesheet.stylesheet, srcDoc, params); + xmlDocDumpFormatMemory(resDoc, &outbuf, &outsize, 1); + outpos = 0; + + //Free our mem + xmlFreeDoc(resDoc); + xmlFreeDoc(srcDoc); +} + +/** + * + */ +XsltInputStream::~XsltInputStream() +{ + xmlFree(outbuf); +} + +/** + * Returns the number of bytes that can be read (or skipped over) from + * this input stream without blocking by the next caller of a method for + * this input stream. + */ +int XsltInputStream::available() +{ + return outsize - outpos; +} + + +/** + * Closes this input stream and releases any system resources + * associated with the stream. + */ +void XsltInputStream::close() +{ + closed = true; +} + +/** + * Reads the next byte of data from the input stream. -1 if EOF + */ +int XsltInputStream::get() +{ + if (closed) + return -1; + if (outpos >= outsize) + return -1; + int ch = (int) outbuf[outpos++]; + return ch; +} + + + + + + +//######################################################################### +//# X S L T O U T P U T S T R E A M +//######################################################################### + +/** + * + */ +XsltOutputStream::XsltOutputStream(OutputStream &dest, XsltStyleSheet &sheet) + : BasicOutputStream(dest), stylesheet(sheet) +{ + flushed = false; +} + +/** + * + */ +XsltOutputStream::~XsltOutputStream() +{ + //do not automatically close +} + +/** + * Closes this output stream and releases any system resources + * associated with this stream. + */ +void XsltOutputStream::close() +{ + flush(); + destination.close(); +} + +/** + * Flushes this output stream and forces any buffered output + * bytes to be written out. + */ +void XsltOutputStream::flush() +{ + if (flushed) + { + destination.flush(); + return; + } + + //Do the processing + xmlChar *resbuf; + int resSize; + const char *params[1]; + params[0] = nullptr; + xmlDocPtr srcDoc = xmlParseMemory(outbuf.raw().c_str(), outbuf.size()); + xmlDocPtr resDoc = xsltApplyStylesheet(stylesheet.stylesheet, srcDoc, params); + xmlDocDumpFormatMemory(resDoc, &resbuf, &resSize, 1); + /* + xmlErrorPtr err = xmlGetLastError(); + if (err) + { + throw StreamException(err->message); + } + */ + + for (int i=0 ; i<resSize ; i++) + { + char ch = resbuf[i]; + destination.put(ch); + } + + //Free our mem + xmlFree(resbuf); + xmlFreeDoc(resDoc); + xmlFreeDoc(srcDoc); + destination.flush(); + flushed = true; +} + +/** + * Writes the specified byte to this output stream. + */ +int XsltOutputStream::put(char ch) +{ + outbuf.push_back(ch); + return 1; +} + + + + + +} // namespace IO +} // namespace Inkscape + + +//######################################################################### +//# E N D O F F I L E +//######################################################################### diff --git a/src/io/stream/xsltstream.h b/src/io/stream/xsltstream.h new file mode 100644 index 0000000..7410ddc --- /dev/null +++ b/src/io/stream/xsltstream.h @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#ifndef SEEN_INKSCAPE_IO_XSLTSTREAM_H +#define SEEN_INKSCAPE_IO_XSLTSTREAM_H +/** + * @file + * Xslt-enabled input and output streams. + */ +/* + * Authors: + * Bob Jamison <ishmalius@gmail.com> + * + * Copyright (C) 2004-2008 Inkscape.org + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + + +#include "inkscapestream.h" + +#include <libxslt/xslt.h> +#include <libxslt/xsltInternals.h> + + +namespace Inkscape +{ +namespace IO +{ + +//######################################################################### +//# X S L T S T Y L E S H E E T +//######################################################################### +/** + * This is a container for reusing a loaded stylesheet + */ +class XsltStyleSheet +{ + +public: + + /** + * Constructor with loading + */ + XsltStyleSheet(InputStream &source); + + /** + * Simple constructor, no loading + */ + XsltStyleSheet(); + + /** + * Loader + */ + bool read(InputStream &source); + + /** + * Destructor + */ + virtual ~XsltStyleSheet(); + + xsltStylesheetPtr stylesheet; + + +}; // class XsltStyleSheet + + +//######################################################################### +//# X S L T I N P U T S T R E A M +//######################################################################### + +/** + * This class is for transforming stream input by a given stylesheet + */ +class XsltInputStream : public BasicInputStream +{ + +public: + + XsltInputStream(InputStream &xmlSource, XsltStyleSheet &stylesheet); + + ~XsltInputStream() override; + + int available() override; + + void close() override; + + int get() override; + + +private: + + XsltStyleSheet &stylesheet; + + xmlChar *outbuf; + int outsize; + int outpos; + +}; // class XsltInputStream + + + + +//######################################################################### +//# X S L T O U T P U T S T R E A M +//######################################################################### + +/** + * This class is for transforming stream output by a given stylesheet + */ +class XsltOutputStream : public BasicOutputStream +{ + +public: + + XsltOutputStream(OutputStream &destination, XsltStyleSheet &stylesheet); + + ~XsltOutputStream() override; + + void close() override; + + void flush() override; + + int put(char ch) override; + +private: + + XsltStyleSheet &stylesheet; + + Glib::ustring outbuf; + + bool flushed; + +}; // class XsltOutputStream + + + +} // namespace IO +} // namespace Inkscape + + +#endif /* __INKSCAPE_IO_XSLTSTREAM_H__ */ |