File: wxSerialize.h

package info (click to toggle)
codelite 14.0+dfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, sid
  • size: 112,816 kB
  • sloc: cpp: 483,662; ansic: 150,144; php: 9,569; lex: 4,186; python: 3,417; yacc: 2,820; sh: 1,147; makefile: 52; xml: 13
file content (1620 lines) | stat: -rw-r--r-- 68,947 bytes parent folder | download | duplicates (3)
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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//
// copyright            : (C) 2008 by Eran Ifrah                            
// file name            : wxSerialize.h              
//                                                                          
// -------------------------------------------------------------------------
// A                                                                        
//              _____           _      _     _ _                            
//             /  __ \         | |    | |   (_) |                           
//             | /  \/ ___   __| | ___| |    _| |_ ___                      
//             | |    / _ \ / _  |/ _ \ |   | | __/ _ )                     
//             | \__/\ (_) | (_| |  __/ |___| | ||  __/                     
//              \____/\___/ \__,_|\___\_____/_|\__\___|                     
//                                                                          
//                                                  F i l e                 
//                                                                          
//    This program is free software; you can redistribute it and/or modify  
//    it under the terms of the GNU General Public License as published by  
//    the Free Software Foundation; either version 2 of the License, or     
//    (at your option) any later version.                                   
//                                                                          
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////

//---------------------------------------------------------------------------
// $RCSfile: wxSerialize.h $
// $Source: include/wx/wxSerialize.h $
// $Revision: 1.16 $
// $Date: 7-sep-2007 11:29:08 $
//---------------------------------------------------------------------------
// Author:      Jorgen Bodde
//              Christian Buhtz
// Copyright:   (c) Jorgen Bodde <jorgb@xs4all.nl>
// License:     see LICENSE for details
//---------------------------------------------------------------------------

#ifndef _WXSERIALIZE_H_
#define _WXSERIALIZE_H_

#include <wx/sstream.h>
#include <wx/buffer.h>
#include <wx/math.h>
#include <wx/datetime.h>
#include <wx/gdicmn.h>  // for wxSize, wxPoint

#define WXSERIALIZE_MAJOR_VERSION 1
#define WXSERIALIZE_MINOR_VERSION 1

/** \author Jorgen Bodde
    \mainpage

    This is the wxSerialize documentation guide. wxSerialize is a serializing class meant for serializing / de-serializing
	a complete (or partial) object model to a stream. The streaming is made type safe and reliable. This means when an
	error occurs (wrong data read back or unexpected end of file) the wxSerialize class logs an error, and refuses to
	read from the stream, leaving all variables that follow the error untouched, or in a default state.

	With the use of a version number and a header, the stream is checked when reading it back. When, for example you
	wrote a stream with version 1000, and upon reading you expect version 900, the wxSerialize class logs an error that
	the expected version is lower then the encountered version, avoiding a mis-read of data that is not supported in the
	code. With the use of a header string, you can double check if the stream offered is really recognised by the
	application.

	Because wxSerialize uses wxInputStream and wxOutputStream for reading and writing, the contents of the serialization
	can be written to a memory based stream, a compression stream (like wxZLibOutputStream), a tcp/ip socket, from
	an wxURL (from the internet, handy for updates), or any other stream based upon wxInputStream / wxOutputStream.

	The streaming is binary compatible on Linux / Windows and MacOSX which means that if you read back the binary data
	from disk, the same results are read back, the values are properly converted from little to big endian.

	\section serializing_exactly Ok but what is serializing exactly?

	Serializing is putting the contents of a class to an output file. Microsoft's MFC used CArchive (which I attempted
	to keep as API compatible as possible) and boost now also has a binary serializer. So, how does it work? Well it
	is really simple. The power of the serializing lies in the fact that the classes themselves are responsible for
	serializing their data. It is very short in code, and the destination of the serialization stream doesn't really
	matter.

    \section how_work So how does it work?

	Consider the following class:

	\code
	class MyDataClass
	{
	public:
		// the serialization class, that streams from and to the
		// specified stream.
		Serialize(wxSerialize &a);

	private:
		wxString m_name;
		wxString m_address;
		wxUint8 m_age;
		wxArrayString m_siblings;
	};
	\endcode
	How does the serializing work .. We simply implement the Serialize method:
	\code
	bool MyDataClass::Serialize(wxSerialize &a)
	{
		if(a.IsStoring())
		{
			a << m_name << m_address << m_age;
			a << m_siblings;
		}
		else
		{
			a >> m_name >> m_address >> m_age;
			a >> m_siblings;
		}

		// return false when the archive encountered an error
		return a.IsOk();
	}
	\endcode

	This is all there is to it! This small piece of code, serializes the 4 used member vars to the stream, on disk
	or where it needs to go. The following code shows how the class is serialized. First when it is saved to disk:

	\code
	wxFileOutputStream file("somefile.dat");
	wxSerialize a(file);

	m_ourClass->Serialize(a);
	\endcode

	That's all! When the file and archive are out of scope, the file is closed and the object is persistent on disk.
	Now to read the data back:

	\code
	wxFileInputStream file("somefile.dat");
	wxSerialize a(file);

	// let's say we just create it and initialize it
	m_ourClass = new MyDataClass();
	m_ourClass->Serialize(a);
	\endcode

	Nearly identical code isn't it ? Even the new MyDataClass() is not needed, it is simply there to illustrate how
	newly created objects can be serialized back into. Only one method is needed, I called it Serialize() but the
	name does not matter.

	\section why_using So why not write using wxConfig, wxFFile, XML or use XTI?

	This serializer class was designed, keeping in mind a small footprint in memory and disk. When serializing to XML
	you gain flexibility and even can hand-edit it, but the overhead in the class is enormous. You have to figure out
	how the data needs to be stored, attribute names, nested hierarchies, handle errors, etc. XML is basically better
	to write to, if user editing or portability is a big issue.

	Serializing to a binary file can be more useful in the following situations:

	- Writing cache data (e.g. an object model that represents a state in memory). By writing this in a serialized
	  stream to disk, the object model can be quickly read back between sessions, or heavy preprocessing (e.g storing
	  a directory structure to disk) can be avoided.
	- Undo / Redo mechanism. Usually undo / redo mechanisms require a lot of overhead in the object model. For example
	  when the user deletes a data item in a GUI window, this item should not be really deleted, only taken apart from the
	  object model. When using a serializer class, the object can be removed, and later on re-created back on it's
	  rightful place. The good thing is that the serialize methods can both handle undo / redo, but also save the
	  data to disk.
    - Small applications that do not require overhead of XML, SQL, or use wxConfig because these all need name / value
	  conventions. With very small applications that only perform minor tasks, the developer is more distracted by
	  the writing to disk then it's really needed.
    - Writing config. This sounds odd, but when you have a global config object, and it is not really necessary to
	  keep all that data in a text file, serializing the object containing the config is rather easy.

	So when is it not useful?

	- Ofcourse when people want to edit the data afterwards.
	- When the data needs to be exchanged between applications using a standard format
	- When the application needs to process huge data, or store entered data on disk to be queried later on (SQL or
	  XML).

    \section what_dp What about data flexibility?

	People who spent some time serializing data, know that when for example a binary serialized file is written to disk
	and the object is extended with more data, you have a problem with serializing it back.
	Why? The data in the stream is only compatible with the old data makeup, and when adding new member vars how are
	you going to read them back? They are not in the stream to begin with, and you don't even know if they are or not.
	Well I deviced two ways of doing this. Let's for example extend our rather trivial MyDataClass class:

	\code
	class MyDataClass
	{
	public:
		// the serialization class, that streams from and to the
		// specified stream.
		Serialize(wxSerialize &a);

	private:
		wxString m_name;
		wxString m_address;
		wxUint8 m_age;
		wxArrayString m_siblings;

		// NEW DATA ADDED, THIS NEEDS SERIALIZING TOO!
		wxUint32 m_monthlyPay;
		bool m_healthInsurance;
	};
	\endcode


	\subsection version_number Using a version number

	The version number you can give to the stream when you write it back. This version number is stored and checked upon
	reading. When creating the stream you specify the version of the stream. You increment this version when there will
	be binary incompatibility with older streams:

	\code
	wxFileOutputStream file("somefile.dat");	
	wxSerialize a(file, 1001);   // latest version is 1001 (was 1000)

	m_ourClass->Serialize(a);
	\endcode

	Now in the code we can take this in account when reading. When we save, we simply save our new data back. And
	as you guessed the drawback, older applications still in the field cannot read the newer stream:

	\code
	bool MyDataClass::Serialize(wxSerialize &a)
	{
		if(a.IsStoring())
		{
			// simply write all
			a << m_name << m_address << m_age;
			a << m_siblings;

			// always append new data here, so reading back goes in
			// the same exact order as it is written
			a << m_monthlyPay << m_healthInsurance;
		}
		else
		{
			a >> m_name >> m_address >> m_age;
			a >> m_siblings;

			// reading back poses a problem. We can have the data but in
			// an older stream we have not. So we need the version check:
			if(a.GetVersion() > 1000)
			{
				a >> m_monthlyPay >> m_healthInsurance;
			}
		}

		// return false when the archive encountered an error
		return a.IsOk();
	}
	\endcode

	As you might have guessed, this can be some overhead. While developing the app, this can happen a lot
	as the classes grow. So the disadvantages are:

	- Older releases you wrote (and are in the field) cannot read the newer data back. So when you use serialization
	  as part of packages or updates, people are obliged to update, or you must provide multiple versions)
	- All the newer data require a version check at read time, and will bloat your application as you must take in
	  account all older streams. A small overhead, but lots of changes will simply bloat your code with GetVersion()
	  checks which is not really elegant.

	\subsection enter_leave Using EnterObject() and LeaveObject()

	To reduce the code overhead, and maintain binary read compatiblity between older and newer releases of your
	application, I deviced a way which allows you to add member data to your serializing routines and not break
	the reading of older or even newer streams. This is how it works;

	\code
	bool MyDataClass::Serialize(wxSerialize &a)
	{
		a.EnterObject();
		if(a.IsStoring())
		{
			// simply write all
			a << m_name << m_address << m_age;
			a << m_siblings;
			a << m_monthlyPay << m_healthInsurance;
		}
		else
		{
			a >> m_name >> m_address >> m_age;
			a >> m_siblings;
			a >> m_monthlyPay >> m_healthInsurance;
		}
		a.LeaveObject();

		return a.IsOk();
	}
	\endcode

	Done! These two powerful boundaries (EnterObject() and LeaveObject()) tackle two situations:

	-	<b>Reading an old stream in a newer application</b>. So what happens, when for example the older stream does not contain the
		m_monthlyPay and m_healthInsurance, the LeaveObject() boundary was already written in the old code. The stream
		recognises this, and refuses to read data into m_monthlyPay and m_healthInsurance. In these cases the default
		value will be kept in these members. Data that follows after the boundary when LeaveObject was not called,
		will be kept default.
    -	<b>Reading a newer stream with an older application</b>. When the application you released in the field is older then the stream
		being written by the newer release, more data is present in the stream then the old application knows about.
		Here the same situation applies. The LeaveObject() in the old code comes sooner then the expected leave boundary
		in the stream, so wxSerialize will go look for the boundary and ignore all data that is newer.

	The EnterObject() and LeaveObject() construction keeps the stream in sync. The only important thing to remember is
	that you MUST USE these boundaries from the first moment and not when you are adding new member objects later on.
	It is a small sacrifice to gain a lot of flexibility! The overhead in the stream is also very small, because the
	footprint of the boundaries is exactly 1 byte for the enter and 1 byte for the leave marker.

	EnterObject() and LeaveObject() can be used multiple times after eachother, and also nested. So when you serialize
	a class hierarchy and in one of your child objects also data changes, this will be possible.

	The only drawback that is left with this approach (but is also present in <b>all</b> data writing when older applications
	write back data that contained newer information) is that newer data is being overwritten. You must take special
	caution (for example using the version tag or wxSerializeStatus object) in your application to warn the user that
	the data being written will destroy newer information in the serializing stream. The newer release of your
	application can still read this stream, but newer data is defaulted again.

    Also another caveat is that when you replace data being read back it will not work, not with EnterObject() / 
    LeaveObject() but also not with a versioned stream. Consider this example:

	\code
	bool MyDataClass::Serialize(wxSerialize &a)
	{
		a.EnterObject();
		if(a.IsStoring())
		{
			// simply write all
			a << m_name << m_address << m_age;
			a << m_siblings; 
            //a << m_monthlyPay << m_healthInsurance;
            // REPLACED NOW with:
            a << m_surName << m_middleName;
		}
		else
		{
			a >> m_name >> m_address >> m_age;
			a >> m_siblings;
			// WON'T WORK! In older versions the two vars m_monthlypay and m_healthInsurance
            // were stored here, instead we read back this. If the stream we read back do not
            // contain these new replaced variables yet, we are hitting an error state. 
            a >> m_surName >> m_middleName;
		}
		a.LeaveObject();

		return a.IsOk();
	}
	\endcode 

	\subsection archive_status wxSerializeStatus Helper Class

	This class is especially designed to keep the status of the stream between reading and writing. It contains the
	last version being written or read, the header, and more important, an NewDataLoss() flag. This flag will be set
	when the stream being read back is newer then the data model it's beaing serialized into. Writing the data back
	using the wxSerializeStatus object earlier retrieved when reading will prevent the write if the flag NewDataLoss()
	is not reset using OverwriteNew() flag. How is the flag determined? Well, if one time in the data serializing
	process the LeaveObject() method needs to search for the marker (thus skipping newer data in the stream) this
	flag is set.

	This wxSerializeStatus class will also remove the need of writing the same header back as being specified when
	reading, and also the version will be preserved. The member wxSerializeStatus::SetVersion() can be used to specify
	a newer version. Here is an example, first when reading we store the last status and keep it:

	\code
	wxFileInputStream file("somefile.dat");
	wxSerialize a(file);

	// let's say we just create it and initialize it
	m_ourClass = new MyDataClass();
	m_ourClass->Serialize(a);

	// store the status (copy class)
	m_ourStatus = a.GetArchiveStatus();
	\endcode

	When writing back, and this application is older then the newer application, thus an overwrite will result
	in newer information loss:


	\code
	// if the last time we read a newer stream, tell the user
	if(m_ourStatus.NewDataLoss())
	{
		if(::wxMessageDialog( ... "ask if we should overwrite, it will result in dataloss" ...) == wxID_YES)
			m_ourStatus.OverwriteNew();	// reset the flag
	}

	// if the flag is reset we continue else we skip
	if(!m_ourStatus.NewDataLoss())
	{
		wxFileOutputStream file("somefile.dat");
		wxSerialize a(file, m_ourStatus.GetVersion(), m_ourStatus.GetHeader());
		// serialize data
		m_ourClass->Serialize(a);
	}
	else
	{
		wxLogError("Data is not saved!");
	}
	\endcode

	This construction prevents the application of accidentally writing data back and destroying newer serialized data.
	The user must explicitly agree upon this, or the developer must provide a mechanism to backup the old file so that
	newer data is not lost when reading it back in the newer application.
*/

/** \class wxSerializeStatus
	\brief A simple helper class that keeps track of the current version of the archive, the header and
	       more important, when at reading time it appears the stream contains newer data then expected.
		   It will help the developer in asking the user if the stream might be saved back or not. See
		   \ref archive_status overview for more information.
*/
class wxSerializeStatus
{
public:
	/** Constructor of the wxSerializeStatus object. This is the default constructor so you can
	    define it in the class itself without having to do anything for it */
	wxSerializeStatus()
		: m_version(0)
		, m_header(wxT(""))
		, m_newDataLoss(false)
	{
	};

	/** Constructor initializer of the wxSerializeStatus object. Used by wxSerialize to fill in the goods
	    so they can be used later */
	wxSerializeStatus(size_t version, const wxString &header)
		: m_version(version)
		, m_header(header)
		, m_newDataLoss(false)
	{
	};

	~wxSerializeStatus() {
	};

	/** Copy operator to get the latest copy of it from the wxSerialize class, and assign it to your copy */
	void operator=(const wxSerializeStatus &s) {
		m_version = s.m_version;
		m_header = s.m_header;
		m_newDataLoss = s.m_newDataLoss;
	};

	/** With this method you tell wxSerialize that it is ok to overwrite the newer data stream with an older
	    version of it. This needs to be set implicitly. Check out \ref archive_status for more information.
	*/
	void OverwriteNew() {
		m_newDataLoss = false;
	};

	/** This method returns the flag of the current NewDataLoss status. It will be set when the wxSerialize
		encounters an out of sync where there is more data then can be read back.  See \ref enter_leave
	*/
	bool NewDataLoss() const {
		return m_newDataLoss;
	};

	/** Sets the NewDataLoss flag again. This is used by wxSerialize only, or you can use it to prevent other
	    parts of the your code to be executed later when new data loss still occurs. The counterpart of this
		flag is OverwriteNew() */
	void SetNewDataLoss() {
		m_newDataLoss = true;
	};

	/** Returns the version of the last read archive */
	size_t GetVersion() const {
		return m_version;
	};

	/** Returns the header of the last read archive */
	const wxString &GetHeader() const {
		return m_header;
	};

private:
	size_t m_version;
	wxString m_header;
	bool m_newDataLoss;
};

/** \class wxSerialize
	\brief A serializer class that can serialize the contents of your class to or from a stream. It uses wxInputStream
	       and wxOutputStream derived classes for input and output.

		   See the \ref mainpage for more information
*/
class wxSerialize
{
public:
    /** Construct an input stream archive. The stream will be used to retrieve the data from, which can be any
		derived stream like a file, zip stream etc. When constructed as input, the wxSerialize object cannot
		be written to.

        The first integer and string are always read from the stream. This contains the version number (or 0 when
		not used) and the header which is empty if not used.

        When setting the version parameter, wxSerialize will check if the version read back is at least the expected
		version. For example, when version argument is set to 1000, wxSerialize will accept versions 0 .. 1000 for reading
		but will give an error if version 1001 and up is read from the stream. You can use this to set the version to
        at least the supported version for your code. When extending the serialization routines after your app has
		been deployed, the version info can be used to dynamically skip parts while loading from an older stream,
		and warn users that the version of the read stream is older which means incompatibility with
        the older application will occur. This is not the recommended method though, see EnterObject() and LeaveObject()
		for a more flexible solution.

        The header tag will also be compared when it is not empty. When an empty header is passed as parameter, the read
		back header tag is ignored. When the header argument is set, and the read back header is empty or different,
		an error will occur and the stream cannot be read back from. This can provide an extra check if the stream
		will contain the data needed.

        The partialMode flag will do nothing else but setting a flag (IsFullSerialize()) which can be used in
		serializing to skip some relational hierarchies and stuff not needed when the object is only partially
		serialized to the stream (handy for undo / redo mechanisms). When set to true, IsFullSerialize() will
		return false.

        \code
        // open and write
        wxFileInputStream in_stream("somefile.dat");
		wxSerialize a(in_stream, 1000, _T("My Stream"));
        if(a.IsOk())
        {
            a >> m_name;
            a >> m_age;
            a >> m_string >> m_count;
        }
        else
            wxLogError(wxT("Archive cannot be opened because : ") + a.GetLastErrorString());

        // end the archive
        a.Close();
        \endcode

		See also \ref enter_leave and read about data flexibility.

		\sa IsFullSerialize(), wxSerializeStatus

    */
    wxSerialize(wxInputStream &stream, size_t version = 0, const wxString &header = wxEmptyString, bool partialMode = false);

    /** Construct an output stream object. The stream will be used to save the data to, which can be any derived
	    stream like a file, zip stream etc. When constructed as output, the wxSerialize object cannot be read from.

        \code
        // open and write
        wxFileOutputStream out_file("somefile.dat");
		wxSerialize a(out_file, 1000, _T("My Stream"));
        a << m_name;
        a << m_age;
        a << m_string << m_count;

        // end all writing (does not close the stream)
        a.Close();
        \endcode

        The version (1000 in example) is saved in the stream, also the header. At reading time these two are checked
		against what the expected version and header are, so that you can be sure the stream is recognised and
		supported.

        Always save your latest supported version here. This means when you extended your application's serialization,
		increment the version. This will allow you to read back older streams and save them with newer information.
		See \ref enter_leave for more ways to make your serialization more flexible.
    */
    wxSerialize(wxOutputStream &stream, size_t version = 1, const wxString &header = wxEmptyString, bool partialMode = false);

    /** Destructor. The passed stream ombject will not be destroyed, because it is used by reference */
    virtual ~wxSerialize();

    /** Closes the archive. This means all writing or reading done to it will not affect the archive or variables
	    passed by reference. A closed archive will not produce any errors when read from and will not advance in
		searching. A closed archive can be re-opened with Open() to allow reading or writing again. */
    void Close() {
        m_opened = false;
    };

    /** Re-opens the archive. But only when the archive is in OK state (IsOk() == true). By default the archive is
	    opened when the constructor is created and everything went ok */
    void Open() {
        // it can be as simple as this
        m_opened = IsOk();
    };

    /** In reading mode, it returns true when the stream we are reading from returns true on Eof().
        It means that it returns true AFTER an attempt has been made to read past the end of the stream.
        In writing mode Eof() returns always false. When the stream is closed, true is always returned, 
        we can't read or write anymore in that case anyway. Reading more from a stream that is at it's 
        end will produce errors.
	*/
    bool Eof();

	/** Returns true when the wxSerialize is in OK condition. This means no error occurred. Errors that can occur are
	    for example:
	        - The underlying stream reports that it is not OK (not able to write, not able to read)
	        - Reading an unexpected type of variable (e.g. expecting int and reading back string)
	        - Reading from a wxSerialize with a higher version then supported
	        - Reading from a wxSerialize with a wrong header
	        - Writing to the wxSerialize when we are in reading mode
	        - Reading from the wxSerialize when we are in writing mode

	    See GetLastError() to retrieve the error, and GetLastErrorString() for an explanation. When the wxSerialize
		encountered errors, it will remain in an error state, subsequent reads and writes will not have effect to
		either the member variables to read to, or write anything to the stream when writing, for example:

	    \code
	    wxSerialize a(in_stream);

	    // .. some code

        if(a.IsStoring())
        {
            // when wxSerialize is not ok, this does nothing
            // so we can do this safely, and report Ok status below

            a << m_name << m_address << m_age;

            // when we are not ok, we can use a.IsOk() to skip
            // the count loop right away (we cannot write and it saves time)

            a << GetCount();
            for(int i = 0; i < GetCount() && a.IsOk(); i++)
                a << m_value[i];

        }
        else
        {
            // reset your object, in case we
            // get errors, all vars will be initialized

            ResetDefaults();

            // reading back from not ok stream also does not affect
            // the passed member vars they will remain default

            a >> m_name >> m_address >> m_age;

            // be careful here, because count is not set by default
			// so we set it to 0. Now the for loop will quit right away
            int count = 0;
            a >> count;
            for(int i = 0; i < count; i++)
                a >> m_value;
        }

	    // return status to lower part
	    return a.IsOk();
		\endcode
	*/
	bool IsOk() {
		bool noerr = (m_errorCode == wxSERIALIZE_ERR_OK);
		if(m_writeMode)
		    return m_odstr.IsOk() && noerr;
		else
		    return m_idstr.IsOk() && noerr;
	};

	/** Returns the last error set in this string. */
	const wxString &GetLastErrorStr() const {
		return m_errMsg;
	};

	/** This method allows you to specify regions of an object that wxSerialize can identify. This allows
	    you to read back old streams, and still serialize all data back from the stream. All the data that
		is not present in the stream reading back is skipped. This will reduce the problem that old streams
		do not contain all data that is needed, it will simply be skipped. See \ref enter_leave for a bigger
		explanation, basically when using this, you ensure older applications can read newer streams, and
		newer applications can also read older streams.

		The only restriction is that you keep the data in the same order. This means the new added data
		always  needs to be read and written at the end of the original data.

		The method returns false when the object entering did not work (always returns true in write mode
		but can return false plus an error when the current level could not be found. If this is the case
		the wxSerialize class stays in an error state so it won't be harmful trying to read or write anyway.

		For example:

		\code
			wxSerialize a(in_stream);

			if(a.EnterObject())
			{
				// we succesfully entered the object level
				if(a.IsLoading())
				{
					a >> m_name;
					a >> m_age;

					// these vars are not present in the older stream. At this point,
					// all serializing into the variables will not take place. They will
					// be left default, so initializing before the construction gives them
					// a default value, but the stream reader does not give errors, here
					// it is best to use the ReadInt and ReadString directly with a default
					// specifier:

					a.ReadInt(m_peopeCount, 0);	// default no people when not present
					a.ReadUint8(m_numberOfPersons, 1);	// default 1 person
				}
				else
				{
					// save the stream back, now all vars can be read back. The interesting
					// thing is that older programs can still read the streams back as they
					// scan for the LeaveObject() marker at the end of their serializing round

					a << m_name;
					a << m_age;

					a << m_peopeCount;
					a << m_numberOfPersons;
				}
				a.LeaveObject();
			}
		\endcode
	*/
	bool EnterObject();

	/** This the leave method that belongs to the EnterObject() method. Please always close the
		section with the LeaveObject() when an EnterObject() is used. These two constructions can
		be nested also. See \ref enter_leave for more information.

		\sa EnterObject()
	*/
	bool LeaveObject();

	/** Indicates current state is writing. This flag will always be true if wxSerialize is constructed with a
	    wxOutputStream. The IsStoring() does not check wether the state of the stream is ok or not,
		to prevent problems do:

        \code
        wxSerialize a(stream);

        // without the a.IsOk() it will work too, but serializing will
        // go on writing to dev/null without aborting when an error occurred.

        if(a.IsOk())
        {
            if(a.IsStoring())
            {
                // write contents
            }
            else
            {
                // read contents
            }
        }
        \endcode
    */
    bool IsStoring() const {
        return m_writeMode;
    };

    /** Indicates current state is reading. This flag will always be true if wxSerialize is constructed with a
	    wxInputStream. The IsLoading() does not check wether the state of the stream is ok or not, to prevent
		problems do:

        \code
        wxSerialize a(stream);

        // without the a.IsOk() it will work too, but serializing will
        // go on without aborting when an error occurred.

        if(a.IsOk())
        {
            if(a.IsLoading())
            {
                // read contents
            }
            else
            {
                // write contents
            }
        }
        \endcode
    */
    bool IsLoading() const {
        return !m_writeMode;
    };

    /** This is an extra flag independent of IsStoring() or IsLoading(). It can be set to indicate that certain
	    parts of the serialized objects must be omitted, can be useful when not the complete hierarchy needs
		serializing, but only a single object, for example to a temporary stream (undo / redo mechanism). See
		the argument 'partialMode' at the constructors for this class.

        \code
        bool SomeObject::Serialize(wxSerialize &a)
        {
            if(a.IsStoring())
            {
                // store our data
                a << m_name << m_address << m_age;

                // in partial mode, the following will return false, not saving
                // any hierachie information of objects
                if(a.IsFullSerialize())
                {
                    a << m_items.Count();
                    for(size_t i = 0 ; a.IsOk() && i < m_items.Count(); i++)
                        m_items[a]->Serialize(a);
                }
            }
            else
            {
                // load our data
                a >> m_name >> m_address >> m_age;

                // in partial mode, the following will return false, not restoring
                // any hierachie information of objects
                if(a.IsFullSerialize())
                {
                    size_t count = 0;
                    a >> count;

                    m_items.DeleteAll();

                    for(size_t i = 0 ; a.IsOk() && i < count; i++)
                    {
                        SomeChild *child = new SomeChild();
                        child->Serialize(a);
                        m_items.Add(child);
                    }
                }
            }
        }
        \endcode
    */
    bool IsFullSerialize() const {
        return !m_partialMode;
    };

    /** Returns true when the stream is open. When opened, reading and writing can take place. When closed,
	    no reading and writing can occur, but also no error will be reported when tried anyway */
    bool IsOpen() const {
        return m_opened;
    };

    // -- saving serializers --

    /** Convenience operator for serializing. See WriteUInt8() */
    virtual wxSerialize &operator <<(wxUint8 value) {
        WriteUint8(value);
	    return *this;
    };

    /** Convenience operator for serializing. See WriteUInt16() */
    virtual wxSerialize &operator <<(wxUint16 value) {
        WriteUint16(value);
	    return *this;
    };

    /** Convenience operator for serializing. See WriteUInt32() */
    virtual wxSerialize &operator <<(wxUint32 value) {
        WriteUint32(value);
	    return *this;
    };

    /** Convenience operator for serializing. See WriteUInt64() */
	virtual wxSerialize &operator <<(wxUint64 value) {
        WriteUint64(value);
	    return *this;
    };

    /** Convenience operator for serializing. See WriteInt() */
    virtual wxSerialize &operator <<(int value) {
        WriteInt(value);
	    return *this;
    };

	/** Convenience operator for serializing. See WriteString() */
	virtual wxSerialize &operator <<(const wxString& value) {
        WriteString(value);
	    return *this;
    };

	/** Convenience operator for serializing. See WriteArrayString() */
	virtual wxSerialize &operator <<(const wxArrayString& value) {
        WriteArrayString(value);
	    return *this;
    };

    /** Convenience operator for serializing. See WriteString() */
	virtual wxSerialize &operator <<(const wxChar* pvalue) {
        wxString value(pvalue);
        WriteString(value);
	    return *this;
    };

    /** Convenience operator for serializing. See WriteBool() */
	virtual wxSerialize &operator <<(bool value) {
        WriteBool(value);
	    return *this;
    };

    /** Convenience operator for serializing. See WriteDouble() */
    virtual wxSerialize &operator <<(wxFloat64 value) {
        WriteDouble(value);
	    return *this;
    };

    /** Convenience operator for serializing. See WriteDateTime() */
	virtual wxSerialize &operator <<(const wxDateTime &value) {
        WriteDateTime(value);
	    return *this;
    };

	/** Convenience operator for serializing. See WriteIntInt() */
	virtual wxSerialize &operator <<(const wxSize& value) {
        WriteIntInt(value.GetWidth(), value.GetHeight());
	    return *this;
    };

	/** Convenience operator for serializing. See WriteIntInt() */
	virtual wxSerialize &operator <<(const wxPoint& value) {
        WriteIntInt(value.x, value.y);
	    return *this;
    };

    // -- loading serializers --

    /** Convenience operator for serializing. See ReadUint8() */
    virtual wxSerialize &operator >>(wxUint8& value) {
        ReadUint8(value);
		return *this;
    };

    /** Convenience operator for serializing. See ReadUint16() */
    virtual wxSerialize &operator >>(wxUint16& value) {
        ReadUint16(value);
		return *this;
    };

    /** Convenience operator for serializing. See ReadUInt32() */
	virtual wxSerialize &operator >>(wxUint32& value) {
        ReadUint32(value);
		return *this;
    };

    /** Convenience operator for serializing. See ReadUInt64() */
    virtual wxSerialize &operator >>(wxUint64& value) {
        ReadUint64(value);
		return *this;
    };

    /** Convenience operator for serializing. See ReadInt() */
    virtual wxSerialize &operator >>(int &value) {
        ReadInt(value);
		return *this;
    };

    /** Convenience operator for serializing. See ReadString() */
	virtual wxSerialize &operator >>(wxString& value) {
        ReadString(value);
		return *this;
    };

	/** Convenience operator for serializing. See ReadArrayString() */
	virtual wxSerialize &operator >>(wxArrayString& value) {
        ReadArrayString(value);
		return *this;
    };

    /** Convenience operator for serializing. See ReadBool() */
	virtual wxSerialize &operator >>(bool& value) {
        ReadBool(value);
		return *this;
    };

    /** Convenience operator for serializing. See ReadDouble() */
	virtual wxSerialize &operator >>(wxFloat64& value) {
        ReadDouble(value);
		return *this;
    };

    /** Convenience operator for serializing. See ReadDateTime() */
	virtual wxSerialize &operator >>(wxDateTime& value) {
        ReadDateTime(value);
		return *this;
    };

    /** Convenience operator for serializing. See ReadIntInt() */
	virtual wxSerialize &operator >>(wxSize& value) {
        int iWidth, iHeight;
        if (ReadIntInt(iWidth, iHeight)) {
            value.SetWidth(iWidth);
            value.SetHeight(iHeight);
        }
		return *this;
    };

    /** Convenience operator for serializing. See ReadIntInt() */
	virtual wxSerialize &operator >>(wxPoint& value) {
        ReadIntInt(value.x, value.y);
		return *this;
    };

	/** Loads a boolean from stream. When the next record to be read is not a bool, an error will occur.
	    When wxSerialize encountered the end of object boundary (see \ref enter_leave) or the archive is
		in an error state, the value is not touched.

        Please note that when an error occurs, all subsequent loading from the stream will result in an
		error. This is to provide a save mechanism out of a read error. So instead of checking every value
		you read back yourself, they can be default and won't produce erratic behaviour.

		The value returned is true when the read was succesful, false when nothing was read.
    */
    bool ReadBool(bool& value);

	/** Variant of ReadBool() that will provide a default if the read was not succesful */
	bool ReadBool(bool& value, bool defval) {
		bool val = ReadBool(value);
		if(!val)
			value = defval;
		return val;

	};

	/** Loads a wxUint8 from stream. When the next record to be read is not a wxUint8, an error will occur.
	    When wxSerialize encountered the end of object boundary (see \ref enter_leave) or the archive is
		in an error state, the value is not touched.

        Please note that when an error occurs, all subsequent loading from the stream will result in an
		error. This is to provide a save mechanism out of a read error. So instead of checking every value
		you read back yourself, they can be default and won't produce erratic behaviour.

		The value returned is true when the read was succesful, false when nothing was read.
    */
    bool ReadUint8(wxUint8& value);

	/** Variant of ReadUint8() that will provide a default if the read was not succesful */
	bool ReadUint8(wxUint8& value, wxUint8 defval) {
		bool val = ReadUint8(value);
		if(!val)
			value = defval;
		return val;
	};

	/** Loads a wxUint16 from stream. When the next record to be read is not a wxUint16, an error will occur.
	    When wxSerialize encountered the end of object boundary (see \ref enter_leave) or the archive is
		in an error state, the value is not touched.

        Please note that when an error occurs, all subsequent loading from the stream will result in an
		error. This is to provide a save mechanism out of a read error. So instead of checking every value
		you read back yourself, they can be default and won't produce erratic behaviour.

		The value returned is true when the read was succesful, false when nothing was read.
    */
    bool ReadUint16(wxUint16& value);

	/** Variant of ReadUint16() that will provide a default if the read was not succesful */
	bool ReadUint16(wxUint16& value, wxUint16 defval) {
		bool val = ReadUint16(value);
		if(!val)
			value = defval;
		return val;
	};

	/** Loads a wxUint32 from stream. When the next record to be read is not a wxUint32, an error will occur.
	    When wxSerialize encountered the end of object boundary (see \ref enter_leave) or the archive is
		in an error state, the value is not touched.

        Please note that when an error occurs, all subsequent loading from the stream will result in an
		error. This is to provide a save mechanism out of a read error. So instead of checking every value
		you read back yourself, they can be default and won't produce erratic behaviour.

		The value returned is true when the read was succesful, false when nothing was read.
    */
	bool ReadUint32(wxUint32& value);

	/** Variant of ReadUint32() that will provide a default if the read was not succesful */
	bool ReadUint32(wxUint32& value, wxUint32 defval) {
		bool val = ReadUint32(value);
		if(!val)
			value = defval;
		return val;
	};

	/** Loads a wxUint64 from stream. When the next record to be read is not a wxUint64, an error will occur.
	    When wxSerialize encountered the end of object boundary (see \ref enter_leave) or the archive is
		in an error state, the value is not touched.

        Please note that when an error occurs, all subsequent loading from the stream will result in an
		error. This is to provide a save mechanism out of a read error. So instead of checking every value
		you read back yourself, they can be default and won't produce erratic behaviour.

		The value returned is true when the read was succesful, false when nothing was read.
    */
    bool ReadUint64(wxUint64& value);

	/** Variant of ReadUint64() that will provide a default if the read was not succesful */
	bool ReadUint64(wxUint64& value, wxUint64 defval) {
		bool val = ReadUint64(value);
		if(!val)
			value = defval;
		return val;
	};

	/** Loads an int from stream. When the next record to be read is not an int, an error will occur.
	    When wxSerialize encountered the end of object boundary (see \ref enter_leave) or the archive is
		in an error state, the value is not touched.

        Please note that when an error occurs, all subsequent loading from the stream will result in an
		error. This is to provide a save mechanism out of a read error. So instead of checking every value
		you read back yourself, they can be default and won't produce erratic behaviour.

		The value returned is true when the read was succesful, false when nothing was read.

		<b>SPECIAL CARE ABOUT THIS FUNCTION MUST BE TAKEN:</b>
		Reading an integer x-platform is potentially unsafe. The size of the integer may vary from 16 bits
		to 64 bits depending on the platform. When sharing data streams, the preferred way of streaming is
		using the wxUint16, wxUint32, wxUint64 data types. However, this method is made as safe as possible
		by also storing the size of the int on the stream. This means reading a stored integer of 4 bytes
		(32 bits) it will be read back as 32 bits, and casted to a 64 bits integer. In theory, this should
		work as the sign flag for a 32 bits container will be extended to match the 64 bits container. The
		only worst case scenario that exists is when an 64 bits int is written, and it needs to be casted
		to a 32 bits integer, problems can occur because the destination container may be too small. No error
		will be logged so be careful storing extreme values that might not fit in smaller integers.
    */
    bool ReadInt(int& value);

	/** Loads an pair of ints from stream. When the next record to be read is not an int, an error will occur.
	    When wxSerialize encountered the end of object boundary (see \ref enter_leave) or the archive is
		in an error state, the value is not touched.

        Please note that when an error occurs, all subsequent loading from the stream will result in an
		error. This is to provide a save mechanism out of a read error. So instead of checking every value
		you read back yourself, they can be default and won't produce erratic behaviour.

		The value returned is true when the read was succesful, false when nothing was read.

		<b>SPECIAL CARE ABOUT THIS FUNCTION MUST BE TAKEN:</b>
		Reading an integer x-platform is potentially unsafe. The size of the integer may vary from 16 bits
		to 64 bits depending on the platform. When sharing data streams, the preferred way of streaming is
		using the wxUint16, wxUint32, wxUint64 data types. However, this method is made as safe as possible
		by also storing the size of the int on the stream. This means reading a stored integer of 4 bytes
		(32 bits) it will be read back as 32 bits, and casted to a 64 bits integer. In theory, this should
		work as the sign flag for a 32 bits container will be extended to match the 64 bits container. The
		only worst case scenario that exists is when an 64 bits int is written, and it needs to be casted
		to a 32 bits integer, problems can occur because the destination container may be too small. No error
		will be logged so be careful storing extreme values that might not fit in smaller integers.
    */
    bool ReadIntInt(int& value1, int& value2);

	/** Variant of ReadIntInt() that will provide a default if the read was not succesful */
	bool ReadIntInt(int& value1, int& value2, int defval1, int defval2) {
		bool val = ReadIntInt(value1, value2);
		if(!val) {
			value1 = defval1;
			value2 = defval2;
		}
		return val;
	};

	/** Variant of ReadInt() that will provide a default if the read was not succesful */
	bool ReadInt(int& value, int defval) {
		bool val = ReadInt(value);
		if(!val)
			value = defval;
		return val;
	};


	/** Loads a wxFloat64 from stream. When the next record to be read is not a wxFloat64, an error will occur.
	    When wxSerialize encountered the end of object boundary (see \ref enter_leave) or the archive is
		in an error state, the value is not touched.

        Please note that when an error occurs, all subsequent loading from the stream will result in an
		error. This is to provide a save mechanism out of a read error. So instead of checking every value
		you read back yourself, they can be default and won't produce erratic behaviour.

		The value returned is true when the read was succesful, false when nothing was read. The wxFloat64 is
		stored as a IEEE converted standard wxFloat64, and is x-platform so it can be shared between other os'es
    */
    bool ReadDouble(wxFloat64& value);

	/** Variant of ReadDouble() that will provide a default if the read was not succesful */
	bool ReadDouble(wxFloat64& value, wxFloat64 defval) {
		bool val = ReadDouble(value);
		if(!val)
			value = defval;
		return val;
	};

	/** Loads a wxString from stream. When the next record to be read is not a wxString, an error will occur.
	    When wxSerialize encountered the end of object boundary (see \ref enter_leave) or the archive is
		in an error state, the value is not touched.

        Please note that when an error occurs, all subsequent loading from the stream will result in an
		error. This is to provide a save mechanism out of a read error. So instead of checking every value
		you read back yourself, they can be default and won't produce erratic behaviour.

		The value returned is true when the read was succesful, false when nothing was read. For the string
		first the count is stored and then the string itself. When storing an empty string, only a 0 count is
		stored.
    */
	bool ReadString(wxString& value);

	/** Variant of ReadString() that will provide a default if the read was not succesful */
	bool ReadString(wxString& value, const wxString &defval) {
		bool val = ReadString(value);
		if(!val)
			value = defval;
		return val;
	};

	/** Loads a wxArrayString from stream. When the next record to be read is not a wxArrayString, an error
		will occur.  When wxSerialize encountered the end of object boundary (see \ref enter_leave) or the archive is
		in an error state, the value is not touched.

        Please note that when an error occurs, all subsequent loading from the stream will result in an
		error. This is to provide a save mechanism out of a read error. So instead of checking every value
		you read back yourself, they can be default and won't produce erratic behaviour.

		The value returned is true when the read was succesful, false when nothing was read. For the string
		first the count is stored and then the string itself. When storing an empty string, only a 0 count is
		stored.
    */
	bool ReadArrayString(wxArrayString& value);

	/** Variant of ReadArrayString() that will provide a default if the read was not succesful */
	bool ReadString(wxArrayString& value, const wxArrayString &defval) {
		bool val = ReadArrayString(value);
		if(!val)
			value = defval;
		return val;
	};

	/** Loads a wxDateTime from stream. When the next record to be read is not a wxDateTime, an error
		will occur.  When wxSerialize encountered the end of object boundary (see \ref enter_leave) or the archive is
		in an error state, the value is not touched.

        Please note that when an error occurs, all subsequent loading from the stream will result in an
		error. This is to provide a save mechanism out of a read error. So instead of checking every value
		you read back yourself, they can be default and won't produce erratic behaviour.

		The value returned is true when the read was succesful, false when nothing was read. For the string
		first the count is stored and then the string itself. When storing an empty string, only a 0 count is
		stored.
    */
	bool ReadDateTime(wxDateTime& value);

    /** Reads a record from the stream. The wxMemoryBuffer is a growable buffer class, which will contain the data
	    being read. The length of the buffer will be the length present so there is no need to define a
		pre-allocated buffer. When the referenced buffer runs out of scope in your code, it is destroyed safely.

        The read buffer can be up to 4 Gb (count is 32 bits). The buffer will be considered an atomic element
        so when the read fails for the specified number of counts, the buffer is corrupted. This will ofcourse only
        happen when the stream unexpectedly terminates and will also occur with other atomic values like reading
        an integer etc.

        NOTICE FOR PLATFORM BINARY COMPATIBILITY: No conversion takes place when writing the buffer. It is written as
	    a sequence of bytes to the stream. So be careful storing the whole data back into a structure (little to big endian)
	*/
    bool Read(wxMemoryBuffer &buffer);

    /** Saves a bool to stream. It writes a header type first, and after that the value. This means when the boolean
	    is read back when it is not expected, an error occurs and the program can terminate gracefully because no
		bogus values are read back. True is returned when the value is saved properly, and false when it's not.
    */
    bool WriteBool(bool value);

    /** Saves a double as a wxFloat64 to stream. It writes a header type first, and after that the value. This means when the wxFloat64
	    is read back when it is not expected, an error occurs and the program can terminate gracefully because no
		bogus values are read back. True is returned when the value is saved properly, and false when it's not.

        The wxFloat64 is saved in a cross platform compatible mode, which means the streams can be interchanged between
		MacOS, Linux and Windows without problems.
    */
    bool WriteDouble(wxFloat64 value);

    /** Saves a wxUint8 to stream. It writes a header type first, and after that the value. This means when the wxUint8
	    is read back when it is not expected, an error occurs and the program can terminate gracefully because no
		bogus values are read back. True is returned when the value is saved properly, and false when it's not.

        The wxUint8 is saved in a cross platform compatible mode, which means the streams can be interchanged between
		MacOS, Linux and Windows without problems.
    */
    bool WriteUint8(wxUint8 value);

    /** Saves a wxUint16 to stream. It writes a header type first, and after that the value. This means when the wxUint16
	    is read back when it is not expected, an error occurs and the program can terminate gracefully because no
		bogus values are read back. True is returned when the value is saved properly, and false when it's not.

        The wxUint16 is saved in a cross platform compatible mode, which means the streams can be interchanged between
		MacOS, Linux and Windows without problems.
    */
    bool WriteUint16(wxUint16 value);

    /** Saves a wxUint32 to stream. It writes a header type first, and after that the value. This means when the wxUint32
	    is read back when it is not expected, an error occurs and the program can terminate gracefully because no
		bogus values are read back. True is returned when the value is saved properly, and false when it's not.

        The wxUint32 is saved in a cross platform compatible mode, which means the streams can be interchanged between
		MacOS, Linux and Windows without problems.
    */

    bool WriteUint32(wxUint32 value);

    /** Saves a wxUint64 to stream. It writes a header type first, and after that the value. This means when the wxUint64
	    is read back when it is not expected, an error occurs and the program can terminate gracefully because no
		bogus values are read back. True is returned when the value is saved properly, and false when it's not.

        The wxUint64 is saved in a cross platform compatible mode, which means the streams can be interchanged between
		MacOS, Linux and Windows without problems.
    */
    bool WriteUint64(wxUint64 value);

    /** Saves an int to stream. It writes a header type first, and after that the value. This means when the int
	    is read back when it is not expected, an error occurs and the program can terminate gracefully because no
		bogus values are read back. True is returned when the value is saved properly, and false when it's not.

		<b>SPECIAL CARE ABOUT THIS FUNCTION MUST BE TAKEN:</b>
		Writing an integer x-platform is potentially unsafe. The size of the integer may vary from 16 bits
		to 64 bits depending on the platform. When sharing data streams, the preferred way of streaming is
		using the wxUint16, wxUint32, wxUint64 data types. See ReadInt() for more information.
	*/
	bool WriteInt(int value);

    /** Saves a pair of ints to a stream. It is used for wxSize and wxPoint. It writes a header type first,
        and after that the value. This means when the int is read back when it is not expected, an error occurs
        and the program can terminate gracefully because no bogus values are read back. True is returned when
        the value is saved properly, and false when it's not.

		<b>SPECIAL CARE ABOUT THIS FUNCTION MUST BE TAKEN:</b>
		Writing an integer x-platform is potentially unsafe. The size of the integer may vary from 16 bits
		to 64 bits depending on the platform. When sharing data streams, the preferred way of streaming is
		using the wxUint16, wxUint32, wxUint64 data types. See ReadInt() for more information.
    */
    bool WriteIntInt(int value1, int value2);

    /** Saves a wxString to stream. It writes a header type first, and after that the value. This means when the wxString
	    is read back when it is not expected, an error occurs and the program can terminate gracefully because no
		bogus values are read back. True is returned when the value is saved properly, and false when it's not.

        The wxString is saved in a cross platform compatible mode, which means the streams can be interchanged between
		MacOS, Linux and Windows without problems. First the count is stored, then the string. With an empty string only
		the 0 count is stored.
    */
    bool WriteString(const wxString& value);

    /** Saves a wxArrayString to stream. It writes a header type first, and after that the value. This means when
		the wxArrayString is read back when it is not expected, an error occurs and the program can terminate
		gracefully because no bogus values are read back. True is returned when the value is saved properly, and
		false when it's not.

        The wxString is saved in a cross platform compatible mode, which means the streams can be interchanged between
		MacOS, Linux and Windows without problems. First the count is stored, then the string. With an empty string only
		the 0 count is stored.
    */
    bool WriteArrayString(const wxArrayString& value);

    /** Saves a wxDateTime to stream. It writes a header type first, and after that the value. This means when
		the wxDateTime is read back when it is not expected, an error occurs and the program can terminate
		gracefully because no bogus values are read back. True is returned when the value is saved properly, and
		false when it's not.

        The wxDateTime is saved in a cross platform compatible mode (e.g. the number of ticks). Please be aware that no
        timezone information or daylight saving information is stored. So if the date read back on a different PC is 
        mis interpreted because the PC is in a different time zone you must find other means of syncing them.
    */
    bool WriteDateTime(const wxDateTime& value);

	/** Saves an arbitrary amount of bytes to the stream using wxMemoryBuffer. It writes a header type first, and after
        that the count to be saved and the bytes in the wxMemoryBuffer. This means when the data is read back when
        it is not expected, an error occurs and the program can terminate gracefully because no bogus values are
        read back. True is returned when the value is saved properly, and false when it's not.

        Data can be saved up to 4Gb. This is not recommended (nor physically possible I think) but the limit is 32 bits for
        the count.

        NOTICE FOR PLATFORM BINARY COMPATIBILITY: No conversion takes place when writing the buffer. It is written as
	    a sequence of bytes to the stream. So be careful storing the whole data back into a structure (little to big endian)
    */
    bool Write(const wxMemoryBuffer &buffer);

    // -- arbitrary functions --

    /** Returns the header that was read by this stream. When writing, the header string contains
        the passed header by the constructor. See GetArchiveStatus() for more information. */
    wxString GetHeaderString() const {
        return m_headerStr;
    };

    /** Returns the version of the stream currently beaing read, or else the version of the stream when it
	    was created. This can be used to exclude parts while reading, if the stream version does not
        support newly added veriables like;

        \code
        // we expect version 1001 at least (lower versions are possible)
        wxSerialize a(in_stream, 1001);

        if(a.IsStoring())
        {
            a << m_name;

            // added since 1001
            a << m_addr;
        }
        else
        {
            a >> m_name;

            // only read when we are above 1000
            if(a.GetVersion() > 1000)
                a >> m_addr;
        }
        \endcode
    */
    size_t GetVersion() const {
        return m_version;
    };

	/** Returns the wxSerializeStatus object. You usually do this when you just read a stream, to get more
	    information about it later, like the version, header, and if the stream contained newer data which
		means writing it back with the older data model you might be using, you destroy information */
	const wxSerializeStatus &GetArchiveStatus() const {
		return m_status;
	};
    /// return the version string of the class wxSerialize
    static wxString GetLibVersionString ();
    /// return the major version number of the class wxSerialize
    static long GetLibVersionMajor ();
    /// return the minor version number of the class wxSerialize
    static long GetLibVersionMinor ();

private:
    // error types
	enum
	{
	    wxSERIALIZE_ERR_OK  =  0,
	    wxSERIALIZE_ERR_EOF = -1,
	    wxSERIALIZE_ERR_ILL = -2,
	    wxSERIALIZE_ERR_MEM = -3
	};

	// all errors that can occur
	enum
	{
		wxSERIALIZE_ERR_STR_HEADER_s1_s2,         /// Illegal header in start of stream
		wxSERIALIZE_ERR_STR_WRONGVERSION_s1_s2,   /// Not a proper version
		wxSERIALIZE_ERR_STR_BADISTREAM,           /// Bad input stream
		wxSERIALIZE_ERR_STR_BADOSTREAM,           /// Bad output stream
		wxSERIALIZE_ERR_STR_NOVERHDR,             /// Cannot write version or header info to stream
		wxSERIALIZE_ERR_STR_NOHEADER_s1,          /// Header expected but not found
		wxSERIALIZE_ERR_STR_NOVERSION,            /// No version found in stream
		wxSERIALIZE_ERR_STR_NOWRITE,              /// Cannot write in read mode
		wxSERIALIZE_ERR_STR_NOREAD,               /// Cannot read in write mode
        wxSERIALIZE_ERR_STR_EOF, 	                /// End of file error in read mode
        wxSERIALIZE_ERR_STR_WRONGCHUNK_s1_s2,     /// Expected header x but got y
        wxSERIALIZE_ERR_STR_MEMORY_s1,            /// Cannot allocate x bytes of memory
		wxSERIALIZE_ERR_STR_READSIZE,				/// Read size mismatch
		wxSERIALIZE_ERR_STR_RINTSIZE,				/// Integer size mismatch
		wxSERIALIZE_ERR_STR_SINTSIZE,				/// Ditto
		wxSERIALIZE_ERR_STR_ILL_LEAVE,			/// Illegal leave marker found
		wxSERIALIZE_ERR_STR_ILL_UNKNOWN_HDR_s1,	/// Unknown header error
		wxSERIALIZE_ERR_STR_ILL_LEVEL				/// Sync level failure!
	};

	// headers
	enum
	{
		wxSERIALIZE_HDR_BOOL      = 'b',
		wxSERIALIZE_HDR_INT8      = 'c',
		wxSERIALIZE_HDR_INT16     = 'w',
		wxSERIALIZE_HDR_INT32     = 'l',
		wxSERIALIZE_HDR_INT64     = 'q',
		wxSERIALIZE_HDR_DOUBLE    = 'd',
		wxSERIALIZE_HDR_STRING    = 's',
		wxSERIALIZE_HDR_RECORD    = 'r',
		wxSERIALIZE_HDR_INT       = 'i',
		wxSERIALIZE_HDR_ARRSTRING = 'a',
		wxSERIALIZE_HDR_DATETIME  = 't',
		wxSERIALIZE_HDR_ENTER     = '<',
		wxSERIALIZE_HDR_LEAVE     = '>',
		wxSERIALIZE_HDR_INTINT    = 'I'
	};

    // pre-check if stream is capable of writing, returns errors
    // when condition is not good (like input stream is defined
    // instead of output)
    bool CanStore();

    // pre-check if stream is capable of reading, returns errors
    // when condition is not good (like output stream is defined
    // instead of input)
    bool CanLoad();

	// loads the header, and sets an error when the expected header is not the same
	// as the header given
	int LoadChunkHeader(int expheader);

    // writes a single char to the stream
	void WriteChar(wxUint8 value);

	// sets an error with arbitrary message using wxLogError
	int LogError(int err, int msgcode, const wxString &s1 = wxEmptyString,
	                                   const wxString &s2 = wxEmptyString);

	// attempts to find the marker that belongs to this
	// current level. We assume the current count but increment when we
	// find one, decrement when we find another ..
	void FindCurrentEnterLevel();

	// finds current leave level. This means all enter levels we encounter
	// we will skip, until we have the level of our object - 1
	void FindCurrentLeaveLevel();

	// skip the data belonging by the header
	void SkipData(wxUint8 hdr);

	// load the buffer from a stream
	void Load(wxMemoryBuffer &buf);

    // reads a string (without header)
	wxString LoadString();

    // reads an array string without header
	wxArrayString LoadArrayString();

    // reads a datetime without header
	wxDateTime LoadDateTime();

    // reads a single char from the stream, returns '\0' when none can be read
	wxUint8 LoadChar();

    // see wxUint8 LoadChar()
    wxUint8 LoadUint8();

	// reads a wxUint16 (without header)
	wxUint16 LoadUint16();

	// reads a wxUint32 (without header)
	wxUint32 LoadUint32();

	// reads a wxUint64 (without header)
	wxUint64 LoadUint64();

    // reads a wxFloat64 (without header)
	wxFloat64 LoadDouble();

	// loads integer
	int LoadInt();

    // loads pair of integers
    void LoadIntInt (int& value1, int& value2);

	// reads a bool (without header)
	bool LoadBool();

    // writes a wxUint8 without header
    void SaveChar(wxUint8 value);

    // see SaveChar(wxUint8)
    void SaveUint8(wxUint8 value);

	// writes a wxUint16 (without header)
	void SaveUint16(wxUint16 value);

	// writes a wxUint32 (without header)
	void SaveUint32(wxUint32 value);

	// writes a wxUint64 (without header)
	void SaveUint64(wxUint64 value);

    // writes a string (without header)
	void SaveString(const wxString &str);

    // translates header name to something readable for errors
	wxString GetHeaderName(int headername);

	/** Sets the error to a specific condition. Valid error conditions are
		- wxSERIALIZE_OK
	    - wxSERIALIZE_ERR_EOF
	    - wxSERIALIZE_ERR_ILL
	    - wxSERIALIZE_ERR_MEM

	    The error will not change from the last error condition when it is
	    already set. Meaning it will keep the last error, even when others
	    follow.
	*/
	void SetError(int err) {
		// only set error when we are still ok
		if(m_errorCode == wxSERIALIZE_ERR_OK)
			m_errorCode = err;
	};

	// initialize function
	void InitAll();

private:
	// last error code issued in wxSerialize
	int m_errorCode;
	// the last logged error message
	wxString m_errMsg;
	// the header received
	wxString m_headerStr;
	// The version written or read
	size_t m_version;
	// opened status (true if open) Close() will close it
	bool m_opened;
	// partial save or load mode
	bool m_partialMode;
	// write or read mode of the stream
	bool m_writeMode;
	// under the hood output data stream (this stream is maintained by us)
	wxOutputStream &m_odstr;
	// under the hood output data stream (this stream is maintained by us)
	wxInputStream &m_idstr;
	// object marker level. Any level above 0 means we have encountered
	// an EnterObject and LeaveObject.
	int m_objectLevel;
	// flag to indicate that we encountered a LEAVE or ENTER marker. This means
	// no read should be done until we reached the LeaveObject() that
	// belongs to our level.
	bool m_haveBoundary;
	// last boundary encountered
	unsigned char m_lastBoundary;
	// temp vars that have only the purpose to initialize streams that
	// need to be initialized by ref. By using wxStringStream variants
	// we can safely read and load from them when this error might occur
	wxString m_tmpostr, m_tmpistr;
	wxStringOutputStream m_otmp;
	wxStringInputStream m_itmp;
	// The archive status object
	wxSerializeStatus m_status;
};

#endif