Working with the various stream classes in POCO. - POCO C++ ...
Working with the various stream classes in POCO. - POCO C++ ...
Working with the various stream classes in POCO. - POCO C++ ...
Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
Streams<br />
<strong>Work<strong>in</strong>g</strong> <strong>with</strong> <strong>the</strong> <strong>various</strong> <strong>stream</strong> <strong>classes</strong> <strong>in</strong> <strong>POCO</strong>.
Overview<br />
> Encod<strong>in</strong>g and Decod<strong>in</strong>g (Base64, HexB<strong>in</strong>ary)<br />
> Data Compression <strong>with</strong> zlib<br />
> B<strong>in</strong>ary I/O<br />
> Utility Streams<br />
(Count<strong>in</strong>gStream, L<strong>in</strong>eEnd<strong>in</strong>gConverter, TeeStream, NullStream)<br />
> FileStream<br />
> Creat<strong>in</strong>g Your Own Streams
The <strong>POCO</strong> Stream Classes<br />
> <strong>POCO</strong> provides a variety of <strong>stream</strong> <strong>classes</strong>, compatible <strong>with</strong><br />
standard <strong>C++</strong> IOStreams.<br />
> Most <strong>POCO</strong> <strong>stream</strong> <strong>classes</strong> are implemented as filters, which<br />
means that <strong>the</strong>y do not write to or read from a device, but ra<strong>the</strong>r<br />
from ano<strong>the</strong>r <strong>stream</strong> <strong>the</strong>y are connected to.<br />
> A few utility <strong>classes</strong> <strong>in</strong> <strong>POCO</strong> make it easy for you to create your<br />
own <strong>stream</strong> buffer and <strong>stream</strong> <strong>classes</strong>.
Encod<strong>in</strong>g and Decod<strong>in</strong>g<br />
> <strong>POCO</strong> provides filter <strong>stream</strong> <strong>classes</strong> for encod<strong>in</strong>g and decod<strong>in</strong>g<br />
data <strong>in</strong> Base64 and HexB<strong>in</strong>ary format.<br />
> Both Base64 and HexB<strong>in</strong>ary can be used to encode arbitrary<br />
b<strong>in</strong>ary data us<strong>in</strong>g only pr<strong>in</strong>table ASCII characters.<br />
> Base64 uses digits, upper and lowercase characters, as well as '+'<br />
and '-' to encode groups of 6 bits. The encoded data takes by a<br />
factor 1.33 as much space as <strong>the</strong> orig<strong>in</strong>al data.<br />
> HexB<strong>in</strong>ary uses digits and <strong>the</strong> characters 'A' to 'F' to encode<br />
groups of 4 bit. The encoded data takes twice <strong>the</strong> space.<br />
> See RFC 4648 for details.
Encod<strong>in</strong>g and Decod<strong>in</strong>g (cont'd)<br />
> Poco::Base64Encoder #<strong>in</strong>clude "Poco/Base64Encoder.h"<br />
Poco::HexB<strong>in</strong>aryEncoder #<strong>in</strong>clude "Poco/HexB<strong>in</strong>aryEncoder.h"<br />
are output <strong>stream</strong>s that must be constructed <strong>with</strong> ano<strong>the</strong>r<br />
output <strong>stream</strong>, where Base64/HexB<strong>in</strong>ary-encoded data is<br />
written to.<br />
> Poco::Base64Decoder #<strong>in</strong>clude "Poco/Base64Decoder.h"<br />
Poco::HexB<strong>in</strong>aryDecoder #<strong>in</strong>clude "Poco/HexB<strong>in</strong>aryDecoder.h"<br />
are <strong>in</strong>put <strong>stream</strong>s that must be constructed <strong>with</strong> ano<strong>the</strong>r <strong>in</strong>put<br />
<strong>stream</strong>, where Base64/HexB<strong>in</strong>ary-encoded data is read from.
#<strong>in</strong>clude "Poco/Base64Encoder.h"<br />
#<strong>in</strong>clude <br />
us<strong>in</strong>g Poco::Base64Encoder;<br />
<strong>in</strong>t ma<strong>in</strong>(<strong>in</strong>t argc, char** argv)<br />
{<br />
Base64Encoder encoder(std::cout);<br />
}<br />
encoder
ZLib Compression<br />
> <strong>POCO</strong> provides filter <strong>stream</strong> wrappers for zlib, support<strong>in</strong>g<br />
"deflate" and "gzip" style compression.<br />
> Input and output <strong>stream</strong>s are provided for compression<br />
(deflat<strong>in</strong>g) and expansion (<strong>in</strong>flat<strong>in</strong>g).<br />
> Four <strong>stream</strong> <strong>classes</strong> (two <strong>in</strong>put <strong>stream</strong>s and two output <strong>stream</strong>s)<br />
are available.
ZLib Stream Classes<br />
raw<br />
data<br />
Deflat<strong>in</strong>gOutputStream o<strong>stream</strong><br />
i<strong>stream</strong><br />
Deflat<strong>in</strong>gInputStream<br />
Inflat<strong>in</strong>gInputStream i<strong>stream</strong><br />
o<strong>stream</strong> Inflat<strong>in</strong>gOutputStream<br />
compressed<br />
data
ZLib Stream Classes (cont'd)<br />
> Deflat<strong>in</strong>g Streams<br />
> #<strong>in</strong>clude "Poco/Deflat<strong>in</strong>gStream.h"<br />
> Poco::Deflat<strong>in</strong>gInputStream<br />
> Poco::Deflat<strong>in</strong>gOutputStream<br />
> Inflat<strong>in</strong>g Streams<br />
> #<strong>in</strong>clude "Poco/Inflat<strong>in</strong>gStream.h"<br />
> Poco::Inflat<strong>in</strong>gInputStream<br />
> Poco::Inflat<strong>in</strong>gOutputStream
ZLib Stream Classes (cont'd)<br />
> Poco::Deflat<strong>in</strong>gInputStream<br />
Poco::Deflat<strong>in</strong>gOutputStream<br />
is constructed <strong>with</strong> ano<strong>the</strong>r <strong>in</strong>put/output <strong>stream</strong> and an optional<br />
argument specify<strong>in</strong>g <strong>the</strong> compression type:<br />
Poco::Deflat<strong>in</strong>gStreamBuf::STREAM_ZLIB (deflate/zlib type)<br />
Poco::Deflat<strong>in</strong>gStreamBuf::STREAM_GZIP (gzip type)<br />
> Poco::Inflat<strong>in</strong>gInputStream<br />
Poco::Inflat<strong>in</strong>gOutputStream<br />
is constructed <strong>with</strong> ano<strong>the</strong>r <strong>in</strong>put/output <strong>stream</strong> and an optional<br />
argument specify<strong>in</strong>g <strong>the</strong> compression type:<br />
Poco::Inflat<strong>in</strong>gStreamBuf::STREAM_ZLIB (deflate/zlib type)<br />
Poco::Inflat<strong>in</strong>gStreamBuf::STREAM_GZIP (gzip type)
#<strong>in</strong>clude "Poco/Deflat<strong>in</strong>gStream.h"<br />
#<strong>in</strong>clude <br />
us<strong>in</strong>g Poco::Deflat<strong>in</strong>gOutputStream;<br />
us<strong>in</strong>g Poco::Deflat<strong>in</strong>gStreamBuf;<br />
<strong>in</strong>t ma<strong>in</strong>(<strong>in</strong>t argc, char** argv)<br />
{<br />
std::of<strong>stream</strong> ostr("test.gz", std::ios::b<strong>in</strong>ary);<br />
Deflat<strong>in</strong>gOutputStream deflater(ostr, Deflat<strong>in</strong>gStreamBuf::STREAM_GZIP);<br />
}<br />
deflater
Count<strong>in</strong>g Streams<br />
> Poco::Count<strong>in</strong>gInputStream and Poco::Count<strong>in</strong>gOutputStream<br />
count <strong>the</strong> number of characters and l<strong>in</strong>es <strong>in</strong> a file. They also keep<br />
track of <strong>the</strong> current l<strong>in</strong>e number and column position.<br />
> #<strong>in</strong>clude "Poco/Count<strong>in</strong>gStream.h"
L<strong>in</strong>e End<strong>in</strong>g Conversion<br />
> Poco::InputL<strong>in</strong>eEnd<strong>in</strong>gConverter and<br />
Poco::OutputL<strong>in</strong>eEnd<strong>in</strong>gConverter converts l<strong>in</strong>e end<strong>in</strong>gs <strong>in</strong> text<br />
files between Unix (LF), DOS/W<strong>in</strong>dows (CRLF) and Mac<strong>in</strong>tosh (CR)<br />
format.<br />
> #<strong>in</strong>clude "Poco/L<strong>in</strong>eEnd<strong>in</strong>gConverter.h"<br />
> Poco::L<strong>in</strong>eEnd<strong>in</strong>g def<strong>in</strong>es l<strong>in</strong>e end<strong>in</strong>g formats:<br />
NEWLINE_DEFAULT (<strong>the</strong> default for <strong>the</strong> current platform)<br />
NEWLINE_CR (Mac<strong>in</strong>tosh l<strong>in</strong>e end<strong>in</strong>gs)<br />
NEWLINE_CRLF (DOS/W<strong>in</strong>dows l<strong>in</strong>e end<strong>in</strong>gs)<br />
NEWLINE_LF (Unix l<strong>in</strong>e end<strong>in</strong>gs)
Splitt<strong>in</strong>g Streams<br />
> Poco::TeeInputStream and Poco::TeeOutputStream copy all<br />
characters go<strong>in</strong>g through <strong>the</strong>m (read or written) to one or more<br />
output <strong>stream</strong>s.<br />
> #<strong>in</strong>clude "Poco/TeeStream.h"<br />
> These <strong>stream</strong>s are quite useful for debugg<strong>in</strong>g purposes.<br />
> void addStream(std::o<strong>stream</strong>& ostr)<br />
adds an output <strong>stream</strong> to a Poco::TeeInputStream or<br />
Poco::TeeOutputStream.
#<strong>in</strong>clude "Poco/TeeStream.h"<br />
#<strong>in</strong>clude <br />
#<strong>in</strong>clude <br />
us<strong>in</strong>g Poco::TeeOutputStream;<br />
<strong>in</strong>t ma<strong>in</strong>(<strong>in</strong>t argc, char** argv)<br />
{<br />
TeeOutputStream tee(std::cout);<br />
}<br />
std::of<strong>stream</strong> fstr("output.txt");<br />
tee.addStream(fstr);<br />
tee
The Null Stream<br />
> Poco::NullOutputStream discards all data written to it.<br />
> Poco::NullInputStream signals end-of-file for every read<br />
operation.<br />
> #<strong>in</strong>clude "Poco/NullStream.h"
Writ<strong>in</strong>g and Read<strong>in</strong>g B<strong>in</strong>ary Data<br />
> Poco::B<strong>in</strong>aryWriter is used to write <strong>the</strong> value of basic types <strong>in</strong><br />
b<strong>in</strong>ary form to an output <strong>stream</strong>, us<strong>in</strong>g a <strong>stream</strong>-like <strong>in</strong>terface.<br />
> #<strong>in</strong>clude "Poco/B<strong>in</strong>aryWriter.h"<br />
> Poco::B<strong>in</strong>aryReader is used to read basic types <strong>in</strong> b<strong>in</strong>ary form<br />
(produced by a Poco::B<strong>in</strong>aryWriter) from an <strong>in</strong>put <strong>stream</strong>.<br />
> #<strong>in</strong>clude "Poco/B<strong>in</strong>aryReader.h"<br />
> Both support big endian and little endian byte order for writ<strong>in</strong>g<br />
and read<strong>in</strong>g, as well as automatic byte order conversions.<br />
> These <strong>classes</strong> are useful for exchang<strong>in</strong>g b<strong>in</strong>ary data between<br />
systems <strong>with</strong> a different architecture.
The B<strong>in</strong>aryWriter Class<br />
> Poco::B<strong>in</strong>aryWriter supports <strong>stream</strong> <strong>in</strong>sertion operators ( The value is written out seven bits at a time, start<strong>in</strong>g <strong>with</strong> <strong>the</strong><br />
seven least significant bits.<br />
> The most significant bit of a byte <strong>in</strong>dicates whe<strong>the</strong>r <strong>the</strong>re are<br />
more bytes com<strong>in</strong>g.<br />
> A value that fits <strong>in</strong>to seven bits takes one storage byte.<br />
> For a 32-bit value, at most five bytes are used.
The B<strong>in</strong>aryWriter Class (cont'd)<br />
> void write7BitEncoded(UInt32 value)<br />
void write7BitEncoded(UInt64 value)<br />
writes an unsigned <strong>in</strong>teger <strong>in</strong> <strong>the</strong> compact 7 bit encoded format<br />
to <strong>the</strong> underly<strong>in</strong>g output <strong>stream</strong><br />
> void writeRaw(const std::str<strong>in</strong>g& rawData)<br />
writes rawData as is to <strong>the</strong> underly<strong>in</strong>g <strong>stream</strong><br />
> void writeBOM()<br />
writes a byte order mark (<strong>the</strong> 16 bit value 0xFEFF <strong>in</strong> host byte<br />
order) to <strong>the</strong> <strong>stream</strong>. A B<strong>in</strong>aryReader uses <strong>the</strong> BOM to<br />
automatically enable byte order conversion, if required.
B<strong>in</strong>aryWriter and Byte Order<br />
> A B<strong>in</strong>aryWriter is constructed <strong>with</strong> an output <strong>stream</strong>, and an<br />
optional byte order argument.<br />
> The byte order can be one of <strong>the</strong> follow<strong>in</strong>g:<br />
> NATIVE_BYTE_ORDER (default)<br />
> BIG_ENDIAN_BYTE_ORDER<br />
> NETWORK_BYTE_ORDER<br />
> LITTLE_ENDIAN_BYTE_ORDER
B<strong>in</strong>aryWriter Stream State<br />
> Poco::B<strong>in</strong>aryWriter provides convenience functions to determ<strong>in</strong>e<br />
or change <strong>the</strong> state of <strong>the</strong> underly<strong>in</strong>g output <strong>stream</strong>.<br />
> void flush()<br />
flushes <strong>the</strong> underly<strong>in</strong>g <strong>stream</strong><br />
> bool good()<br />
returns true if <strong>the</strong> <strong>stream</strong> is okay<br />
> bool fail()<br />
returns <strong>the</strong> state of <strong>the</strong> <strong>stream</strong>'s fail bit<br />
> bool bad()<br />
returns <strong>the</strong> state of <strong>the</strong> <strong>stream</strong>'s bad bit
The B<strong>in</strong>aryReader Class<br />
> Poco::B<strong>in</strong>aryReader provides <strong>stream</strong> extraction operators (>>) for<br />
all built-<strong>in</strong> <strong>C++</strong> types, as well as std::str<strong>in</strong>g.<br />
> void read7BitEncoded(UInt32& value)<br />
void read7BitEncoded(UInt64& value)<br />
read an <strong>in</strong>teger stored <strong>in</strong> 7 bit compressed format<br />
> void readRaw(<strong>in</strong>t length, std::str<strong>in</strong>g& value)<br />
reads length bytes of raw data <strong>in</strong>to value<br />
> void readBOM()<br />
reads a byte order mark and enables or disables automatic byte<br />
order conversion for all data read <strong>in</strong> <strong>the</strong> future
The B<strong>in</strong>aryReader Class (cont'd)<br />
> bool good()<br />
returns true if <strong>the</strong> <strong>stream</strong> is okay<br />
> bool fail()<br />
returns <strong>the</strong> state of <strong>the</strong> <strong>stream</strong>'s fail bit<br />
> bool bad()<br />
returns <strong>the</strong> state of <strong>the</strong> <strong>stream</strong>'s bad bit<br />
> bool eof()<br />
returns <strong>the</strong> state of <strong>the</strong> <strong>stream</strong>'s eof bit
#<strong>in</strong>clude "Poco/B<strong>in</strong>aryWriter.h"<br />
#<strong>in</strong>clude <br />
us<strong>in</strong>g Poco::B<strong>in</strong>aryWriter;<br />
<strong>in</strong>t ma<strong>in</strong>(<strong>in</strong>t argc, char** argv)<br />
{<br />
std::of<strong>stream</strong> ostr("b<strong>in</strong>ary.dat", std::ios::b<strong>in</strong>ary);<br />
B<strong>in</strong>aryWriter writer(ostr);<br />
}<br />
writer.writeBOM();<br />
writer
#<strong>in</strong>clude "Poco/B<strong>in</strong>aryReader.h"<br />
#<strong>in</strong>clude <br />
us<strong>in</strong>g Poco::B<strong>in</strong>aryReader;<br />
<strong>in</strong>t ma<strong>in</strong>(<strong>in</strong>t argc, char** argv)<br />
{<br />
std::if<strong>stream</strong> istr("b<strong>in</strong>ary.dat", std::ios::b<strong>in</strong>ary);<br />
B<strong>in</strong>aryReader reader(istr);<br />
}<br />
reader.readBOM();<br />
std::str<strong>in</strong>g hello;<br />
<strong>in</strong>t i;<br />
bool b;<br />
reader >> hello >> i;<br />
reader.read7BitEncoded(i);<br />
reader >> b;<br />
return 0;
Cross-Platform Considerations<br />
> Poco::B<strong>in</strong>aryWriter and Poco::B<strong>in</strong>aryReader can be used to<br />
exchange data between systems <strong>with</strong> different architectures.<br />
> Ei<strong>the</strong>r write <strong>the</strong> data <strong>in</strong> a fixed byte order (e.g., big endian), or use<br />
a byte order mark and write <strong>in</strong> native byte order.<br />
> Be careful <strong>with</strong> <strong>in</strong>tegers. Prefer Poco::UIntXX and Poco::IntXX to<br />
(unsigned) short, (unsigned) <strong>in</strong>t and (unsigned) long.<br />
> For textual data, ensure that a common encod<strong>in</strong>g (e.g., Lat<strong>in</strong>-1 or<br />
UTF-8) is used.
File Streams<br />
> <strong>POCO</strong> provides <strong>stream</strong> <strong>classes</strong> for read<strong>in</strong>g and writ<strong>in</strong>g files:<br />
FileStream, FileInputStream, FileOutputStream<br />
> #<strong>in</strong>clude "Poco/FileStream.h"<br />
> On W<strong>in</strong>dows platforms, <strong>the</strong> path passed to a File Stream is UTF-8<br />
encoded.<br />
> No l<strong>in</strong>e end<strong>in</strong>g conversion is performed. File <strong>stream</strong>s are always<br />
open <strong>in</strong> b<strong>in</strong>ary mode. Seek<strong>in</strong>g is supported.<br />
> Use InputL<strong>in</strong>eEnd<strong>in</strong>gConverter or OutputL<strong>in</strong>eEnd<strong>in</strong>gConverter if<br />
you need CR-LF conversion.
Writ<strong>in</strong>g Your Own Stream Classes<br />
> <strong>POCO</strong> provides <strong>stream</strong> buffer class templates that simplify <strong>the</strong><br />
implementation of custom <strong>stream</strong> <strong>classes</strong>.<br />
> Streams are implemented by first creat<strong>in</strong>g a <strong>stream</strong> buffer class<br />
(<strong>stream</strong>buf), and <strong>the</strong>n add<strong>in</strong>g IOS, i<strong>stream</strong> and o<strong>stream</strong> <strong>classes</strong>.<br />
> The follow<strong>in</strong>g <strong>stream</strong> buffer class templates are available:<br />
> Poco::BasicUnbufferedStreamBuf<br />
> Poco::BasicBufferedStreamBuf<br />
> Poco::BasicBufferedBidirectionalStreamBuf
UnbufferedStreamBuf<br />
> Poco::BasicUnbufferedStreamBuf is a class template that must be<br />
<strong>in</strong>stantiated for a character type.<br />
> Poco::UnbufferedStreamBuf is an <strong>in</strong>stantiation of<br />
Poco::BasicUnbufferedStreamBuf for char.<br />
> #<strong>in</strong>clude "Poco/UnbufferedStreamBuf.h"<br />
> Poco::UnbufferedStreamBuf is <strong>the</strong> simplest way to implement a<br />
custom <strong>stream</strong>. It does not do any buffer<strong>in</strong>g.
UnbufferedStreamBuf (cont'd)<br />
> Sub<strong>classes</strong> must override <strong>the</strong> follow<strong>in</strong>g member functions:<br />
> <strong>in</strong>t readFromDevice()<br />
reads and returns a s<strong>in</strong>gle (unsigned) byte. Returns<br />
char_traits::eof() (-1) if no more data is available.<br />
NOTE: Never return a char value directly, as char might be<br />
signed. Always use <strong>in</strong>t charToInt(char c) to convert <strong>the</strong><br />
!<br />
character to an <strong>in</strong>teger.<br />
> <strong>in</strong>t writeToDevice(char c)<br />
writes a s<strong>in</strong>gle byte. Returns <strong>the</strong> byte (as <strong>in</strong>teger) if successful,<br />
o<strong>the</strong>rwise char_traits::eof() (-1).
#<strong>in</strong>clude "Poco/UnbufferedStreamBuf.h"<br />
#<strong>in</strong>clude <br />
#<strong>in</strong>clude <br />
class UpperStreamBuf: public UnbufferedStreamBuf<br />
{<br />
public:<br />
UpperStreamBuf(std::o<strong>stream</strong>& ostr): _ostr(ostr)<br />
{<br />
}<br />
protected:<br />
<strong>in</strong>t writeToDevice(char c)<br />
{<br />
_ostr.put(toupper(c));<br />
return charToInt(c);<br />
}<br />
private:<br />
std::o<strong>stream</strong>& _ostr;<br />
};
class UpperIOS: public virtual std::ios<br />
{<br />
public:<br />
UpperIOS(std::o<strong>stream</strong>& ostr): _buf(ostr)<br />
{<br />
poco_ios_<strong>in</strong>it(&_buf);<br />
}<br />
protected:<br />
UpperStreamBuf _buf;<br />
};<br />
class UpperOutputStream: public UpperIOS, public std::o<strong>stream</strong><br />
{<br />
public:<br />
UpperOutputStream(std::o<strong>stream</strong>& ostr):<br />
UpperIOS(ostr),<br />
std::o<strong>stream</strong>(&_buf)<br />
{<br />
}<br />
};
<strong>in</strong>t ma<strong>in</strong>(<strong>in</strong>t argc, char** argv)<br />
{<br />
UpperOutputStream upper(std::cout);<br />
}<br />
upper
Buffered Streams<br />
> Poco::BasicBufferedStreamBuf is a class template that must be<br />
<strong>in</strong>stantiated for a character type.<br />
> Poco::BufferedStreamBuf is an <strong>in</strong>stantiation of<br />
Poco::BasicBufferedStreamBuf for char.<br />
> #<strong>in</strong>clude "Poco/BufferedStreamBuf.h"<br />
> An <strong>in</strong>stance of Poco::BufferedStreamBuf supports ei<strong>the</strong>r read<strong>in</strong>g<br />
or writ<strong>in</strong>g, but not both.<br />
> Poco::BasicBufferedBidirectionalStreamBuf supports read<strong>in</strong>g and<br />
writ<strong>in</strong>g. Internally, it ma<strong>in</strong>ta<strong>in</strong>s two buffers.<br />
> #<strong>in</strong>clude "Poco/BufferedBidirectionalStreamBuf.h"
Buffered Streams (cont'd)<br />
> Sub<strong>classes</strong> of Buffered[Bidirectional]StreamBuf must override <strong>the</strong><br />
follow<strong>in</strong>g member functions:<br />
> <strong>in</strong>t readFromDevice(char* buffer, std::<strong>stream</strong>size length)<br />
read up to length characters and place <strong>the</strong>m <strong>in</strong> buffer. Return<br />
<strong>the</strong> number of characters read, or -1 if someth<strong>in</strong>g went wrong.<br />
> <strong>in</strong>t writeToDevice(const char* buffer, std::<strong>stream</strong>size length)<br />
write length bytes start<strong>in</strong>g from buffer and return <strong>the</strong> number<br />
of bytes written, or -1 if someth<strong>in</strong>g went wrong.
Stream Buffers and Exceptions<br />
> Exceptions thrown by <strong>stream</strong> buffers will normally be catched by<br />
<strong>the</strong> <strong>stream</strong> class and result <strong>in</strong> <strong>the</strong> <strong>stream</strong>'s bad bit be<strong>in</strong>g set. The<br />
exception will not propagate; <strong>in</strong>stead, <strong>the</strong> <strong>stream</strong>'s bad bit will be<br />
set.<br />
> This behavior of a <strong>stream</strong> can be changed by call<strong>in</strong>g <strong>the</strong><br />
exceptions() member function of a <strong>stream</strong> <strong>with</strong> true as argument.
Copyright © 2006-2010 by Applied Informatics Software Eng<strong>in</strong>eer<strong>in</strong>g GmbH.<br />
Some rights reserved.<br />
www.app<strong>in</strong>f.com | <strong>in</strong>fo@app<strong>in</strong>f.com<br />
T +43 4253 32596 | F +43 4253 32096