Subversion Repositories oidplus

Rev

Rev 965 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 965 Rev 992
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-09-26                         *)
6
(* Revision: 2022-10-10                         *)
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-09-26';
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;
420
  list: PStringList;
421
  iId: LongInt;
421
  iId: LongInt;
422
  sId: string;
422
  sId: string;
423
begin
423
begin
424
  (* Put all found files into a list *)
424
  (* Put all found files into a list *)
425
  CreateList(list);
425
  CreateList(list);
426
  FindFirst(RepeatStr('?',8)+OID_EXTENSION, Archive, DirInfo);
426
  FindFirst(RepeatStr('?',8)+OID_EXTENSION, Archive, DirInfo);
427
  while DosError = 0 do
427
  while DosError = 0 do
428
  begin
428
  begin
429
    sId := Copy(DirInfo.Name, 1, 8);
429
    sId := Copy(DirInfo.Name, 1, 8);
430
    ListAppend(list, sId);
430
    ListAppend(list, sId);
431
    FindNext(DirInfo);
431
    FindNext(DirInfo);
432
  end;
432
  end;
433
 
433
 
434
  (* Search for the first non existing item in the list *)
434
  (* Search for the first non existing item in the list *)
435
  sId := '';
435
  sId := '';
436
  for iId := 0 to 99999999 do
436
  for iId := 0 to 99999999 do
437
  begin
437
  begin
438
    sId := ZeroPad(iId, 8);
438
    sId := ZeroPad(iId, 8);
439
    if not ListContains(list, sId) then break;
439
    if not ListContains(list, sId) then break;
440
  end;
440
  end;
441
  NextPossibleFileId := sId;
441
  NextPossibleFileId := sId;
442
  FreeList(list);
442
  FreeList(list);
443
end;
443
end;
444
 
444
 
445
function NumIdAlreadyExisting(parentOID: POID; arcval: string): boolean;
445
function NumIdAlreadyExisting(parentOID: POID; arcval: string): boolean;
446
var
446
var
447
  searchDotNotation: string;
447
  searchDotNotation: string;
448
  sTmp: string;
448
  sTmp: string;
449
  i: integer;
449
  i: integer;
450
begin
450
begin
451
  if parentOID^.DotNotation = '' then
451
  if parentOID^.DotNotation = '' then
452
    searchDotNotation := arcval
452
    searchDotNotation := arcval
453
  else
453
  else
454
    searchDotNotation := parentOID^.DotNotation + '.' + arcval;
454
    searchDotNotation := parentOID^.DotNotation + '.' + arcval;
455
  for i := 0 to ListCount(parentOID^.SubIds)-1 do
455
  for i := 0 to ListCount(parentOID^.SubIds)-1 do
456
  begin
456
  begin
457
    sTmp := ListGetElement(parentOID^.SubIds, i);
457
    sTmp := ListGetElement(parentOID^.SubIds, i);
458
    if DotNotationPart(sTmp) = searchDotNotation then
458
    if DotNotationPart(sTmp) = searchDotNotation then
459
    begin
459
    begin
460
      NumIdAlreadyExisting := true;
460
      NumIdAlreadyExisting := true;
461
      exit;
461
      exit;
462
    end;
462
    end;
463
  end;
463
  end;
464
  NumIdAlreadyExisting := false;
464
  NumIdAlreadyExisting := false;
465
end;
465
end;
466
 
466
 
467
function NumIdEditor(oid: POID; parentOID: POID): boolean;
467
function NumIdEditor(oid: POID; parentOID: POID): boolean;
468
var
468
var
469
  sInput: string;
469
  sInput: string;
470
  title: string;
470
  title: string;
471
  base36mode: boolean;
471
  base36mode: boolean;
472
  arcval: string;
472
  arcval: string;
473
begin
473
begin
474
  NumIdEditor := false;
474
  NumIdEditor := false;
475
  sInput := '';
475
  sInput := '';
476
 
476
 
477
  base36mode := false;
477
  base36mode := false;
478
  CursorOn;
478
  CursorOn;
479
  repeat
479
  repeat
480
    if base36mode then
480
    if base36mode then
481
    begin
481
    begin
482
      DrawStatusBar('Press ESC to cancel');
482
      DrawStatusBar('Press ESC to cancel');
483
      title := 'ENTER BASE36 ID'
483
      title := 'ENTER BASE36 ID'
484
    end
484
    end
485
    else
485
    else
486
    begin
486
    begin
487
      DrawStatusBar('Enter "WEID" to enter a Base36 instead of Base10; press ESC to cancel');
487
      DrawStatusBar('Enter "WEID" to enter a Base36 instead of Base10; press ESC to cancel');
488
      title := 'ENTER NUMERIC ID';
488
      title := 'ENTER NUMERIC ID';
489
    end;
489
    end;
490
    if QueryVal(sInput,
490
    if QueryVal(sInput,
491
                SINGLE_LINE_BOX_PADDING_INNER,
491
                SINGLE_LINE_BOX_PADDING_INNER,
492
                ScreenHeight div 2,
492
                ScreenHeight div 2,
493
                ScreenWidth - (SINGLE_LINE_BOX_PADDING_INNER-1)*2,
493
                ScreenWidth - (SINGLE_LINE_BOX_PADDING_INNER-1)*2,
494
                1,
494
                1,
495
                title,
495
                title,
496
                2) then
496
                2) then
497
    begin
497
    begin
498
      if sInput = '' then continue;
498
      if sInput = '' then continue;
499
      if not base36mode and (sInput = 'WEID') then
499
      if not base36mode and (sInput = 'WEID') then
500
      begin
500
      begin
501
        sInput := '';
501
        sInput := '';
502
        base36mode := true;
502
        base36mode := true;
503
      end
503
      end
504
      else if not base36mode and not IsPositiveIntegerOrZero(sInput) then
504
      else if not base36mode and not IsPositiveIntegerOrZero(sInput) then
505
      begin
505
      begin
506
        ShowMessage('Invalid numeric ID (must be a positive integer)', 'ERROR', true);
506
        ShowMessage('Invalid numeric ID (must be a positive integer)', 'ERROR', true);
507
        _Pause;
507
        _Pause;
508
      end
508
      end
509
      else if base36mode and not IsBase36String(sInput) then
509
      else if base36mode and not IsBase36String(sInput) then
510
      begin
510
      begin
511
        ShowMessage('Invalid base36 ID (must be 0..9, A..Z)', 'ERROR', true);
511
        ShowMessage('Invalid base36 ID (must be 0..9, A..Z)', 'ERROR', true);
512
        _Pause;
512
        _Pause;
513
      end
513
      end
514
      else
514
      else
515
      begin
515
      begin
516
        if base36mode then
516
        if base36mode then
517
          arcval := base_convert_bigint(sInput, 36, 10)
517
          arcval := base_convert_bigint(sInput, 36, 10)
518
        else
518
        else
519
          arcval := sInput;
519
          arcval := sInput;
520
        arcval := StripLeadingZeros(arcval);
520
        arcval := StripLeadingZeros(arcval);
521
 
521
 
522
        if (parentOID^.DotNotation='') and (arcval <> '0') and (arcval <> '1') and (arcval <> '2') then
522
        if (parentOID^.DotNotation='') and (arcval <> '0') and (arcval <> '1') and (arcval <> '2') then
523
        begin
523
        begin
524
          ShowMessage('Invalid numeric ID (root arc can only be 0, 1, or 2)', 'ERROR', true);
524
          ShowMessage('Invalid numeric ID (root arc can only be 0, 1, or 2)', 'ERROR', true);
525
          _Pause;
525
          _Pause;
526
        end
526
        end
527
        else if ((parentOID^.DotNotation='0') or (parentOID^.DotNotation='1')) and
527
        else if ((parentOID^.DotNotation='0') or (parentOID^.DotNotation='1')) and
528
                ((Length(arcval)>2) or (StrToInt(arcval) > 39)) then
528
                ((Length(arcval)>2) or (StrToInt(arcval) > 39)) then
529
        begin
529
        begin
530
          ShowMessage('Invalid numeric ID (root 0 and 1 must have sub-arc of 0..39)', 'ERROR', true);
530
          ShowMessage('Invalid numeric ID (root 0 and 1 must have sub-arc of 0..39)', 'ERROR', true);
531
          _Pause;
531
          _Pause;
532
        end
532
        end
533
        else if NumIdAlreadyExisting(parentOID, arcval) then
533
        else if NumIdAlreadyExisting(parentOID, arcval) then
534
        begin
534
        begin
535
          ShowMessage('This numeric ID is already used in this arc', 'ERROR', true);
535
          ShowMessage('This numeric ID is already used in this arc', 'ERROR', true);
536
          _Pause;
536
          _Pause;
537
        end
537
        end
538
        else
538
        else
539
        begin
539
        begin
540
          if parentOID^.DotNotation = '' then
540
          if parentOID^.DotNotation = '' then
541
            oid^.DotNotation := arcval
541
            oid^.DotNotation := arcval
542
          else
542
          else
543
            oid^.DotNotation := parentOID^.DotNotation + '.' + arcval;
543
            oid^.DotNotation := parentOID^.DotNotation + '.' + arcval;
544
          NumIdEditor := true; (* request caller to save <oid> *)
544
          NumIdEditor := true; (* request caller to save <oid> *)
545
          Break;
545
          Break;
546
        end;
546
        end;
547
      end;
547
      end;
548
    end
548
    end
549
    else
549
    else
550
    begin
550
    begin
551
      (* User pressed ESC *)
551
      (* User pressed ESC *)
552
      Break;
552
      Break;
553
    end;
553
    end;
554
  until false;
554
  until false;
555
  CursorOff;
555
  CursorOff;
556
end;
556
end;
557
 
557
 
558
function NewOidEditor(oid: POID): boolean;
558
function NewOidEditor(oid: POID): boolean;
559
var
559
var
560
  newfilename: string;
560
  newfilename: string;
561
  newOID: POID;
561
  newOID: POID;
562
begin
562
begin
563
  NewOidEditor := false;
563
  NewOidEditor := false;
564
 
564
 
565
  CreateOidDef(newOID);
565
  CreateOidDef(newOID);
566
  newOID^.FileId := NextPossibleFileID;
566
  newOID^.FileId := NextPossibleFileID;
567
  newOID^.ParentFileId := oid^.FileId;
567
  newOID^.ParentFileId := oid^.FileId;
568
  newOID^.ParentDotNotation := oid^.DotNotation;
568
  newOID^.ParentDotNotation := oid^.DotNotation;
569
  if NumIdEditor(newOID, oid) and
569
  if NumIdEditor(newOID, oid) and
570
     AsnEditor(newOID) and
570
     AsnEditor(newOID) and
571
     IriEditor(newOID) and
571
     IriEditor(newOID) and
572
     DescEditor(newOID) then
572
     DescEditor(newOID) then
573
  begin
573
  begin
574
    newfilename := newOID^.FileId + OID_EXTENSION;
574
    newfilename := newOID^.FileId + OID_EXTENSION;
575
    if _WriteOidFile(newfilename, newOID, true) then
575
    if _WriteOidFile(newfilename, newOID, true) then
576
    begin
576
    begin
577
      (* Add link to original file and enable the saving of it *)
577
      (* Add link to original file and enable the saving of it *)
578
      ListAppend(oid^.SubIds, newOID^.FileId + newOID^.DotNotation);
578
      ListAppend(oid^.SubIds, newOID^.FileId + newOID^.DotNotation);
579
      NewOidEditor := true; (* request caller to save <oid> *)
579
      NewOidEditor := true; (* request caller to save <oid> *)
580
    end;
580
    end;
581
  end;
581
  end;
582
  FreeOidDef(newOID);
582
  FreeOidDef(newOID);
583
end;
583
end;
584
 
584
 
585
procedure DeleteChildrenRecursive(oid: POID);
585
procedure DeleteChildrenRecursive(oid: POID);
586
var
586
var
587
  i: integer;
587
  i: integer;
588
  childOID: POID;
588
  childOID: POID;
589
  filenameChild: string;
589
  filenameChild: string;
590
begin
590
begin
591
  for i := 0 to ListCount(oid^.SubIds)-1 do
591
  for i := 0 to ListCount(oid^.SubIds)-1 do
592
  begin
592
  begin
593
    filenameChild := FileIdPart(ListGetElement(oid^.SubIds, i)) + OID_EXTENSION;
593
    filenameChild := FileIdPart(ListGetElement(oid^.SubIds, i)) + OID_EXTENSION;
594
    if FileExists(filenameChild) then
594
    if FileExists(filenameChild) then
595
    begin
595
    begin
596
      CreateOidDef(childOID);
596
      CreateOidDef(childOID);
597
      if _ReadOidFile(filenameChild, childOID, false) and
597
      if _ReadOidFile(filenameChild, childOID, false) and
598
         (childOID^.ParentFileId = oid^.FileId) and
598
         (childOID^.ParentFileId = oid^.FileId) and
599
         (childOID^.ParentDotNotation = oid^.DotNotation) then
599
         (childOID^.ParentDotNotation = oid^.DotNotation) then
600
      begin
600
      begin
601
        DeleteChildrenRecursive(childOID);
601
        DeleteChildrenRecursive(childOID);
602
      end;
602
      end;
603
      FreeOidDef(childOID);
603
      FreeOidDef(childOID);
604
      DeleteFile(filenameChild);
604
      DeleteFile(filenameChild);
605
    end;
605
    end;
606
  end;
606
  end;
607
  ListClear(oid^.SubIds);
607
  ListClear(oid^.SubIds);
608
end;
608
end;
609
 
609
 
610
procedure DeleteOidRecursive(selfOID: POID);
610
procedure DeleteOidRecursive(selfOID: POID);
611
var
611
var
612
  i: integer;
612
  i: integer;
613
  parentOID: POID;
613
  parentOID: POID;
614
  filenameSelf, filenameParent: string;
614
  filenameSelf, filenameParent: string;
615
begin
615
begin
616
  (* Remove all children and their files recursively *)
616
  (* Remove all children and their files recursively *)
617
  DeleteChildrenRecursive(selfOID);
617
  DeleteChildrenRecursive(selfOID);
618
 
618
 
619
  (* Remove forward reference in parent OID *)
619
  (* Remove forward reference in parent OID *)
620
  (* (this is the most important part)      *)
620
  (* (this is the most important part)      *)
621
  filenameParent := selfOID^.ParentFileId + OID_EXTENSION;
621
  filenameParent := selfOID^.ParentFileId + OID_EXTENSION;
622
  if FileExists(filenameParent) then
622
  if FileExists(filenameParent) then
623
  begin
623
  begin
624
    CreateOidDef(parentOID);
624
    CreateOidDef(parentOID);
625
    if _ReadOidFile(filenameParent, parentOID, true) then
625
    if _ReadOidFile(filenameParent, parentOID, true) then
626
    begin
626
    begin
627
      if ListDeleteElementByValue(parentOID^.SubIds, selfOID^.FileId + selfOID^.DotNotation) then
627
      if ListDeleteElementByValue(parentOID^.SubIds, selfOID^.FileId + selfOID^.DotNotation) then
628
      begin
628
      begin
629
        _WriteOidFile(filenameParent, parentOID, true);
629
        _WriteOidFile(filenameParent, parentOID, true);
630
      end;
630
      end;
631
    end;
631
    end;
632
    FreeOidDef(parentOID);
632
    FreeOidDef(parentOID);
633
  end;
633
  end;
634
 
634
 
635
  (* Delete own file *)
635
  (* Delete own file *)
636
  filenameSelf := selfOID^.FileId + OID_EXTENSION;
636
  filenameSelf := selfOID^.FileId + OID_EXTENSION;
637
  if FileExists(filenameSelf) then
637
  if FileExists(filenameSelf) then
638
  begin
638
  begin
639
    DeleteFile(filenameSelf);
639
    DeleteFile(filenameSelf);
640
  end;
640
  end;
641
end;
641
end;
642
 
642
 
643
function _DeleteConfirmation: boolean;
643
function _DeleteConfirmation: boolean;
644
var
644
var
645
  sc: Char;
645
  sc: Char;
646
begin
646
begin
647
  repeat
647
  repeat
648
    ShowMessage('Are you sure you want to delete this OID? (Y/N)', 'DELETE OID', true);
648
    ShowMessage('Are you sure you want to delete this OID? (Y/N)', 'DELETE OID', true);
649
    DrawStatusBar('Y=Yes, N=No');
649
    DrawStatusBar('Y=Yes, N=No');
650
 
650
 
651
    CursorOn;
651
    CursorOn;
652
    sc := ReadKey;
652
    sc := ReadKey;
653
    CursorOff;
653
    CursorOff;
654
    if sc = #0 then
654
    if sc = #0 then
655
    begin
655
    begin
656
      (* Extended key. Nothing we care about. *)
656
      (* Extended key. Nothing we care about. *)
657
      ReadKey;
657
      ReadKey;
658
      continue;
658
      continue;
659
    end;
659
    end;
660
 
660
 
661
    if UpCase(sc) = 'Y' then
661
    if UpCase(sc) = 'Y' then
662
    begin
662
    begin
663
      _DeleteConfirmation := true;
663
      _DeleteConfirmation := true;
664
      break;
664
      break;
665
    end
665
    end
666
    else if UpCase(sc) = 'N' then
666
    else if UpCase(sc) = 'N' then
667
    begin
667
    begin
668
      _DeleteConfirmation := false;
668
      _DeleteConfirmation := false;
669
      break;
669
      break;
670
    end;
670
    end;
671
  until false;
671
  until false;
672
end;
672
end;
673
 
673
 
674
procedure _DrawOidTitleBar(filename: string; oid: POID);
674
procedure _DrawOidTitleBar(filename: string; oid: POID);
675
begin
675
begin
676
  if oid^.DotNotation = '' then
676
  if oid^.DotNotation = '' then
677
    DrawTitleBar('OID ROOT', TITLEBAR_LEFT_TEXT, filename)
677
    DrawTitleBar('OID ROOT', TITLEBAR_LEFT_TEXT, filename)
678
  else
678
  else
679
    DrawTitleBar('OID ' + oid^.DotNotation, TITLEBAR_LEFT_TEXT, filename);
679
    DrawTitleBar('OID ' + oid^.DotNotation, TITLEBAR_LEFT_TEXT, filename);
680
end;
680
end;
681
 
681
 
682
function DotNotation(oid: POid): string;
682
function DotNotation(oid: POid): string;
683
var
683
var
684
  res: string;
684
  res: string;
685
begin
685
begin
686
  res := oid^.DotNotation;
686
  res := oid^.DotNotation;
687
  if res = '' then res := '.'; (* root *)
687
  if res = '' then res := '.'; (* root *)
688
  DotNotation := res;
688
  DotNotation := res;
689
end;
689
end;
690
 
690
 
691
function OidLastArc(oid: POid): string;
691
function OidLastArc(oid: POid): string;
692
var
692
var
693
  s: string;
693
  s: string;
694
  p: integer;
694
  p: integer;
695
begin
695
begin
696
  s := oid^.DotNotation;
696
  s := oid^.DotNotation;
697
 
697
 
698
  while true do
698
  while true do
699
  begin
699
  begin
700
    p := Pos('.', s);
700
    p := Pos('.', s);
701
    if p = 0 then break;
701
    if p = 0 then break;
702
    Delete(s, 1, p);
702
    Delete(s, 1, p);
703
  end;
703
  end;
704
 
704
 
705
  OidLastArc := s;
705
  OidLastArc := s;
706
end;
706
end;
707
 
707
 
708
function AsnNotation(oid: POid): string;
708
function AsnNotation(oid: POid): string;
709
var
709
var
710
  prevOid, curOid: POid;
710
  prevOid, curOid: POid;
711
  res: string;
711
  res: string;
712
begin
712
begin
713
  CreateOidDef(curOid);
713
  CreateOidDef(curOid);
714
  prevOid := oid;
714
  prevOid := oid;
715
  res := '';
715
  res := '';
716
 
716
 
717
  while true do
717
  while true do
718
  begin
718
  begin
719
    (* Note: BackRef is not checked yet! Infinite loop is possible! (TODO) *)
719
    (* Note: BackRef is not checked yet! Infinite loop is possible! (TODO) *)
720
    ReadOidFile(prevOid^.ParentFileId + '.OID', curOid);
720
    ReadOidFile(prevOid^.ParentFileId + '.OID', curOid);
721
    if curOid^.ParentFileId = '' then break;
721
    if curOid^.ParentFileId = '' then break;
722
    if curOid^.ParentFileId = curOid^.FileId then break;
722
    if curOid^.ParentFileId = curOid^.FileId then break;
723
    if ListCount(curOid^.AsnIds) > 0 then
723
    if ListCount(curOid^.AsnIds) > 0 then
724
      res := ListGetElement(curOid^.AsnIds, 0) + '('+OidLastArc(curOid)+') ' + res
724
      res := ListGetElement(curOid^.AsnIds, 0) + '('+OidLastArc(curOid)+') ' + res
725
    else
725
    else
726
      res := OidLastArc(curOid) + ' ' + res;
726
      res := OidLastArc(curOid) + ' ' + res;
727
    prevOid := curOid;
727
    prevOid := curOid;
728
  end;
728
  end;
729
  FreeOidDef(curOid);
729
  FreeOidDef(curOid);
730
  if ListCount(oid^.AsnIds) > 0 then
730
  if ListCount(oid^.AsnIds) > 0 then
731
    res := res + ListGetElement(oid^.AsnIds, 0) + '('+OidLastArc(oid)+')'
731
    res := res + ListGetElement(oid^.AsnIds, 0) + '('+OidLastArc(oid)+')'
732
  else
732
  else
733
    res := res + OidLastArc(oid);
733
    res := res + OidLastArc(oid);
734
  if res = '' then
734
  if res = '' then
735
    AsnNotation := ''
735
    AsnNotation := ''
736
  else
736
  else
737
    AsnNotation := '{ ' + res + ' }';
737
    AsnNotation := '{ ' + res + ' }';
738
end;
738
end;
739
 
739
 
740
function IriNotation(oid: POid): string;
740
function IriNotation(oid: POid): string;
741
var
741
var
742
  prevOid, curOid: POid;
742
  prevOid, curOid: POid;
743
  res: string;
743
  res: string;
744
begin
744
begin
745
  CreateOidDef(curOid);
745
  CreateOidDef(curOid);
746
  prevOid := oid;
746
  prevOid := oid;
747
  res := '';
747
  res := '';
748
 
748
 
749
  while true do
749
  while true do
750
  begin
750
  begin
751
    (* Note: BackRef is not checked yet! Infinite loop is possible! (TODO) *)
751
    (* Note: BackRef is not checked yet! Infinite loop is possible! (TODO) *)
752
    ReadOidFile(prevOid^.ParentFileId + '.OID', curOid);
752
    ReadOidFile(prevOid^.ParentFileId + '.OID', curOid);
753
    if curOid^.ParentFileId = '' then break;
753
    if curOid^.ParentFileId = '' then break;
754
    if curOid^.ParentFileId = curOid^.FileId then break;
754
    if curOid^.ParentFileId = curOid^.FileId then break;
755
    if ListCount(curOid^.UnicodeLabels) > 0 then
755
    if ListCount(curOid^.UnicodeLabels) > 0 then
756
      res := ListGetElement(curOid^.UnicodeLabels, 0) + '/' + res
756
      res := ListGetElement(curOid^.UnicodeLabels, 0) + '/' + res
757
    else
757
    else
758
      res := OidLastArc(curOid) + '/' + res;
758
      res := OidLastArc(curOid) + '/' + res;
759
    prevOid := curOid;
759
    prevOid := curOid;
760
  end;
760
  end;
761
  FreeOidDef(curOid);
761
  FreeOidDef(curOid);
762
  if ListCount(oid^.UnicodeLabels) > 0 then
762
  if ListCount(oid^.UnicodeLabels) > 0 then
763
    res := res + ListGetElement(oid^.UnicodeLabels, 0)
763
    res := res + ListGetElement(oid^.UnicodeLabels, 0)
764
  else
764
  else
765
    res := res + OidLastArc(oid);
765
    res := res + OidLastArc(oid);
766
  IriNotation := '/' + res;
766
  IriNotation := '/' + res;
767
end;
767
end;
768
 
768
 
769
function WeidNotation(oid: POid): string;
769
function WeidNotation(oid: POid): string;
770
begin
770
begin
771
  WeidNotation := OidToWeid(oid^.DotNotation);
771
  WeidNotation := OidToWeid(oid^.DotNotation);
772
end;
772
end;
773
 
773
 
774
procedure DisplayOIDFile(filename, from: string);
774
procedure DisplayOIDFile(filename, from: string);
775
var
775
var
776
  isRoot: boolean;
776
  isRoot: boolean;
777
  oid, tmpOID: POID;
777
  oid, tmpOID: POID;
778
  i: integer;
778
  i: integer;
779
  sTmp, subfile: string;
779
  sTmp, subfile: string;
780
  subsel, subfiles: PStringList;
780
  subsel, subfiles: PStringList;
781
  subselres: integer;
781
  subselres: integer;
782
  exitRequest: boolean;
782
  exitRequest: boolean;
783
  menuIdExit, menuIdAsnEdit, menuIdIriEdit, menuIdDescEdit, menuIdAdd, menuIdDelete: integer;
783
  menuIdExit, menuIdAsnEdit, menuIdIriEdit, menuIdDescEdit, menuIdAdd, menuIdDelete: integer;
784
  menuX, menuY: integer;
784
  menuX, menuY: integer;
785
begin
785
begin
786
  exitRequest := false;
786
  exitRequest := false;
787
  repeat
787
  repeat
788
    CreateOidDef(oid);
788
    CreateOidDef(oid);
789
 
789
 
790
    if not _ReadOidFile(filename, oid, true) then
790
    if not _ReadOidFile(filename, oid, true) then
791
    begin
791
    begin
792
      FreeOidDef(oid);
792
      FreeOidDef(oid);
793
      exit;
793
      exit;
794
    end;
794
    end;
795
 
795
 
796
    (* Print OID information *)
796
    (* Print OID information *)
797
 
797
 
798
    ClrScr;
798
    ClrScr;
799
    _DrawOidTitleBar(filename, oid);
799
    _DrawOidTitleBar(filename, oid);
800
    DrawStatusBar('');
800
    DrawStatusBar('');
801
    GotoXY(1,2);
801
    GotoXY(1,2);
802
 
802
 
803
    Write('Dot notation:   ');
803
    Write('Dot notation:   ');
804
    WriteLnKeepX(DotNotation(oid));
804
    WriteLnKeepX(DotNotation(oid));
805
    Write('ASN.1 notation: ');
805
    Write('ASN.1 notation: ');
806
    WriteLnKeepX(AsnNotation(oid));
806
    WriteLnKeepX(AsnNotation(oid));
807
    Write('OID-IRI:        ');
807
    Write('OID-IRI:        ');
808
    WriteLnKeepX(IriNotation(oid));
808
    WriteLnKeepX(IriNotation(oid));
809
    Write('WEID notation:  ');
809
    Write('WEID notation:  ');
810
    WriteLnKeepX(WeidNotation(oid));
810
    WriteLnKeepX(WeidNotation(oid));
811
    WriteLn('');
811
    WriteLn('');
812
 
812
 
813
    if Trim(oid^.Description) <> '' then
813
    if Trim(oid^.Description) <> '' then
814
    begin
814
    begin
815
      (* WriteLn('Description:'); *)
815
      (* WriteLn('Description:'); *)
-
 
816
      (* TODO: We should avoid that this is more than 10 lines *)
816
      WriteLn(oid^.Description);
817
      WriteLn(oid^.Description);
817
      WriteLn('');
818
      WriteLn('');
818
    end
819
    end
819
    else
820
    else
820
    begin
821
    begin
821
      WriteLn('(No description has been added to this OID.)');
822
      WriteLn('(No description has been added to this OID.)');
822
      WriteLn('');
823
      WriteLn('');
823
    end;
824
    end;
824
 
825
 
825
    (* Now prepare the menu entries *)
826
    (* Now prepare the menu entries *)
826
 
827
 
827
    CreateList(subsel);   (* Contains the human-readable OID name *)
828
    CreateList(subsel);   (* Contains the human-readable OID name *)
828
    CreateList(subfiles); (* Contains the file name               *)
829
    CreateList(subfiles); (* Contains the file name               *)
829
 
830
 
830
    if oid^.ParentFileId = '' then
831
    if oid^.ParentFileId = '' then
831
    begin
832
    begin
832
      isRoot := true;
833
      isRoot := true;
833
    end
834
    end
834
    else
835
    else
835
    begin
836
    begin
836
      isRoot := oid^.ParentDotNotation = oid^.DotNotation;
837
      isRoot := oid^.ParentDotNotation = oid^.DotNotation;
837
    end;
838
    end;
838
 
839
 
839
    if (oid^.ParentFileId <> '') and not isRoot then
840
    if (oid^.ParentFileId <> '') and not isRoot then
840
    begin
841
    begin
841
      subfile := oid^.ParentFileId + OID_EXTENSION;
842
      subfile := oid^.ParentFileId + OID_EXTENSION;
842
      if FileExists(subfile) then
843
      if FileExists(subfile) then
843
      begin
844
      begin
844
        CreateOidDef(tmpOID);
845
        CreateOidDef(tmpOID);
845
        if not _ReadOidFile(subfile, tmpOID, true) then
846
        if not _ReadOidFile(subfile, tmpOID, true) then
846
        begin
847
        begin
847
          ListAppend(subsel, 'Go to parent ' + oid^.ParentDotNotation + ' (READ ERROR)');
848
          ListAppend(subsel, 'Go to parent ' + oid^.ParentDotNotation + ' (READ ERROR)');
848
          ListAppend(subfiles, 'ERROR: '+subfile+' Read error or file invalid');
849
          ListAppend(subfiles, 'ERROR: '+subfile+' Read error or file invalid');
849
        end
850
        end
850
        else
851
        else
851
        begin
852
        begin
852
          ListAppend(subsel, 'Go to parent ' + oid^.ParentDotNotation + _ShowASNIds(tmpOID));
853
          ListAppend(subsel, 'Go to parent ' + oid^.ParentDotNotation + _ShowASNIds(tmpOID));
853
          ListAppend(subfiles, subfile);
854
          ListAppend(subfiles, subfile);
854
        end;
855
        end;
855
        FreeOidDef(tmpOID);
856
        FreeOidDef(tmpOID);
856
      end
857
      end
857
      else
858
      else
858
      begin
859
      begin
859
        ListAppend(subsel, 'Go to parent ' + oid^.ParentDotNotation + ' (FILE NOT FOUND)');
860
        ListAppend(subsel, 'Go to parent ' + oid^.ParentDotNotation + ' (FILE NOT FOUND)');
860
        ListAppend(subfiles, 'ERROR: File '+subfile+' was not found');
861
        ListAppend(subfiles, 'ERROR: File '+subfile+' was not found');
861
      end;
862
      end;
862
    end;
863
    end;
863
 
864
 
864
    if isRoot then
865
    if isRoot then
865
    begin
866
    begin
866
      menuIdExit := ListAppend(subsel, 'Back to '+from);
867
      menuIdExit := ListAppend(subsel, 'Back to '+from);
867
      ListAppend(subfiles, '');
868
      ListAppend(subfiles, '');
868
    end
869
    end
869
    else menuIdExit := -99;
870
    else menuIdExit := -99;
870
 
871
 
871
    for i := 0 to ListCount(oid^.SubIds)-1 do
872
    for i := 0 to ListCount(oid^.SubIds)-1 do
872
    begin
873
    begin
873
      sTmp := ListGetElement(oid^.SubIds, i);
874
      sTmp := ListGetElement(oid^.SubIds, i);
874
      subfile := FileIdPart(sTmp) + OID_EXTENSION;
875
      subfile := FileIdPart(sTmp) + OID_EXTENSION;
875
      if FileExists(subfile) then
876
      if FileExists(subfile) then
876
      begin
877
      begin
877
        CreateOidDef(tmpOID);
878
        CreateOidDef(tmpOID);
878
        if not _ReadOidFile(subfile, tmpOID, true) then
879
        if not _ReadOidFile(subfile, tmpOID, true) then
879
        begin
880
        begin
880
          ListAppend(subsel, 'Go to child  ' + DotNotationPart(sTmp) + ' (READ ERROR)');
881
          ListAppend(subsel, 'Go to child  ' + DotNotationPart(sTmp) + ' (READ ERROR)');
881
          ListAppend(subfiles, 'ERROR: Read error at file '+subfile+', or file is invalid.');
882
          ListAppend(subfiles, 'ERROR: Read error at file '+subfile+', or file is invalid.');
882
        end
883
        end
883
        else if (tmpOID^.ParentFileId <> oid^.FileId) or
884
        else if (tmpOID^.ParentFileId <> oid^.FileId) or
884
                (tmpOID^.ParentDotNotation <> oid^.DotNotation) then
885
                (tmpOID^.ParentDotNotation <> oid^.DotNotation) then
885
        begin
886
        begin
886
          ListAppend(subsel, 'Go to child  ' + DotNotationPart(sTmp) + ' (BAD BACKREF)');
887
          ListAppend(subsel, 'Go to child  ' + DotNotationPart(sTmp) + ' (BAD BACKREF)');
887
          ListAppend(subfiles, 'ERROR: File '+subfile+' has a wrong back-reference.');
888
          ListAppend(subfiles, 'ERROR: File '+subfile+' has a wrong back-reference.');
888
        end
889
        end
889
        else
890
        else
890
        begin
891
        begin
891
          ListAppend(subsel, 'Go to child  ' + DotNotationPart(sTmp) + _ShowASNIds(tmpOID));
892
          ListAppend(subsel, 'Go to child  ' + DotNotationPart(sTmp) + _ShowASNIds(tmpOID));
892
          ListAppend(subfiles, subfile);
893
          ListAppend(subfiles, subfile);
893
        end;
894
        end;
894
        FreeOidDef(tmpOID);
895
        FreeOidDef(tmpOID);
895
      end
896
      end
896
      else
897
      else
897
      begin
898
      begin
898
        ListAppend(subsel, 'Go to child  ' + DotNotationPart(sTmp) + ' (FILE NOT FOUND)');
899
        ListAppend(subsel, 'Go to child  ' + DotNotationPart(sTmp) + ' (FILE NOT FOUND)');
899
        ListAppend(subfiles, 'ERROR: File '+subfile+' was not found');
900
        ListAppend(subfiles, 'ERROR: File '+subfile+' was not found');
900
      end;
901
      end;
901
    end;
902
    end;
902
 
903
 
903
    if oid^.DotNotation <> '' then
904
    if oid^.DotNotation <> '' then
904
    begin
905
    begin
905
      menuIdAsnEdit := ListAppend(subsel, 'View/Edit ASN.1 identifiers');
906
      menuIdAsnEdit := ListAppend(subsel, 'View/Edit ASN.1 identifiers');
906
      ListAppend(subfiles, '');
907
      ListAppend(subfiles, '');
907
    end
908
    end
908
    else menuIdAsnEdit := -99;
909
    else menuIdAsnEdit := -99;
909
 
910
 
910
    if oid^.DotNotation <> '' then
911
    if oid^.DotNotation <> '' then
911
    begin
912
    begin
912
      menuIdIriEdit := ListAppend(subsel, 'View/Edit Unicode Labels (OID-IRI)');
913
      menuIdIriEdit := ListAppend(subsel, 'View/Edit Unicode Labels (OID-IRI)');
913
      ListAppend(subfiles, '');
914
      ListAppend(subfiles, '');
914
    end
915
    end
915
    else menuIdIriEdit := -99;
916
    else menuIdIriEdit := -99;
916
 
917
 
917
    menuIdDescEdit := ListAppend(subsel, 'Edit description');
918
    menuIdDescEdit := ListAppend(subsel, 'Edit description');
918
    ListAppend(subfiles, '');
919
    ListAppend(subfiles, '');
919
 
920
 
920
    menuIdAdd := ListAppend(subsel, 'Add child');
921
    menuIdAdd := ListAppend(subsel, 'Add child');
921
    ListAppend(subfiles, '');
922
    ListAppend(subfiles, '');
922
 
923
 
923
    if not isRoot then
924
    if not isRoot then
924
    begin
925
    begin
925
      menuIdDelete := ListAppend(subsel, 'Delete OID');
926
      menuIdDelete := ListAppend(subsel, 'Delete OID');
926
      ListAppend(subfiles, '');
927
      ListAppend(subfiles, '');
927
    end
928
    end
928
    else menuIdDelete := -99;
929
    else menuIdDelete := -99;
929
 
930
 
930
    (* Show menu *)
931
    (* Show menu *)
931
 
932
 
932
    menuX := WhereX + 1;
933
    menuX := WhereX + 1;
933
    menuY := ScreenHeight - ACTIONMENU_SIZE - 1;
934
    menuY := ScreenHeight - ACTIONMENU_SIZE - 1;
934
    subselres := DrawSelectionList(menuX, menuY,
935
    subselres := DrawSelectionList(menuX, menuY,
935
                                   ScreenWidth-2,
936
                                   ScreenWidth-2,
936
                                   ACTIONMENU_SIZE,
937
                                   ACTIONMENU_SIZE,
937
                                   subsel,
938
                                   subsel,
938
                                   true,
939
                                   true,
939
                                   'SELECT ACTION',
940
                                   'SELECT ACTION',
940
                                   1);
941
                                   1);
941
 
942
 
942
    (* Process user selection *)
943
    (* Process user selection *)
943
 
944
 
944
    if subselres = -1 then
945
    if subselres = -1 then
945
    begin
946
    begin
946
      exitRequest := true;
947
      exitRequest := true;
947
    end
948
    end
948
    else if subselres = menuIdAsnEdit then
949
    else if subselres = menuIdAsnEdit then
949
    begin
950
    begin
950
      if AsnEditor(oid) then
951
      if AsnEditor(oid) then
951
        _WriteOidFile(filename, oid, true);
952
        _WriteOidFile(filename, oid, true);
952
    end
953
    end
953
    else if subselres = menuIdIriEdit then
954
    else if subselres = menuIdIriEdit then
954
    begin
955
    begin
955
      if IriEditor(oid) then
956
      if IriEditor(oid) then
956
        _WriteOidFile(filename, oid, true);
957
        _WriteOidFile(filename, oid, true);
957
    end
958
    end
958
    else if subselres = menuIdDescEdit then
959
    else if subselres = menuIdDescEdit then
959
    begin
960
    begin
960
      if DescEditor(oid) then
961
      if DescEditor(oid) then
961
        _WriteOidFile(filename, oid, true);
962
        _WriteOidFile(filename, oid, true);
962
    end
963
    end
963
    else if subselres = menuIdAdd then
964
    else if subselres = menuIdAdd then
964
    begin
965
    begin
965
      if NewOidEditor(oid) then
966
      if NewOidEditor(oid) then
966
        _WriteOidFile(filename, oid, true);
967
        _WriteOidFile(filename, oid, true);
967
    end
968
    end
968
    else if subselres = menuIdDelete then
969
    else if subselres = menuIdDelete then
969
    begin
970
    begin
970
      if _DeleteConfirmation then
971
      if _DeleteConfirmation then
971
      begin
972
      begin
972
        sTmp := oid^.ParentFileId + OID_EXTENSION;
973
        sTmp := oid^.ParentFileId + OID_EXTENSION;
973
        DeleteOidRecursive(oid);
974
        DeleteOidRecursive(oid);
974
        if FileExists(sTmp) then
975
        if FileExists(sTmp) then
975
        begin
976
        begin
976
          filename := sTmp;
977
          filename := sTmp;
977
        end
978
        end
978
        else
979
        else
979
        begin
980
        begin
980
          ShowMessage('Parent file ' + sTmp + ' was not found', 'ERROR', true);
981
          ShowMessage('Parent file ' + sTmp + ' was not found', 'ERROR', true);
981
          _Pause;
982
          _Pause;
982
          exitRequest := true;
983
          exitRequest := true;
983
        end;
984
        end;
984
      end;
985
      end;
985
    end
986
    end
986
    else if subselres = menuIdExit then
987
    else if subselres = menuIdExit then
987
    begin
988
    begin
988
      exitRequest := true;
989
      exitRequest := true;
989
    end
990
    end
990
    else
991
    else
991
    begin
992
    begin
992
      (* Normal OID *)
993
      (* Normal OID *)
993
      (* Above we already checked if the files are valild and existing *)
994
      (* Above we already checked if the files are valild and existing *)
994
      sTmp := ListGetElement(subfiles, subselres);
995
      sTmp := ListGetElement(subfiles, subselres);
995
      if Copy(sTmp, 1, Length('ERROR: ')) = 'ERROR: ' then
996
      if Copy(sTmp, 1, Length('ERROR: ')) = 'ERROR: ' then
996
      begin
997
      begin
997
        Delete(sTmp, 1, Length('ERROR: '));
998
        Delete(sTmp, 1, Length('ERROR: '));
998
        ShowMessage(sTmp, 'ERROR', true);
999
        ShowMessage(sTmp, 'ERROR', true);
999
        _Pause;
1000
        _Pause;
1000
      end
1001
      end
1001
      else
1002
      else
1002
      begin
1003
      begin
1003
        filename := sTmp;
1004
        filename := sTmp;
1004
      end;
1005
      end;
1005
    end;
1006
    end;
1006
    FreeList(subsel);
1007
    FreeList(subsel);
1007
    FreeList(subfiles);
1008
    FreeList(subfiles);
1008
 
1009
 
1009
    FreeOidDef(oid);
1010
    FreeOidDef(oid);
1010
  until exitRequest;
1011
  until exitRequest;
1011
end;
1012
end;
1012
 
1013
 
1013
function CreateRootOIDFile(filename: string; ShowErrorMessage: boolean): boolean;
1014
function CreateRootOIDFile(filename: string; ShowErrorMessage: boolean): boolean;
1014
var
1015
var
1015
  oid: POID;
1016
  oid: POID;
1016
begin
1017
begin
1017
  CreateOidDef(oid);
1018
  CreateOidDef(oid);
1018
  oid^.Description  := 'This is the root of the OID tree.' +#13#10 +
1019
  oid^.Description  := 'This is the root of the OID tree.' +#13#10 +
1019
                       #13#10 +
1020
                       #13#10 +
1020
                       'Valid subsequent arcs are per definition:' + #13#10 +
1021
                       'Valid subsequent arcs are per definition:' + #13#10 +
1021
                       '- 0 (itu-t)' + #13#10 +
1022
                       '- 0 (itu-t)' + #13#10 +
1022
                       '- 1 (iso)' + #13#10 +
1023
                       '- 1 (iso)' + #13#10 +
1023
                       '- 2 (joint-iso-itu-t)';
1024
                       '- 2 (joint-iso-itu-t)';
1024
  oid^.FileId       := ZeroPad(0, 8);
1025
  oid^.FileId       := ZeroPad(0, 8);
1025
  oid^.DotNotation  := '';
1026
  oid^.DotNotation  := '';
1026
  oid^.ParentFileId := ZeroPad(0, 8);
1027
  oid^.ParentFileId := ZeroPad(0, 8);
1027
  oid^.ParentDotNotation := '';
1028
  oid^.ParentDotNotation := '';
1028
  CreateRootOIDFile := _WriteOidFile(filename, oid, ShowErrorMessage);
1029
  CreateRootOIDFile := _WriteOidFile(filename, oid, ShowErrorMessage);
1029
  FreeOidDef(oid);
1030
  FreeOidDef(oid);
1030
end;
1031
end;
1031
 
1032
 
1032
function _GetRootFile(ShowErrorMessage: boolean): string;
1033
function _GetRootFile(ShowErrorMessage: boolean): string;
1033
var
1034
var
1034
  rootFile: string;
1035
  rootFile: string;
1035
begin
1036
begin
1036
  rootFile := ZeroPad(0, 8) + OID_EXTENSION;
1037
  rootFile := ZeroPad(0, 8) + OID_EXTENSION;
1037
  _GetRootFile := rootFile;
1038
  _GetRootFile := rootFile;
1038
  if not FileExists(rootFile) then
1039
  if not FileExists(rootFile) then
1039
  begin
1040
  begin
1040
    if not CreateRootOIDFile(rootFile, ShowErrorMessage) then
1041
    if not CreateRootOIDFile(rootFile, ShowErrorMessage) then
1041
    begin
1042
    begin
1042
      _GetRootFile := '';
1043
      _GetRootFile := '';
1043
    end;
1044
    end;
1044
  end;
1045
  end;
1045
end;
1046
end;
1046
 
1047
 
1047
procedure OP_ManageOIDs;
1048
procedure OP_ManageOIDs;
1048
var
1049
var
1049
  rootfile: string;
1050
  rootfile: string;
1050
begin
1051
begin
1051
  ClrScr;
1052
  ClrScr;
1052
  DrawTitleBar('Manage Object Identifiers', TITLEBAR_LEFT_TEXT, '');
1053
  DrawTitleBar('Manage Object Identifiers', TITLEBAR_LEFT_TEXT, '');
1053
  DrawStatusBar('Loading data... please wait...');
1054
  DrawStatusBar('Loading data... please wait...');
1054
 
1055
 
1055
  (* This will try creating a new root file if it does not exist *)
1056
  (* This will try creating a new root file if it does not exist *)
1056
  rootfile := _GetRootFile(true);
1057
  rootfile := _GetRootFile(true);
1057
  if rootfile = '' then Exit;
1058
  if rootfile = '' then Exit;
1058
 
1059
 
1059
  DisplayOIDFile(rootfile, 'main menu');
1060
  DisplayOIDFile(rootfile, 'main menu');
1060
end;
1061
end;
1061
 
1062
 
1062
procedure OP_ReturnToMSDOS;
1063
procedure OP_ReturnToMSDOS;
1063
begin
1064
begin
1064
  (* Note: These two lines don't seem to be necessary if you use DoneVideo *)
1065
  (* Note: These two lines don't seem to be necessary if you use DoneVideo *)
1065
  ResetDefaultDosColors;
1066
  ResetDefaultDosColors;
1066
  ClrScr; (*Important, so that the DOS command prompt is also LightGray *)
1067
  ClrScr; (*Important, so that the DOS command prompt is also LightGray *)
1067
 
1068
 
1068
  WriteLn('Thank you for using OIDplus for DOS.');
1069
  WriteLn('Thank you for using OIDplus for DOS.');
1069
  WriteLn('');
1070
  WriteLn('');
1070
end;
1071
end;
1071
 
1072
 
1072
function _GetTreeViewLine(oid: POID; indent: integer): string;
1073
function _GetTreeViewLine(oid: POID; indent: integer): string;
1073
var
1074
var
1074
  i: integer;
1075
  i: integer;
1075
  sTmp, sTmp2: string;
1076
  sTmp, sTmp2: string;
1076
begin
1077
begin
1077
  (* Build line *)
1078
  (* Build line *)
1078
  sTmp := RepeatStr(' ', indent*TREEVIEW_INDENT);
1079
  sTmp := RepeatStr(' ', indent*TREEVIEW_INDENT);
1079
  if oid^.DotNotation = '' then
1080
  if oid^.DotNotation = '' then
1080
    sTmp := sTmp + 'Object Identifiers'
1081
    sTmp := sTmp + 'Object Identifiers'
1081
  else
1082
  else
1082
    sTmp := sTmp + oid^.DotNotation;
1083
    sTmp := sTmp + oid^.DotNotation;
1083
  sTmp := sTmp + _ShowAsnIds(oid);
1084
  sTmp := sTmp + _ShowAsnIds(oid);
1084
  if TREEVIEW_INCLUDE_DESC then
1085
  if TREEVIEW_INCLUDE_DESC then
1085
  begin
1086
  begin
1086
    if Trim(oid^.Description) <> '' then
1087
    if Trim(oid^.Description) <> '' then
1087
    begin
1088
    begin
1088
      sTmp := sTmp + ': ' + oid^.Description;
1089
      sTmp := sTmp + ': ' + oid^.Description;
1089
    end;
1090
    end;
1090
  end;
1091
  end;
1091
 
1092
 
1092
  sTmp := StringReplace(sTmp, #13#10, ' ');
1093
  sTmp := StringReplace(sTmp, #13#10, ' ');
1093
  repeat
1094
  repeat
1094
    sTmp2 := sTmp;
1095
    sTmp2 := sTmp;
1095
    sTmp := StringReplace(sTmp, '  ', ' ');
1096
    sTmp := StringReplace(sTmp, '  ', ' ');
1096
  until sTmp = sTmp2;
1097
  until sTmp = sTmp2;
1097
 
1098
 
1098
  sTmp := TrimLineToWidth(sTmp, TREEVIEW_WIDTH);
1099
  sTmp := TrimLineToWidth(sTmp, TREEVIEW_WIDTH);
1099
  _GetTreeViewLine := sTmp;
1100
  _GetTreeViewLine := sTmp;
1100
end;
1101
end;
1101
 
1102
 
1102
procedure _RecTreeExport(oid: POID; visList, targetList: PStringList; indent: integer);
1103
procedure _RecTreeExport(oid: POID; visList, targetList: PStringList; indent: integer);
1103
var
1104
var
1104
  i: integer;
1105
  i: integer;
1105
  sTmp: string;
1106
  sTmp: string;
1106
  suboid: POID;
1107
  suboid: POID;
1107
  childFilename: string;
1108
  childFilename: string;
1108
begin
1109
begin
1109
  sTmp := _GetTreeViewLine(oid, indent);
1110
  sTmp := _GetTreeViewLine(oid, indent);
1110
  sTmp := TrimLineToWidth(sTmp, TREEVIEW_WIDTH);
1111
  sTmp := TrimLineToWidth(sTmp, TREEVIEW_WIDTH);
1111
  ListAppend(visList, sTmp);
1112
  ListAppend(visList, sTmp);
1112
  ListAppend(targetList, oid^.FileID);
1113
  ListAppend(targetList, oid^.FileID);
1113
 
1114
 
1114
  (* Recursively call children *)
1115
  (* Recursively call children *)
1115
  for i := 0 to ListCount(oid^.SubIds)-1 do
1116
  for i := 0 to ListCount(oid^.SubIds)-1 do
1116
  begin
1117
  begin
1117
    sTmp := ListGetElement(oid^.SubIds, i);
1118
    sTmp := ListGetElement(oid^.SubIds, i);
1118
    CreateOidDef(suboid);
1119
    CreateOidDef(suboid);
1119
    childFilename := FileIdPart(sTmp) + OID_EXTENSION;
1120
    childFilename := FileIdPart(sTmp) + OID_EXTENSION;
1120
    if not FileExists(childFilename) then
1121
    if not FileExists(childFilename) then
1121
    begin
1122
    begin
1122
      sTmp := 'ERROR: MISSING ' + childFilename + ' (SHALL CONTAIN ' + DotNotationPart(sTmp) + ')!';
1123
      sTmp := 'ERROR: MISSING ' + childFilename + ' (SHALL CONTAIN ' + DotNotationPart(sTmp) + ')!';
1123
      sTmp := TrimLineToWidth(sTmp, TREEVIEW_WIDTH);
1124
      sTmp := TrimLineToWidth(sTmp, TREEVIEW_WIDTH);
1124
      ListAppend(visList, sTmp);
1125
      ListAppend(visList, sTmp);
1125
      ListAppend(targetList, 'ERROR');
1126
      ListAppend(targetList, 'ERROR');
1126
    end
1127
    end
1127
    else if not _ReadOidFile(childFilename, suboid, false) then
1128
    else if not _ReadOidFile(childFilename, suboid, false) then
1128
    begin
1129
    begin
1129
      sTmp := 'ERROR: READ ERROR AT ' + childFilename + ' (SHALL CONTAIN ' + DotNotationPart(sTmp) + ')!';
1130
      sTmp := 'ERROR: READ ERROR AT ' + childFilename + ' (SHALL CONTAIN ' + DotNotationPart(sTmp) + ')!';
1130
      sTmp := TrimLineToWidth(sTmp, TREEVIEW_WIDTH);
1131
      sTmp := TrimLineToWidth(sTmp, TREEVIEW_WIDTH);
1131
      ListAppend(visList, sTmp);
1132
      ListAppend(visList, sTmp);
1132
      ListAppend(targetList, 'ERROR');
1133
      ListAppend(targetList, 'ERROR');
1133
    end
1134
    end
1134
    else if (suboid^.ParentFileId <> oid^.FileId) or
1135
    else if (suboid^.ParentFileId <> oid^.FileId) or
1135
            (suboid^.ParentDotNotation <> oid^.DotNotation) then
1136
            (suboid^.ParentDotNotation <> oid^.DotNotation) then
1136
    begin
1137
    begin
1137
      (* This can happen if a file is missing, and then another OID gets this filename since the number seems to be free *)
1138
      (* This can happen if a file is missing, and then another OID gets this filename since the number seems to be free *)
1138
      sTmp := 'ERROR: BAD BACKREF AT ' + childFilename + ' (SHALL CONTAIN ' + DotNotationPart(sTmp) + ')!';
1139
      sTmp := 'ERROR: BAD BACKREF AT ' + childFilename + ' (SHALL CONTAIN ' + DotNotationPart(sTmp) + ')!';
1139
      sTmp := TrimLineToWidth(sTmp, TREEVIEW_WIDTH);
1140
      sTmp := TrimLineToWidth(sTmp, TREEVIEW_WIDTH);
1140
      ListAppend(visList, sTmp);
1141
      ListAppend(visList, sTmp);
1141
      ListAppend(targetList, 'ERROR');
1142
      ListAppend(targetList, 'ERROR');
1142
    end
1143
    end
1143
    else
1144
    else
1144
    begin
1145
    begin
1145
      _RecTreeExport(suboid, visList, targetList, indent+1);
1146
      _RecTreeExport(suboid, visList, targetList, indent+1);
1146
      FreeOidDef(suboid);
1147
      FreeOidDef(suboid);
1147
    end
1148
    end
1148
  end;
1149
  end;
1149
end;
1150
end;
1150
 
1151
 
1151
procedure TreeViewPreview(visList, targetList: PStringList);
1152
procedure TreeViewPreview(visList, targetList: PStringList);
1152
var
1153
var
1153
  res: integer;
1154
  res: integer;
1154
  sTmp: string;
1155
  sTmp: string;
1155
begin
1156
begin
1156
  ClrScr;
1157
  ClrScr;
1157
  DrawTitleBar('TreeView Export', TITLEBAR_LEFT_TEXT, TREEVIEW_FILENAME);
1158
  DrawTitleBar('TreeView Export', TITLEBAR_LEFT_TEXT, TREEVIEW_FILENAME);
1158
  DrawStatusBar('Press ESC to return to the main menu. Enter to jump to OID.');
1159
  DrawStatusBar('Press ESC to return to the main menu. Enter to jump to OID.');
1159
 
1160
 
1160
  while true do
1161
  while true do
1161
  begin
1162
  begin
1162
    res := DrawSelectionList(2, 3, ScreenWidth-2, ScreenHeight-4,
1163
    res := DrawSelectionList(2, 3, ScreenWidth-2, ScreenHeight-4,
1163
                             visList, true, 'PREVIEW OF '+TREEVIEW_FILENAME, 2);
1164
                             visList, true, 'PREVIEW OF '+TREEVIEW_FILENAME, 2);
1164
    if res > -1 then
1165
    if res > -1 then
1165
    begin
1166
    begin
1166
      (* Jump to selected OID or show error *)
1167
      (* Jump to selected OID or show error *)
1167
      sTmp := ListGetElement(targetList, res);
1168
      sTmp := ListGetElement(targetList, res);
1168
      if sTmp = 'ERROR' then
1169
      if sTmp = 'ERROR' then
1169
      begin
1170
      begin
1170
        ShowMessage(ListGetElement(visList, res), 'ERROR', true);
1171
        ShowMessage(ListGetElement(visList, res), 'ERROR', true);
1171
        _Pause;
1172
        _Pause;
1172
      end
1173
      end
1173
      else
1174
      else
1174
      begin
1175
      begin
1175
        DisplayOidFile(sTmp + '.OID', 'TreeView Export');
1176
        DisplayOidFile(sTmp + '.OID', 'TreeView Export');
1176
      end;
1177
      end;
1177
    end
1178
    end
1178
    else
1179
    else
1179
    begin
1180
    begin
1180
      break;
1181
      break;
1181
    end;
1182
    end;
1182
  end;
1183
  end;
1183
 
1184
 
1184
  DrawStatusBar('');
1185
  DrawStatusBar('');
1185
end;
1186
end;
1186
 
1187
 
1187
procedure OP_TreeView;
1188
procedure OP_TreeView;
1188
var
1189
var
1189
  F: Text;
1190
  F: Text;
1190
  rootoid: POID;
1191
  rootoid: POID;
1191
  rootfile: string;
1192
  rootfile: string;
1192
  res: boolean;
1193
  res: boolean;
1193
  visList, targetList: PStringList;
1194
  visList, targetList: PStringList;
1194
begin
1195
begin
1195
  ClrScr;
1196
  ClrScr;
1196
  DrawTitleBar('TreeView Export', TITLEBAR_LEFT_TEXT, '');
1197
  DrawTitleBar('TreeView Export', TITLEBAR_LEFT_TEXT, '');
1197
  DrawStatusBar('Exporting data... please wait...');
1198
  DrawStatusBar('Exporting data... please wait...');
1198
 
1199
 
1199
  (* This will try creating a new root file if it does not exist *)
1200
  (* This will try creating a new root file if it does not exist *)
1200
  rootfile := _GetRootFile(true);
1201
  rootfile := _GetRootFile(true);
1201
  if rootfile = '' then
1202
  if rootfile = '' then
1202
  begin
1203
  begin
1203
    DrawStatusBar('');
1204
    DrawStatusBar('');
1204
    Exit;
1205
    Exit;
1205
  end;
1206
  end;
1206
 
1207
 
1207
  CreateList(visList);
1208
  CreateList(visList);
1208
  CreateList(targetList);
1209
  CreateList(targetList);
1209
 
1210
 
1210
  (* First check if the disk is read-only *)
1211
  (* First check if the disk is read-only *)
1211
  Assign(F, TREEVIEW_FILENAME);
1212
  Assign(F, TREEVIEW_FILENAME);
1212
  {$I-}
1213
  {$I-}
1213
  Rewrite(F);
1214
  Rewrite(F);
1214
  {$I+}
1215
  {$I+}
1215
  if IoResult <> 0 then
1216
  if IoResult <> 0 then
1216
  begin
1217
  begin
1217
    (* Can happen if disk is read-only (Runtime Error 150) *)
1218
    (* Can happen if disk is read-only (Runtime Error 150) *)
1218
    ShowMessage('Cannot open '+TREEVIEW_FILENAME+' for writing.', 'ERROR', true);
1219
    ShowMessage('Cannot open '+TREEVIEW_FILENAME+' for writing.', 'ERROR', true);
1219
    _Pause;
1220
    _Pause;
1220
    DrawStatusBar('');
1221
    DrawStatusBar('');
1221
    Exit;
1222
    Exit;
1222
  end;
1223
  end;
1223
  Close(F);
1224
  Close(F);
1224
 
1225
 
1225
  (* Now do the export *)
1226
  (* Now do the export *)
1226
  res := false;
1227
  res := false;
1227
  CreateOidDef(rootoid);
1228
  CreateOidDef(rootoid);
1228
  if _ReadOidFile(rootfile, rootoid, true) then
1229
  if _ReadOidFile(rootfile, rootoid, true) then
1229
  begin
1230
  begin
1230
    _RecTreeExport(rootoid, visList, targetList, 0);
1231
    _RecTreeExport(rootoid, visList, targetList, 0);
1231
    res := true;
1232
    res := true;
1232
  end;
1233
  end;
1233
  FreeOidDef(rootoid);
1234
  FreeOidDef(rootoid);
1234
 
1235
 
1235
  (* Save the list (visual part only) *)
1236
  (* Save the list (visual part only) *)
1236
  ListSaveToFile(visList, TREEVIEW_FILENAME);
1237
  ListSaveToFile(visList, TREEVIEW_FILENAME);
1237
 
1238
 
1238
  DrawStatusBar('');
1239
  DrawStatusBar('');
1239
  if res then
1240
  if res then
1240
  begin
1241
  begin
1241
    ShowMessage('TreeView successfully exported as '+TREEVIEW_FILENAME, 'TREEVIEW EXPORT', true);
1242
    ShowMessage('TreeView successfully exported as '+TREEVIEW_FILENAME, 'TREEVIEW EXPORT', true);
1242
    _Pause;
1243
    _Pause;
1243
  end;
1244
  end;
1244
 
1245
 
1245
  TreeViewPreview(visList, targetList);
1246
  TreeViewPreview(visList, targetList);
1246
 
1247
 
1247
  FreeList(visList);
1248
  FreeList(visList);
1248
  FreeList(targetList);
1249
  FreeList(targetList);
1249
end;
1250
end;
1250
 
1251
 
1251
procedure OP_MainMenu;
1252
procedure OP_MainMenu;
1252
var
1253
var
1253
  menu: PStringList;
1254
  menu: PStringList;
1254
  menuRes, menuLeft, menuTop: integer;
1255
  menuRes, menuLeft, menuTop: integer;
1255
  menuIdOID, menuIdTree, menuIdExit: integer;
1256
  menuIdOID, menuIdTree, menuIdExit: integer;
1256
begin
1257
begin
1257
  repeat
1258
  repeat
1258
    ClrScr;
1259
    ClrScr;
1259
 
1260
 
1260
    DrawTitleBar('Welcome to OIDplus for DOS', '', '');
1261
    DrawTitleBar('Welcome to OIDplus for DOS', '', '');
1261
    DrawStatusBar('(C)2020-2022 ViaThinkSoft. Licensed under the terms of the Apache 2.0 license.');
1262
    DrawStatusBar('(C)2020-2022 ViaThinkSoft. Licensed under the terms of the Apache 2.0 license.');
1262
    GoToXY(ScreenWidth-Length(VERSIONINFO), ScreenHeight-1);
1263
    GoToXY(ScreenWidth-Length(VERSIONINFO), ScreenHeight-1);
1263
    Write(VERSIONINFO);
1264
    Write(VERSIONINFO);
1264
 
1265
 
1265
    CreateList(menu);
1266
    CreateList(menu);
1266
 
1267
 
1267
    menuIdOID  := ListAppend(menu, 'Manage OIDs');
1268
    menuIdOID  := ListAppend(menu, 'Manage OIDs');
1268
    menuIdTree := ListAppend(menu, 'Export TreeView');
1269
    menuIdTree := ListAppend(menu, 'Export TreeView');
1269
    menuIdExit := ListAppend(menu, 'Return to DOS');
1270
    menuIdExit := ListAppend(menu, 'Return to DOS');
1270
 
1271
 
1271
    menuLeft := round(ScreenWidth/2 -MAINMENU_WIDTH/2);
1272
    menuLeft := round(ScreenWidth/2 -MAINMENU_WIDTH/2);
1272
    menuTop  := round(ScreenHeight/2-MAINMENU_HEIGHT/2);
1273
    menuTop  := round(ScreenHeight/2-MAINMENU_HEIGHT/2);
1273
    menuRes  := DrawSelectionList(menuLeft, menuTop,
1274
    menuRes  := DrawSelectionList(menuLeft, menuTop,
1274
                                  MAINMENU_WIDTH, MAINMENU_HEIGHT,
1275
                                  MAINMENU_WIDTH, MAINMENU_HEIGHT,
1275
                                  menu, true, 'MAIN MENU', 2);
1276
                                  menu, true, 'MAIN MENU', 2);
1276
    FreeList(menu);
1277
    FreeList(menu);
1277
 
1278
 
1278
    if menuRes = menuIdOID then
1279
    if menuRes = menuIdOID then
1279
    begin
1280
    begin
1280
      OP_ManageOIDs;
1281
      OP_ManageOIDs;
1281
    end
1282
    end
1282
    else if menuRes = menuIdTree then
1283
    else if menuRes = menuIdTree then
1283
    begin
1284
    begin
1284
      OP_Treeview;
1285
      OP_Treeview;
1285
    end;
1286
    end;
1286
  until (menuRes = menuIdExit) or (MAINMENU_ALLOW_ESC and (menuRes = -1));
1287
  until (menuRes = menuIdExit) or (MAINMENU_ALLOW_ESC and (menuRes = -1));
1287
 
1288
 
1288
  OP_ReturnToMSDOS;
1289
  OP_ReturnToMSDOS;
1289
end;
1290
end;
1290
 
1291
 
1291
begin
1292
begin
1292
  InitVideo; (* sets ScreenWidth and ScreenHeight *)
1293
  InitVideo; (* sets ScreenWidth and ScreenHeight *)
1293
  CursorOff;
1294
  CursorOff;
1294
  OP_MainMenu;
1295
  OP_MainMenu;
1295
  CursorOn;
1296
  CursorOn;
1296
  DoneVideo;
1297
  DoneVideo;
1297
end.
1298
end.
1298
 
1299