SAGA API  v9.5
table_dbase.cpp
Go to the documentation of this file.
1 /**********************************************************
2  * Version $Id$
3  *********************************************************/
4 
6 // //
7 // SAGA //
8 // //
9 // System for Automated Geoscientific Analyses //
10 // //
11 // Application Programming Interface //
12 // //
13 // Library: SAGA_API //
14 // //
15 //-------------------------------------------------------//
16 // //
17 // table_dbase.cpp //
18 // //
19 // Copyright (C) 2005 by Olaf Conrad //
20 // //
21 //-------------------------------------------------------//
22 // //
23 // This file is part of 'SAGA - System for Automated //
24 // Geoscientific Analyses'. //
25 // //
26 // This library is free software; you can redistribute //
27 // it and/or modify it under the terms of the GNU Lesser //
28 // General Public License as published by the Free //
29 // Software Foundation, either version 2.1 of the //
30 // License, or (at your option) any later version. //
31 // //
32 // This library is distributed in the hope that it will //
33 // be useful, but WITHOUT ANY WARRANTY; without even the //
34 // implied warranty of MERCHANTABILITY or FITNESS FOR A //
35 // PARTICULAR PURPOSE. See the GNU Lesser General Public //
36 // License for more details. //
37 // //
38 // You should have received a copy of the GNU Lesser //
39 // General Public License along with this program; if //
40 // not, see <http://www.gnu.org/licenses/>. //
41 // //
42 //-------------------------------------------------------//
43 // //
44 // contact: Olaf Conrad //
45 // Institute of Geography //
46 // University of Goettingen //
47 // Goldschmidtstr. 5 //
48 // 37077 Goettingen //
49 // Germany //
50 // //
51 // e-mail: oconrad@saga-gis.org //
52 // //
54 
55 //---------------------------------------------------------
56 
57 
59 // //
60 // //
61 // //
63 
64 //---------------------------------------------------------
65 #include <stdlib.h>
66 #include <string.h>
67 #include <time.h>
68 
69 #include "api_core.h"
70 #include "table_dbase.h"
71 #include "table.h"
72 #include "datetime.h"
73 
74 
76 // //
77 // //
78 // //
80 
81 //---------------------------------------------------------
83 {
84  m_hFile = NULL;
85  m_Record = NULL;
86  m_Fields = NULL;
87  m_nFields = 0;
88  m_Encoding = Encoding;
89 }
90 
91 //---------------------------------------------------------
93 {
94  Close();
95 }
96 
97 //---------------------------------------------------------
99 {
100  if( m_hFile )
101  {
102  Flush_Record();
103  Header_Write();
104 
105  fclose(m_hFile);
106  m_hFile = NULL;
107  }
108 
109  SG_FREE_SAFE(m_Record);
110  SG_FREE_SAFE(m_Fields);
111 
112  m_nFields = 0;
113  m_nRecords = 0;
114  m_nHeaderBytes = 0;
115  m_nRecordBytes = 0;
116  m_nFileBytes = 0;
117 
118  m_bModified = false;
119 }
120 
121 
123 // //
125 
126 //---------------------------------------------------------
127 bool CSG_Table_DBase::Open_Read(const SG_Char *FileName, CSG_Table *pTable, bool bRecords_Load)
128 {
129  Close();
130 
131  if( (m_hFile = fopen(CSG_String(FileName), "rb")) == NULL )
132  {
133  SG_UI_Msg_Add_Error(_TL("dbf read: could not open file"));
134 
135  return( false );
136  }
137 
138  m_bReadOnly = true;
139 
140  if( !Header_Read() )
141  {
142  SG_UI_Msg_Add_Error(_TL("dbf read: could not read header"));
143 
144  Close();
145 
146  return( false );
147  }
148 
149  fseek(m_hFile, 0, SEEK_END);
150  m_nFileBytes = ftell(m_hFile);
151  fseek(m_hFile, 0, SEEK_SET);
152 
153  //-----------------------------------------------------
154  if( pTable )
155  {
156  int iField;
157 
158  pTable->Destroy();
159 
160  for(iField=0; iField<Get_Field_Count(); iField++)
161  {
162  switch( Get_Field_Type(iField) )
163  {
164  case DBF_FT_LOGICAL:
165  pTable->Add_Field(Get_Field_Name(iField), SG_DATATYPE_Char);
166  break;
167 
168  case DBF_FT_CHARACTER: default:
169  pTable->Add_Field(Get_Field_Name(iField), SG_DATATYPE_String);
170  break;
171 
172  case DBF_FT_DATE:
173  pTable->Add_Field(Get_Field_Name(iField), SG_DATATYPE_Date);
174  break;
175 
176  case DBF_FT_FLOAT:
177  pTable->Add_Field(Get_Field_Name(iField), SG_DATATYPE_Double);
178  break;
179 
180  case DBF_FT_NUMERIC:
181  pTable->Add_Field(Get_Field_Name(iField), Get_Field_Decimals(iField) > 0
184  );
185  }
186  }
187 
188  //-------------------------------------------------
189  if( bRecords_Load && Get_Count() > 0 && Move_First() )
190  {
191  for(int iRecord=0; iRecord<Get_Count() && SG_UI_Process_Set_Progress(iRecord, Get_Count()); iRecord++)
192  {
193  CSG_Table_Record *pRecord = pTable->Add_Record();
194 
195  for(iField=0; iField<Get_Field_Count(); iField++)
196  {
197  switch( Get_Field_Type(iField) )
198  {
199  default:
200  pRecord->Set_Value(iField, asString(iField));
201  break;
202 
203  case DBF_FT_FLOAT:
204  case DBF_FT_NUMERIC:
205  {
206  double Value;
207 
208  if( asDouble(iField, Value) )
209  pRecord->Set_Value(iField, Value);
210  else
211  pRecord->Set_NoData(iField);
212  }
213  break;
214  }
215  }
216 
217  Move_Next();
218  }
219 
221  }
222  }
223 
224  return( true );
225 }
226 
227 //---------------------------------------------------------
228 bool CSG_Table_DBase::Header_Read(void)
229 {
230  if( !m_hFile )
231  {
232  return( false );
233  }
234 
235  //-----------------------------------------------------
236  char buf[16];
237  TDBF_Header h;
238 
239  fseek(m_hFile, 0, SEEK_SET);
240 
241  //-----------------------------------------------------
242  // Bytes 0-31: File Header...
243  fread(&h.FileType , sizeof(char), 1, m_hFile); // 00 FoxBase+, FoxPro, dBaseIII+, dBaseIV, no memo - 0x03
244  // FoxBase+, dBaseIII+ with memo - 0x83
245  // FoxPro with memo - 0xF5
246  // dBaseIV with memo - 0x8B
247  // dBaseIV with SQL Table - 0x8E
248  fread(&h.LastUpdate , sizeof(char), 3, m_hFile); // 01-03 Last update, format YYYYMMDD **correction: it is YYMMDD**
249  fread(&m_nRecords , sizeof(char), 4, m_hFile); // 04-07 Number of records in file (32-bit number)
250  fread(&m_nHeaderBytes , sizeof(char), 2, m_hFile); // 08-09 Number of bytes in header (16-bit number)
251  fread(&m_nRecordBytes , sizeof(char), 2, m_hFile); // 10-11 Number of bytes in record (16-bit number)
252  fread( buf , sizeof(char), 2, m_hFile); // 12-13 Reserved, fill with 0x00
253  fread(&h.Transaction , sizeof(char), 1, m_hFile); // 14 dBaseIV flag, incomplete transaction
254  // Begin Transaction sets it to - 0x01
255  // End Transaction or RollBack reset it to - 0x00
256  fread(&h.bEncrypted , sizeof(char), 1, m_hFile); // 15 Encryption flag, encrypted 0x01 else 0x00
257  // Changing the flag does not encrypt or decrypt the records
258  fread( buf , sizeof(char), 12, m_hFile); // 16-27 dBaseIV multi-user environment use
259  fread(&h.ProductionIdx , sizeof(char), 1, m_hFile); // 28 Production index exists - 0x01 else 0x00
260  fread(&h.LanguageDrvID , sizeof(char), 1, m_hFile); // 29 dBaseIV language driver ID
261  fread( buf , sizeof(char), 2, m_hFile); // 30-31 Reserved fill with 0x00
262 
263  //-----------------------------------------------------
264  // Bytes 32-n: Field Descriptor Array...
265  while( ftell(m_hFile) < (long)m_nHeaderBytes - 1 && !feof(m_hFile) )
266  {
267  m_Fields = (TDBF_Field *)SG_Realloc(m_Fields, (m_nFields + 1) * sizeof(TDBF_Field));
268 
269  fread( m_Fields[m_nFields].Name , sizeof(char), 11, m_hFile); // 0-10 Field Name ASCII padded with 0x00
270  fread(&m_Fields[m_nFields].Type , sizeof(char), 1, m_hFile); // 11 Field Type Identifier (see table)
271  fread(&m_Fields[m_nFields].Displacement , sizeof(char), 4, m_hFile); // 12-15 Displacement of field in record
272  fread(&m_Fields[m_nFields].Width , sizeof(char), 1, m_hFile); // 16 Field length in bytes
273  fread(&m_Fields[m_nFields].Decimals , sizeof(char), 1, m_hFile); // 17 Field decimal places
274  fread( buf , sizeof(char), 2, m_hFile); // 18-19 Reserved
275  fread(&m_Fields[m_nFields].WorkAreaID , sizeof(char), 1, m_hFile); // 20 dBaseIV work area ID
276  fread( buf , sizeof(char), 10, m_hFile); // 21-30 Reserved
277  fread(&m_Fields[m_nFields].ProductionIdx , sizeof(char), 1, m_hFile); // 31 Field is part of production index - 0x01 else 0x00
278 
279  m_Fields[m_nFields].Name[11] = '\0';
280 
281  m_nFields++;
282  }
283 
284  //-----------------------------------------------------
285  // Byte n+1: Header m_Record Terminator (0x0D)...
286  fread( buf , sizeof(char), 1, m_hFile);
287 
288  if( buf[0] == 0x0d )
289  {
290  Init_Record();
291  Move_First();
292 
293  return( true );
294  }
295 
296  Close();
297 
298  return( false );
299 }
300 
301 
303 // //
305 
306 //---------------------------------------------------------
307 bool CSG_Table_DBase::Open_Write(const SG_Char *FileName, CSG_Table *pTable, bool bRecords_Save)
308 {
309  Close();
310 
311  if( pTable == NULL || pTable->Get_Field_Count() <= 0 )
312  {
313  SG_UI_Msg_Add_Error(_TL("dbf write: invalid table"));
314 
315  return( false );
316  }
317 
318  if( (m_hFile = fopen(CSG_String(FileName), "w+b")) == NULL )
319  {
320  SG_UI_Msg_Add_Error(_TL("dbf write: could open file"));
321 
322  return( false );
323  }
324 
325  m_bReadOnly = false;
326 
327  //-----------------------------------------------------
328  int iField, nBytes;
329 
330  m_nFields = pTable->Get_Field_Count();
331  m_Fields = (TDBF_Field *)SG_Calloc(m_nFields, sizeof(TDBF_Field)); // init all bytes with 0x00
332 
333  for(iField=0; iField<Get_Field_Count(); iField++)
334  {
335  CSG_String Name(pTable->Get_Field_Name(iField));
336 
337  for(int j=0; j<11 && j<(int)Name.Length(); j++)
338  {
339  m_Fields[iField].Name[j] = Name.b_str()[j];
340  }
341 
342  switch( pTable->Get_Field_Type(iField) )
343  {
344  case SG_DATATYPE_String: default:
345  m_Fields[iField].Type = DBF_FT_CHARACTER;
346  m_Fields[iField].Width = (BYTE)((nBytes = pTable->Get_Field_Length(iField, m_Encoding)) > 255 ? 255 : nBytes < 1 ? 1 : nBytes);
347  break;
348 
349  case SG_DATATYPE_Date:
350  m_Fields[iField].Type = DBF_FT_DATE;
351  m_Fields[iField].Width = (BYTE)8;
352  break;
353 
354  case SG_DATATYPE_Char:
355  m_Fields[iField].Type = DBF_FT_CHARACTER;
356  m_Fields[iField].Width = (BYTE)1;
357  break;
358 
359  case SG_DATATYPE_Bit:
360  m_Fields[iField].Type = DBF_FT_NUMERIC;
361  m_Fields[iField].Width = (BYTE)1;
362  break;
363 
364  case SG_DATATYPE_Byte:
365  m_Fields[iField].Type = DBF_FT_NUMERIC;
366  m_Fields[iField].Width = (BYTE)3;
367  break;
368 
369  case SG_DATATYPE_Word:
370  case SG_DATATYPE_Short:
371  m_Fields[iField].Type = DBF_FT_NUMERIC;
372  m_Fields[iField].Width = (BYTE)6;
373  break;
374 
375  case SG_DATATYPE_DWord:
376  case SG_DATATYPE_Int:
377  case SG_DATATYPE_ULong:
378  case SG_DATATYPE_Long:
379  case SG_DATATYPE_Color:
380  m_Fields[iField].Type = DBF_FT_NUMERIC;
381  m_Fields[iField].Width = (BYTE)16;
382  break;
383 
384  case SG_DATATYPE_Float:
385  m_Fields[iField].Type = DBF_FT_NUMERIC;
386  m_Fields[iField].Width = (BYTE)16;
387  m_Fields[iField].Decimals = (BYTE)8;
388  break;
389 
390  case SG_DATATYPE_Double:
391  m_Fields[iField].Type = DBF_FT_FLOAT;
392  m_Fields[iField].Width = (BYTE)19;
393  m_Fields[iField].Decimals = (BYTE)10;
394  break;
395  }
396  }
397 
398  Header_Write();
399 
400  m_nFileBytes = m_nHeaderBytes;
401 
402  //-----------------------------------------------------
403  if( bRecords_Save )
404  {
405  for(sLong iRecord=0; iRecord<pTable->Get_Count() && SG_UI_Process_Set_Progress(iRecord, pTable->Get_Count()); iRecord++)
406  {
407  CSG_Table_Record *pRecord = pTable->Get_Record(iRecord);
408 
409  Add_Record();
410 
411  for(iField=0; iField<Get_Field_Count(); iField++)
412  {
413  if( pRecord->is_NoData(iField) )
414  {
415  Set_NoData(iField);
416  }
417  else switch( Get_Field_Type(iField) )
418  {
419  default:
420  Set_Value(iField, pRecord->asString(iField));
421  break;
422 
423  case DBF_FT_FLOAT:
424  case DBF_FT_NUMERIC:
425  Set_Value(iField, pRecord->asDouble(iField));
426  break;
427  }
428  }
429 
430  Flush_Record();
431  }
432 
434  }
435 
436  return( true );
437 }
438 
439 //---------------------------------------------------------
440 void CSG_Table_DBase::Header_Write(void)
441 {
442  if( !m_hFile || m_bReadOnly )
443  {
444  return;
445  }
446 
447  //-----------------------------------------------------
448  char buf[16];
449  int iField;
450  time_t ltime;
451  TDBF_Header h;
452 
453  time(&ltime);
454  struct tm *pTime = localtime(&ltime);
455 
456  h.FileType = 0x03;
457  h.Transaction = 0;
458  h.bEncrypted = 0;
459  h.LanguageDrvID = 0;
460  h.ProductionIdx = 0;
461  h.LastUpdate[0] = (unsigned char)pTime->tm_year;
462  h.LastUpdate[1] = (unsigned char)pTime->tm_mon + 1;
463  h.LastUpdate[2] = (unsigned char)pTime->tm_mday;
464 
465  m_nHeaderBytes = (m_nFields + 1) * 32 + 1;
466  m_nRecordBytes = 1; // Delete-Flag = Byte 0...
467 
468  for(iField=0; iField<m_nFields; iField++)
469  {
470  if( m_Fields[iField].Type == DBF_FT_CHARACTER )
471  {
472  if( m_Fields[iField].Width < 1 )
473  {
474  m_Fields[iField].Width = 1;
475  }
476  else if( m_Fields[iField].Width > 255 )
477  {
478  m_Fields[iField].Width = 255;
479  }
480  }
481 
482  m_nRecordBytes += m_Fields[iField].Width;
483  }
484 
485  Init_Record();
486 
487  fseek(m_hFile, 0, SEEK_SET);
488 
489  memset(buf, 0, 16 * sizeof(char));
490 
491  //-----------------------------------------------------
492  // Bytes 0-31: File Header...
493  fwrite(&h.FileType , sizeof(char), 1, m_hFile); // 00 FoxBase+, FoxPro, dBaseIII+, dBaseIV, no memo - 0x03
494  // FoxBase+, dBaseIII+ with memo - 0x83
495  // FoxPro with memo - 0xF5
496  // dBaseIV with memo - 0x8B
497  // dBaseIV with SQL Table - 0x8E
498  fwrite(&h.LastUpdate , sizeof(char), 3, m_hFile); // 01-03 Last update, format YYYYMMDD **correction: it is YYMMDD**
499  fwrite(&m_nRecords , sizeof(char), 4, m_hFile); // 04-07 Number of records in file (32-bit number)
500  fwrite(&m_nHeaderBytes , sizeof(char), 2, m_hFile); // 08-09 Number of bytes in header (16-bit number)
501  fwrite(&m_nRecordBytes , sizeof(char), 2, m_hFile); // 10-11 Number of bytes in record (16-bit number)
502  fwrite( buf , sizeof(char), 2, m_hFile); // 12-13 Reserved, fill with 0x00
503  fwrite(&h.Transaction , sizeof(char), 1, m_hFile); // 14 dBaseIV flag, incomplete transaction
504  // Begin Transaction sets it to - 0x01
505  // End Transaction or RollBack reset it to - 0x00
506  fwrite(&h.bEncrypted , sizeof(char), 1, m_hFile); // 15 Encryption flag, encrypted 0x01 else 0x00
507  // Changing the flag does not encrypt or decrypt the records
508  fwrite( buf , sizeof(char), 12, m_hFile); // 16-27 dBaseIV multi-user environment use
509  fwrite(&h.ProductionIdx , sizeof(char), 1, m_hFile); // 28 Production index exists - 0x01 else 0x00
510  fwrite(&h.LanguageDrvID , sizeof(char), 1, m_hFile); // 29 dBaseIV language driver ID
511  fwrite( buf , sizeof(char), 2, m_hFile); // 30-31 Reserved fill with 0x00
512 
513  //-----------------------------------------------------
514  // Bytes 32-n: Field Descriptor Array...
515  for(iField=0; iField<m_nFields; iField++)
516  {
517  fwrite( m_Fields[iField].Name , sizeof(char), 11, m_hFile); // 00-10 Field Name ASCII padded with 0x00
518  fwrite(&m_Fields[iField].Type , sizeof(char), 1, m_hFile); // 11 Field Type Identifier (see table)
519  fwrite(&m_Fields[iField].Displacement , sizeof(char), 4, m_hFile); // 12-15 Displacement of field in record
520  fwrite(&m_Fields[iField].Width , sizeof(char), 1, m_hFile); // 16 Field length in bytes
521  fwrite(&m_Fields[iField].Decimals , sizeof(char), 1, m_hFile); // 17 Field decimal places
522  fwrite( buf , sizeof(char), 2, m_hFile); // 18-19 Reserved
523  fwrite(&m_Fields[iField].WorkAreaID , sizeof(char), 1, m_hFile); // 20 dBaseIV work area ID
524  fwrite( buf , sizeof(char), 10, m_hFile); // 21-30 Reserved
525  fwrite(&m_Fields[iField].ProductionIdx , sizeof(char), 1, m_hFile); // 31 Field is part of production index - 0x01 else 0x00
526  }
527 
528  //-----------------------------------------------------
529  // Byte n+1: Header m_Record Terminator (0x0D)...
530  buf[0] = 0x0D;
531  fwrite( buf , sizeof(char), 1, m_hFile);
532 }
533 
534 
536 // //
538 
539 //---------------------------------------------------------
540 void CSG_Table_DBase::Init_Record(void)
541 {
542  m_Record = (char *)SG_Realloc(m_Record, m_nRecordBytes * sizeof(char));
543  m_Record[0] = ' '; // Data records are preceded by one byte, that is, a space (0x20) if the record is not deleted, an asterisk (0x2A) if the record is deleted.
544 
545  for(int iField=0, iPos=1; iField<m_nFields; iPos+=m_Fields[iField++].Width)
546  {
547  m_Fields[iField].Offset = iPos;
548  }
549 }
550 
551 //---------------------------------------------------------
553 {
554  return( m_hFile ? ftell(m_hFile) : 0 );
555 }
556 
557 
559 // //
561 
562 //---------------------------------------------------------
564 {
565  bool Result = false;
566 
567  if( m_hFile )
568  {
569  Flush_Record();
570 
571  fseek(m_hFile, m_nHeaderBytes, SEEK_SET);
572 
573  if( fread(m_Record, m_nRecordBytes, sizeof(char), m_hFile) == 1 )
574  {
575  Result = true;
576  }
577 
578  fseek(m_hFile, m_nHeaderBytes, SEEK_SET);
579  }
580 
581  return( Result );
582 }
583 
584 //---------------------------------------------------------
586 {
587  bool Result = false;
588 
589  if( m_hFile )
590  {
591  Flush_Record();
592 
593  fseek(m_hFile, m_nRecordBytes, SEEK_CUR);
594 
595  if( fread(m_Record, m_nRecordBytes, sizeof(char), m_hFile) == 1 )
596  {
597  Result = true;
598  }
599 
600  fseek(m_hFile, -m_nRecordBytes, SEEK_CUR);
601  }
602 
603  return( Result );
604 }
605 
606 
608 // //
610 
611 //---------------------------------------------------------
613 {
614  if( m_hFile )
615  {
616  m_bModified = true;
617 
618  memset(m_Record, ' ', m_nRecordBytes);
619 
620  fseek(m_hFile, 0, SEEK_END);
621  fwrite(m_Record, m_nRecordBytes, sizeof(char), m_hFile);
622  fseek(m_hFile, -m_nRecordBytes, SEEK_END);
623 
624  m_nRecords ++;
625  m_nFileBytes += m_nRecordBytes;
626  }
627 }
628 
629 //---------------------------------------------------------
631 {
632  if( m_hFile && !m_bReadOnly && m_bModified )
633  {
634  m_bModified = false;
635  fwrite(m_Record, m_nRecordBytes, sizeof(char), m_hFile);
636  fseek(m_hFile, -m_nRecordBytes, SEEK_CUR);
637  }
638 }
639 
640 
642 // //
644 
645 //---------------------------------------------------------
647 {
648  return( m_hFile && *m_Record == '*' );
649 }
650 
651 //---------------------------------------------------------
652 bool CSG_Table_DBase::asInt(int iField, int &Value)
653 {
654  double d;
655 
656  if( asDouble(iField, d) )
657  {
658  Value = (int)d;
659 
660  return( true );
661  }
662 
663  return( false );
664 }
665 
666 //---------------------------------------------------------
667 bool CSG_Table_DBase::asDouble(int iField, double &Value)
668 {
669  if( !m_hFile || iField < 0 || iField >= m_nFields )
670  {
671  return( false );
672  }
673 
674  //-----------------------------------------------------
675  CSG_String s;
676 
677  char *c = m_Record + m_Fields[iField].Offset;
678 
679  for(int i=0; i<m_Fields[iField].Width && *c; i++, c++)
680  {
681  s += *c;
682  }
683 
684  //-----------------------------------------------------
685  if( m_Fields[iField].Type == DBF_FT_FLOAT
686  || m_Fields[iField].Type == DBF_FT_NUMERIC )
687  {
688  s.Replace(",", ".");
689 
690  return( s.asDouble(Value) );
691  }
692 
693  //-----------------------------------------------------
694  if( m_Fields[iField].Type == DBF_FT_DATE )
695  {
696  if( s.Length() < 8 )
697  {
698  return( false );
699  }
700 
701  int d = s.Mid(6, 2).asInt(); if( d < 1 ) d = 1; else if( d > 31 ) d = 31;
702  int m = s.Mid(4, 2).asInt(); if( m < 1 ) m = 1; else if( m > 12 ) m = 12;
703  int y = s.Mid(0, 4).asInt();
704 
705  Value = 10000 * y + 100 * m + d;
706  }
707 
708  //-----------------------------------------------------
709  return( true );
710 }
711 
712 //---------------------------------------------------------
714 {
715  CSG_String Value;
716 
717  if( !m_hFile || iField < 0 || iField >= m_nFields )
718  {
719  return( Value );
720  }
721 
722  //-----------------------------------------------------
723  if( m_Fields[iField].Type != DBF_FT_DATE )
724  {
725  switch( m_Encoding )
726  {
727  case SG_FILE_ENCODING_ANSI: default:
728  { char *s = m_Record + m_Fields[iField].Offset;
729 
730  for(int i=0; i<m_Fields[iField].Width && *s; i++, s++)
731  {
732  Value += *s;
733  }
734  } break;
735 
737  Value = CSG_String::from_UTF8(m_Record + m_Fields[iField].Offset, m_Fields[iField].Width);
738  break;
739  }
740 
741  Value.Trim(true);
742  }
743 
744  //-----------------------------------------------------
745  if( m_Fields[iField].Type == DBF_FT_DATE ) // SAGA(DD.MM.YYYY) from DBASE(YYYYMMDD)
746  {
747  char *s = m_Record + m_Fields[iField].Offset;
748 
749  Value += s[0]; // Y1
750  Value += s[1]; // Y2
751  Value += s[2]; // Y3
752  Value += s[3]; // Y4
753  Value += '-';
754  Value += s[4]; // M1
755  Value += s[5]; // M2
756  Value += '-';
757  Value += s[6]; // D1
758  Value += s[7]; // D2
759  }
760 
761  //-----------------------------------------------------
762  return( Value );
763 }
764 
765 
767 // //
769 
770 //---------------------------------------------------------
771 bool CSG_Table_DBase::Set_Value(int iField, double Value)
772 {
773  if( !m_hFile || iField < 0 || iField >= m_nFields || m_Fields[iField].Width < 1 )
774  {
775  return( false );
776  }
777 
778  //-----------------------------------------------------
779  if( m_Fields[iField].Type == DBF_FT_DATE )
780  { // Value is expected to be Julian Day Number
781  CSG_DateTime d(Value);
782 
783  return( Set_Value(iField, CSG_String::Format("%04d-%02d-%02d",
784  d.Get_Year (),
785  1 + (int)d.Get_Month(),
786  1 + d.Get_Day ()
787  )));
788  }
789 
790  //-----------------------------------------------------
791  if( m_Fields[iField].Type == DBF_FT_FLOAT )
792  { // Number stored as a string, right justified, and padded with blanks to the width of the field.
793  char s[256];
794 
795  sprintf(s, "%*.*e", m_Fields[iField].Width, m_Fields[iField].Decimals, Value);
796 
797  size_t n = strlen(s); if( n > m_Fields[iField].Width ) { n = m_Fields[iField].Width; }
798 
799  memset(m_Record + m_Fields[iField].Offset, ' ', m_Fields[iField].Width);
800  memcpy(m_Record + m_Fields[iField].Offset, s , M_GET_MIN(strlen(s), m_Fields[iField].Width));
801 
802  m_bModified = true;
803 
804  return( true );
805  }
806 
807  //-----------------------------------------------------
808  if( m_Fields[iField].Type == DBF_FT_NUMERIC )
809  { // Number stored as a string, right justified, and padded with blanks to the width of the field.
810  char s[256];
811 
812  if( m_Fields[iField].Decimals > 0 )
813  {
814  sprintf(s, "%*.*f", m_Fields[iField].Width, m_Fields[iField].Decimals, Value);
815  }
816  else
817  {
818  sprintf(s, "%*d" , m_Fields[iField].Width, (int)Value);
819  }
820 
821  memset(m_Record + m_Fields[iField].Offset, ' ', m_Fields[iField].Width);
822  memcpy(m_Record + m_Fields[iField].Offset, s , M_GET_MIN(strlen(s), m_Fields[iField].Width));
823 
824  m_bModified = true;
825 
826  return( true );
827  }
828 
829  //-----------------------------------------------------
830  return( false );
831 }
832 
833 //---------------------------------------------------------
834 bool CSG_Table_DBase::Set_Value(int iField, const CSG_String &Value)
835 {
836  if( !m_hFile || iField < 0 || iField >= m_nFields || m_Fields[iField].Width < 1 )
837  {
838  return( false );
839  }
840 
841  //-----------------------------------------------------
842  if( m_Fields[iField].Type == DBF_FT_CHARACTER )
843  { // All OEM code page characters - padded with blanks to the width of the field.
844  if( Value.Length() < 1 )
845  {
846  memset(m_Record + m_Fields[iField].Offset, ' ', m_Fields[iField].Width);
847 
848  m_bModified = true;
849 
850  return( true );
851  }
852 
853  CSG_Buffer s;
854 
855  switch( m_Encoding )
856  {
857  case SG_FILE_ENCODING_ANSI: default:
858  s = Value.to_ASCII();
859  break;
860 
862  s = Value.to_UTF8 ();
863  break;
864  }
865 
866  if( s.Get_Size() >= Value.Length() )
867  {
868  memset(m_Record + m_Fields[iField].Offset, ' ', m_Fields[iField].Width);
869  memcpy(m_Record + m_Fields[iField].Offset, s.Get_Data(), M_GET_MIN(s.Get_Size(), m_Fields[iField].Width));
870 
871  m_bModified = true;
872 
873  return( true );
874  }
875  }
876 
877  //-----------------------------------------------------
878  if( m_Fields[iField].Type == DBF_FT_DATE ) // SAGA(YYYY-MM-DD) to DBASE(YYYYMMDD)
879  { // 8 bytes - date stored as a string in the format YYYYMMDD
880  if( Value.Length() >= 10 )
881  {
882  char *s = m_Record + m_Fields[iField].Offset;
883 
884  s[0] = Value.b_str()[0]; // Y1
885  s[1] = Value.b_str()[1]; // Y2
886  s[2] = Value.b_str()[2]; // Y3
887  s[3] = Value.b_str()[3]; // Y4
888  s[4] = Value.b_str()[5]; // M1
889  s[5] = Value.b_str()[6]; // M2
890  s[6] = Value.b_str()[8]; // D1
891  s[7] = Value.b_str()[9]; // D2
892 
893  m_bModified = true;
894 
895  return( true );
896  }
897  }
898 
899  //-----------------------------------------------------
900  return( false );
901 }
902 
903 //---------------------------------------------------------
905 {
906  if( !m_hFile || iField < 0 || iField >= m_nFields || m_Fields[iField].Width < 1 )
907  {
908  return( false );
909  }
910 
911  //-----------------------------------------------------
912  memset(m_Record + m_Fields[iField].Offset, ' ', m_Fields[iField].Width);
913 
914  m_bModified = true;
915 
916  return( true );
917 }
918 
919 
921 // //
922 // //
923 // //
925 
926 //---------------------------------------------------------
SG_DATATYPE_Color
@ SG_DATATYPE_Color
Definition: api_core.h:1007
SG_DATATYPE_Int
@ SG_DATATYPE_Int
Definition: api_core.h:1000
CSG_Table_Record::asDouble
double asDouble(int Field) const
Definition: table_record.cpp:527
DBF_FT_FLOAT
#define DBF_FT_FLOAT
Definition: table_dbase.h:77
SG_FREE_SAFE
#define SG_FREE_SAFE(PTR)
Definition: api_core.h:205
SG_DATATYPE_String
@ SG_DATATYPE_String
Definition: api_core.h:1005
_TL
#define _TL(s)
Definition: api_core.h:1489
SG_DATATYPE_DWord
@ SG_DATATYPE_DWord
Definition: api_core.h:999
CSG_String::to_ASCII
bool to_ASCII(char **pString, char Replace='_') const
Definition: api_string.cpp:909
CSG_String::Length
size_t Length(void) const
Definition: api_string.cpp:172
CSG_String::b_str
const char * b_str(void) const
Definition: api_string.cpp:242
CSG_String::Mid
CSG_String Mid(size_t first, size_t count=0) const
Definition: api_string.cpp:699
CSG_Table_Record
Definition: table.h:130
CSG_Table_DBase::~CSG_Table_DBase
virtual ~CSG_Table_DBase(void)
Definition: table_dbase.cpp:92
CSG_String::asInt
int asInt(void) const
Definition: api_string.cpp:722
CSG_Table::Get_Record
virtual CSG_Table_Record * Get_Record(sLong Index) const
Definition: table.h:394
CSG_String::from_UTF8
static CSG_String from_UTF8(const char *String, size_t Length=0)
Definition: api_string.cpp:787
SG_DATATYPE_Byte
@ SG_DATATYPE_Byte
Definition: api_core.h:995
CSG_Table_DBase::asInt
bool asInt(int iField, int &Value)
Definition: table_dbase.cpp:652
CSG_Table::Destroy
virtual bool Destroy(void)
Definition: table.cpp:332
CSG_Table_DBase::Get_File_Position
int Get_File_Position(void)
Definition: table_dbase.cpp:552
CSG_Table_DBase::isDeleted
bool isDeleted(void)
Definition: table_dbase.cpp:646
CSG_Table_DBase::Get_Field_Count
int Get_Field_Count(void)
Definition: table_dbase.h:103
CSG_Table_DBase::Get_Field_Decimals
int Get_Field_Decimals(int iField)
Definition: table_dbase.h:115
api_core.h
DBF_FT_CHARACTER
#define DBF_FT_CHARACTER
Definition: table_dbase.h:75
CSG_Table_DBase::Open_Write
bool Open_Write(const SG_Char *FileName, class CSG_Table *pTable, bool bRecords_Save=true)
Definition: table_dbase.cpp:307
CSG_Table::Get_Field_Count
int Get_Field_Count(void) const
Definition: table.h:356
CSG_Table::Get_Field_Length
int Get_Field_Length(int iField, int Encoding=SG_FILE_ENCODING_UNDEFINED) const
Definition: table.cpp:659
CSG_String::Replace
size_t Replace(const CSG_String &sOld, const CSG_String &sNew, bool bReplaceAll=true)
Definition: api_string.cpp:563
CSG_DateTime::Get_Year
int Get_Year(void) const
Definition: datetime.cpp:384
CSG_Table_DBase::Move_Next
bool Move_Next(void)
Definition: table_dbase.cpp:585
SG_Calloc
SAGA_API_DLL_EXPORT void * SG_Calloc(size_t num, size_t size)
Definition: api_memory.cpp:71
CSG_Table_Record::is_NoData
bool is_NoData(int Field) const
Definition: table_record.cpp:416
CSG_Table_DBase::asString
CSG_String asString(int iField)
Definition: table_dbase.cpp:713
CSG_DateTime::Get_Month
Month Get_Month(void) const
Definition: datetime.cpp:379
CSG_Table_DBase::Move_First
bool Move_First(void)
Definition: table_dbase.cpp:563
SG_DATATYPE_Long
@ SG_DATATYPE_Long
Definition: api_core.h:1002
CSG_Buffer
Definition: api_core.h:224
CSG_Table_DBase::Open_Read
bool Open_Read(const SG_Char *FileName, class CSG_Table *pTable, bool bRecords_Load=true)
Definition: table_dbase.cpp:127
CSG_Table_Record::asString
const SG_Char * asString(int Field, int Decimals=-99) const
Definition: table_record.cpp:461
CSG_Table::Get_Field_Name
const SG_Char * Get_Field_Name(int iField) const
Definition: table.h:357
CSG_String::Trim
int Trim(bool fromRight=false)
Definition: api_string.cpp:590
DBF_FT_LOGICAL
#define DBF_FT_LOGICAL
Definition: table_dbase.h:79
CSG_Table_DBase::Get_Count
int Get_Count(void)
Definition: table_dbase.h:122
sLong
signed long long sLong
Definition: api_core.h:158
CSG_Table_DBase::Get_Field_Type
char Get_Field_Type(int iField)
Definition: table_dbase.h:109
CSG_Buffer::Get_Size
size_t Get_Size(void) const
Definition: api_core.h:241
CSG_Table::Get_Count
sLong Get_Count(void) const
Definition: table.h:392
SG_DATATYPE_Float
@ SG_DATATYPE_Float
Definition: api_core.h:1003
CSG_Table_DBase::Add_Record
void Add_Record(void)
Definition: table_dbase.cpp:612
CSG_DateTime
Definition: datetime.h:183
SG_DATATYPE_Date
@ SG_DATATYPE_Date
Definition: api_core.h:1006
SG_DATATYPE_Word
@ SG_DATATYPE_Word
Definition: api_core.h:997
CSG_Buffer::Get_Data
char * Get_Data(int Offset=0) const
Definition: api_core.h:244
CSG_Table::m_Encoding
int m_Encoding
Definition: table.h:449
M_GET_MIN
#define M_GET_MIN(a, b)
Definition: mat_tools.h:143
CSG_String::Format
static CSG_String Format(const char *Format,...)
Definition: api_string.cpp:270
CSG_Table_DBase::Flush_Record
void Flush_Record(void)
Definition: table_dbase.cpp:630
CSG_Table::Add_Field
virtual bool Add_Field(const CSG_String &Name, TSG_Data_Type Type, int Position=-1)
Definition: table.cpp:481
CSG_Table
Definition: table.h:283
table_dbase.h
CSG_String::to_UTF8
size_t to_UTF8(char **pString) const
Definition: api_string.cpp:813
SG_Char
#define SG_Char
Definition: api_core.h:536
CSG_Table_DBase::Set_Value
bool Set_Value(int iField, double Value)
Definition: table_dbase.cpp:771
CSG_String
Definition: api_core.h:563
SG_UI_Process_Set_Progress
bool SG_UI_Process_Set_Progress(int Position, int Range)
Definition: api_callback.cpp:256
CSG_Table_DBase::CSG_Table_DBase
CSG_Table_DBase(int Encoding=SG_FILE_ENCODING_ANSI)
Definition: table_dbase.cpp:82
CSG_Table_Record::Set_Value
bool Set_Value(int Field, const CSG_String &Value)
Definition: table_record.cpp:270
SG_DATATYPE_Short
@ SG_DATATYPE_Short
Definition: api_core.h:998
CSG_Table_DBase::Close
void Close(void)
Definition: table_dbase.cpp:98
DBF_FT_DATE
#define DBF_FT_DATE
Definition: table_dbase.h:76
CSG_Table_DBase::asDouble
bool asDouble(int iField, double &Value)
Definition: table_dbase.cpp:667
CSG_DateTime::Get_Day
unsigned short Get_Day(void) const
Definition: datetime.cpp:377
CSG_Table::m_nFields
int m_nFields
Definition: table.h:449
CSG_Table_DBase::Set_NoData
bool Set_NoData(int iField)
Definition: table_dbase.cpp:904
SG_DATATYPE_Bit
@ SG_DATATYPE_Bit
Definition: api_core.h:994
CSG_Table_DBase::Get_Field_Name
const char * Get_Field_Name(int iField)
Definition: table_dbase.h:106
CSG_String::asDouble
double asDouble(void) const
Definition: api_string.cpp:760
SG_UI_Process_Set_Ready
bool SG_UI_Process_Set_Ready(void)
Definition: api_callback.cpp:306
SG_Realloc
SAGA_API_DLL_EXPORT void * SG_Realloc(void *memblock, size_t size)
Definition: api_memory.cpp:77
SG_UI_Msg_Add_Error
void SG_UI_Msg_Add_Error(const char *Message)
Definition: api_callback.cpp:557
CSG_Table::Get_Field_Type
TSG_Data_Type Get_Field_Type(int iField) const
Definition: table.h:358
CSG_Table::Add_Record
virtual CSG_Table_Record * Add_Record(CSG_Table_Record *pCopy=NULL)
Definition: table.cpp:795
DBF_FT_NUMERIC
#define DBF_FT_NUMERIC
Definition: table_dbase.h:78
SG_FILE_ENCODING_ANSI
@ SG_FILE_ENCODING_ANSI
Definition: api_core.h:550
SG_FILE_ENCODING_UTF8
@ SG_FILE_ENCODING_UTF8
Definition: api_core.h:552
SG_DATATYPE_Char
@ SG_DATATYPE_Char
Definition: api_core.h:996
table.h
CSG_Table_Record::Set_NoData
bool Set_NoData(int Field)
Definition: table_record.cpp:366
SG_DATATYPE_ULong
@ SG_DATATYPE_ULong
Definition: api_core.h:1001
CSG_Table::m_nRecords
sLong m_nRecords
Definition: table.h:451
datetime.h
SG_DATATYPE_Double
@ SG_DATATYPE_Double
Definition: api_core.h:1004