Subversion Repositories oidplus

Rev

Rev 992 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 992 Rev 995
1
program OIDPLUS;
1
program OIDPLUS;
2
 
2
 
3
(************************************************)
3
(************************************************)
4
(* OIDPLUS.PAS                                  *)
4
(* OIDPLUS.PAS                                  *)
5
(* Author:   Daniel Marschall                   *)
5
(* Author:   Daniel Marschall                   *)
6
(* Revision: 2022-10-10                         *)
6
(* Revision: 2022-10-11                         *)
7
(* License:  Apache 2.0                         *)
7
(* License:  Apache 2.0                         *)
8
(* This file contains:                          *)
8
(* This file contains:                          *)
9
(* - "OIDplus for DOS" program                  *)
9
(* - "OIDplus for DOS" program                  *)
10
(************************************************)
10
(************************************************)
11
 
11
 
12
(* IMPORTANT:                                                  *)
12
(* IMPORTANT:                                                  *)
13
(* When you compile this code with Turbo Pascal 7.01,          *)
13
(* When you compile this code with Turbo Pascal 7.01,          *)
14
(* it won't run on fast PCs (Runtime Error 200).               *)
14
(* it won't run on fast PCs (Runtime Error 200).               *)
15
(* The built EXE file needs to be patched.                     *)
15
(* The built EXE file needs to be patched.                     *)
16
(* The program "PatchCRT" by Kennedy Software                  *)
16
(* The program "PatchCRT" by Kennedy Software                  *)
17
(* WON'T work because it somehow breaks our "_Pause" function. *)
17
(* WON'T work because it somehow breaks our "_Pause" function. *)
18
(* Instead, use the tool "TPPATCH" by Andreas Bauer.           *)
18
(* Instead, use the tool "TPPATCH" by Andreas Bauer.           *)
19
 
19
 
20
uses
20
uses
21
  Dos, Crt, Drivers, StrList, VtsFuncs, VtsCui, OidFile, OidUtils,
21
  Dos, Crt, Drivers, StrList, VtsFuncs, VtsCui, OidFile, OidUtils,
22
  Weid;
22
  Weid;
23
 
23
 
24
const
24
const
25
  VERSIONINFO            = 'Revision: 2022-10-10';
25
  VERSIONINFO            = 'Revision: 2022-10-10';
26
  TITLEBAR_LEFT_TEXT     = 'OIDplus';
26
  TITLEBAR_LEFT_TEXT     = 'OIDplus';
27
  DISKIO_SOUND_DEBUGGING = false;
27
  DISKIO_SOUND_DEBUGGING = false;
28
  DISKIO_SOUND_DELAY     = 500;
28
  DISKIO_SOUND_DELAY     = 500;
29
  ASNEDIT_LINES          = 10;
29
  ASNEDIT_LINES          = 10;
30
  DESCEDIT_LINES         = 10;
30
  DESCEDIT_LINES         = 10;
31
  DESCEDIT_PADDING       = 3;
31
  DESCEDIT_PADDING       = 3;
32
  ACTIONMENU_SIZE        = 5;
32
  ACTIONMENU_SIZE        = 5;
33
  MAINMENU_WIDTH         = 15;
33
  MAINMENU_WIDTH         = 15;
34
  MAINMENU_HEIGHT        = 3;
34
  MAINMENU_HEIGHT        = 3;
35
  MAINMENU_ALLOW_ESC     = false;
35
  MAINMENU_ALLOW_ESC     = false;
36
  TREEVIEW_INDENT        = 0;
36
  TREEVIEW_INDENT        = 0;
37
  TREEVIEW_INCLUDE_DESC  = true;
37
  TREEVIEW_INCLUDE_DESC  = true;
38
  TREEVIEW_WIDTH         = 80;
38
  TREEVIEW_WIDTH         = 80;
39
  OID_EXTENSION          = '.OID';
39
  OID_EXTENSION          = '.OID';
40
  TREEVIEW_FILENAME      = 'OIDTREE.TXT';
40
  TREEVIEW_FILENAME      = 'OIDTREE.TXT';
41
 
41
 
42
procedure _Pause;
42
procedure _Pause;
43
begin
43
begin
44
  DrawStatusBar('Press any key to continue');
44
  DrawStatusBar('Press any key to continue');
45
  CursorOn;
45
  CursorOn;
46
  ReadKey;
46
  ReadKey;
47
  CursorOff;
47
  CursorOff;
48
  DrawStatusBar('');
48
  DrawStatusBar('');
49
end;
49
end;
50
 
50
 
51
function _WriteOidFile(filename: string; oid: POid; ShowErrorMessage: boolean): boolean;
51
function _WriteOidFile(filename: string; oid: POid; ShowErrorMessage: boolean): boolean;
52
var
52
var
53
  res: boolean;
53
  res: boolean;
54
begin
54
begin
55
  DrawStatusBar('Write file ' + filename + '...');
55
  DrawStatusBar('Write file ' + filename + '...');
56
  res := WriteOidFile(filename, oid);
56
  res := WriteOidFile(filename, oid);
57
  if DISKIO_SOUND_DEBUGGING then
57
  if DISKIO_SOUND_DEBUGGING then
58
  begin
58
  begin
59
    Sound(70);
59
    Sound(70);
60
    Delay(DISKIO_SOUND_DELAY - 10);
60
    Delay(DISKIO_SOUND_DELAY - 10);
61
    NoSound;
61
    NoSound;
62
    Delay(10);
62
    Delay(10);
63
  end;
63
  end;
64
  DrawStatusBar('');
64
  DrawStatusBar('');
65
 
65
 
66
  _WriteOidFile := res;
66
  _WriteOidFile := res;
67
 
67
 
68
  if ShowErrorMessage and not res then
68
  if ShowErrorMessage and not res then
69
  begin
69
  begin
70
    ShowMessage('Cannot write to file ' + filename, 'ERROR', true);
70
    ShowMessage('Cannot write to file ' + filename, 'ERROR', true);
71
    _Pause;
71
    _Pause;
72
  end;
72
  end;
73
end;
73
end;
74
 
74
 
75
function _ReadOidFile(filename: string; oid: POid; ShowErrorMessage: boolean): boolean;
75
function _ReadOidFile(filename: string; oid: POid; ShowErrorMessage: boolean): boolean;
76
var
76
var
77
  res: boolean;
77
  res: boolean;
78
begin
78
begin
79
  DrawStatusBar('Read file ' + filename + '...');
79
  DrawStatusBar('Read file ' + filename + '...');
80
  res := ReadOidFile(filename, oid);
80
  res := ReadOidFile(filename, oid);
81
  if DISKIO_SOUND_DEBUGGING then
81
  if DISKIO_SOUND_DEBUGGING then
82
  begin
82
  begin
83
    Sound(50);
83
    Sound(50);
84
    Delay(DISKIO_SOUND_DELAY - 10);
84
    Delay(DISKIO_SOUND_DELAY - 10);
85
    NoSound;
85
    NoSound;
86
    Delay(10);
86
    Delay(10);
87
  end;
87
  end;
88
  DrawStatusBar('');
88
  DrawStatusBar('');
89
 
89
 
90
  _ReadOidFile := res;
90
  _ReadOidFile := res;
91
 
91
 
92
  if ShowErrorMessage and not res then
92
  if ShowErrorMessage and not res then
93
  begin
93
  begin
94
    ShowMessage('Cannot read file ' + filename, 'ERROR', true);
94
    ShowMessage('Cannot read file ' + filename, 'ERROR', true);
95
    _Pause;
95
    _Pause;
96
  end;
96
  end;
97
end;
97
end;
98
 
98
 
99
function _ShowASNIds(childOID: POID): string;
99
function _ShowASNIds(childOID: POID): string;
100
var
100
var
101
  j, jmax: integer;
101
  j, jmax: integer;
102
  sTmp: string;
102
  sTmp: string;
103
begin
103
begin
104
  sTmp := '';
104
  sTmp := '';
105
  jmax := ListCount(childOID^.ASNIds)-1;
105
  jmax := ListCount(childOID^.ASNIds)-1;
106
  for j := 0 to jmax do
106
  for j := 0 to jmax do
107
  begin
107
  begin
108
    if j = 0 then sTmp := sTmp + ' (';
108
    if j = 0 then sTmp := sTmp + ' (';
109
    sTmp := sTmp + ListGetElement(childOID^.ASNIds, j);
109
    sTmp := sTmp + ListGetElement(childOID^.ASNIds, j);
110
    if j = jmax then
110
    if j = jmax then
111
      sTmp := sTmp + ')'
111
      sTmp := sTmp + ')'
112
    else
112
    else
113
      sTmp := sTmp + ', ';
113
      sTmp := sTmp + ', ';
114
  end;
114
  end;
115
  _ShowASNIds := sTmp;
115
  _ShowASNIds := sTmp;
116
end;
116
end;
117
 
117
 
118
function AsnAlreadyExisting(oid: POID; asnid: string): boolean;
118
function AsnAlreadyExisting(oid: POID; asnid: string): boolean;
119
begin
119
begin
120
  AsnAlreadyExisting := ListContains(oid^.AsnIds, asnid);
120
  AsnAlreadyExisting := ListContains(oid^.AsnIds, asnid);
121
end;
121
end;
122
 
122
 
123
function AsnEditor(oid: POID): boolean;
123
function AsnEditor(oid: POID): boolean;
124
var
124
var
125
  asnList: PStringList;
125
  asnList: PStringList;
126
  i: integer;
126
  i: integer;
127
  x, y, w, h: integer;
127
  x, y, w, h: integer;
128
  res: integer;
128
  res: integer;
129
  sInput: string;
129
  sInput: string;
130
  menuIdNew, menuIdSave, menuIdExit: integer;
130
  menuIdNew, menuIdSave, menuIdExit: integer;
131
begin
131
begin
132
  AsnEditor := false;
132
  AsnEditor := false;
133
 
133
 
134
  repeat
134
  repeat
135
    CreateList(asnList);
135
    CreateList(asnList);
136
 
136
 
137
    for i := 0 to ListCount(oid^.ASNIds)-1 do
137
    for i := 0 to ListCount(oid^.ASNIds)-1 do
138
    begin
138
    begin
139
      ListAppend(asnList, ListGetElement(oid^.ASNIDs, i));
139
      ListAppend(asnList, ListGetElement(oid^.ASNIDs, i));
140
    end;
140
    end;
141
    menuIdNew  := ListAppend(asnList, '<NEW>');
141
    menuIdNew  := ListAppend(asnList, '<NEW>');
142
    menuIdSave := ListAppend(asnList, '<SAVE>');
142
    menuIdSave := ListAppend(asnList, '<SAVE>');
143
    menuIdExit := ListAppend(asnList, '<CANCEL>');
143
    menuIdExit := ListAppend(asnList, '<CANCEL>');
144
 
144
 
145
    DrawStatusBar('');
145
    DrawStatusBar('');
146
    x := SINGLE_LINE_BOX_PADDING;
146
    x := SINGLE_LINE_BOX_PADDING;
147
    y := ScreenHeight div 2 - ASNEDIT_LINES div 2;
147
    y := ScreenHeight div 2 - ASNEDIT_LINES div 2;
148
    w := ScreenWidth - (SINGLE_LINE_BOX_PADDING-1)*2;
148
    w := ScreenWidth - (SINGLE_LINE_BOX_PADDING-1)*2;
149
    h := ASNEDIT_LINES;
149
    h := ASNEDIT_LINES;
150
    res := DrawSelectionList(x, y, w, h,
150
    res := DrawSelectionList(x, y, w, h,
151
                             asnList, true,
151
                             asnList, true,
152
                             'EDIT ASN.1 IDENTIFIERS',
152
                             'EDIT ASN.1 IDENTIFIERS',
153
                             2);
153
                             2);
154
    FreeList(asnList);
154
    FreeList(asnList);
155
 
155
 
156
    (* Change double-border to thin-border *)
156
    (* Change double-border to thin-border *)
157
    DrawThinBorder(x-1, y-1, w+2, h+2);
157
    DrawThinBorder(x-1, y-1, w+2, h+2);
158
    GoToXY(x+1, y-1);
158
    GoToXY(x+1, y-1);
159
    Write('EDIT ASN.1 IDENTIFIERS');
159
    Write('EDIT ASN.1 IDENTIFIERS');
160
 
160
 
161
    if res = -1 then
161
    if res = -1 then
162
    begin
162
    begin
163
      exit;
163
      exit;
164
    end
164
    end
165
    else if res = menuIdNew then
165
    else if res = menuIdNew then
166
    begin
166
    begin
167
      (* "NEW" item was selected *)
167
      (* "NEW" item was selected *)
168
      sInput := '';
168
      sInput := '';
169
      CursorOn;
169
      CursorOn;
170
      repeat
170
      repeat
171
        if QueryVal(sInput,
171
        if QueryVal(sInput,
172
                    SINGLE_LINE_BOX_PADDING_INNER,
172
                    SINGLE_LINE_BOX_PADDING_INNER,
173
                    ScreenHeight div 2,
173
                    ScreenHeight div 2,
174
                    ScreenWidth - (SINGLE_LINE_BOX_PADDING_INNER-1)*2,
174
                    ScreenWidth - (SINGLE_LINE_BOX_PADDING_INNER-1)*2,
175
                    1,
175
                    1,
176
                    'ADD SINGLE ASN.1 ID',
176
                    'ADD SINGLE ASN.1 ID',
177
                    2) then
177
                    2) then
178
        begin
178
        begin
179
          if sInput = '' then continue;
179
          if sInput = '' then continue;
180
          if not ASN1IDValid(sInput) then
180
          if not ASN1IDValid(sInput) then
181
          begin
181
          begin
182
            ShowMessage('Invalid ASN1.ID! (Require -, a..z, A..Z, 0..9, begin with a-z)', 'ERROR', true);
182
            ShowMessage('Invalid ASN1.ID! (Require -, a..z, A..Z, 0..9, begin with a-z)', 'ERROR', true);
183
            _Pause;
183
            _Pause;
184
          end
184
          end
185
          else if AsnAlreadyExisting(oid, sInput) then
185
          else if AsnAlreadyExisting(oid, sInput) then
186
          begin
186
          begin
187
            ShowMessage('ASN.1 identifier is already existing on this arc', 'ERROR', true);
187
            ShowMessage('ASN.1 identifier is already existing on this arc', 'ERROR', true);
188
            _Pause;
188
            _Pause;
189
          end
189
          end
190
          else
190
          else
191
          begin
191
          begin
192
            ListAppend(oid^.ASNIDs, sInput);
192
            ListAppend(oid^.ASNIDs, sInput);
193
            break;
193
            break;
194
          end;
194
          end;
195
        end
195
        end
196
        else break;
196
        else break;
197
      until false;
197
      until false;
198
      CursorOff;
198
      CursorOff;
199
    end
199
    end
200
    else if res = menuIdSave then
200
    else if res = menuIdSave then
201
    begin
201
    begin
202
      (* "SAVE" item was selected *)
202
      (* "SAVE" item was selected *)
203
      AsnEditor := true;
203
      AsnEditor := true;
204
      Exit;
204
      Exit;
205
    end
205
    end
206
    else if res = menuIdExit then
206
    else if res = menuIdExit then
207
    begin
207
    begin
208
      (* "CANCEL" item was selected *)
208
      (* "CANCEL" item was selected *)
209
      AsnEditor := false;
209
      AsnEditor := false;
210
      Exit;
210
      Exit;
211
    end
211
    end
212
    else
212
    else
213
    begin
213
    begin
214
      DrawStatusBar('Note: Remove the text to delete the ASN.1 identifier');
214
      DrawStatusBar('Note: Remove the text to delete the ASN.1 identifier');
215
      sInput := ListGetElement(oid^.ASNIDs, res);
215
      sInput := ListGetElement(oid^.ASNIDs, res);
216
          CursorOn;
216
          CursorOn;
217
      repeat
217
      repeat
218
        if QueryVal(sInput,
218
        if QueryVal(sInput,
219
                    SINGLE_LINE_BOX_PADDING_INNER,
219
                    SINGLE_LINE_BOX_PADDING_INNER,
220
                    ScreenHeight div 2,
220
                    ScreenHeight div 2,
221
                    ScreenWidth - (SINGLE_LINE_BOX_PADDING_INNER-1)*2,
221
                    ScreenWidth - (SINGLE_LINE_BOX_PADDING_INNER-1)*2,
222
                    1,
222
                    1,
223
                    'EDIT SINGLE ASN.1 ID',
223
                    'EDIT SINGLE ASN.1 ID',
224
                    2) then
224
                    2) then
225
        begin
225
        begin
226
          if sInput = '' then
226
          if sInput = '' then
227
          begin
227
          begin
228
            (* Empty input = Delete ASN.1 ID *)
228
            (* Empty input = Delete ASN.1 ID *)
229
            ListDeleteElementByIndex(oid^.ASNIDs, res);
229
            ListDeleteElementByIndex(oid^.ASNIDs, res);
230
            break;
230
            break;
231
          end
231
          end
232
          else if not ASN1IDValid(sInput) then
232
          else if not ASN1IDValid(sInput) then
233
          begin
233
          begin
234
            ShowMessage('Invalid ASN1.ID! (Require -, a..z, A..Z, 0..9, begin with a-z)', 'ERROR', true);
234
            ShowMessage('Invalid ASN1.ID! (Require -, a..z, A..Z, 0..9, begin with a-z)', 'ERROR', true);
235
            _Pause;
235
            _Pause;
236
          end
236
          end
237
          else if AsnAlreadyExisting(oid, sInput) and
237
          else if AsnAlreadyExisting(oid, sInput) and
238
              not (ListGetElement(oid^.ASNIDs, res) = sInput) then
238
              not (ListGetElement(oid^.ASNIDs, res) = sInput) then
239
          begin
239
          begin
240
            ShowMessage('ASN.1 identifier is already existing on this arc', 'ERROR', true);
240
            ShowMessage('ASN.1 identifier is already existing on this arc', 'ERROR', true);
241
            _Pause;
241
            _Pause;
242
          end
242
          end
243
          else
243
          else
244
          begin
244
          begin
245
            ListSetElement(oid^.ASNIDs, res, sInput);
245
            ListSetElement(oid^.ASNIDs, res, sInput);
246
            break;
246
            break;
247
          end;
247
          end;
248
        end
248
        end
249
        else break;
249
        else break;
250
      until false;
250
      until false;
251
      CursorOff;
251
      CursorOff;
252
    end;
252
    end;
253
  until false;
253
  until false;
254
end;
254
end;
255
 
255
 
256
function UnicodeLabelAlreadyExisting(oid: POID; unicodeLabel: string): boolean;
256
function UnicodeLabelAlreadyExisting(oid: POID; unicodeLabel: string): boolean;
257
begin
257
begin
258
  UnicodeLabelAlreadyExisting := ListContains(oid^.UnicodeLabels, unicodeLabel);
258
  UnicodeLabelAlreadyExisting := ListContains(oid^.UnicodeLabels, unicodeLabel);
259
end;
259
end;
260
 
260
 
261
function IriEditor(oid: POID): boolean;
261
function IriEditor(oid: POID): boolean;
262
var
262
var
263
  iriList: PStringList;
263
  iriList: PStringList;
264
  i: integer;
264
  i: integer;
265
  x, y, w, h: integer;
265
  x, y, w, h: integer;
266
  res: integer;
266
  res: integer;
267
  sInput: string;
267
  sInput: string;
268
  menuIdNew, menuIdSave, menuIdExit: integer;
268
  menuIdNew, menuIdSave, menuIdExit: integer;
269
begin
269
begin
270
  IriEditor := false;
270
  IriEditor := false;
271
 
271
 
272
  repeat
272
  repeat
273
    CreateList(iriList);
273
    CreateList(iriList);
274
 
274
 
275
    for i := 0 to ListCount(oid^.UnicodeLabels)-1 do
275
    for i := 0 to ListCount(oid^.UnicodeLabels)-1 do
276
    begin
276
    begin
277
      ListAppend(iriList, ListGetElement(oid^.UnicodeLabels, i));
277
      ListAppend(iriList, ListGetElement(oid^.UnicodeLabels, i));
278
    end;
278
    end;
279
    menuIdNew  := ListAppend(iriList, '<NEW>');
279
    menuIdNew  := ListAppend(iriList, '<NEW>');
280
    menuIdSave := ListAppend(iriList, '<SAVE>');
280
    menuIdSave := ListAppend(iriList, '<SAVE>');
281
    menuIdExit := ListAppend(iriList, '<CANCEL>');
281
    menuIdExit := ListAppend(iriList, '<CANCEL>');
282
 
282
 
283
    DrawStatusBar('');
283
    DrawStatusBar('');
284
    x := SINGLE_LINE_BOX_PADDING;
284
    x := SINGLE_LINE_BOX_PADDING;
285
    y := ScreenHeight div 2 - ASNEDIT_LINES div 2;
285
    y := ScreenHeight div 2 - ASNEDIT_LINES div 2;
286
    w := ScreenWidth - (SINGLE_LINE_BOX_PADDING-1)*2;
286
    w := ScreenWidth - (SINGLE_LINE_BOX_PADDING-1)*2;
287
    h := ASNEDIT_LINES;
287
    h := ASNEDIT_LINES;
288
    res := DrawSelectionList(x, y, w, h,
288
    res := DrawSelectionList(x, y, w, h,
289
                             iriList, true,
289
                             iriList, true,
290
                             'EDIT UNICODE LABELS',
290
                             'EDIT UNICODE LABELS',
291
                             2);
291
                             2);
292
    FreeList(iriList);
292
    FreeList(iriList);
293
 
293
 
294
    (* Change double-border to thin-border *)
294
    (* Change double-border to thin-border *)
295
    DrawThinBorder(x-1, y-1, w+2, h+2);
295
    DrawThinBorder(x-1, y-1, w+2, h+2);
296
    GoToXY(x+1, y-1);
296
    GoToXY(x+1, y-1);
297
    Write('EDIT UNICODE LABELS');
297
    Write('EDIT UNICODE LABELS');
298
 
298
 
299
    if res = -1 then
299
    if res = -1 then
300
    begin
300
    begin
301
      exit;
301
      exit;
302
    end
302
    end
303
    else if res = menuIdNew then
303
    else if res = menuIdNew then
304
    begin
304
    begin
305
      (* "NEW" item was selected *)
305
      (* "NEW" item was selected *)
306
      sInput := '';
306
      sInput := '';
307
      CursorOn;
307
      CursorOn;
308
      repeat
308
      repeat
309
        if QueryVal(sInput,
309
        if QueryVal(sInput,
310
                    SINGLE_LINE_BOX_PADDING_INNER,
310
                    SINGLE_LINE_BOX_PADDING_INNER,
311
                    ScreenHeight div 2,
311
                    ScreenHeight div 2,
312
                    ScreenWidth - (SINGLE_LINE_BOX_PADDING_INNER-1)*2,
312
                    ScreenWidth - (SINGLE_LINE_BOX_PADDING_INNER-1)*2,
313
                    1,
313
                    1,
314
                    'ADD SINGLE UNICODE LABEL',
314
                    'ADD SINGLE UNICODE LABEL',
315
                    2) then
315
                    2) then
316
        begin
316
        begin
317
          if sInput = '' then continue;
317
          if sInput = '' then continue;
318
          if not UnicodeLabelValid(sInput) then
318
          if not UnicodeLabelValid(sInput) then
319
          begin
319
          begin
320
            ShowMessage('Invalid Unicode Label!', 'ERROR', true);
320
            ShowMessage('Invalid Unicode Label!', 'ERROR', true);
321
            _Pause;
321
            _Pause;
322
          end
322
          end
323
          else if UnicodeLabelAlreadyExisting(oid, sInput) then
323
          else if UnicodeLabelAlreadyExisting(oid, sInput) then
324
          begin
324
          begin
325
            ShowMessage('Unicode Label is already existing on this arc', 'ERROR', true);
325
            ShowMessage('Unicode Label is already existing on this arc', 'ERROR', true);
326
            _Pause;
326
            _Pause;
327
          end
327
          end
328
          else
328
          else
329
          begin
329
          begin
330
            ListAppend(oid^.UnicodeLabels, sInput);
330
            ListAppend(oid^.UnicodeLabels, sInput);
331
            break;
331
            break;
332
          end;
332
          end;
333
        end
333
        end
334
        else break;
334
        else break;
335
      until false;
335
      until false;
336
      CursorOff;
336
      CursorOff;
337
    end
337
    end
338
    else if res = menuIdSave then
338
    else if res = menuIdSave then
339
    begin
339
    begin
340
      (* "SAVE" item was selected *)
340
      (* "SAVE" item was selected *)
341
      IriEditor := true;
341
      IriEditor := true;
342
      Exit;
342
      Exit;
343
    end
343
    end
344
    else if res = menuIdExit then
344
    else if res = menuIdExit then
345
    begin
345
    begin
346
      (* "CANCEL" item was selected *)
346
      (* "CANCEL" item was selected *)
347
      IriEditor := false;
347
      IriEditor := false;
348
      Exit;
348
      Exit;
349
    end
349
    end
350
    else
350
    else
351
    begin
351
    begin
352
      DrawStatusBar('Note: Remove the text to delete the Unicode Label');
352
      DrawStatusBar('Note: Remove the text to delete the Unicode Label');
353
      sInput := ListGetElement(oid^.UnicodeLabels, res);
353
      sInput := ListGetElement(oid^.UnicodeLabels, res);
354
          CursorOn;
354
          CursorOn;
355
      repeat
355
      repeat
356
        if QueryVal(sInput,
356
        if QueryVal(sInput,
357
                    SINGLE_LINE_BOX_PADDING_INNER,
357
                    SINGLE_LINE_BOX_PADDING_INNER,
358
                    ScreenHeight div 2,
358
                    ScreenHeight div 2,
359
                    ScreenWidth - (SINGLE_LINE_BOX_PADDING_INNER-1)*2,
359
                    ScreenWidth - (SINGLE_LINE_BOX_PADDING_INNER-1)*2,
360
                    1,
360
                    1,
361
                    'EDIT SINGLE UNICODE LABEL',
361
                    'EDIT SINGLE UNICODE LABEL',
362
                    2) then
362
                    2) then
363
        begin
363
        begin
364
          if sInput = '' then
364
          if sInput = '' then
365
          begin
365
          begin
366
            (* Empty input = Delete Unicode label *)
366
            (* Empty input = Delete Unicode label *)
367
            ListDeleteElementByIndex(oid^.UnicodeLabels, res);
367
            ListDeleteElementByIndex(oid^.UnicodeLabels, res);
368
            break;
368
            break;
369
          end
369
          end
370
          else if not UnicodeLabelValid(sInput) then
370
          else if not UnicodeLabelValid(sInput) then
371
          begin
371
          begin
372
            ShowMessage('Invalid Unicode Label!', 'ERROR', true);
372
            ShowMessage('Invalid Unicode Label!', 'ERROR', true);
373
            _Pause;
373
            _Pause;
374
          end
374
          end
375
          else if UnicodeLabelAlreadyExisting(oid, sInput) and
375
          else if UnicodeLabelAlreadyExisting(oid, sInput) and
376
              not (ListGetElement(oid^.UnicodeLabels, res) = sInput) then
376
              not (ListGetElement(oid^.UnicodeLabels, res) = sInput) then
377
          begin
377
          begin
378
            ShowMessage('Unicode Label is already existing on this arc', 'ERROR', true);
378
            ShowMessage('Unicode Label is already existing on this arc', 'ERROR', true);
379
            _Pause;
379
            _Pause;
380
          end
380
          end
381
          else
381
          else
382
          begin
382
          begin
383
            ListSetElement(oid^.UnicodeLabels, res, sInput);
383
            ListSetElement(oid^.UnicodeLabels, res, sInput);
384
            break;
384
            break;
385
          end;
385
          end;
386
        end
386
        end
387
        else break;
387
        else break;
388
      until false;
388
      until false;
389
      CursorOff;
389
      CursorOff;
390
    end;
390
    end;
391
  until false;
391
  until false;
392
end;
392
end;
393
 
393
 
394
function DescEditor(oid: POID): boolean;
394
function DescEditor(oid: POID): boolean;
395
var
395
var
396
  sInput: string;
396
  sInput: string;
397
begin
397
begin
398
  DescEditor := false;
398
  DescEditor := false;
399
 
399
 
400
  DrawStatusBar('Note: Press Ctrl+Return for a line-break.');
400
  DrawStatusBar('Note: Press Ctrl+Return for a line-break.');
401
  sInput := oid^.description;
401
  sInput := oid^.description;
402
  CursorOn;
402
  CursorOn;
403
  if QueryVal(sInput,
403
  if QueryVal(sInput,
404
              DESCEDIT_PADDING,
404
              DESCEDIT_PADDING,
405
              ScreenHeight div 2 - DESCEDIT_LINES div 2,
405
              ScreenHeight div 2 - DESCEDIT_LINES div 2,
406
              ScreenWidth - (DESCEDIT_PADDING-1)*2,
406
              ScreenWidth - (DESCEDIT_PADDING-1)*2,
407
              DESCEDIT_LINES,
407
              DESCEDIT_LINES,
408
              'EDIT DESCRIPTION',
408
              'EDIT DESCRIPTION',
409
              2) then
409
              2) then
410
  begin
410
  begin
411
    oid^.description := sInput;
411
    oid^.description := sInput;
412
    DescEditor := true; (* request caller to save <oid> *)
412
    DescEditor := true; (* request caller to save <oid> *)
413
  end;
413
  end;
414
  CursorOff;
414
  CursorOff;
415
end;
415
end;
416
 
416
 
417
function NextPossibleFileID: string;
417
function NextPossibleFileID: string;
418
var
418
var
419
  DirInfo: SearchRec;
419
  DirInfo: SearchRec;
420
  list: PStringList;
-
 
421
  iId: LongInt;
420
  iId, imax: LongInt;
422
  sId: string;
421
  sId: string;
423
begin
422
begin
424
  (* Put all found files into a list *)
-
 
425
  CreateList(list);
-
 
426
  FindFirst(RepeatStr('?',8)+OID_EXTENSION, Archive, DirInfo);
423
  FindFirst(RepeatStr('?',8)+OID_EXTENSION, Archive, DirInfo);
-
 
424
  imax := -1;
427
  while DosError = 0 do
425
  while DosError = 0 do
428
  begin
426
  begin
429
    sId := Copy(DirInfo.Name, 1, 8);
427
    sId := Copy(DirInfo.Name, 1, 8);
430
    ListAppend(list, sId);
428
    if IsPositiveIntegerOrZero(sId) then
431
    FindNext(DirInfo);
-
 
432
  end;
-
 
433
 
-
 
434
  (* Search for the first non existing item in the list *)
-
 
435
  sId := '';
-
 
436
  for iId := 0 to 99999999 do
-
 
437
  begin
429
    begin
438
    sId := ZeroPad(iId, 8);
430
      iId := StrToInt(sId);
439
    if not ListContains(list, sId) then break;
431
      if iId > iMax then iMax := iId;
-
 
432
    end;
-
 
433
    FindNext(DirInfo);
440
  end;
434
  end;
441
  NextPossibleFileId := sId;
435
  NextPossibleFileId := ZeroPad(iMax+1, 8);
442
  FreeList(list);
-
 
443
end;
436
end;
444
 
437
 
445
function NumIdAlreadyExisting(parentOID: POID; arcval: string): boolean;
438
function NumIdAlreadyExisting(parentOID: POID; arcval: string): boolean;
446
var
439
var
447
  searchDotNotation: string;
440
  searchDotNotation: string;
448
  sTmp: string;
441
  sTmp: string;
449
  i: integer;
442
  i: integer;
450
begin
443
begin
451
  if parentOID^.DotNotation = '' then
444
  if parentOID^.DotNotation = '' then
452
    searchDotNotation := arcval
445
    searchDotNotation := arcval
453
  else
446
  else
454
    searchDotNotation := parentOID^.DotNotation + '.' + arcval;
447
    searchDotNotation := parentOID^.DotNotation + '.' + arcval;
455
  for i := 0 to ListCount(parentOID^.SubIds)-1 do
448
  for i := 0 to ListCount(parentOID^.SubIds)-1 do
456
  begin
449
  begin
457
    sTmp := ListGetElement(parentOID^.SubIds, i);
450
    sTmp := ListGetElement(parentOID^.SubIds, i);
458
    if DotNotationPart(sTmp) = searchDotNotation then
451
    if DotNotationPart(sTmp) = searchDotNotation then
459
    begin
452
    begin
460
      NumIdAlreadyExisting := true;
453
      NumIdAlreadyExisting := true;
461
      exit;
454
      exit;
462
    end;
455
    end;
463
  end;
456
  end;
464
  NumIdAlreadyExisting := false;
457
  NumIdAlreadyExisting := false;
465
end;
458
end;
466
 
459
 
467
function NumIdEditor(oid: POID; parentOID: POID): boolean;
460
function NumIdEditor(oid: POID; parentOID: POID): boolean;
468
var
461
var
469
  sInput: string;
462
  sInput: string;
470
  title: string;
463
  title: string;
471
  base36mode: boolean;
464
  base36mode: boolean;
472
  arcval: string;
465
  arcval: string;
473
begin
466
begin
474
  NumIdEditor := false;
467
  NumIdEditor := false;
475
  sInput := '';
468
  sInput := '';
476
 
469
 
477
  base36mode := false;
470
  base36mode := false;
478
  CursorOn;
471
  CursorOn;
479
  repeat
472
  repeat
480
    if base36mode then
473
    if base36mode then
481
    begin
474
    begin
482
      DrawStatusBar('Press ESC to cancel');
475
      DrawStatusBar('Press ESC to cancel');
483
      title := 'ENTER BASE36 ID'
476
      title := 'ENTER BASE36 ID'
484
    end
477
    end
485
    else
478
    else
486
    begin
479
    begin
487
      DrawStatusBar('Enter "WEID" to enter a Base36 instead of Base10; press ESC to cancel');
480
      DrawStatusBar('Enter "WEID" to enter a Base36 instead of Base10; press ESC to cancel');
488
      title := 'ENTER NUMERIC ID';
481
      title := 'ENTER NUMERIC ID';
489
    end;
482
    end;
490
    if QueryVal(sInput,
483
    if QueryVal(sInput,
491
                SINGLE_LINE_BOX_PADDING_INNER,
484
                SINGLE_LINE_BOX_PADDING_INNER,
492
                ScreenHeight div 2,
485
                ScreenHeight div 2,
493
                ScreenWidth - (SINGLE_LINE_BOX_PADDING_INNER-1)*2,
486
                ScreenWidth - (SINGLE_LINE_BOX_PADDING_INNER-1)*2,
494
                1,
487
                1,
495
                title,
488
                title,
496
                2) then
489
                2) then
497
    begin
490
    begin
498
      if sInput = '' then continue;
491
      if sInput = '' then continue;
499
      if not base36mode and (sInput = 'WEID') then
492
      if not base36mode and (sInput = 'WEID') then
500
      begin
493
      begin
501
        sInput := '';
494
        sInput := '';
502
        base36mode := true;
495
        base36mode := true;
503
      end
496
      end
504
      else if not base36mode and not IsPositiveIntegerOrZero(sInput) then
497
      else if not base36mode and not IsPositiveIntegerOrZero(sInput) then
505
      begin
498
      begin
506
        ShowMessage('Invalid numeric ID (must be a positive integer)', 'ERROR', true);
499
        ShowMessage('Invalid numeric ID (must be a positive integer)', 'ERROR', true);
507
        _Pause;
500
        _Pause;
508
      end
501
      end
509
      else if base36mode and not IsBase36String(sInput) then
502
      else if base36mode and not IsBase36String(sInput) then
510
      begin
503
      begin
511
        ShowMessage('Invalid base36 ID (must be 0..9, A..Z)', 'ERROR', true);
504
        ShowMessage('Invalid base36 ID (must be 0..9, A..Z)', 'ERROR', true);
512
        _Pause;
505
        _Pause;
513
      end
506
      end
514
      else
507
      else
515
      begin
508
      begin
516
        if base36mode then
509
        if base36mode then
517
          arcval := base_convert_bigint(sInput, 36, 10)
510
          arcval := base_convert_bigint(sInput, 36, 10)
518
        else
511
        else
519
          arcval := sInput;
512
          arcval := sInput;
520
        arcval := StripLeadingZeros(arcval);
513
        arcval := StripLeadingZeros(arcval);
521
 
514
 
522
        if (parentOID^.DotNotation='') and (arcval <> '0') and (arcval <> '1') and (arcval <> '2') then
515
        if (parentOID^.DotNotation='') and (arcval <> '0') and (arcval <> '1') and (arcval <> '2') then
523
        begin
516
        begin
524
          ShowMessage('Invalid numeric ID (root arc can only be 0, 1, or 2)', 'ERROR', true);
517
          ShowMessage('Invalid numeric ID (root arc can only be 0, 1, or 2)', 'ERROR', true);
525
          _Pause;
518
          _Pause;
526
        end
519
        end
527
        else if ((parentOID^.DotNotation='0') or (parentOID^.DotNotation='1')) and
520
        else if ((parentOID^.DotNotation='0') or (parentOID^.DotNotation='1')) and
528
                ((Length(arcval)>2) or (StrToInt(arcval) > 39)) then
521
                ((Length(arcval)>2) or (StrToInt(arcval) > 39)) then
529
        begin
522
        begin
530
          ShowMessage('Invalid numeric ID (root 0 and 1 must have sub-arc of 0..39)', 'ERROR', true);
523
          ShowMessage('Invalid numeric ID (root 0 and 1 must have sub-arc of 0..39)', 'ERROR', true);
531
          _Pause;
524
          _Pause;
532
        end
525
        end
533
        else if NumIdAlreadyExisting(parentOID, arcval) then
526
        else if NumIdAlreadyExisting(parentOID, arcval) then
534
        begin
527
        begin
535
          ShowMessage('This numeric ID is already used in this arc', 'ERROR', true);
528
          ShowMessage('This numeric ID is already used in this arc', 'ERROR', true);
536
          _Pause;
529
          _Pause;
537
        end
530
        end
538
        else
531
        else
539
        begin
532
        begin
540
          if parentOID^.DotNotation = '' then
533
          if parentOID^.DotNotation = '' then
541
            oid^.DotNotation := arcval
534
            oid^.DotNotation := arcval
542
          else
535
          else
543
            oid^.DotNotation := parentOID^.DotNotation + '.' + arcval;
536
            oid^.DotNotation := parentOID^.DotNotation + '.' + arcval;
544
          NumIdEditor := true; (* request caller to save <oid> *)
537
          NumIdEditor := true; (* request caller to save <oid> *)
545
          Break;
538
          Break;
546
        end;
539
        end;
547
      end;
540
      end;
548
    end
541
    end
549
    else
542
    else
550
    begin
543
    begin
551
      (* User pressed ESC *)
544
      (* User pressed ESC *)
552
      Break;
545
      Break;
553
    end;
546
    end;
554
  until false;
547
  until false;
555
  CursorOff;
548
  CursorOff;
556
end;
549
end;
557
 
550
 
558
function NewOidEditor(oid: POID): boolean;
551
function NewOidEditor(oid: POID): boolean;
559
var
552
var
560
  newfilename: string;
553
  newfilename: string;
561
  newOID: POID;
554
  newOID: POID;
562
begin
555
begin
563
  NewOidEditor := false;
556
  NewOidEditor := false;
564
 
557
 
565
  CreateOidDef(newOID);
558
  CreateOidDef(newOID);
566
  newOID^.FileId := NextPossibleFileID;
559
  newOID^.FileId := NextPossibleFileID;
567
  newOID^.ParentFileId := oid^.FileId;
560
  newOID^.ParentFileId := oid^.FileId;
568
  newOID^.ParentDotNotation := oid^.DotNotation;
561
  newOID^.ParentDotNotation := oid^.DotNotation;
569
  if NumIdEditor(newOID, oid) and
562
  if NumIdEditor(newOID, oid) and
570
     AsnEditor(newOID) and
563
     AsnEditor(newOID) and
571
     IriEditor(newOID) and
564
     IriEditor(newOID) and
572
     DescEditor(newOID) then
565
     DescEditor(newOID) then
573
  begin
566
  begin
574
    newfilename := newOID^.FileId + OID_EXTENSION;
567
    newfilename := newOID^.FileId + OID_EXTENSION;
575
    if _WriteOidFile(newfilename, newOID, true) then
568
    if _WriteOidFile(newfilename, newOID, true) then
576
    begin
569
    begin
577
      (* Add link to original file and enable the saving of it *)
570
      (* Add link to original file and enable the saving of it *)
578
      ListAppend(oid^.SubIds, newOID^.FileId + newOID^.DotNotation);
571
      ListAppend(oid^.SubIds, newOID^.FileId + newOID^.DotNotation);
579
      NewOidEditor := true; (* request caller to save <oid> *)
572
      NewOidEditor := true; (* request caller to save <oid> *)
580
    end;
573
    end;
581
  end;
574
  end;
582
  FreeOidDef(newOID);
575
  FreeOidDef(newOID);
583
end;
576
end;
584
 
577
 
585
procedure DeleteChildrenRecursive(oid: POID);
578
procedure DeleteChildrenRecursive(oid: POID);
586
var
579
var
587
  i: integer;
580
  i: integer;
588
  childOID: POID;
581
  childOID: POID;
589
  filenameChild: string;
582
  filenameChild: string;
590
begin
583
begin
591
  for i := 0 to ListCount(oid^.SubIds)-1 do
584
  for i := 0 to ListCount(oid^.SubIds)-1 do
592
  begin
585
  begin
593
    filenameChild := FileIdPart(ListGetElement(oid^.SubIds, i)) + OID_EXTENSION;
586
    filenameChild := FileIdPart(ListGetElement(oid^.SubIds, i)) + OID_EXTENSION;
594
    if FileExists(filenameChild) then
587
    if FileExists(filenameChild) then
595
    begin
588
    begin
596
      CreateOidDef(childOID);
589
      CreateOidDef(childOID);
597
      if _ReadOidFile(filenameChild, childOID, false) and
590
      if _ReadOidFile(filenameChild, childOID, false) and
598
         (childOID^.ParentFileId = oid^.FileId) and
591
         (childOID^.ParentFileId = oid^.FileId) and
599
         (childOID^.ParentDotNotation = oid^.DotNotation) then
592
         (childOID^.ParentDotNotation = oid^.DotNotation) then
600
      begin
593
      begin
601
        DeleteChildrenRecursive(childOID);
594
        DeleteChildrenRecursive(childOID);
602
      end;
595
      end;
603
      FreeOidDef(childOID);
596
      FreeOidDef(childOID);
604
      DeleteFile(filenameChild);
597
      DeleteFile(filenameChild);
605
    end;
598
    end;
606
  end;
599
  end;
607
  ListClear(oid^.SubIds);
600
  ListClear(oid^.SubIds);
608
end;
601
end;
609
 
602
 
610
procedure DeleteOidRecursive(selfOID: POID);
603
procedure DeleteOidRecursive(selfOID: POID);
611
var
604
var
612
  i: integer;
605
  i: integer;
613
  parentOID: POID;
606
  parentOID: POID;
614
  filenameSelf, filenameParent: string;
607
  filenameSelf, filenameParent: string;
615
begin
608
begin
616
  (* Remove all children and their files recursively *)
609
  (* Remove all children and their files recursively *)
617
  DeleteChildrenRecursive(selfOID);
610
  DeleteChildrenRecursive(selfOID);
618
 
611
 
619
  (* Remove forward reference in parent OID *)
612
  (* Remove forward reference in parent OID *)
620
  (* (this is the most important part)      *)
613
  (* (this is the most important part)      *)
621
  filenameParent := selfOID^.ParentFileId + OID_EXTENSION;
614
  filenameParent := selfOID^.ParentFileId + OID_EXTENSION;
622
  if FileExists(filenameParent) then
615
  if FileExists(filenameParent) then
623
  begin
616
  begin
624
    CreateOidDef(parentOID);
617
    CreateOidDef(parentOID);
625
    if _ReadOidFile(filenameParent, parentOID, true) then
618
    if _ReadOidFile(filenameParent, parentOID, true) then
626
    begin
619
    begin
627
      if ListDeleteElementByValue(parentOID^.SubIds, selfOID^.FileId + selfOID^.DotNotation) then
620
      if ListDeleteElementByValue(parentOID^.SubIds, selfOID^.FileId + selfOID^.DotNotation) then
628
      begin
621
      begin
629
        _WriteOidFile(filenameParent, parentOID, true);
622
        _WriteOidFile(filenameParent, parentOID, true);
630
      end;
623
      end;
631
    end;
624
    end;
632
    FreeOidDef(parentOID);
625
    FreeOidDef(parentOID);
633
  end;
626
  end;
634
 
627
 
635
  (* Delete own file *)
628
  (* Delete own file *)
636
  filenameSelf := selfOID^.FileId + OID_EXTENSION;
629
  filenameSelf := selfOID^.FileId + OID_EXTENSION;
637
  if FileExists(filenameSelf) then
630
  if FileExists(filenameSelf) then
638
  begin
631
  begin
639
    DeleteFile(filenameSelf);
632
    DeleteFile(filenameSelf);
640
  end;
633
  end;
641
end;
634
end;
642
 
635
 
643
function _DeleteConfirmation: boolean;
636
function _DeleteConfirmation: boolean;
644
var
637
var
645
  sc: Char;
638
  sc: Char;
646
begin
639
begin
647
  repeat
640
  repeat
648
    ShowMessage('Are you sure you want to delete this OID? (Y/N)', 'DELETE OID', true);
641
    ShowMessage('Are you sure you want to delete this OID? (Y/N)', 'DELETE OID', true);
649
    DrawStatusBar('Y=Yes, N=No');
642
    DrawStatusBar('Y=Yes, N=No');
650
 
643
 
651
    CursorOn;
644
    CursorOn;
652
    sc := ReadKey;
645
    sc := ReadKey;
653
    CursorOff;
646
    CursorOff;
654
    if sc = #0 then
647
    if sc = #0 then
655
    begin
648
    begin
656
      (* Extended key. Nothing we care about. *)
649
      (* Extended key. Nothing we care about. *)
657
      ReadKey;
650
      ReadKey;
658
      continue;
651
      continue;
659
    end;
652
    end;
660
 
653
 
661
    if UpCase(sc) = 'Y' then
654
    if UpCase(sc) = 'Y' then
662
    begin
655
    begin
663
      _DeleteConfirmation := true;
656
      _DeleteConfirmation := true;
664
      break;
657
      break;
665
    end
658
    end
666
    else if UpCase(sc) = 'N' then
659
    else if UpCase(sc) = 'N' then
667
    begin
660
    begin
668
      _DeleteConfirmation := false;
661
      _DeleteConfirmation := false;
669
      break;
662
      break;
670
    end;
663
    end;
671
  until false;
664
  until false;
672
end;
665
end;
673
 
666
 
674
procedure _DrawOidTitleBar(filename: string; oid: POID);
667
procedure _DrawOidTitleBar(filename: string; oid: POID);
675
begin
668
begin
676
  if oid^.DotNotation = '' then
669
  if oid^.DotNotation = '' then
677
    DrawTitleBar('OID ROOT', TITLEBAR_LEFT_TEXT, filename)
670
    DrawTitleBar('OID ROOT', TITLEBAR_LEFT_TEXT, filename)
678
  else
671
  else
679
    DrawTitleBar('OID ' + oid^.DotNotation, TITLEBAR_LEFT_TEXT, filename);
672
    DrawTitleBar('OID ' + oid^.DotNotation, TITLEBAR_LEFT_TEXT, filename);
680
end;
673
end;
681
 
674
 
682
function DotNotation(oid: POid): string;
675
function DotNotation(oid: POid): string;
683
var
676
var
684
  res: string;
677
  res: string;
685
begin
678
begin
686
  res := oid^.DotNotation;
679
  res := oid^.DotNotation;
687
  if res = '' then res := '.'; (* root *)
680
  if res = '' then res := '.'; (* root *)
688
  DotNotation := res;
681
  DotNotation := res;
689
end;
682
end;
690
 
683
 
691
function OidLastArc(oid: POid): string;
684
function OidLastArc(oid: POid): string;
692
var
685
var
693
  s: string;
686
  s: string;
694
  p: integer;
687
  p: integer;
695
begin
688
begin
696
  s := oid^.DotNotation;
689
  s := oid^.DotNotation;
697
 
690
 
698
  while true do
691
  while true do
699
  begin
692
  begin
700
    p := Pos('.', s);
693
    p := Pos('.', s);
701
    if p = 0 then break;
694
    if p = 0 then break;
702
    Delete(s, 1, p);
695
    Delete(s, 1, p);
703
  end;
696
  end;
704
 
697
 
705
  OidLastArc := s;
698
  OidLastArc := s;
706
end;
699
end;
707
 
700
 
708
function AsnNotation(oid: POid): string;
701
function AsnNotation(oid: POid): string;
709
var
702
var
710
  prevOid, curOid: POid;
703
  prevOid, curOid: POid;
711
  res: string;
704
  res: string;
712
begin
705
begin
713
  CreateOidDef(curOid);
706
  CreateOidDef(curOid);
714
  prevOid := oid;
707
  prevOid := oid;
715
  res := '';
708
  res := '';
716
 
709
 
717
  while true do
710
  while true do
718
  begin
711
  begin
719
    (* Note: BackRef is not checked yet! Infinite loop is possible! (TODO) *)
712
    (* Note: BackRef is not checked yet! Infinite loop is possible! (TODO) *)
720
    ReadOidFile(prevOid^.ParentFileId + '.OID', curOid);
713
    ReadOidFile(prevOid^.ParentFileId + '.OID', curOid);
721
    if curOid^.ParentFileId = '' then break;
714
    if curOid^.ParentFileId = '' then break;
722
    if curOid^.ParentFileId = curOid^.FileId then break;
715
    if curOid^.ParentFileId = curOid^.FileId then break;
723
    if ListCount(curOid^.AsnIds) > 0 then
716
    if ListCount(curOid^.AsnIds) > 0 then
724
      res := ListGetElement(curOid^.AsnIds, 0) + '('+OidLastArc(curOid)+') ' + res
717
      res := ListGetElement(curOid^.AsnIds, 0) + '('+OidLastArc(curOid)+') ' + res
725
    else
718
    else
726
      res := OidLastArc(curOid) + ' ' + res;
719
      res := OidLastArc(curOid) + ' ' + res;
727
    prevOid := curOid;
720
    prevOid := curOid;
728
  end;
721
  end;
729
  FreeOidDef(curOid);
722
  FreeOidDef(curOid);
730
  if ListCount(oid^.AsnIds) > 0 then
723
  if ListCount(oid^.AsnIds) > 0 then
731
    res := res + ListGetElement(oid^.AsnIds, 0) + '('+OidLastArc(oid)+')'
724
    res := res + ListGetElement(oid^.AsnIds, 0) + '('+OidLastArc(oid)+')'
732
  else
725
  else
733
    res := res + OidLastArc(oid);
726
    res := res + OidLastArc(oid);
734
  if res = '' then
727
  if res = '' then
735
    AsnNotation := ''
728
    AsnNotation := ''
736
  else
729
  else
737
    AsnNotation := '{ ' + res + ' }';
730
    AsnNotation := '{ ' + res + ' }';
738
end;
731
end;
739
 
732
 
740
function IriNotation(oid: POid): string;
733
function IriNotation(oid: POid): string;
741
var
734
var
742
  prevOid, curOid: POid;
735
  prevOid, curOid: POid;
743
  res: string;
736
  res: string;
744
begin
737
begin
745
  CreateOidDef(curOid);
738
  CreateOidDef(curOid);
746
  prevOid := oid;
739
  prevOid := oid;
747
  res := '';
740
  res := '';
748
 
741
 
749
  while true do
742
  while true do
750
  begin
743
  begin
751
    (* Note: BackRef is not checked yet! Infinite loop is possible! (TODO) *)
744
    (* Note: BackRef is not checked yet! Infinite loop is possible! (TODO) *)
752
    ReadOidFile(prevOid^.ParentFileId + '.OID', curOid);
745
    ReadOidFile(prevOid^.ParentFileId + '.OID', curOid);
753
    if curOid^.ParentFileId = '' then break;
746
    if curOid^.ParentFileId = '' then break;
754
    if curOid^.ParentFileId = curOid^.FileId then break;
747
    if curOid^.ParentFileId = curOid^.FileId then break;
755
    if ListCount(curOid^.UnicodeLabels) > 0 then
748
    if ListCount(curOid^.UnicodeLabels) > 0 then
756
      res := ListGetElement(curOid^.UnicodeLabels, 0) + '/' + res
749
      res := ListGetElement(curOid^.UnicodeLabels, 0) + '/' + res
757
    else
750
    else
758
      res := OidLastArc(curOid) + '/' + res;
751
      res := OidLastArc(curOid) + '/' + res;
759
    prevOid := curOid;
752
    prevOid := curOid;
760
  end;
753
  end;
761
  FreeOidDef(curOid);
754
  FreeOidDef(curOid);
762
  if ListCount(oid^.UnicodeLabels) > 0 then
755
  if ListCount(oid^.UnicodeLabels) > 0 then
763
    res := res + ListGetElement(oid^.UnicodeLabels, 0)
756
    res := res + ListGetElement(oid^.UnicodeLabels, 0)
764
  else
757
  else
765
    res := res + OidLastArc(oid);
758
    res := res + OidLastArc(oid);
766
  IriNotation := '/' + res;
759
  IriNotation := '/' + res;
767
end;
760
end;
768
 
761
 
769
function WeidNotation(oid: POid): string;
762
function WeidNotation(oid: POid): string;
770
begin
763
begin
771
  WeidNotation := OidToWeid(oid^.DotNotation);
764
  WeidNotation := OidToWeid(oid^.DotNotation);
772
end;
765
end;
773
 
766
 
774
procedure DisplayOIDFile(filename, from: string);
767
procedure DisplayOIDFile(filename, from: string);
775
var
768
var
776
  isRoot: boolean;
769
  isRoot: boolean;
777
  oid, tmpOID: POID;
770
  oid, tmpOID: POID;
778
  i: integer;
771
  i: integer;
779
  sTmp, subfile: string;
772
  sTmp, subfile: string;
780
  subsel, subfiles: PStringList;
773
  subsel, subfiles: PStringList;
781
  subselres: integer;
774
  subselres: integer;
782
  exitRequest: boolean;
775
  exitRequest: boolean;
783
  menuIdExit, menuIdAsnEdit, menuIdIriEdit, menuIdDescEdit, menuIdAdd, menuIdDelete: integer;
776
  menuIdExit, menuIdAsnEdit, menuIdIriEdit, menuIdDescEdit, menuIdAdd, menuIdDelete: integer;
784
  menuX, menuY: integer;
777
  menuX, menuY: integer;
785
begin
778
begin
786
  exitRequest := false;
779
  exitRequest := false;
787
  repeat
780
  repeat
788
    CreateOidDef(oid);
781
    CreateOidDef(oid);
789
 
782
 
790
    if not _ReadOidFile(filename, oid, true) then
783
    if not _ReadOidFile(filename, oid, true) then
791
    begin
784
    begin
792
      FreeOidDef(oid);
785
      FreeOidDef(oid);
793
      exit;
786
      exit;
794
    end;
787
    end;
795
 
788
 
796
    (* Print OID information *)
789
    (* Print OID information *)
797
 
790
 
798
    ClrScr;
791
    ClrScr;
799
    _DrawOidTitleBar(filename, oid);
792
    _DrawOidTitleBar(filename, oid);
800
    DrawStatusBar('');
793
    DrawStatusBar('');
801
    GotoXY(1,2);
794
    GotoXY(1,2);
802
 
795
 
803
    Write('Dot notation:   ');
796
    Write('Dot notation:   ');
804
    WriteLnKeepX(DotNotation(oid));
797
    WriteLnKeepX(DotNotation(oid));
805
    Write('ASN.1 notation: ');
798
    Write('ASN.1 notation: ');
806
    WriteLnKeepX(AsnNotation(oid));
799
    WriteLnKeepX(AsnNotation(oid));
807
    Write('OID-IRI:        ');
800
    Write('OID-IRI:        ');
808
    WriteLnKeepX(IriNotation(oid));
801
    WriteLnKeepX(IriNotation(oid));
809
    Write('WEID notation:  ');
802
    Write('WEID notation:  ');
810
    WriteLnKeepX(WeidNotation(oid));
803
    WriteLnKeepX(WeidNotation(oid));
811
    WriteLn('');
804
    WriteLn('');
812
 
805
 
813
    if Trim(oid^.Description) <> '' then
806
    if Trim(oid^.Description) <> '' then
814
    begin
807
    begin
815
      (* WriteLn('Description:'); *)
808
      (* WriteLn('Description:'); *)
816
      (* TODO: We should avoid that this is more than 10 lines *)
809
      (* TODO: We should avoid that this is more than 10 lines *)
817
      WriteLn(oid^.Description);
810
      WriteLn(oid^.Description);
818
      WriteLn('');
811
      WriteLn('');
819
    end
812
    end
820
    else
813
    else
821
    begin
814
    begin
822
      WriteLn('(No description has been added to this OID.)');
815
      WriteLn('(No description has been added to this OID.)');
823
      WriteLn('');
816
      WriteLn('');
824
    end;
817
    end;
825
 
818
 
826
    (* Now prepare the menu entries *)
819
    (* Now prepare the menu entries *)
827
 
820
 
828
    CreateList(subsel);   (* Contains the human-readable OID name *)
821
    CreateList(subsel);   (* Contains the human-readable OID name *)
829
    CreateList(subfiles); (* Contains the file name               *)
822
    CreateList(subfiles); (* Contains the file name               *)
830
 
823
 
831
    if oid^.ParentFileId = '' then
824
    if oid^.ParentFileId = '' then
832
    begin
825
    begin
833
      isRoot := true;
826
      isRoot := true;
834
    end
827
    end
835
    else
828
    else
836
    begin
829
    begin
837
      isRoot := oid^.ParentDotNotation = oid^.DotNotation;
830
      isRoot := oid^.ParentDotNotation = oid^.DotNotation;
838
    end;
831
    end;
839
 
832
 
840
    if (oid^.ParentFileId <> '') and not isRoot then
833
    if (oid^.ParentFileId <> '') and not isRoot then
841
    begin
834
    begin
842
      subfile := oid^.ParentFileId + OID_EXTENSION;
835
      subfile := oid^.ParentFileId + OID_EXTENSION;
843
      if FileExists(subfile) then
836
      if FileExists(subfile) then
844
      begin
837
      begin
845
        CreateOidDef(tmpOID);
838
        CreateOidDef(tmpOID);
846
        if not _ReadOidFile(subfile, tmpOID, true) then
839
        if not _ReadOidFile(subfile, tmpOID, true) then
847
        begin
840
        begin
848
          ListAppend(subsel, 'Go to parent ' + oid^.ParentDotNotation + ' (READ ERROR)');
841
          ListAppend(subsel, 'Go to parent ' + oid^.ParentDotNotation + ' (READ ERROR)');
849
          ListAppend(subfiles, 'ERROR: '+subfile+' Read error or file invalid');
842
          ListAppend(subfiles, 'ERROR: '+subfile+' Read error or file invalid');
850
        end
843
        end
851
        else
844
        else
852
        begin
845
        begin
853
          ListAppend(subsel, 'Go to parent ' + oid^.ParentDotNotation + _ShowASNIds(tmpOID));
846
          ListAppend(subsel, 'Go to parent ' + oid^.ParentDotNotation + _ShowASNIds(tmpOID));
854
          ListAppend(subfiles, subfile);
847
          ListAppend(subfiles, subfile);
855
        end;
848
        end;
856
        FreeOidDef(tmpOID);
849
        FreeOidDef(tmpOID);
857
      end
850
      end
858
      else
851
      else
859
      begin
852
      begin
860
        ListAppend(subsel, 'Go to parent ' + oid^.ParentDotNotation + ' (FILE NOT FOUND)');
853
        ListAppend(subsel, 'Go to parent ' + oid^.ParentDotNotation + ' (FILE NOT FOUND)');
861
        ListAppend(subfiles, 'ERROR: File '+subfile+' was not found');
854
        ListAppend(subfiles, 'ERROR: File '+subfile+' was not found');
862
      end;
855
      end;
863
    end;
856
    end;
864
 
857
 
865
    if isRoot then
858
    if isRoot then
866
    begin
859
    begin
867
      menuIdExit := ListAppend(subsel, 'Back to '+from);
860
      menuIdExit := ListAppend(subsel, 'Back to '+from);
868
      ListAppend(subfiles, '');
861
      ListAppend(subfiles, '');
869
    end
862
    end
870
    else menuIdExit := -99;
863
    else menuIdExit := -99;
871
 
864
 
872
    for i := 0 to ListCount(oid^.SubIds)-1 do
865
    for i := 0 to ListCount(oid^.SubIds)-1 do
873
    begin
866
    begin
874
      sTmp := ListGetElement(oid^.SubIds, i);
867
      sTmp := ListGetElement(oid^.SubIds, i);
875
      subfile := FileIdPart(sTmp) + OID_EXTENSION;
868
      subfile := FileIdPart(sTmp) + OID_EXTENSION;
876
      if FileExists(subfile) then
869
      if FileExists(subfile) then
877
      begin
870
      begin
878
        CreateOidDef(tmpOID);
871
        CreateOidDef(tmpOID);
879
        if not _ReadOidFile(subfile, tmpOID, true) then
872
        if not _ReadOidFile(subfile, tmpOID, true) then
880
        begin
873
        begin
881
          ListAppend(subsel, 'Go to child  ' + DotNotationPart(sTmp) + ' (READ ERROR)');
874
          ListAppend(subsel, 'Go to child  ' + DotNotationPart(sTmp) + ' (READ ERROR)');
882
          ListAppend(subfiles, 'ERROR: Read error at file '+subfile+', or file is invalid.');
875
          ListAppend(subfiles, 'ERROR: Read error at file '+subfile+', or file is invalid.');
883
        end
876
        end
884
        else if (tmpOID^.ParentFileId <> oid^.FileId) or
877
        else if (tmpOID^.ParentFileId <> oid^.FileId) or
885
                (tmpOID^.ParentDotNotation <> oid^.DotNotation) then
878
                (tmpOID^.ParentDotNotation <> oid^.DotNotation) then
886
        begin
879
        begin
887
          ListAppend(subsel, 'Go to child  ' + DotNotationPart(sTmp) + ' (BAD BACKREF)');
880
          ListAppend(subsel, 'Go to child  ' + DotNotationPart(sTmp) + ' (BAD BACKREF)');
888
          ListAppend(subfiles, 'ERROR: File '+subfile+' has a wrong back-reference.');
881
          ListAppend(subfiles, 'ERROR: File '+subfile+' has a wrong back-reference.');
889
        end
882
        end
890
        else
883
        else
891
        begin
884
        begin
892
          ListAppend(subsel, 'Go to child  ' + DotNotationPart(sTmp) + _ShowASNIds(tmpOID));
885
          ListAppend(subsel, 'Go to child  ' + DotNotationPart(sTmp) + _ShowASNIds(tmpOID));
893
          ListAppend(subfiles, subfile);
886
          ListAppend(subfiles, subfile);
894
        end;
887
        end;
895
        FreeOidDef(tmpOID);
888
        FreeOidDef(tmpOID);
896
      end
889
      end
897
      else
890
      else
898
      begin
891
      begin
899
        ListAppend(subsel, 'Go to child  ' + DotNotationPart(sTmp) + ' (FILE NOT FOUND)');
892
        ListAppend(subsel, 'Go to child  ' + DotNotationPart(sTmp) + ' (FILE NOT FOUND)');
900
        ListAppend(subfiles, 'ERROR: File '+subfile+' was not found');
893
        ListAppend(subfiles, 'ERROR: File '+subfile+' was not found');
901
      end;
894
      end;
902
    end;
895
    end;
903
 
896
 
904
    if oid^.DotNotation <> '' then
897
    if oid^.DotNotation <> '' then
905
    begin
898
    begin
906
      menuIdAsnEdit := ListAppend(subsel, 'View/Edit ASN.1 identifiers');
899
      menuIdAsnEdit := ListAppend(subsel, 'View/Edit ASN.1 identifiers');
907
      ListAppend(subfiles, '');
900
      ListAppend(subfiles, '');
908
    end
901
    end
909
    else menuIdAsnEdit := -99;
902
    else menuIdAsnEdit := -99;
910
 
903
 
911
    if oid^.DotNotation <> '' then
904
    if oid^.DotNotation <> '' then
912
    begin
905
    begin
913
      menuIdIriEdit := ListAppend(subsel, 'View/Edit Unicode Labels (OID-IRI)');
906
      menuIdIriEdit := ListAppend(subsel, 'View/Edit Unicode Labels (OID-IRI)');
914
      ListAppend(subfiles, '');
907
      ListAppend(subfiles, '');
915
    end
908
    end
916
    else menuIdIriEdit := -99;
909
    else menuIdIriEdit := -99;
917
 
910
 
918
    menuIdDescEdit := ListAppend(subsel, 'Edit description');
911
    menuIdDescEdit := ListAppend(subsel, 'Edit description');
919
    ListAppend(subfiles, '');
912
    ListAppend(subfiles, '');
920
 
913
 
921
    menuIdAdd := ListAppend(subsel, 'Add child');
914
    menuIdAdd := ListAppend(subsel, 'Add child');
922
    ListAppend(subfiles, '');
915
    ListAppend(subfiles, '');
923
 
916
 
924
    if not isRoot then
917
    if not isRoot then
925
    begin
918
    begin
926
      menuIdDelete := ListAppend(subsel, 'Delete OID');
919
      menuIdDelete := ListAppend(subsel, 'Delete OID');
927
      ListAppend(subfiles, '');
920
      ListAppend(subfiles, '');
928
    end
921
    end
929
    else menuIdDelete := -99;
922
    else menuIdDelete := -99;
930
 
923
 
931
    (* Show menu *)
924
    (* Show menu *)
932
 
925
 
933
    menuX := WhereX + 1;
926
    menuX := WhereX + 1;
934
    menuY := ScreenHeight - ACTIONMENU_SIZE - 1;
927
    menuY := ScreenHeight - ACTIONMENU_SIZE - 1;
935
    subselres := DrawSelectionList(menuX, menuY,
928
    subselres := DrawSelectionList(menuX, menuY,
936
                                   ScreenWidth-2,
929
                                   ScreenWidth-2,
937
                                   ACTIONMENU_SIZE,
930
                                   ACTIONMENU_SIZE,
938
                                   subsel,
931
                                   subsel,
939
                                   true,
932
                                   true,
940
                                   'SELECT ACTION',
933
                                   'SELECT ACTION',
941
                                   1);
934
                                   1);
942
 
935
 
943
    (* Process user selection *)
936
    (* Process user selection *)
944
 
937
 
945
    if subselres = -1 then
938
    if subselres = -1 then
946
    begin
939
    begin
947
      exitRequest := true;
940
      exitRequest := true;
948
    end
941
    end
949
    else if subselres = menuIdAsnEdit then
942
    else if subselres = menuIdAsnEdit then
950
    begin
943
    begin
951
      if AsnEditor(oid) then
944
      if AsnEditor(oid) then
952
        _WriteOidFile(filename, oid, true);
945
        _WriteOidFile(filename, oid, true);
953
    end
946
    end
954
    else if subselres = menuIdIriEdit then
947
    else if subselres = menuIdIriEdit then
955
    begin
948
    begin
956
      if IriEditor(oid) then
949
      if IriEditor(oid) then
957
        _WriteOidFile(filename, oid, true);
950
        _WriteOidFile(filename, oid, true);
958
    end
951
    end
959
    else if subselres = menuIdDescEdit then
952
    else if subselres = menuIdDescEdit then
960
    begin
953
    begin
961
      if DescEditor(oid) then
954
      if DescEditor(oid) then
962
        _WriteOidFile(filename, oid, true);
955
        _WriteOidFile(filename, oid, true);
963
    end
956
    end
964
    else if subselres = menuIdAdd then
957
    else if subselres = menuIdAdd then
965
    begin
958
    begin
966
      if NewOidEditor(oid) then
959
      if NewOidEditor(oid) then
967
        _WriteOidFile(filename, oid, true);
960
        _WriteOidFile(filename, oid, true);
968
    end
961
    end
969
    else if subselres = menuIdDelete then
962
    else if subselres = menuIdDelete then
970
    begin
963
    begin
971
      if _DeleteConfirmation then
964
      if _DeleteConfirmation then
972
      begin
965
      begin
973
        sTmp := oid^.ParentFileId + OID_EXTENSION;
966
        sTmp := oid^.ParentFileId + OID_EXTENSION;
974
        DeleteOidRecursive(oid);
967
        DeleteOidRecursive(oid);
975
        if FileExists(sTmp) then
968
        if FileExists(sTmp) then
976
        begin
969
        begin
977
          filename := sTmp;
970
          filename := sTmp;
978
        end
971
        end
979
        else
972
        else
980
        begin
973
        begin
981
          ShowMessage('Parent file ' + sTmp + ' was not found', 'ERROR', true);
974
          ShowMessage('Parent file ' + sTmp + ' was not found', 'ERROR', true);
982
          _Pause;
975
          _Pause;
983
          exitRequest := true;
976
          exitRequest := true;
984
        end;
977
        end;
985
      end;
978
      end;
986
    end
979
    end
987
    else if subselres = menuIdExit then
980
    else if subselres = menuIdExit then
988
    begin
981
    begin
989
      exitRequest := true;
982
      exitRequest := true;
990
    end
983
    end
991
    else
984
    else
992
    begin
985
    begin
993
      (* Normal OID *)
986
      (* Normal OID *)
994
      (* Above we already checked if the files are valild and existing *)
987
      (* Above we already checked if the files are valild and existing *)
995
      sTmp := ListGetElement(subfiles, subselres);
988
      sTmp := ListGetElement(subfiles, subselres);
996
      if Copy(sTmp, 1, Length('ERROR: ')) = 'ERROR: ' then
989
      if Copy(sTmp, 1, Length('ERROR: ')) = 'ERROR: ' then
997
      begin
990
      begin
998
        Delete(sTmp, 1, Length('ERROR: '));
991
        Delete(sTmp, 1, Length('ERROR: '));
999
        ShowMessage(sTmp, 'ERROR', true);
992
        ShowMessage(sTmp, 'ERROR', true);
1000
        _Pause;
993
        _Pause;
1001
      end
994
      end
1002
      else
995
      else
1003
      begin
996
      begin
1004
        filename := sTmp;
997
        filename := sTmp;
1005
      end;
998
      end;
1006
    end;
999
    end;
1007
    FreeList(subsel);
1000
    FreeList(subsel);
1008
    FreeList(subfiles);
1001
    FreeList(subfiles);
1009
 
1002
 
1010
    FreeOidDef(oid);
1003
    FreeOidDef(oid);
1011
  until exitRequest;
1004
  until exitRequest;
1012
end;
1005
end;
1013
 
1006
 
1014
function CreateRootOIDFile(filename: string; ShowErrorMessage: boolean): boolean;
1007
function CreateRootOIDFile(filename: string; ShowErrorMessage: boolean): boolean;
1015
var
1008
var
1016
  oid: POID;
1009
  oid: POID;
1017
begin
1010
begin
1018
  CreateOidDef(oid);
1011
  CreateOidDef(oid);
1019
  oid^.Description  := 'This is the root of the OID tree.' +#13#10 +
1012
  oid^.Description  := 'This is the root of the OID tree.' +#13#10 +
1020
                       #13#10 +
1013
                       #13#10 +
1021
                       'Valid subsequent arcs are per definition:' + #13#10 +
1014
                       'Valid subsequent arcs are per definition:' + #13#10 +
1022
                       '- 0 (itu-t)' + #13#10 +
1015
                       '- 0 (itu-t)' + #13#10 +
1023
                       '- 1 (iso)' + #13#10 +
1016
                       '- 1 (iso)' + #13#10 +
1024
                       '- 2 (joint-iso-itu-t)';
1017
                       '- 2 (joint-iso-itu-t)';
1025
  oid^.FileId       := ZeroPad(0, 8);
1018
  oid^.FileId       := ZeroPad(0, 8);
1026
  oid^.DotNotation  := '';
1019
  oid^.DotNotation  := '';
1027
  oid^.ParentFileId := ZeroPad(0, 8);
1020
  oid^.ParentFileId := ZeroPad(0, 8);
1028
  oid^.ParentDotNotation := '';
1021
  oid^.ParentDotNotation := '';
1029
  CreateRootOIDFile := _WriteOidFile(filename, oid, ShowErrorMessage);
1022
  CreateRootOIDFile := _WriteOidFile(filename, oid, ShowErrorMessage);
1030
  FreeOidDef(oid);
1023
  FreeOidDef(oid);
1031
end;
1024
end;
1032
 
1025
 
1033
function _GetRootFile(ShowErrorMessage: boolean): string;
1026
function _GetRootFile(ShowErrorMessage: boolean): string;
1034
var
1027
var
1035
  rootFile: string;
1028
  rootFile: string;
1036
begin
1029
begin
1037
  rootFile := ZeroPad(0, 8) + OID_EXTENSION;
1030
  rootFile := ZeroPad(0, 8) + OID_EXTENSION;
1038
  _GetRootFile := rootFile;
1031
  _GetRootFile := rootFile;
1039
  if not FileExists(rootFile) then
1032
  if not FileExists(rootFile) then
1040
  begin
1033
  begin
1041
    if not CreateRootOIDFile(rootFile, ShowErrorMessage) then
1034
    if not CreateRootOIDFile(rootFile, ShowErrorMessage) then
1042
    begin
1035
    begin
1043
      _GetRootFile := '';
1036
      _GetRootFile := '';
1044
    end;
1037
    end;
1045
  end;
1038
  end;
1046
end;
1039
end;
1047
 
1040
 
1048
procedure OP_ManageOIDs;
1041
procedure OP_ManageOIDs;
1049
var
1042
var
1050
  rootfile: string;
1043
  rootfile: string;
1051
begin
1044
begin
1052
  ClrScr;
1045
  ClrScr;
1053
  DrawTitleBar('Manage Object Identifiers', TITLEBAR_LEFT_TEXT, '');
1046
  DrawTitleBar('Manage Object Identifiers', TITLEBAR_LEFT_TEXT, '');
1054
  DrawStatusBar('Loading data... please wait...');
1047
  DrawStatusBar('Loading data... please wait...');
1055
 
1048
 
1056
  (* This will try creating a new root file if it does not exist *)
1049
  (* This will try creating a new root file if it does not exist *)
1057
  rootfile := _GetRootFile(true);
1050
  rootfile := _GetRootFile(true);
1058
  if rootfile = '' then Exit;
1051
  if rootfile = '' then Exit;
1059
 
1052
 
1060
  DisplayOIDFile(rootfile, 'main menu');
1053
  DisplayOIDFile(rootfile, 'main menu');
1061
end;
1054
end;
1062
 
1055
 
1063
procedure OP_ReturnToMSDOS;
1056
procedure OP_ReturnToMSDOS;
1064
begin
1057
begin
1065
  (* Note: These two lines don't seem to be necessary if you use DoneVideo *)
1058
  (* Note: These two lines don't seem to be necessary if you use DoneVideo *)
1066
  ResetDefaultDosColors;
1059
  ResetDefaultDosColors;
1067
  ClrScr; (*Important, so that the DOS command prompt is also LightGray *)
1060
  ClrScr; (*Important, so that the DOS command prompt is also LightGray *)
1068
 
1061
 
1069
  WriteLn('Thank you for using OIDplus for DOS.');
1062
  WriteLn('Thank you for using OIDplus for DOS.');
1070
  WriteLn('');
1063
  WriteLn('');
1071
end;
1064
end;
1072
 
1065
 
1073
function _GetTreeViewLine(oid: POID; indent: integer): string;
1066
function _GetTreeViewLine(oid: POID; indent: integer): string;
1074
var
1067
var
1075
  i: integer;
1068
  i: integer;
1076
  sTmp, sTmp2: string;
1069
  sTmp, sTmp2: string;
1077
begin
1070
begin
1078
  (* Build line *)
1071
  (* Build line *)
1079
  sTmp := RepeatStr(' ', indent*TREEVIEW_INDENT);
1072
  sTmp := RepeatStr(' ', indent*TREEVIEW_INDENT);
1080
  if oid^.DotNotation = '' then
1073
  if oid^.DotNotation = '' then
1081
    sTmp := sTmp + 'Object Identifiers'
1074
    sTmp := sTmp + 'Object Identifiers'
1082
  else
1075
  else
1083
    sTmp := sTmp + oid^.DotNotation;
1076
    sTmp := sTmp + oid^.DotNotation;
1084
  sTmp := sTmp + _ShowAsnIds(oid);
1077
  sTmp := sTmp + _ShowAsnIds(oid);
1085
  if TREEVIEW_INCLUDE_DESC then
1078
  if TREEVIEW_INCLUDE_DESC then
1086
  begin
1079
  begin
1087
    if Trim(oid^.Description) <> '' then
1080
    if Trim(oid^.Description) <> '' then
1088
    begin
1081
    begin
1089
      sTmp := sTmp + ': ' + oid^.Description;
1082
      sTmp := sTmp + ': ' + oid^.Description;
1090
    end;
1083
    end;
1091
  end;
1084
  end;
1092
 
1085
 
1093
  sTmp := StringReplace(sTmp, #13#10, ' ');
1086
  sTmp := StringReplace(sTmp, #13#10, ' ');
1094
  repeat
1087
  repeat
1095
    sTmp2 := sTmp;
1088
    sTmp2 := sTmp;
1096
    sTmp := StringReplace(sTmp, '  ', ' ');
1089
    sTmp := StringReplace(sTmp, '  ', ' ');
1097
  until sTmp = sTmp2;
1090
  until sTmp = sTmp2;
1098
 
1091
 
1099
  sTmp := TrimLineToWidth(sTmp, TREEVIEW_WIDTH);
1092
  sTmp := TrimLineToWidth(sTmp, TREEVIEW_WIDTH);
1100
  _GetTreeViewLine := sTmp;
1093
  _GetTreeViewLine := sTmp;
1101
end;
1094
end;
1102
 
1095
 
1103
procedure _RecTreeExport(oid: POID; visList, targetList: PStringList; indent: integer);
1096
procedure _RecTreeExport(oid: POID; visList, targetList: PStringList; indent: integer);
1104
var
1097
var
1105
  i: integer;
1098
  i: integer;
1106
  sTmp: string;
1099
  sTmp: string;
1107
  suboid: POID;
1100
  suboid: POID;
1108
  childFilename: string;
1101
  childFilename: string;
1109
begin
1102
begin
1110
  sTmp := _GetTreeViewLine(oid, indent);
1103
  sTmp := _GetTreeViewLine(oid, indent);
1111
  sTmp := TrimLineToWidth(sTmp, TREEVIEW_WIDTH);
1104
  sTmp := TrimLineToWidth(sTmp, TREEVIEW_WIDTH);
1112
  ListAppend(visList, sTmp);
1105
  ListAppend(visList, sTmp);
1113
  ListAppend(targetList, oid^.FileID);
1106
  ListAppend(targetList, oid^.FileID);
1114
 
1107
 
1115
  (* Recursively call children *)
1108
  (* Recursively call children *)
1116
  for i := 0 to ListCount(oid^.SubIds)-1 do
1109
  for i := 0 to ListCount(oid^.SubIds)-1 do
1117
  begin
1110
  begin
1118
    sTmp := ListGetElement(oid^.SubIds, i);
1111
    sTmp := ListGetElement(oid^.SubIds, i);
1119
    CreateOidDef(suboid);
1112
    CreateOidDef(suboid);
1120
    childFilename := FileIdPart(sTmp) + OID_EXTENSION;
1113
    childFilename := FileIdPart(sTmp) + OID_EXTENSION;
1121
    if not FileExists(childFilename) then
1114
    if not FileExists(childFilename) then
1122
    begin
1115
    begin
1123
      sTmp := 'ERROR: MISSING ' + childFilename + ' (SHALL CONTAIN ' + DotNotationPart(sTmp) + ')!';
1116
      sTmp := 'ERROR: MISSING ' + childFilename + ' (SHALL CONTAIN ' + DotNotationPart(sTmp) + ')!';
1124
      sTmp := TrimLineToWidth(sTmp, TREEVIEW_WIDTH);
1117
      sTmp := TrimLineToWidth(sTmp, TREEVIEW_WIDTH);
1125
      ListAppend(visList, sTmp);
1118
      ListAppend(visList, sTmp);
1126
      ListAppend(targetList, 'ERROR');
1119
      ListAppend(targetList, 'ERROR');
1127
    end
1120
    end
1128
    else if not _ReadOidFile(childFilename, suboid, false) then
1121
    else if not _ReadOidFile(childFilename, suboid, false) then
1129
    begin
1122
    begin
1130
      sTmp := 'ERROR: READ ERROR AT ' + childFilename + ' (SHALL CONTAIN ' + DotNotationPart(sTmp) + ')!';
1123
      sTmp := 'ERROR: READ ERROR AT ' + childFilename + ' (SHALL CONTAIN ' + DotNotationPart(sTmp) + ')!';
1131
      sTmp := TrimLineToWidth(sTmp, TREEVIEW_WIDTH);
1124
      sTmp := TrimLineToWidth(sTmp, TREEVIEW_WIDTH);
1132
      ListAppend(visList, sTmp);
1125
      ListAppend(visList, sTmp);
1133
      ListAppend(targetList, 'ERROR');
1126
      ListAppend(targetList, 'ERROR');
1134
    end
1127
    end
1135
    else if (suboid^.ParentFileId <> oid^.FileId) or
1128
    else if (suboid^.ParentFileId <> oid^.FileId) or
1136
            (suboid^.ParentDotNotation <> oid^.DotNotation) then
1129
            (suboid^.ParentDotNotation <> oid^.DotNotation) then
1137
    begin
1130
    begin
1138
      (* This can happen if a file is missing, and then another OID gets this filename since the number seems to be free *)
1131
      (* This can happen if a file is missing, and then another OID gets this filename since the number seems to be free *)
1139
      sTmp := 'ERROR: BAD BACKREF AT ' + childFilename + ' (SHALL CONTAIN ' + DotNotationPart(sTmp) + ')!';
1132
      sTmp := 'ERROR: BAD BACKREF AT ' + childFilename + ' (SHALL CONTAIN ' + DotNotationPart(sTmp) + ')!';
1140
      sTmp := TrimLineToWidth(sTmp, TREEVIEW_WIDTH);
1133
      sTmp := TrimLineToWidth(sTmp, TREEVIEW_WIDTH);
1141
      ListAppend(visList, sTmp);
1134
      ListAppend(visList, sTmp);
1142
      ListAppend(targetList, 'ERROR');
1135
      ListAppend(targetList, 'ERROR');
1143
    end
1136
    end
1144
    else
1137
    else
1145
    begin
1138
    begin
1146
      _RecTreeExport(suboid, visList, targetList, indent+1);
1139
      _RecTreeExport(suboid, visList, targetList, indent+1);
1147
      FreeOidDef(suboid);
1140
      FreeOidDef(suboid);
1148
    end
1141
    end
1149
  end;
1142
  end;
1150
end;
1143
end;
1151
 
1144
 
1152
procedure TreeViewPreview(visList, targetList: PStringList);
1145
procedure TreeViewPreview(visList, targetList: PStringList);
1153
var
1146
var
1154
  res: integer;
1147
  res: integer;
1155
  sTmp: string;
1148
  sTmp: string;
1156
begin
1149
begin
1157
  ClrScr;
1150
  ClrScr;
1158
  DrawTitleBar('TreeView Export', TITLEBAR_LEFT_TEXT, TREEVIEW_FILENAME);
1151
  DrawTitleBar('TreeView Export', TITLEBAR_LEFT_TEXT, TREEVIEW_FILENAME);
1159
  DrawStatusBar('Press ESC to return to the main menu. Enter to jump to OID.');
1152
  DrawStatusBar('Press ESC to return to the main menu. Enter to jump to OID.');
1160
 
1153
 
1161
  while true do
1154
  while true do
1162
  begin
1155
  begin
1163
    res := DrawSelectionList(2, 3, ScreenWidth-2, ScreenHeight-4,
1156
    res := DrawSelectionList(2, 3, ScreenWidth-2, ScreenHeight-4,
1164
                             visList, true, 'PREVIEW OF '+TREEVIEW_FILENAME, 2);
1157
                             visList, true, 'PREVIEW OF '+TREEVIEW_FILENAME, 2);
1165
    if res > -1 then
1158
    if res > -1 then
1166
    begin
1159
    begin
1167
      (* Jump to selected OID or show error *)
1160
      (* Jump to selected OID or show error *)
1168
      sTmp := ListGetElement(targetList, res);
1161
      sTmp := ListGetElement(targetList, res);
1169
      if sTmp = 'ERROR' then
1162
      if sTmp = 'ERROR' then
1170
      begin
1163
      begin
1171
        ShowMessage(ListGetElement(visList, res), 'ERROR', true);
1164
        ShowMessage(ListGetElement(visList, res), 'ERROR', true);
1172
        _Pause;
1165
        _Pause;
1173
      end
1166
      end
1174
      else
1167
      else
1175
      begin
1168
      begin
1176
        DisplayOidFile(sTmp + '.OID', 'TreeView Export');
1169
        DisplayOidFile(sTmp + '.OID', 'TreeView Export');
1177
      end;
1170
      end;
1178
    end
1171
    end
1179
    else
1172
    else
1180
    begin
1173
    begin
1181
      break;
1174
      break;
1182
    end;
1175
    end;
1183
  end;
1176
  end;
1184
 
1177
 
1185
  DrawStatusBar('');
1178
  DrawStatusBar('');
1186
end;
1179
end;
1187
 
1180
 
1188
procedure OP_TreeView;
1181
procedure OP_TreeView;
1189
var
1182
var
1190
  F: Text;
1183
  F: Text;
1191
  rootoid: POID;
1184
  rootoid: POID;
1192
  rootfile: string;
1185
  rootfile: string;
1193
  res: boolean;
1186
  res: boolean;
1194
  visList, targetList: PStringList;
1187
  visList, targetList: PStringList;
1195
begin
1188
begin
1196
  ClrScr;
1189
  ClrScr;
1197
  DrawTitleBar('TreeView Export', TITLEBAR_LEFT_TEXT, '');
1190
  DrawTitleBar('TreeView Export', TITLEBAR_LEFT_TEXT, '');
1198
  DrawStatusBar('Exporting data... please wait...');
1191
  DrawStatusBar('Exporting data... please wait...');
1199
 
1192
 
1200
  (* This will try creating a new root file if it does not exist *)
1193
  (* This will try creating a new root file if it does not exist *)
1201
  rootfile := _GetRootFile(true);
1194
  rootfile := _GetRootFile(true);
1202
  if rootfile = '' then
1195
  if rootfile = '' then
1203
  begin
1196
  begin
1204
    DrawStatusBar('');
1197
    DrawStatusBar('');
1205
    Exit;
1198
    Exit;
1206
  end;
1199
  end;
1207
 
1200
 
1208
  CreateList(visList);
1201
  CreateList(visList);
1209
  CreateList(targetList);
1202
  CreateList(targetList);
1210
 
1203
 
1211
  (* First check if the disk is read-only *)
1204
  (* First check if the disk is read-only *)
1212
  Assign(F, TREEVIEW_FILENAME);
1205
  Assign(F, TREEVIEW_FILENAME);
1213
  {$I-}
1206
  {$I-}
1214
  Rewrite(F);
1207
  Rewrite(F);
1215
  {$I+}
1208
  {$I+}
1216
  if IoResult <> 0 then
1209
  if IoResult <> 0 then
1217
  begin
1210
  begin
1218
    (* Can happen if disk is read-only (Runtime Error 150) *)
1211
    (* Can happen if disk is read-only (Runtime Error 150) *)
1219
    ShowMessage('Cannot open '+TREEVIEW_FILENAME+' for writing.', 'ERROR', true);
1212
    ShowMessage('Cannot open '+TREEVIEW_FILENAME+' for writing.', 'ERROR', true);
1220
    _Pause;
1213
    _Pause;
1221
    DrawStatusBar('');
1214
    DrawStatusBar('');
1222
    Exit;
1215
    Exit;
1223
  end;
1216
  end;
1224
  Close(F);
1217
  Close(F);
1225
 
1218
 
1226
  (* Now do the export *)
1219
  (* Now do the export *)
1227
  res := false;
1220
  res := false;
1228
  CreateOidDef(rootoid);
1221
  CreateOidDef(rootoid);
1229
  if _ReadOidFile(rootfile, rootoid, true) then
1222
  if _ReadOidFile(rootfile, rootoid, true) then
1230
  begin
1223
  begin
1231
    _RecTreeExport(rootoid, visList, targetList, 0);
1224
    _RecTreeExport(rootoid, visList, targetList, 0);
1232
    res := true;
1225
    res := true;
1233
  end;
1226
  end;
1234
  FreeOidDef(rootoid);
1227
  FreeOidDef(rootoid);
1235
 
1228
 
1236
  (* Save the list (visual part only) *)
1229
  (* Save the list (visual part only) *)
1237
  ListSaveToFile(visList, TREEVIEW_FILENAME);
1230
  ListSaveToFile(visList, TREEVIEW_FILENAME);
1238
 
1231
 
1239
  DrawStatusBar('');
1232
  DrawStatusBar('');
1240
  if res then
1233
  if res then
1241
  begin
1234
  begin
1242
    ShowMessage('TreeView successfully exported as '+TREEVIEW_FILENAME, 'TREEVIEW EXPORT', true);
1235
    ShowMessage('TreeView successfully exported as '+TREEVIEW_FILENAME, 'TREEVIEW EXPORT', true);
1243
    _Pause;
1236
    _Pause;
1244
  end;
1237
  end;
1245
 
1238
 
1246
  TreeViewPreview(visList, targetList);
1239
  TreeViewPreview(visList, targetList);
1247
 
1240
 
1248
  FreeList(visList);
1241
  FreeList(visList);
1249
  FreeList(targetList);
1242
  FreeList(targetList);
1250
end;
1243
end;
1251
 
1244
 
1252
procedure OP_MainMenu;
1245
procedure OP_MainMenu;
1253
var
1246
var
1254
  menu: PStringList;
1247
  menu: PStringList;
1255
  menuRes, menuLeft, menuTop: integer;
1248
  menuRes, menuLeft, menuTop: integer;
1256
  menuIdOID, menuIdTree, menuIdExit: integer;
1249
  menuIdOID, menuIdTree, menuIdExit: integer;
1257
begin
1250
begin
1258
  repeat
1251
  repeat
1259
    ClrScr;
1252
    ClrScr;
1260
 
1253
 
1261
    DrawTitleBar('Welcome to OIDplus for DOS', '', '');
1254
    DrawTitleBar('Welcome to OIDplus for DOS', '', '');
1262
    DrawStatusBar('(C)2020-2022 ViaThinkSoft. Licensed under the terms of the Apache 2.0 license.');
1255
    DrawStatusBar('(C)2020-2022 ViaThinkSoft. Licensed under the terms of the Apache 2.0 license.');
1263
    GoToXY(ScreenWidth-Length(VERSIONINFO), ScreenHeight-1);
1256
    GoToXY(ScreenWidth-Length(VERSIONINFO), ScreenHeight-1);
1264
    Write(VERSIONINFO);
1257
    Write(VERSIONINFO);
1265
 
1258
 
1266
    CreateList(menu);
1259
    CreateList(menu);
1267
 
1260
 
1268
    menuIdOID  := ListAppend(menu, 'Manage OIDs');
1261
    menuIdOID  := ListAppend(menu, 'Manage OIDs');
1269
    menuIdTree := ListAppend(menu, 'Export TreeView');
1262
    menuIdTree := ListAppend(menu, 'Export TreeView');
1270
    menuIdExit := ListAppend(menu, 'Return to DOS');
1263
    menuIdExit := ListAppend(menu, 'Return to DOS');
1271
 
1264
 
1272
    menuLeft := round(ScreenWidth/2 -MAINMENU_WIDTH/2);
1265
    menuLeft := round(ScreenWidth/2 -MAINMENU_WIDTH/2);
1273
    menuTop  := round(ScreenHeight/2-MAINMENU_HEIGHT/2);
1266
    menuTop  := round(ScreenHeight/2-MAINMENU_HEIGHT/2);
1274
    menuRes  := DrawSelectionList(menuLeft, menuTop,
1267
    menuRes  := DrawSelectionList(menuLeft, menuTop,
1275
                                  MAINMENU_WIDTH, MAINMENU_HEIGHT,
1268
                                  MAINMENU_WIDTH, MAINMENU_HEIGHT,
1276
                                  menu, true, 'MAIN MENU', 2);
1269
                                  menu, true, 'MAIN MENU', 2);
1277
    FreeList(menu);
1270
    FreeList(menu);
1278
 
1271
 
1279
    if menuRes = menuIdOID then
1272
    if menuRes = menuIdOID then
1280
    begin
1273
    begin
1281
      OP_ManageOIDs;
1274
      OP_ManageOIDs;
1282
    end
1275
    end
1283
    else if menuRes = menuIdTree then
1276
    else if menuRes = menuIdTree then
1284
    begin
1277
    begin
1285
      OP_Treeview;
1278
      OP_Treeview;
1286
    end;
1279
    end;
1287
  until (menuRes = menuIdExit) or (MAINMENU_ALLOW_ESC and (menuRes = -1));
1280
  until (menuRes = menuIdExit) or (MAINMENU_ALLOW_ESC and (menuRes = -1));
1288
 
1281
 
1289
  OP_ReturnToMSDOS;
1282
  OP_ReturnToMSDOS;
1290
end;
1283
end;
1291
 
1284
 
1292
begin
1285
begin
1293
  InitVideo; (* sets ScreenWidth and ScreenHeight *)
1286
  InitVideo; (* sets ScreenWidth and ScreenHeight *)
1294
  CursorOff;
1287
  CursorOff;
1295
  OP_MainMenu;
1288
  OP_MainMenu;
1296
  CursorOn;
1289
  CursorOn;
1297
  DoneVideo;
1290
  DoneVideo;
1298
end.
1291
end.
1299
 
1292