summaryrefslogtreecommitdiff
path: root/src/sysync/itemfield.h
blob: 468d831f683ed74d38dbb4f3e637a38081def313 (plain)
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
/*
 *  File:         itemfield.h
 *
 *  Author:       Lukas Zeller (luz@synthesis.ch)
 *
 *  TItemField
 *    Abstract class, holds a single field value
 *  TStringField, TIntegerField, TTelephoneField, TTimeStampField etc.
 *    Implementations of field types
 *
 *  Copyright (c) 2001-2009 by Synthesis AG (www.synthesis.ch)
 *
 *  2001-08-08 : luz : created
 *
 */

#ifndef ItemField_H
#define ItemField_H

// includes
#include "sysync_globs.h"
#include "sysync_utils.h"

#include "engineinterface.h"

#include <string>

#ifdef ARRAYFIELD_SUPPORT
#include <vector>
#endif

namespace sysync {

extern cAppCharP const ItemFieldTypeNames[numFieldTypes];

extern const TPropDataTypes devInfPropTypes[numFieldTypes];


#ifndef NO64BITINT
typedef sInt64 fieldinteger_t;
#define StrToFieldinteger(s,i) StrToLongLong(s,i)
#else
typedef sInt32 fieldinteger_t;
#define StrToFieldinteger(s,i) StrToLong(s,i)
#endif

// our own implementation for dynamic casts for Items without needing RTTI
#define ITEMFIELD_DYNAMIC_CAST_PTR(ty,tyid,src) (src->isBasedOn(tyid) ? static_cast<ty *>(src) : NULL)


// basically abstract class, but can be used to represent EMPTY and ASSIGNED values
class TItemField
{
public:
  TItemField();
  virtual ~TItemField();
  #ifdef ARRAYFIELD_SUPPORT
  // check array
  virtual bool isArray(void) const { return false; }
  virtual TItemField *getArrayField(sInt16 aArrIdx, bool /* aExistingOnly */=false) { return aArrIdx==0 ? this : NULL; };
  virtual sInt16 arraySize(void) const { return 1; } // non-array has one element
  virtual TItemFieldTypes getElementType(void) const { return getType(); } // non array element is same as base type
  #else
  // non-virtual versions if we have no array fields at all
  bool isArray(void) const { return false; }
  TItemField *getArrayField(sInt16 aArrIdx, bool aExistingOnly=false) { return aArrIdx==0 ? this : NULL; };
  sInt16 arraySize(void) const { return 1; } // non-array has one element
  TItemFieldTypes getElementType(void) const { return getType(); }
  #endif
  // changelog support
  #if defined(CHECKSUM_CHANGELOG) && !defined(RECORDHASH_FROM_DBAPI)
  virtual uInt16 getDataCRC(uInt16 crc=0) { return crc; }; // base class is always empty
  #endif
  // access to type
  virtual TItemFieldTypes getType(void) const { return fty_none; } // no real type
  virtual TItemFieldTypes getCalcType(void) const { return getType(); };
  virtual bool isBasedOn(TItemFieldTypes aFieldType) const { return aFieldType==fty_none; };
  virtual bool elementsBasedOn(TItemFieldTypes aFieldType) const { return isBasedOn(aFieldType); };
  // dependency on a local ID
  virtual void setParentLocalID(cAppCharP /* aParentLocalID */) { /* nop */ };
  // access to field contents
  #ifdef STREAMFIELD_SUPPORT
  // - stream interface (default implementation accesses string representation of field)
  virtual void resetStream(size_t aPos=0);
  virtual size_t getStreamSize(void) { return getStringSize(); };
  virtual size_t getStreamPos(void) const { return fStreamPos; };
  virtual size_t readStream(void *aBuffer, size_t aMaxBytes);
  virtual size_t writeStream(void *aBuffer, size_t aNumBytes);
  void appendStream(void) { resetStream(getStreamSize()); };
  #endif
  virtual bool hasProxy(void) { return false; }; // normal fields don't have a proxy
  // - as string
  virtual void setAsString(cAppCharP /* aString */) { fAssigned=true; }; // basic setter, this one must be derived for all non-string descendants
  virtual void setAsString(cAppCharP aString, size_t aLen);
  virtual void setAsString(const string &aString) { setAsString(aString.c_str(),aString.size()); };
  virtual void getAsString(string &aString) { aString.erase(); }; // empty string by default
  virtual void appendToString(string &aString, size_t aMaxLen=0) { string s; getAsString(s); if (aMaxLen) aString.append(s,0,aMaxLen); else aString.append(s); }; // generic append
  virtual cAppCharP getCStr(void) { return NULL; } // only real strings can return CStr (used for PalmOS optimization)
  virtual void getAsNormalizedString(string &aString) { getAsString(aString); };
  virtual size_t getStringSize(void);
  // - as boolean (default: non-empty is true)
  virtual bool getAsBoolean(void) { return !isEmpty(); };
  virtual void setAsBoolean(bool aBool) { if (aBool) setAsString("1"); else assignEmpty(); };
  // - as integer
  virtual fieldinteger_t getAsInteger(void);
  virtual void setAsInteger(fieldinteger_t aInteger);
  // some string operations
  // - append string/char
  virtual void appendString(cAppCharP /* aString */, size_t /* aMaxChars */) { /* nop */ };
  void appendString(cAppCharP aString) { appendString(aString,strlen(aString)); };
  void appendString(const string &aString) { appendString(aString.c_str(),aString.size()); };
  void appendChar(const char aChar) { appendString(&aChar,1); };
  // - check if specified value is contained in myself
  virtual bool contains(TItemField &aItemField, bool aCaseInsensitive);
  // - find string in contents
  virtual sInt16 findInString(cAppCharP /* aString */, bool /* aCaseInsensitive */) { return -1; };
  // - check if specified field is shortened version of this one
  virtual bool isShortVers(TItemField & /* aItemField */, sInt32 /* aOthersMax */) { return false; };
  // - assignment
  virtual bool isAssigned(void) { return fAssigned; };
  bool isUnassigned(void) { return !isAssigned(); };
  virtual void unAssign(void) { fAssigned=false; };
  // empty is NOT always same as unassigned; e.g. for strings empty can be empty string assigned
  virtual bool isEmpty(void) { return getType()==fty_none ? true : isUnassigned(); }
  // - make assigned, but empty (explicit "" string assigned)
  virtual void assignEmpty(void) { fAssigned=true; };
  // assignment
  virtual TItemField& operator=(TItemField &aItemField);
  // field comparison
  bool operator==(TItemField &aItem) { return compareWith(aItem)==0; }
  bool operator!=(TItemField &aItem) { return compareWith(aItem)!=0; }
  bool operator>(TItemField &aItem) { return compareWith(aItem)>0; }
  bool operator>=(TItemField &aItem) { return compareWith(aItem)>=0; }
  bool operator<(TItemField &aItem) { return compareWith(aItem)<0; }
  bool operator<=(TItemField &aItem) { return compareWith(aItem)<=0; }
  // append (default to appending string value of other field)
  virtual void append(TItemField &aItemField);
  // merge fields
  virtual bool merge(TItemField & /* aItemField */, const char /* aSep */=0) { return false; /* nop */ };
  // compare: returns 0 if equal, 1 if this > aItem, -1 if this < aItem,
  // SYSYNC_NOT_COMPARABLE if not comparable at all or not equal and no ordering known
  virtual sInt16 compareWith(TItemField & /* aItemField */, bool =false /* aCaseInsensitive */) { return SYSYNC_NOT_COMPARABLE; };
  // debug support
  #ifdef SYDEBUG
  virtual size_t StringObjFieldAppend(string &s, uInt16 aMaxStrLen); // show field contents as string for debug output
  #endif
protected:
  // assigned flag
  bool fAssigned;
  #ifdef STREAMFIELD_SUPPORT
  // stream position
  size_t fStreamPos;
  #endif
}; // TItemField

typedef TItemField *TItemFieldP;



#ifdef ARRAYFIELD_SUPPORT

typedef std::vector<TItemField *> TFieldArray;

// array field, contains a list of fields of TItemFields
class TArrayField : public TItemField
{
  typedef TItemField inherited;
public:
  TArrayField(TItemFieldTypes aLeafFieldType, GZones *aGZonesP);
  virtual ~TArrayField();
  // check array
  virtual bool isArray(void) const { return true; }
  virtual TItemField *getArrayField(sInt16 aArrIdx, bool aExistingOnly=false);
  virtual sInt16 arraySize(void) const { return fArray.size(); } // return size of array
  // changelog support
  #if defined(CHECKSUM_CHANGELOG) && !defined(RECORDHASH_FROM_DBAPI)
  virtual uInt16 getDataCRC(uInt16 crc=0);
  #endif
  // access to type
  virtual TItemFieldTypes getType(void) const { return fty_none; } // array has no type
  virtual TItemFieldTypes getElementType(void) const { return fLeafFieldType; } // type of leaf fields (accessible even if array is empty)
  virtual bool elementsBasedOn(TItemFieldTypes aFieldType) const;
  // some string operations
  // - assignment
  virtual bool isAssigned(void) { return !isEmpty() || fAssigned; }; // empty, but explicitly assigned so is assigned as well
  virtual void unAssign(void); // clear all elements and clear fAssigned
  // - append string to array = append string as last element of array
  virtual void appendString(cAppCharP aString, size_t aMaxChars);
  // empty is array with no elements
  virtual bool isEmpty(void) { return arraySize()==0; };
  // - make assigned
  virtual void assignEmpty(void) { unAssign(); fAssigned = true; }; // assigning emptyness must make isAssigned true!
  // assignment
  virtual TItemField& operator=(TItemField &aItemField);
  // check if specified value is contained in myself
  virtual bool contains(TItemField &aItemField, bool aCaseInsensitive);
  // append (default to appending value of other field as a new array element)
  virtual void append(TItemField &aItemField);
  // merge fields
  virtual bool merge(TItemField & /* aItemField */, const char /* aSep */=0) { return false; /* nop */ };
  // compare: returns 0 if equal, 1 if this > aItem, -1 if this < aItem,
  // SYSYNC_NOT_COMPARABLE if not comparable at all or not equal and no ordering known
  virtual sInt16 compareWith(TItemField &aItemField, bool aCaseInsensitive=false);
  // debug support
  #ifdef SYDEBUG
  virtual size_t StringObjFieldAppend(string &s, uInt16); // show field contents as string for debug output
  #endif
protected:
  // type of contained leaf fields
  TItemFieldTypes fLeafFieldType;
  // first field, is instantiated with array to allow type comparisons
  TItemField *fFirstField;
  // Zones for fields
  GZones *fGZonesP;
  // actual field vector
  TFieldArray fArray;
}; // TArrayField
#endif


#ifndef STREAMFIELD_SUPPORT
  #define PULLFROMPROXY
  #define DELETEPROXY
  #define PROXYINSTALLED false
#else
  #define PULLFROMPROXY pullFromProxy()
  #define DELETEPROXY setBlobProxy(NULL)
  #define PROXYINSTALLED (fBlobProxyP!=NULL)

// forward
class TStringField;

// abstract Proxy object for Blob contents, allows loading a BLOB from DB at the moment it is
// actually required.
// Intended to be derived by database implementations
class TBlobProxy
{
public:
  TBlobProxy() { fUsage=1; } // initial creator also gets owner
  virtual ~TBlobProxy() {};
  // - returns size of entire blob
  virtual size_t getBlobSize(TStringField *aFieldP) = 0;
  // - read from Blob from specified stream position and update stream pos
  virtual size_t readBlobStream(TStringField *aFieldP, size_t &aPos, void *aBuffer, size_t aMaxBytes) = 0;
  // - dependency on a local ID
  virtual void setParentLocalID(cAppCharP aParentLocalID) { /* nop */ };
  // - usage control
  void link(void) { fUsage++; };
  static void unlink(TBlobProxy *&aProxyP) { if (aProxyP) { if (--(aProxyP->fUsage) == 0) delete aProxyP; aProxyP=NULL; } };
private:
  uInt16 fUsage;
}; // TBlobProxy

#endif


// string field.
// Note that a string can also be a string of binary data,
// not only a NUL-terminated string (as used in derived blob class)
class TStringField: public TItemField
{
  typedef TItemField inherited;
  friend class TBlobProxy;
public:
  TStringField();
  virtual ~TStringField();
  // access to type
  virtual TItemFieldTypes getType(void) const { return fty_string; };
  virtual bool isBasedOn(TItemFieldTypes aFieldType) const { return aFieldType==fty_string ? true : TItemField::isBasedOn(aFieldType); };
  // changelog support
  #if defined(CHECKSUM_CHANGELOG) && !defined(RECORDHASH_FROM_DBAPI)
  virtual uInt16 getDataCRC(uInt16 crc=0);
  #endif
  // assignment
  virtual TItemField& operator=(TItemField &aItemField);
  // access to normalized version of content
  virtual void getAsNormalizedString(string &aString);
  // access to field contents
  #ifdef STREAMFIELD_SUPPORT
  // - set blob loader proxy (ownership is passed to field)
  void setBlobProxy(TBlobProxy *aBlobProxyP);
  // - stream interface
  virtual size_t getStreamSize(void);
  virtual size_t readStream(void *aBuffer, size_t aMaxBytes);
  virtual size_t writeStream(void *aBuffer, size_t aNumBytes);
  virtual bool hasProxy(void) { return fBlobProxyP!=NULL; };
  // - stream field proxies actually can have dependencies on a local ID
  virtual void setParentLocalID(cAppCharP aParentLocalID) { if (fBlobProxyP) fBlobProxyP->setParentLocalID(aParentLocalID); };
  #endif
  // - as string
  virtual void setAsString(cAppCharP aString) { DELETEPROXY; if (aString) fString=aString; else fString.erase(); stringWasAssigned(); };
  virtual void setAsString(const string &aString) { DELETEPROXY; fString=aString; stringWasAssigned(); }; // works even if string contains NULs
  virtual void setAsString(cAppCharP aString, size_t aLen);
  virtual void getAsString(string &aString) { PULLFROMPROXY; aString=fString; };
  virtual void appendToString(string &aString, size_t aMaxLen=0) { PULLFROMPROXY; if (aMaxLen) aString.append(fString,0,aMaxLen); else aString.append(fString); };
  virtual cAppCharP getCStr(void) { PULLFROMPROXY; return fString.c_str(); } // string can return CStr (used for PalmOS optimization)
  virtual size_t getStringSize(void); // can cause proxied values to be retrieved, so use with care with BLOBS
  virtual void unAssign(void) { DELETEPROXY; fString.erase(); TItemField::unAssign(); };
  // empty test
  virtual bool isEmpty(void) { return isUnassigned() || getStringSize()==0; }
  virtual void assignEmpty(void) { DELETEPROXY; fString.erase(); TItemField::assignEmpty(); };
  // some string operations
  // - append string
  virtual void appendString(cAppCharP aString, size_t aMaxChars);
  // - check if specified field is shortened version of this one
  virtual bool isShortVers(TItemField &aItemField, sInt32 aOthersMax);
  // - check if String is contained in value and returns position
  virtual sInt16 findInString(cAppCharP aString, bool aCaseInsensitive=false);
  // merge fields
  virtual bool merge(TItemField &aItemField, const char aSep=0);
  // compare: returns 0 if equal, 1 if this > aItem, -1 if this < aItem
  // SYSYNC_NOT_COMPARABLE if not equal and no ordering known
  virtual sInt16 compareWith(TItemField &aItemField, bool aCaseInsensitive=false);
  #ifdef STREAMFIELD_SUPPORT
  void pullFromProxy(void);
  #endif
  // debug support
  #ifdef SYDEBUG
  virtual size_t StringObjFieldAppend(string &s, uInt16 aMaxStrLen);
  #endif
protected:
	virtual void stringWasAssigned(void) { fAssigned=true; }; // post-process string that was just assigned
  #ifdef STREAMFIELD_SUPPORT
  TBlobProxy *fBlobProxyP;
  #endif
  string fString;
}; // TStringField


// BLOB field. This is a string field but has many direct access functions
// disabled, contents should only be read using stream interface,
// comparing is not possible
class TBlobField: public TStringField
{
  typedef TStringField inherited;
public:
  TBlobField();
  virtual ~TBlobField();
  // access to type
  virtual TItemFieldTypes getType(void) const { return fty_blob; };
  virtual bool isBasedOn(TItemFieldTypes aFieldType) const { return aFieldType==fty_blob ? true : TStringField::isBasedOn(aFieldType); };
  // changelog support
  //  Note: uses inherited implementation of TStringField
  // assignment
  virtual TItemField& operator=(TItemField &aItemField);
  // - as string
  virtual void getAsString(string &aString) { StringObjPrintf(aString,"<BLOB size=%ld>", long(getStringSize())); }; // must be read with stream interface
  void getBlobAsString(string &aString) { TStringField::getAsString(aString); }; // must use this one to get as string
  // - as Pointer/Data
  void getBlobDataPtrSz(void *&aPtr, size_t &aSize) { aPtr=(void *)TStringField::getCStr(); aSize=TStringField::getStringSize(); };
  void setBlobDataPtrSz(void *aPtr, size_t aSize) { setAsString((cAppCharP)aPtr, aSize); };
  // - test
  virtual bool isEmpty(void) { return isUnassigned(); } // do not test for empty string as this would cause BLOB to be read
  // some string operations
  // - check if specified field is shortened version of this one
  virtual bool isShortVers(TItemField & /* aItemField */, sInt32 /* aOthersMax */) { return false; }; // cannot compare
  // - check if String is contained in value and returns position
  virtual sInt16 findInString(cAppCharP /* aString */, bool /* aCaseInsensitive */) { return -1; }; // cannot search
  // merge fields
  virtual bool merge(TItemField & /* aItemField */, const char /* aSep */=0) { return false; }; // cannot merge
  // compare: returns 0 if equal, 1 if this > aItem, -1 if this < aItem
  // SYSYNC_NOT_COMPARABLE if not equal and no ordering known
  virtual sInt16 compareWith(TItemField & /* aItemField */, bool /* aCaseInsensitive */) { return SYSYNC_NOT_COMPARABLE; }; // cannot compare
  // make contents and encoding/charset valid
  void makeContentsValid(void) { PULLFROMPROXY; };
  // debug support
  #ifdef SYDEBUG
  virtual size_t StringObjFieldAppend(string &s, uInt16 aMaxStrLen); // show field contents as string for debug output
  #endif
  // extra info about BLOB contents
  TEncodingTypes fHasEncoding;
  TEncodingTypes fWantsEncoding;
  TCharSets fCharset;
}; // TBlobField


// telephone number string field
// compares normalized version of number text (only +*# and digits)
class TTelephoneField: public TStringField
{
  typedef TStringField inherited;
public:
  TTelephoneField();
  virtual ~TTelephoneField();
  // access to type
  virtual TItemFieldTypes getType(void) const { return fty_telephone; };
  virtual TItemFieldTypes getCalcType(void) const { return fty_string; };
  virtual bool isBasedOn(TItemFieldTypes aFieldType) const { return aFieldType==fty_telephone ? true : TStringField::isBasedOn(aFieldType); };
  // assignment
  virtual TItemField& operator=(TItemField &aItemField) { return TStringField::operator=(aItemField); };
  // access to normalized version of content
  virtual void getAsNormalizedString(string &aString);
  // compare: returns 0 if equal, 1 if this > aItem, -1 if this < aItem
  // SYSYNC_NOT_COMPARABLE if not equal and no ordering known
  virtual sInt16 compareWith(TItemField &aItemField, bool aCaseInsensitive=false);
}; // TTelephoneField


// multiline string field
// compares without any leading or trailing whitespace, linefeeds, controlchars
class TMultilineField: public TStringField
{
  typedef TStringField inherited;
public:
  TMultilineField();
  virtual ~TMultilineField();
  // access to type
  virtual TItemFieldTypes getType(void) const { return fty_multiline; };
  virtual TItemFieldTypes getCalcType(void) const { return fty_string; };
  virtual bool isBasedOn(TItemFieldTypes aFieldType) const { return aFieldType==fty_multiline ? true : TStringField::isBasedOn(aFieldType); };
  // assignment
  virtual TItemField& operator=(TItemField &aItemField) { return TStringField::operator=(aItemField); };
  // compare: returns 0 if equal, 1 if this > aItem, -1 if this < aItem
  // SYSYNC_NOT_COMPARABLE if not equal and no ordering known
  virtual sInt16 compareWith(TItemField &aItemField, bool aCaseInsensitive=false);
}; // TMultilineField


// URL field
// normalizes URL (appends http:// if no protocol part specified)
class TURLField: public TStringField
{
  typedef TStringField inherited;
public:
  TURLField();
  virtual ~TURLField();
  // access to type
  virtual TItemFieldTypes getType(void) const { return fty_url; };
  virtual TItemFieldTypes getCalcType(void) const { return fty_string; };
  virtual bool isBasedOn(TItemFieldTypes aFieldType) const { return aFieldType==fty_url ? true : TStringField::isBasedOn(aFieldType); };
  // assignment
  virtual TItemField& operator=(TItemField &aItemField) { return TStringField::operator=(aItemField); };
  //%%%virtual void setAsString(cAppCharP aString);
  virtual void stringWasAssigned(void); // post-process string that was just assigned
}; // TURLField


class TTimestampField: public TItemField
{
  typedef TItemField inherited;
public:
  TTimestampField(GZones *aGZonesP);
  virtual ~TTimestampField();
  // access to type
  virtual TItemFieldTypes getType(void) const { return fty_timestamp; };
  virtual TItemFieldTypes getCalcType(void) const { return fty_integer; };
  virtual bool isBasedOn(TItemFieldTypes aFieldType) const { return aFieldType==fty_timestamp ? true : TItemField::isBasedOn(aFieldType); };
  // assignment
  virtual TItemField& operator=(TItemField &aItemField);
  // changelog support
  #if defined(CHECKSUM_CHANGELOG) && !defined(RECORDHASH_FROM_DBAPI)
  virtual uInt16 getDataCRC(uInt16 crc=0);
  #endif
  // access to field contents
  virtual void setAsString(cAppCharP aString);
  virtual void getAsString(string &aString);
  virtual fieldinteger_t getAsInteger(void) { return (fieldinteger_t)fTimestamp; };
  virtual void setAsInteger(fieldinteger_t aInteger) { fTimestamp = (lineartime_t)aInteger; }; // does not touch the timecontext!
  virtual void unAssign(void) { fTimestamp=noLinearTime; fTimecontext=TCTX_UNKNOWN; TItemField::unAssign(); };
  // empty test (zero timestamp means empty, unless it is a duration)
  virtual bool isEmpty(void) { return isUnassigned() || (fTimestamp==noLinearTime && !TCTX_IS_DURATION(fTimecontext)); }
  virtual void assignEmpty(void) { fTimestamp=noLinearTime; fTimecontext=TCTX_UNKNOWN; TItemField::assignEmpty(); };
  // compare: returns 0 if equal, 1 if this > aItem, -1 if this < aItem
  // SYSYNC_NOT_COMPARABLE if not equal and no ordering known
  virtual sInt16 compareWith(TItemField &aItemField, bool aCaseInsensitive=false);
  // type specific access and utilities
  /// @brief add a delta time to the timestamp
  /// @param aDeltaTime[in] : delta time value in lineartime_t units
  void addTime(lineartime_t aDeltaTime);
  /// @brief get time context
  /// @return time context
  timecontext_t getTimeContext(void) { return fTimecontext; }
  /// @brief get time context
  /// @return minute offset east of UTC, returns 0 for floating timestamps (and UTC, of course)
  sInt16 getMinuteOffset(void);
  /// @brief test for floating time (=time not in a specified zone context)
  /// @return true if context is TCTX_UNKNOWN
  bool isFloating(void);
  /// @brief make timestamp floating (i.e. remove time zone info from context)
  void makeFloating(void);
  /// @brief test for duration
  /// @return true if context has TCTX_DURATION rendering flag set
  bool isDuration(void);
  /// @brief make timestamp a duration (also implies making it floating)
  void makeDuration(void);
  /// @brief get timestamp converted to a specified time context
  /// @param aTargetContext[in] : requests output context for timestamp.
  ///        Use TCTX_UNKNOWN to get timestamp as-is.
  ///        If timestamp is floating, it will always be returned as-is
  /// @param aActualContext[out] : if not NULL, the actual context of the returned value
  ///        will be returned here. This might be another
  //         context than specified with aTargetContext depending on floating/notime status.
  /// @return timestamp in lineartime
  lineartime_t getTimestampAs(timecontext_t aTargetContext, timecontext_t *aActualContext=NULL);
  /// @brief get timestamp as ISO8601 string.
  /// @param aISOString[out] : timestamp in ISO8601 format
  /// @param aTargetContext[in] : requests output context for timestamp. Use TCTX_UNKNOWN to show timestamp as-is.
  /// @param aShowWithZ[in] : if set and timezone is UTC, value will be shown with "Z" appended
  /// @param aShowWithZone[in] : if set and timestamp is not floating, zone offset will be appended in +-xx:xx form
  /// @param aExtFormat[in] : if set, ISO8601 extended format is used
  /// @param aWithFracSecs[in] : if set, fractions of seconds will be shown (millisecond resolution)
  void getAsISO8601(string &aISOString, timecontext_t aTargetContext, bool aShowWithZ=true, bool aShowWithZone=false, bool aExtFormat=false, bool aWithFracSecs=false);
  /// @brief set timestamp value and context
  /// @param aTimestamp[in] : timestamp to set
  /// @param aTimecontext[in] : context to set
  void setTimestampAndContext(lineartime_t aTimestamp, timecontext_t aTimecontext) { setTimestamp(aTimestamp); setTimeContext(aTimecontext); };
  /// @brief set timestamp value without context
  /// @param aTimestamp[in] : timestamp to set
  void setTimestamp(lineartime_t aTimestamp) { fTimestamp=aTimestamp; fAssigned=true; };
  /// @brief set timestamp value and context
  /// @param aTimecontext[in] : context to set (timestamp will not be touched or converted)
  virtual void setTimeContext(timecontext_t aTimecontext) { fTimecontext=aTimecontext; fAssigned=true; };
  /// @brief move timestamp to specified context (i.e. convert the timestamp value from current to
  ///        specified context). Floating timestamps cannot and will not be moved.
  /// @param aNewcontext[in] : context to move timestamp to.
  ///                          timestamp will be converted to represent the same point in time in the new context
  /// @param aSetUnmovables : if set, non-movable timestamps will be just assigned the new context,
  //                          that is floating timestamps will be bound to specified context or
  //                          non-floating timestamps will be made floating if new context is TCTX_UNKNOWN
  bool moveToContext(timecontext_t aNewcontext, bool aSetUnmovables=false);
  /// @brief set timestamp from ISO8601 string.
  /// @return true if successful
  /// @param aISOString[in] : timestamp in ISO8601 basic or extended format, optionally including Z or +xx:xx zone specifier
  /// @param aDefaultContext[in] : timezone context to use when ISO8601 does not specify a zone context or when aIgnoreZone is true
  /// @param aIgnoreZone[in] : if set, timezone specification contained in ISO8601 is ignored. Resulting time context will be aDefaultContext
  bool setAsISO8601(cAppCharP aISOString, timecontext_t aDefaultContext=TCTX_UNKNOWN, bool aIgnoreZone=false);
  #ifdef EMAIL_FORMAT_SUPPORT
  /// @brief get timestamp as RFC(2)822 style date
  /// @param aRFC822String[out] : timestamp in RFC(2)822 format
  /// @param aTargetContext[in] : requests output context for timestamp. Use TCTX_UNKNOWN to show timestamp as-is.
  /// @param aShowWithZone[in] : if set and timestamp is not floating, zone offset will be shown
  void getAsRFC822date(string &aRFC822String, timecontext_t aTargetContext, bool aShowWithZone=false);
  /// @brief set timestamp as RFC(2)822 style date
  /// @return true if successful
  /// @param aRFC822String[in] : timestamp in RFC(2)822 format
  /// @param aDefaultContext[in] : timezone context to use when RFC822 date does not specify a time zone
  /// @param aIgnoreZone[in] : if set, timezone specification contained in input string is ignored. Resulting time context will be aDefaultContext
  bool setAsRFC822date(cAppCharP aRFC822String, timecontext_t aDefaultContext=TCTX_UNKNOWN, bool aIgnoreZone=false);
  #endif // EMAIL_FORMAT_SUPPORT
  // debug support
  #ifdef SYDEBUG
  virtual size_t StringObjFieldAppend(string &s, uInt16 aMaxStrLen);
  #endif
  GZones *getGZones(void) { return fGZonesP; };
protected:
  lineartime_t fTimestamp;    // timestamp in context indicated by fTimecontext
  timecontext_t fTimecontext; // context/options of timestamp
  GZones *fGZonesP; // zones
}; // TTimestampField


class TDateField: public TTimestampField
{
  typedef TTimestampField inherited;
public:
  TDateField(GZones *aGZonesP);
  virtual ~TDateField();
  // assignment
  virtual TItemField& operator=(TItemField &aItemField) { return TTimestampField::operator=(aItemField); };
  // access to type
  virtual TItemFieldTypes getType(void) const { return fty_date; };
  virtual TItemFieldTypes getCalcType(void) const { return fty_integer; };
  virtual bool isBasedOn(TItemFieldTypes aFieldType) const { return aFieldType==fty_date ? true : TTimestampField::isBasedOn(aFieldType); };
  // access to field contents
  virtual void setAsString(cAppCharP aString);
  virtual void getAsString(string &aString);
  // compare: returns 0 if equal, 1 if this > aItem, -1 if this < aItem
  // SYSYNC_NOT_COMPARABLE if not equal and no ordering known
  virtual sInt16 compareWith(TItemField &aItemField, bool aCaseInsensitive=false);
  /// @brief set timestamp value and context
  /// @param aTimecontext[in] : context to set (timestamp will not be touched or converted)
  virtual void setTimeContext(timecontext_t aTimecontext) { fTimecontext=aTimecontext | TCTX_DATEONLY; fAssigned=true; };
}; // TDateField


class TIntegerField: public TItemField
{
  typedef TItemField inherited;
public:
  TIntegerField();
  virtual ~TIntegerField();
  // access to type
  virtual TItemFieldTypes getType(void) const { return fty_integer; };
  virtual bool isBasedOn(TItemFieldTypes aFieldType) const { return aFieldType==fty_integer ? true : TItemField::isBasedOn(aFieldType); };
  // assignment
  virtual TItemField& operator=(TItemField &aItemField);
  // changelog support
  #if defined(CHECKSUM_CHANGELOG) && !defined(RECORDHASH_FROM_DBAPI)
  virtual uInt16 getDataCRC(uInt16 crc=0);
  #endif
  // access to field contents
  // - as string
  virtual void setAsString(cAppCharP aString);
  virtual void getAsString(string &aString);
  virtual void unAssign(void) { fInteger=0; TItemField::unAssign(); };
  // - as boolean (empty is false, zero value is false, other values are true)
  virtual bool getAsBoolean(void) { return !(isEmpty() || fInteger==0); };
  virtual void setAsBoolean(bool aBool) { fAssigned=true; fEmpty=false; if (aBool) fInteger=1; else fInteger=0; };
  virtual fieldinteger_t getAsInteger(void);
  virtual void setAsInteger(fieldinteger_t aInteger);
  // empty test and assignment
  virtual bool isEmpty(void) { return isUnassigned() || fEmpty; };
  virtual void assignEmpty(void) { fInteger=0; fEmpty=true; TItemField::assignEmpty(); };
  // compare: returns 0 if equal, 1 if this > aItem, -1 if this < aItem
  // SYSYNC_NOT_COMPARABLE if not equal and no ordering known
  virtual sInt16 compareWith(TItemField &aItemField, bool aCaseInsensitive=false);
protected:
  fieldinteger_t fInteger; // integer value
  bool fEmpty; // extra empty flag
}; // TIntegerField



// factory function
TItemField *newItemField(const TItemFieldTypes aType, GZones *aGZonesP, bool aAsArray=false);


#ifdef ENGINEINTERFACE_SUPPORT


// special flags coded into value ID
#define VALID_FLAG_TZNAME  0x010000
#define VALID_FLAG_TZOFFS  0x020000
#define VALID_FLAG_ARRSIZ  0x040000
#define VALID_FLAG_VALNAME 0x080000
#define VALID_FLAG_VALTYPE 0x100000
#define VALID_FLAG_NORM    0x200000
#define VALID_MASK_FID     0x00FFFF


// key for access to a item using the settings key API
class TItemFieldKey :
  public TSettingsKeyImpl
{
  typedef TSettingsKeyImpl inherited;
public:
  TItemFieldKey(TEngineInterface *aEngineInterfaceP) :
    inherited(aEngineInterfaceP),
    fWritten(false)
  {};

  // get value's ID (e.g. internal index)
  virtual sInt32 GetValueID(cAppCharP aName);

  bool isWritten(void) { return fWritten; };
protected:

  // get value's native type
  virtual uInt16 GetValueType(sInt32 aID);

  // get value
  virtual TSyError GetValueInternal(
    sInt32 aID, sInt32 aArrayIndex,
    appPointer aBuffer, memSize aBufSize, memSize &aValSize
  );

  // set value
  virtual TSyError SetValueInternal(
    sInt32 aID, sInt32 aArrayIndex,
    cAppPointer aBuffer, memSize aValSize
  );

  // flag that will be set on first write access
  bool fWritten;

  // abstract methods to actually access a TItemField
  virtual sInt16 getFidFor(cAppCharP aName, stringSize aNameSz) = 0;
  virtual TItemField *getBaseFieldFromFid(sInt16 aFid) = 0;
  virtual bool getFieldNameFromFid(sInt16 aFid, string &aFieldName) { return false; /* no name */ };

private:
  // utility
  TItemField *getFieldFromFid(sInt16 aFid, sInt16 aRepOffset, bool aExistingOnly=false);


}; // TItemFieldKey

#endif // ENGINEINTERFACE_SUPPORT


}	// namespace sysync

#endif	// ItemField_H

// eof