1 (* Copyright (C) DooM 2D:Forever Developers
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *)
16 {$INCLUDE a_modes.inc}
19 interface
21 uses
22 Classes,
26 // ////////////////////////////////////////////////////////////////////////// //
27 type
37 // this is base type for all scalars (and arrays)
39 public
40 type
41 TType = (TBool, TChar, TByte, TUByte, TShort, TUShort, TInt, TUInt, TString, TPoint, TSize, TList, TTrigData);
42 // TPoint: pair of Integers
43 // TSize: pair of UShorts
44 // TList: actually, array of records
45 // TTrigData: array of mMaxDim bytes, but internally a record (mRecRef)
46 // arrays of chars are pascal shortstrings (with counter in the first byte)
51 private
52 type
55 private
76 // default value
83 mEBSType: TObject; // either TDynRecord or TDynEBS; nil means "simple type"; nil for `TTrigData` too
85 // for binary parser
88 private
93 procedure parseDefaultValue (); // parse `mDefUnparsed` to `mDefSVal`, `mDefIVal`, `mDefIVal2`, `mDefRecRef`
97 public
114 // won't work for lists
119 public
140 // "value" header record contains TList fields, with name equal to record type
142 private
152 mHeaderRec: TDynRecord; // for "value" records this is header record with data, for "type" records this is header type record
154 private
164 protected
169 public
186 // find field with `TriggerType` type
189 public
203 private
212 private
221 public
227 // return empty string if not found
230 public
239 public
244 private
249 public
257 // creates new header record
260 // creates new header record
263 public
268 implementation
270 uses
271 SysUtils;
274 // ////////////////////////////////////////////////////////////////////////// //
276 begin
287 begin
294 begin
301 begin
335 var
337 begin
348 begin
351 end
352 else
353 begin
380 // won't work for lists
382 begin
400 begin
410 var
412 begin
414 try
416 finally
423 var
429 begin
431 begin
436 end
437 else
438 begin
444 try
451 finally
463 // default value should be parsed
465 begin
468 begin
470 raise Exception.Create(Format('field ''%s'' in record ''%s'' of record type ''%s'' is not set', [mName, mOwner.mId, mOwner.mName]));
480 // default value should be parsed
482 begin
495 begin
516 begin
525 TEBS.TBitSet: begin result += ' bitset '; if mBitSetUnique then result += 'unique '; result += mEBSTypeName; end;
529 begin
530 if (mType = TType.TPoint) then begin if (mAsT) then result += ' as txy' else result += ' as xy'; end
531 else if (mType = TType.TSize) then begin if (mAsT) then result += ' as twh' else result += ' as wh'; end;
539 var
556 begin
577 // field name
580 // field type
584 // fixed-size array?
586 begin
588 if (lmaxdim < 1) then raise Exception.Create(Format('invalid field ''%s'' array size', [fldname]));
593 begin
595 begin
596 if (fldofs >= 0) then raise Exception.Create(Format('duplicate field ''%s'' offset', [fldname]));
599 continue;
603 begin
609 continue;
613 begin
615 if (Length(fldrecname) <> 0) then raise Exception.Create(Format('field ''%s'' already typed as ''%s''', [fldname, fldrecname]));
617 continue;
621 begin
623 if (Length(fldrecname) <> 0) then raise Exception.Create(Format('field ''%s'' already typed as ''%s''', [fldname, fldrecname]));
626 continue;
630 begin
631 if hasdefStr or hasdefInt or hasdefId then raise Exception.Create(Format('field ''%s'' has duplicate default', [fldname]));
634 begin
639 begin
644 begin
648 else
651 continue;
655 begin
657 continue;
661 begin
663 continue;
666 if (pr.tokType <> pr.TTId) then raise Exception.Create(Format('field ''%s'' has something unexpected in definition', [fldname]));
668 if (Length(fldrecname) <> 0) then raise Exception.Create(Format('field ''%s'' already typed as ''%s''', [fldname, fldrecname]));
675 // create field
690 else raise Exception.Create(Format('field ''%s'' has invalid type ''%s''', [fldname, fldtype]));
692 if (lmaxdim > 0) and (mType <> TType.TChar) and (mType <> TType.TTrigData) then raise Exception.Create(Format('field ''%s'' of type ''%s'' cannot be array', [fldname, fldtype]));
694 begin
695 if (lmaxdim < 1) then raise Exception.Create(Format('field ''%s'' of type ''%s'' cannot be array', [fldname, fldtype]));
696 if (Length(fldrecname) > 0) then raise Exception.Create(Format('field ''%s'' of type ''%s'' cannot have another type', [fldname, fldtype]));
720 var
726 begin
730 begin
732 begin
733 // this must be triggerdata
735 begin
736 raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
738 // write triggerdata
740 if (buf = nil) then raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
741 try
744 begin
749 finally
753 exit;
755 // record reference
757 begin
758 // no ref, write -1
763 else raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
765 exit;
774 else raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
776 // find record number
778 if (f < 0) then raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' not found in record list', [mEBSTypeName, mName]));
779 if (f > maxv) then raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' has too big index', [mEBSTypeName, mName]));
784 else raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
786 exit;
795 begin
797 begin
799 end
800 else
801 begin
804 exit;
807 begin
808 if (mMaxDim = 0) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
810 begin
811 if (Length(mSVal) <> 1) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
813 end
814 else
815 begin
816 if (Length(mSVal) > mMaxDim) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
821 exit;
825 begin
826 // triggerdata array was processed earlier
827 if (mMaxDim >= 0) then Exception.Create(Format('byte array in field ''%s'' cannot be written', [mName]));
829 exit;
833 begin
834 if (mMaxDim >= 0) then raise Exception.Create(Format('short array in field ''%s'' cannot be written', [mName]));
836 exit;
840 begin
841 if (mMaxDim >= 0) then raise Exception.Create(Format('int array in field ''%s'' cannot be written', [mName]));
843 exit;
846 begin
850 begin
851 if (mMaxDim >= 0) then raise Exception.Create(Format('pos/size array in field ''%s'' cannot be written', [mName]));
854 exit;
857 begin
858 if (mMaxDim >= 0) then raise Exception.Create(Format('pos/size array in field ''%s'' cannot be written', [mName]));
861 exit;
864 begin
866 exit;
869 begin
871 exit;
879 var
883 begin
889 begin
891 begin
893 end
895 begin
897 end
898 else
899 begin
903 exit;
906 begin
907 //def := mOwner.mOwner;
908 //es := def.findEBSType(mEBSTypeName);
911 if (es = nil) or (not es.mIsEnum) then raise Exception.Create(Format('record enum type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
913 begin
915 begin
918 exit;
921 raise Exception.Create(Format('value %d in record enum type ''%s'' for field ''%s'' not found', [mIVal, mEBSTypeName, mName]));
924 begin
925 //def := mOwner.mOwner;
926 //es := def.findEBSType(mEBSTypeName);
929 if (es = nil) or es.mIsEnum then raise Exception.Create(Format('record bitset type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
930 // none?
932 begin
934 begin
936 begin
939 exit;
942 raise Exception.Create(Format('value %d in record bitset type ''%s'' for field ''%s'' not found', [0, mEBSTypeName, mName]));
944 // not none
948 begin
950 begin
953 begin
955 begin
959 break;
962 if not found then raise Exception.Create(Format('value %d in record bitset type ''%s'' for field ''%s'' not found', [mask, mEBSTypeName, mName]));
967 exit;
974 begin
976 exit;
979 begin
980 if (mMaxDim = 0) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
983 exit;
991 begin
993 exit;
996 begin
999 exit;
1003 begin
1005 exit;
1008 begin
1010 exit;
1013 begin
1015 exit;
1023 var
1030 begin
1034 begin
1035 // this must be triggerdata
1037 begin
1040 // find trigger definition
1042 if (tfld = nil) then raise Exception.Create(Format('triggerdata value for field ''%s'' in record ''%s'' without TriggerType field', [mName, rec.mName]));
1044 if (rc = nil) then raise Exception.Create(Format('triggerdata definition for field ''%s'' in record ''%s'' with type ''%s'' not found', [mName, rec.mName, tfld.mSVal]));
1047 try
1051 finally
1055 exit;
1056 end
1057 else
1058 begin
1059 // not a trigger data
1067 else raise Exception.Create(Format('invalid non-numeric type ''%s'' for field ''%s'' of record ''%s''', [getTypeName(mType), mName, mEBSTypeName]));
1072 exit;
1076 begin
1085 else raise Exception.Create(Format('invalid non-numeric type ''%s'' for field ''%s'' of record ''%s''', [getTypeName(mType), mName, mEBSTypeName]));
1089 if (es = nil) or (es.mIsEnum <> (mEBS = TEBS.TEnum)) then raise Exception.Create(Format('record enum type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1091 // build enum/bitfield values
1093 begin
1095 if (Length(mSVal) = 0) then raise Exception.Create(Format('record enum type ''%s'' for field ''%s'' has invalid value %d', [mEBSTypeName, mName, mIVal]));
1096 end
1097 else
1098 begin
1099 // special for 'none'
1101 begin
1103 if (Length(mSVal) = 0) then raise Exception.Create(Format('record bitset type ''%s'' for field ''%s'' has invalid value %d', [mEBSTypeName, mName, mIVal]));
1104 end
1105 else
1106 begin
1110 begin
1112 begin
1114 if (Length(s) = 0) then raise Exception.Create(Format('record bitset type ''%s'' for field ''%s'' has invalid value %d', [mEBSTypeName, mName, mask]));
1122 //writeln('ebs <', es.mName, '>: ', mSVal);
1124 exit;
1131 begin
1137 exit;
1140 begin
1142 begin
1144 end
1145 else
1146 begin
1149 try
1154 begin
1159 finally
1164 exit;
1173 begin
1175 exit;
1178 begin
1182 exit;
1185 begin
1189 exit;
1192 begin
1194 exit;
1197 begin
1199 exit;
1210 begin
1212 if (mIVal < min) or (mIVal > max) then raise Exception.Create(Format('invalid %s value for field ''%s''', [getTypeName(mType), mName]));
1216 var
1222 begin
1223 // if this field should contain struct, convert type and parse struct
1227 begin
1228 // ugly hack. sorry.
1230 begin
1233 begin
1234 // '{}'
1237 end
1238 else
1239 begin
1241 // find trigger definition
1243 if (tfld = nil) then raise Exception.Create(Format('triggerdata value for field ''%s'' in record ''%s'' without ''type'' field', [mName, rec.mName]));
1245 if (rc = nil) then raise Exception.Create(Format('triggerdata definition for field ''%s'' in record ''%s'' with type ''%s'' not found', [mName, rec.mName, tfld.mSVal]));
1248 //writeln(rc.definition);
1249 try
1253 finally
1259 exit;
1261 // other record types
1263 begin
1265 begin
1267 end
1268 else
1269 begin
1271 if (rec = nil) then raise Exception.Create(Format('record ''%s'' (%s) value for field ''%s'' not found', [pr.tokStr, mEBSTypeName, mName]));
1277 exit;
1278 end
1280 begin
1281 //rec := mOwner.mOwner.findRecType(mEBSTypeName); // find in mapdef
1284 if (rec = nil) then raise Exception.Create(Format('record type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1292 exit;
1297 begin
1298 //es := mOwner.mOwner.findEBSType(mEBSTypeName); // find in mapdef
1301 if (es = nil) or (not es.mIsEnum) then raise Exception.Create(Format('record enum type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1303 if not es.has[tk] then raise Exception.Create(Format('record enum value ''%s'' of type ''%s'' for field ''%s'' not found', [tk, mEBSTypeName, mName]));
1306 //writeln('ENUM ', mEBSName, '; element <', mSVal, '> with value ', mIVal);
1309 exit;
1312 begin
1313 //es := mOwner.mOwner.findEBSType(mEBSTypeName); // find in mapdef
1316 if (es = nil) or es.mIsEnum then raise Exception.Create(Format('record bitset type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1319 begin
1321 if not es.has[tk] then raise Exception.Create(Format('record bitset value ''%s'' of type ''%s'' for field ''%s'' not found', [tk, mEBSTypeName, mName]));
1325 if mBitSetUnique then raise Exception.Create(Format('record bitset of type ''%s'' for field ''%s'' expects only one value', [tk, mEBSTypeName, mName]));
1326 //pr.expectDelim('|');
1331 exit;
1338 begin
1344 exit;
1347 begin
1348 if (mMaxDim = 0) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
1351 begin
1352 // single char
1353 if (Length(mSVal) <> 1) then raise Exception.Create(Format('invalid string size for field ''%s''', [mName]));
1356 end
1357 else
1358 begin
1359 // string
1360 if (Length(mSVal) > mMaxDim) then raise Exception.Create(Format('invalid string size for field ''%s''', [mName]));
1364 exit;
1367 begin
1370 exit;
1373 begin
1376 exit;
1379 begin
1382 exit;
1385 begin
1388 exit;
1391 begin
1394 exit;
1397 begin
1400 exit;
1403 begin
1407 exit;
1411 begin
1415 begin
1416 if (mIVal < 0) or (mIVal > 32767) then raise Exception.Create(Format('invalid %s value for field ''%s''', [getTypeName(mType), mName]));
1420 begin
1421 if (mIVal2 < 0) or (mIVal2 > 32767) then raise Exception.Create(Format('invalid %s value for field ''%s''', [getTypeName(mType), mName]));
1426 exit;
1429 begin
1431 exit;
1434 begin
1436 exit;
1444 // ////////////////////////////////////////////////////////////////////////// //
1446 begin
1447 if (pr = nil) then raise Exception.Create('cannot create record type without type definition');
1461 begin
1472 begin
1483 begin
1486 begin
1495 begin
1501 var
1503 begin
1510 begin
1516 var
1518 begin
1526 var
1529 begin
1537 begin
1550 var
1553 begin
1556 // find record data
1559 if (fld.mType <> fld.TType.TList) then raise Exception.Create(Format('cannot get record of type ''%s'' due to name conflict with ordinary field', [atypename]));
1560 // find by id
1562 begin
1564 begin
1568 // alas
1572 function TDynRecord.findRecordNumByType (const atypename: AnsiString; rc: TDynRecord): Integer;
1573 var
1576 begin
1578 // find record data
1581 if (fld.mType <> fld.TType.TList) then raise Exception.Create(Format('cannot get record of type ''%s'' due to name conflict with ordinary field', [atypename]));
1582 // find by ref
1584 begin
1586 begin
1590 // alas
1595 var
1597 begin
1598 // find record data
1601 begin
1602 // first record
1607 if (fld.mType <> fld.TType.TList) then raise Exception.Create(Format('cannot append record of type ''%s'' due to name conflict with ordinary field', [atypename]));
1608 // append
1615 var
1617 begin
1623 begin
1631 var
1634 begin
1636 begin
1648 var
1651 begin
1653 begin
1656 begin
1658 begin
1662 if isForTrig[tdn] then raise Exception.Create(Format('duplicate trigdata ''%s'' trigtype ''%s''', [mName, tdn]));
1666 end
1667 else
1668 begin
1674 end
1675 else
1676 begin
1681 begin
1684 begin
1685 if (mSize > 0) then raise Exception.Create(Format('duplicate `size` in record ''%s''', [mName]));
1687 if (mSize < 1) then raise Exception.Create(Format('invalid record ''%s'' size: %d', [mName, mSize]));
1689 continue;
1692 begin
1693 if (mBinBlock >= 0) then raise Exception.Create(Format('duplicate `binblock` in record ''%s''', [mName]));
1695 if (mBinBlock < 1) then raise Exception.Create(Format('invalid record ''%s'' binblock: %d', [mName, mBinBlock]));
1696 continue;
1702 // load fields
1704 begin
1706 if hasByName(fld.name) then begin fld.Free(); raise Exception.Create(Format('duplicate field ''%s''', [fld.name])); end;
1707 // append
1710 // done with field
1717 var
1719 begin
1721 begin
1722 // trigger data
1725 begin
1728 begin
1733 end
1734 else
1735 begin
1738 end
1739 else
1740 begin
1741 // record
1748 begin
1758 var
1770 var
1773 begin
1774 //writeln('*** rec: ', rec.mName, '.', rec.mId, ' (', rec.mFields.count, ')');
1776 begin
1778 begin
1780 continue;
1785 if (rt = nil) then raise Exception.Create(Format('record of type ''%s'' with id ''%s'' links to inexistant record of type ''%s'' with id ''%d''', [rec.mName, rec.mId, fld.mEBSTypeName, fld.mRecRefId]));
1786 //writeln(' ', rec.mName, '.', rec.mId, ':', fld.mName, ' -> ', rt.mName, '.', rt.mId, ' (', fld.mEBSTypeName, '.', fld.mRecRefId, ')');
1792 begin
1793 //writeln(' ', fld.mName);
1798 begin
1801 try
1803 begin
1804 // parse map file as sequence of blocks
1808 // parse blocks
1810 begin
1816 if (bsize < 0) or (bsize > $1fffffff) then raise Exception.Create(Format('block of type %d has invalid size %d', [btype, bsize]));
1817 if loaded[btype] then raise Exception.Create(Format('block of type %d already loaded', [btype]));
1819 // find record type for this block
1822 if (rect = nil) then raise Exception.Create(Format('block of type %d has no corresponding record', [btype]));
1824 if (rec.mSize = 0) or ((bsize mod rec.mSize) <> 0) then raise Exception.Create(Format('block of type %d has invalid number of records', [btype]));
1825 // header?
1827 begin
1828 if (bsize <> mSize) then raise Exception.Create(Format('header block of type %d has invalid number of records', [btype]));
1833 end
1834 else
1835 begin
1836 // create list for this type
1841 begin
1845 begin
1852 //writeln('parsed ''', rec.mId, '''...');
1858 //st.position := st.position+bsize;
1860 // link fields
1862 begin
1866 exit;
1869 // read fields
1871 if (mSize < 1) then raise Exception.Create(Format('cannot read record of type ''%s'' with unknown size', [mName]));
1875 begin
1878 if (fld.mBinOfs >= st.size) then raise Exception.Create(Format('record of type ''%s'' has invalid field ''%s''', [fld.mName]));
1880 //writeln('parsing ''', mName, '.', fld.mName, '''...');
1883 finally
1891 var
1897 //f, c: Integer;
1900 begin
1902 begin
1903 if (mBinBlock < 1) then raise Exception.Create('cannot write binary record without block number');
1906 end
1907 else
1908 begin
1911 try
1916 // write normal fields
1918 begin
1919 // record list?
1923 if (fld.mBinOfs >= bufsz) then raise Exception.Create('binary value offset is outside of the buffer');
1925 //writeln('writing field <', fld.mName, '>');
1929 // write block with normal fields
1931 begin
1932 //writeln('writing header...');
1933 // signature and version
1944 // write other blocks, if any
1946 begin
1947 // calculate blkmax
1950 begin
1951 // record list?
1953 begin
1961 // write blocks
1963 begin
1967 begin
1968 // record list?
1970 begin
1979 // flush block
1981 begin
1992 // write end marker
1997 finally
2005 var
2008 begin
2010 begin
2017 try
2019 begin
2020 // record list?
2022 begin
2025 begin
2027 begin
2033 continue;
2040 finally
2049 var
2052 begin
2053 if (mOwner = nil) then raise Exception.Create(Format('can''t parse record ''%s'' value without owner', [mName]));
2055 // not a header?
2057 begin
2058 // id?
2060 end
2061 else
2062 begin
2066 //writeln('parsing record <', mName, '>');
2069 begin
2071 //writeln('<', mName, '.', pr.tokStr, '>');
2073 // records
2075 begin
2076 // add records with this type (if any)
2079 begin
2082 try
2086 begin
2089 begin
2091 begin
2092 if (Length(rv.mId) > 0) and (CompareText(rv.mId, rec.mId) = 0) then raise Exception.Create(Format('duplicate thing ''%s'' in record ''%s''', [fld.mName, mName]));
2098 finally
2101 continue;
2105 // fields
2108 begin
2109 if fld.defined then raise Exception.Create(Format('duplicate field ''%s'' in record ''%s''', [fld.mName, mName]));
2110 if fld.internal then raise Exception.Create(Format('internal field ''%s'' in record ''%s''', [fld.mName, mName]));
2113 continue;
2116 // something is wrong
2120 // fix field defaults
2122 //writeln('done parsing record <', mName, '>');
2126 // ////////////////////////////////////////////////////////////////////////// //
2128 begin
2135 begin
2142 begin
2153 begin
2156 begin
2165 begin
2171 var
2173 begin
2180 var
2182 begin
2186 // fields
2189 begin
2193 begin
2197 end
2198 else
2199 begin
2204 // max field
2211 var
2213 begin
2215 begin
2223 var
2229 begin
2238 begin
2241 begin
2242 if (CompareText(mIds[f], idname) = 0) then raise Exception.Create(Format('duplicate field ''%s'' in enum/bitset ''%s''', [idname, mName]));
2244 if (CompareText(mMaxName, idname) = 0) then raise Exception.Create(Format('duplicate field ''%s'' in enum/bitset ''%s''', [idname, mName]));
2248 // has value?
2250 begin
2252 begin
2253 if (Length(mMaxName) > 0) then raise Exception.Create(Format('duplicate max field ''%s'' in enum/bitset ''%s''', [idname, mName]));
2256 end
2257 else
2258 begin
2264 // append it?
2266 begin
2267 // fix maxvalue
2269 begin
2276 // next cv
2278 begin
2287 // add max field
2289 begin
2298 // ////////////////////////////////////////////////////////////////////////// //
2300 begin
2309 var
2312 begin
2327 begin
2334 var
2336 begin
2338 begin
2346 var
2348 begin
2350 begin
2358 var
2360 begin
2362 begin
2370 var
2375 // setup header links and type links
2377 var
2379 begin
2382 begin
2387 begin
2389 if (fld.mEBSType = nil) then raise Exception.Create(Format('field ''%s'' of type ''%s'' has no correcponding record definition', [fld.mName, fld.mEBSTypeName]));
2393 begin
2395 if (fld.mEBSType = nil) then raise Exception.Create(Format('field ''%s'' of type ''%s'' has no correcponding enum/bitset', [fld.mName, fld.mEBSTypeName]));
2396 if ((fld.mEBS = TDynField.TEBS.TEnum) <> (fld.mEBSType as TDynEBS).mIsEnum) then raise Exception.Create(Format('field ''%s'' of type ''%s'' enum/bitset type conflict', [fld.mName, fld.mEBSTypeName]));
2402 // setup default values
2404 var
2406 begin
2410 begin
2413 begin
2418 begin
2421 begin
2427 //writeln(eb.definition); writeln;
2428 continue;
2432 begin
2435 begin
2437 begin
2444 //writeln(dr.definition); writeln;
2445 continue;
2449 //writeln(dr.definition); writeln;
2450 if (findRecType(rec.name) <> nil) then begin rec.Free(); raise Exception.Create(Format('duplicate record ''%s''', [rec.name])); end;
2451 if (hdr <> nil) and (CompareText(rec.name, hdr.name) = 0) then begin rec.Free(); raise Exception.Create(Format('duplicate record ''%s''', [rec.name])); end;
2454 begin
2455 if (hdr <> nil) then begin rec.Free(); raise Exception.Create(Format('duplicate header record ''%s'' (previous is ''%s'')', [rec.name, hdr.name])); end;
2457 end
2458 else
2459 begin
2464 // put header record to top
2470 // setup header links and type links
2474 // setup default values
2480 // ////////////////////////////////////////////////////////////////////////// //
2482 var
2484 begin
2486 try
2494 begin
2503 var
2505 begin
2507 try
2514 begin