1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
|
/*
* rtdelphi.h
*
* Copyright (c) 2000-2004 by Florian Fischer (florianfischer@gmx.de)
* and Martin Trautmann (martintrautmann@gmx.de)
*
* This file may be distributed and/or modified under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation.
*
* This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
* WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
*/
/** \file
* Support for the Delphi binary file formats.
* They are quite a good format for saving binary data.
*/
#ifndef __LRT_DELPHI_STREAMS__
#define __LRT_DELPHI_STREAMS__
#include "rtsystem.h"
#include "rtcollect.h"
#include "rtstring.h"
#include "rtstreams.h"
namespace lrt {
/** This data type can hold either a String, an integer or a floating-point
* (double) value. It is much like a typesafe union of these types.
*/
class Variant {
public:
/// The possible types this variable may have
enum VariantType {
typeString = 0, ///< The variant is currently a string.
typeInt, ///< The variant is currently an integer.
typeDouble ///< The variant is currently a double.
};
/// Creates a Variant which contains the integer 0.
Variant();
/// Copies the data over from the other variant.
Variant(const Variant&);
/// Copies the data over from the other variant.
Variant& operator=(const Variant&);
~Variant();
/// Creates a Variant which contains the given integer.
explicit Variant(int);
/// Creates a Variant which contains the given double.
explicit Variant(double);
/// Creates a Variant which contains the given String.
explicit Variant(const String&);
/// Sets this variant's value to the given integer.
void set(int);
/// Sets this variant's value to the given double.
void set(double);
/// Sets this variant's value to the given String.
void set(const String&);
/** Extracts an integer from this variant.
* Note that it is unimportant which type this variant actually contains,
* an integer will be generated from it.
* @param def (optional) The default value which is used if this variant
* is currently a String and not interpretable as an integer.
*/
int getInt(int def = 0) const;
/** Extracts a double from this variant.
* Note that it is unimportant which type this variant actually contains,
* a double will be generated from it.
* @param def (optional) The default value which is used if this variant
* is currently a String and not interpretable as a double.
*/
double getDouble(double def = 0.) const;
/** Converts this variant's data to a String representation and returns
* it. The operation does not change the variant itself.
*/
String getString() const;
/** Returns the current type of this variant.
*/
VariantType getCurrentType() const;
private:
union {
int i;
double d;
String* str;
};
VariantType curType;
};
/** Supports reading binary files in the Delphi format.
* The advantage of the Delphi binary file format is that it has prefixes
* which indicate the type of the next data structure in the file, so that
* even if you don't know what's in the file, you can still properly parse it.
* <p>
* Even though the original Delphi format is Intel-centric, with little-endian
* data format, this library should work on any platform.
*/
class DelphiDataInputStream : public FilterInputStream
{
public:
/** Creates a Delphi binary input stream which reads from another input stream.
* <b>Note:</b> When this input stream is deleted, the other one is deleted as well.
*/
DelphiDataInputStream(InputStream* in);
/** Creates a Delphi binary input stream which reads from a file (given by its name).
* This is a convenience constructor which ensures that the file is opened in binary
* mode.
*/
DelphiDataInputStream(const String& filename);
virtual ~DelphiDataInputStream();
/** Reads the next contained element from the file.
* If the next data in the file is not a known element, exits the app.
*/
Variant readAny();
/** Reads a String from the file.
* <b>Note:</b> If the next data in the file is not a Delphi string, exits the app. <br>
* <b>Note:</b> Supports short (<tt>0x06</tt>) and long (<tt>0x0C</tt>) strings. */
String readString();
/** Reads an integer from the file.
* <b>Note:</b> If the next data in the file is not a Delphi integer, exits the app. <br>
* <b>Note:</b> Supports 8-bit, 16-bit and 32-bit integers. */
int readInt();
/** Reads a floating-point number from the file.
* <b>Note:</b> If the next data in the file is not a Delphi floating-point, exits the app. <br>
* <b>Note:</b> Supports 80-bit Delphi floating point numbers. */
double readDouble();
private:
String doReadString(int type);
int doReadInt(int type);
double doReadDouble(int type);
double ld2d(Array<unsigned char>&);
void inverseByteOrder(unsigned char* data, int len);
};
/** Supports writing binary files in the Delphi format.
* The advantage of the Delphi binary file format is that it has prefixes
* which indicate the type of the next data structure in the file, so that
* even if you don't know what's in the file, you can still properly parse it.
* <p>
* Even though the original Delphi format is Intel-centric, with little-endian
* data format, this library should work on any platform.
*/
class DelphiDataOutputStream : public FilterOutputStream
{
public:
/** Creates a Delphi binary output stream which writes to another input stream.
* <b>Note:</b> When this output stream is deleted, the other one is deleted as well.
*/
DelphiDataOutputStream(OutputStream* out);
/** Writes another element to the stream. */
bool writeAny(const Variant&);
/** Writes a String to the stream.
* <b>Note:</b> This implementation uses the short (<tt>0x06</tt>) and long (<tt>0x0C</tt>) strings.
*/
bool writeString(const String&);
/** Writes an integer to the stream.
* <b>Note:</b> This implementation uses the 8-bit, 16-bit and 32-bit integer formats,
* and always writes the smallest one which can hold the given number.
*/
bool writeInt(int);
/** Writes a double to the stream.
*/
bool writeDouble(double);
private:
void d2ld(double d, Array<unsigned char>& ld);
void inverseByteOrder(unsigned char* data, int len);
bool write4(int);
};
} // namespace
#endif
|