1 unit common;
2 
3 {
4     Copyright (C) 2005-2008 Olaf Klein, o.b.klein@gpsbabel.org
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
19 }
20 
21 interface
22 
23 uses
24   Windows, SysUtils, Classes, Messages, Controls, StdCtrls, ExtCtrls;
25 
26 const
27   OTypes: array[0..6] of PChar =
28     ('unknown', 'integer', 'float', 'string', 'boolean', 'file', 'outfile');
29 
30   gpsbabel_knows_inifile: Boolean = False;
31 //gpsbabel_ini: TInifile = nil;
32   gpsbabel_knows_swap_filter: Boolean = False;
33 
34 resourcestring
35   SGPSBabelURL =         'http://www.gpsbabel.org';
36   SGPSBabelTitle =       'GPSBabelGUI-2';
37 
38 const
39   SGPSBabelIniFilename = 'gpsbabel.ini';
40   SGPSBabelExeFilename = 'gpsbabel.exe';
41 
42 var
43   gpsbabel_exe: string;
44   gpsbabel_version: string;        // 1.101.010-beta...
45   gpsbabel_vfmt: string;           // 001.101.010
46   gpsbabel_minor, gpsbabel_major, gpsbabel_release: Integer;
47   SGPSBabelGUIVersion: string;
48   CFixedFileinfo: TVSFixedFileInfo;
49 
50 const
51   WM_STARTUP = WM_USER + 1;
52   WM_OPTIONS_CHANGED = WM_USER + 2;
53 
54 const
55   MAX_NO_OF_SERIAL_PORTS = 8;
56 
57 const
58   SREG_TARGET_DIR = 'Target:Directory';
59   SREG_SOURCE_DIR = 'Source:Directory';
60 
61   SREG_TARGET_DEV = 'Target:Device';
62   SREG_SOURCE_DEV = 'Source:Device';
63 
64   SREG_SOURCE_FMT = 'Source:FileFormat';
65   SREG_TARGET_FMT = 'Target:FileFormat';
66 
67   SREG_SOURCE_SER = 'Source:DeviceFormat';
68   SREG_TARGET_SER = 'Target:DeviceFormat';
69 
70   SREG_TARGET_FILE = 'Target:File';
71   SREG_SOURCE_FILE = 'Source:File';
72 
73   SREG_GLOBAL_LANG = 'Global:Language';
74 
75   SREG_MAIN_LAYOUT = 'Main:Layout';
76   SREG_MAIN_WAYPOINTS = 'Main:Waypoints';
77   SREG_MAIN_ROUTES    = 'Main:Routes';
78   SREG_MAIN_TRACKS    = 'Main:Tracks';
79 
80 const
81   Profile: array[0..15] of string =
82   ('?',
83    SREG_SOURCE_DIR,
84    SREG_SOURCE_FMT,
85    SREG_SOURCE_DEV,
86    SREG_SOURCE_SER,
87    SREG_TARGET_DIR,
88    SREG_TARGET_FMT,
89    SREG_TARGET_DEV,
90    SREG_TARGET_SER,
91    SREG_TARGET_FILE,
92    SREG_SOURCE_FILE,
93    SREG_GLOBAL_LANG,
94    SREG_MAIN_LAYOUT,
95    SREG_MAIN_WAYPOINTS,
96    SREG_MAIN_ROUTES,
97    SREG_MAIN_TRACKS
98    );
99 
100 const
101   GPSBabel_Domain = 'gpsbabel';
102 
103 type
104   TCapability = class
105   protected
106     FName : String;
107     FDescription : string;
108     FExt:   string;
109     internal: string;
110     Furl: PChar;
111   protected
CanReadAnynull112     function CanReadAny : Boolean;
CanWriteAnynull113     function CanWriteAny : Boolean;
FIsDevicenull114     function FIsDevice : Boolean;
FIsFilenull115     function FIsFile : Boolean;
116   public
117     Capas: Integer;
118     property Name : String read FName;
119     property Description : String read FDescription write FDescription;
120     property Ext : String read FExt;
121     property ReadAny : Boolean read CanReadAny;
122     property WriteAny : Boolean read CanWriteAny;
123     property IsDevice : Boolean read FIsDevice;
124     property IsFile : Boolean read FIsFile;
125   end;
126 
127 type
128   TOptionEdit = class;
129 
130   TOption = record
131     format: string;
132     name:   string;
133     hint:   string;
134     defname: string;
135     otype:  Byte;
136     def:    PChar;       // default value from gpsbabel or ini-file
137     gbdef:  PChar;       // default value from gpsbabel
138     min:    PChar;
139     max:    PChar;
140     chb:    TCheckBox;
141     edit:   TOptionEdit;
142     dir:    Byte;        // 1 = only in; 2 = only out
143   end;
144   POption = ^TOption;
145 
146   TOptionEdit = class(TObject)
147   protected
148     FOption : POption;
GetValuenull149     function GetValue : String; virtual; abstract;
150     procedure SetValue(Value : String); virtual; abstract;
GetEnablednull151     function GetEnabled : Boolean; virtual; abstract;
152     procedure SetEnabled(Value : Boolean); virtual; abstract;
153   public
154     property Value : String read GetValue write SetValue;
155     property Option : POption read FOption;
156     property Enabled : Boolean read GetEnabled write SetEnabled;
157   end;
158 
159   TCapabilities = class;
160 
161   TOptions = class(TStringList)
162   private
163     FCaps: TCapabilities;
GetListnull164     function GetList: TStrings;
165     procedure SetList(const Value: TStrings);
166   protected
167   public
168     constructor Create(ACapabilities: TCapabilities);
169     procedure AddOptionLine(const ALine: string);
170     procedure DebugGetHints(List: TStringList);
FormatOptsnull171     function FormatOpts(const Descr: string): TStringList; overload;
FormatOptsnull172     function FormatOpts(cap : TCapability): TStringList; overload;
HasFormatOptsnull173     function HasFormatOpts(const Format: string): Boolean; overload;
HasFormatOptsnull174     function HasFormatOpts(cap : TCapability): Boolean; overload;
175   property
176     List: TStrings read GetList write SetList;
177   end;
178 
179   TCapabilities = class(TStringList)
180   private
181     FList: TStrings;
182     procedure AddFormat(const Line: string);
GetListnull183     function GetList: TStrings;
184     procedure SetList(const Value: TStrings);
185   public
GetCapabilityByNamenull186     function GetCapabilityByName(const Descr: string): TCapability;
GetCapabilitynull187     function GetCapability(Index: Integer) : TCapability;
188 
189     property List: TStrings read GetList write SetList;
190     property Capability[Index : Integer] : TCapability read GetCapability;
191   end;
192 
193 type
194   eGPSBabelError = class(Exception);
195 
atoinull196 function atoi(str: PChar): Integer;
197 
198 implementation
199 
atoinull200 function atoi(str: PChar): Integer;
201 begin
202   Result := 0;
203   while (str^ <> #0) do
204   begin
205     if ((str^ < '0') or (str^ > '9')) then Break;
206     Result := (Result * 10) + (Ord(str^) - Ord('0'));
207     str := str + 1;
208   end;
209 end;
210 
GetFileVersionnull211 function GetFileVersion(const Filename: string): string;
212 var
213   buff: PChar;
214   hdl: DWORD;
215   len: DWORD;
216   sub: PChar;
217   sublen: UINT;
218   fix: PVSFixedFileInfo;
219   i:   Integer;
220 begin
221   Result := '?.?';
222 
223   FillChar(CFixedFileinfo, SizeOf(CFixedFileinfo), #0);
224 
225   len := GetFileVersionInfoSize(PChar(Filename), hdl);
226   if not(len > 0) then exit;
227 
228   GetMem(buff, len);
229   try
230 
231     if not GetFileVersionInfo(PChar(FileName), 0, len, buff) then Exit;
232 
233     fix := Pointer(buff);
234     i := len - SizeOf(fix^);
235     while (i > 0) do
236     begin
237       Dec(i);
238       if (fix.dwSignature = $feef04bd) then
239       begin
240         CFixedFileinfo := fix^;
241         Break;
242       end;
243       PChar(fix) := PChar(fix) + 1;
244     end;
245 
246     if not VerQueryValue(buff, PChar('\\StringFileInfo\\040904E4\\FileVersion'),
247       Pointer(sub), sublen) then Exit;
248     if not(sublen > 0) then Exit;
249     Result := string(sub);
250   finally
251     FreeMem(buff);
252   end;
253 end;
254 
255 { TOptions }
256 
257 constructor TOptions.Create(ACapabilities: TCapabilities);
258 begin
259   inherited Create;
260   FCaps := ACapabilities;
261   Sorted := False;
262 end;
263 
264 procedure TOptions.AddOptionLine(const ALine: string);
265 var
266   buff: array[0..1023] of Char;
267   cin, cend: PChar;
268   index: Integer;
269   opt, opt2: POption;
270   list: TStringList;
271   i: Integer;
272   s: string;
273 begin
274   StrPCopy(buff, ALine);
275   StrCat(buff, #9);
276 
277   cin := @buff;
278   index := 0;
279   while (true) do
280   begin
281     cend := StrScan(cin, #9);
282     if (cend = nil) then break;
283     cend^ := #0;
284 
285     case index of
286       0:
287         if (StrIComp(cin, 'option') <> 0) then
288           Exit else
289         begin
290           New(opt);
291           FillChar(opt^, SizeOf(opt^), #0);
292         end;
293       1:
294         opt.format := string(cin);
295       2:
296         opt.name := string(cin);
297       3:
298         opt.hint := string(cin);
299       4:
300         for i := 0 to high(OTypes) do
301           if (StrIComp(cin, OTypes[i]) = 0) then
302           begin
303             opt.otype := i;
304             Break;
305           end;
306       5:
307         if (cin^ <> #0) then
308         begin
309           opt.gbdef := StrNew(cin);
310           if (opt.def = nil) then
311             opt.def := opt.gbdef;
312         end;
313       6:
314         if (cin^ <> #0) then
315           opt.min := StrNew(cin);
316       7:
317         if (cin^ <> #0) then
318           opt.max := StrNew(cin);
319     end;
320 
321     index := index + 1;
322     cin := cend + 1;
323   end;
324 
325   if (opt.name = 'snlen') and (opt.gbdef = nil) then
326   begin
327     opt.gbdef := StrNew('10');
328     opt.def := opt.gbdef;
329   end;
330 
331   opt.dir := 3;  // in and out
332   opt.defname := opt.name;
333 
334   index := Self.IndexOf(opt.format);
335   if (index >= 0) then
336     list := TStringList(Self.Objects[index])
337   else begin
338     list := TStringList.Create;
339     list.Sorted := True;
340     Self.AddObject(opt.format, list);
341   end;
342   list.AddObject(opt.name, Pointer(opt));
343   if (opt.format = 'xcsv') then
344   begin
345     if (opt.name = 'style') then
346     begin
347       opt.dir := 1;
348       New(opt2);
349       opt2^ := opt^;
350       opt2.name := 'style_out';
351       opt2.dir := 2;
352       list.AddObject(opt2.name, Pointer(opt2));
353     end;
354   end;
355 end;
356 
357 procedure TOptions.DebugGetHints(List: TStringList);
358 var
359   i, j, k: Integer;
360   l: TStrings;
361   o: POption;
362 begin
363   List.Clear;
364   List.Sorted := True;
365   for i := 0 to Count - 1 do
366   begin
367     l := Pointer(Objects[i]);
368     for j := 0 to l.Count - 1 do
369     begin
370       o := Pointer(l.Objects[j]);
371       k := List.IndexOf(o.hint);
372       if (k < 0) then
373         List.Add(o.hint);
374     end;
375   end;
376 end;
377 
TOptions.FormatOptsnull378 function TOptions.FormatOpts(const Descr: string): TStringList;
379 var
380   i: Integer;
381   s: string;
382   cap : TCapability;
383 begin
384   cap:=FCaps.GetCapabilityByName(Descr);
385   result:=FormatOpts(cap);
386 end;
387 
TOptions.FormatOptsnull388 function TOptions.FormatOpts(cap : TCapability): TStringList;
389 var
390   i: Integer;
391   s: string;
392 begin
393   if (Assigned(Cap)) and Self.Find(Cap.Name, i) then
394     Result := TStringList(Self.Objects[i])
395   else
396     Result := nil;
397 end;
398 
TOptions.GetListnull399 function TOptions.GetList: TStrings;
400 begin
401   Result := Self;
402 end;
403 
HasFormatOptsnull404 function TOptions.HasFormatOpts(const Format: string): Boolean;
405 begin
406   Result := (FormatOpts(Format) <> nil);
407 end;
408 
HasFormatOptsnull409 function TOptions.HasFormatOpts(cap : TCapability): Boolean;
410 begin
411   Result := (FormatOpts(cap) <> nil);
412 end;
413 
414 procedure TOptions.SetList(const Value: TStrings);
415 var
416   i: Integer;
417 begin
418   Clear;
419   for i := 0 to Value.Count - 1 do
420     AddOptionLine(Value[i]);
421   Sorted := True;
422 end;
423 
424 { TCapabilities }
425 
426 procedure TCapabilities.AddFormat(const Line: string);
427 var
428   index: Integer;
429   buff: array[0..1023] of Char;
430   cin, cend: PChar;
431   i: Integer;
432   scaps: string;
433   ext: string;
434   comment: string;
435   name: string;
436   internal: string;
437   caps: Integer;
438   info: TCapability;
439 
440 begin
441   StrPCopy(buff, Line);
442   StrCat(buff, #9);
443   //OutputDebugString(buff);
444 
445   cin := @buff;
446   index := 0;
447 
448   while (true) do
449   begin
450     cend := StrScan(cin, #9);
451     if (cend = nil) then break;
452     cend^ := #0;
453 
454     case index of
455       0:
456         if (StrIComp(cin, 'option') = 0) then
457           Exit
458         else
459           internal := StrPas(cin);
460       1:
461         scaps := StrPas(cin);
462       2:
463         name := StrPas(cin);
464       3:
465         begin
466           ext := StrPas(cin);
467           while (Pos('.', ext) <> 0) do
468             System.Delete(ext, Pos('.', ext), 1);
469         end
470     else begin
471       comment := StrPas(cin);
472       if (Length(comment) = 0) or (Length(name) = 0) then break;
473 
474 //    if (comment[1] = '?') then break;
475 
476       caps := 0;
477       for i := 1 to Length(scaps) do
478         if (scaps[i] <> '-') then caps := caps or (1 shl (i - 1));
479 
480         info:=TCapability.Create;
481         info.FName:=name;
482         info.FDescription := comment;
483         info.FExt := ext;
484         info.internal := internal;
485         info.Capas := caps;
486 
487         SELF.AddObject(name,info);
488 
489         if (name = 'garmin_txt') then
490         begin
491           gpsbabel_knows_inifile := True;
492           // add -p "" to command-line
493         end
494         else if (name = 'xcsv') then
495           info.internal := 'file';
496         break;
497       end;
498     end;
499 
500     index := index + 1;
501     cin := cend + 1;
502   end;
503 end;
504 
TCapability.FIsDevicenull505 function TCapability.FIsDevice : Boolean;
506 begin
507   Result := (AnsiCompareText(Internal, 'serial') = 0);
508 end;
509 
FIsFilenull510 function TCapability.FIsFile : Boolean;
511 begin
512   Result := (AnsiCompareText(Internal, 'file') = 0);
513 end;
514 
CanReadAnynull515 function TCapability.CanReadAny : Boolean;
516 begin
517   Result := capas and (1 or 4 or 16) <> 0;
518 end;
519 
TCapability.CanWriteAnynull520 function TCapability.CanWriteAny : Boolean;
521 begin
522   Result := capas and (2 or 8 or 32) <> 0;
523 end;
524 
TCapabilities.GetListnull525 function TCapabilities.GetList: TStrings;
526 begin
527   Result := TStringList.Create;
528 end;
529 
GetCapabilityByNamenull530 function TCapabilities.GetCapabilityByName(const Descr: string): TCapability;
531 var
532   i: Integer;
533   info: TCapability;
534 begin
535   for i := 0 to Count - 1 do
536   begin
537     info := TCapability(Objects[i]);
538     if (AnsiCompareText(info.Description, Descr) = 0) then
539     begin
540       Result := info;
541       Exit;
542     end;
543   end;
544   Result := nil;
545 end;
546 
GetCapabilitynull547 function TCapabilities.GetCapability(Index: Integer) : TCapability;
548 begin
549   Result := TCapability(Objects[Index]);
550 end;
551 
552 
553 procedure TCapabilities.SetList(const Value: TStrings);
554 var
555   i: Integer;
556   s: string;
557 begin
558   Clear;
559   for i := 0 to Value.Count - 1 do
560   begin
561     s := Value.Strings[i];
562     AddFormat(s);
563   end;
564 end;
565 
566 (*
567 function Open_gpsbabel_ini(): TInifile;
568 var
569   s: string;
570 begin
571   s := SysUtils.ExpandFileName(SGPSBabelIniFilename);
572   if not(SysUtils.FileExists(s)) then
573     s := SysUtils.ExtractFilePath(ParamStr(0)) + SGPSBabelIniFilename;
574   if not(SysUtils.FileExists(s)) then
575     Result := TIniFile.Create(SGPSBabelIniFilename)
576   else
577     Result := TIniFile.Create(s)
578 end;
579 *)
580 
581 initialization
582 
583   gpsbabel_exe := SysUtils.ExtractFilePath(ParamStr(0)) + SGPSBabelExeFilename;
584   SGPSBabelGUIVersion := GetFileVersion(ParamStr(0));
585 //gpsbabel_ini := Open_gpsbabel_ini();
586   DecimalSeparator := '.';
587 
588 end.
589