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
31 // this is base type for all scalars (and arrays)
33 public
34 type
35 TType = (TBool, TChar, TByte, TUByte, TShort, TUShort, TInt, TUInt, TString, TPoint, TSize, TList, TTrigData);
36 // TPoint: pair of Shorts
37 // TSize: pair of UShorts
38 // TList: actually, array of records
39 // TTrigData: array of bytes
40 // arrays of chars are pascal shortstrings (with counter in the first byte)
42 type
46 private
47 type
50 private
60 //mRecRefOwned: Boolean; // was mRecRef created from inline definition?
71 // default values
78 // temp
81 private
92 public
109 // won't work for lists
112 public
137 private
148 private
158 public
173 public
187 private
196 private
205 public
211 public
220 private
223 private
228 public
233 private
238 public
250 public
255 implementation
257 uses
258 SysUtils,
259 utils;
262 // ////////////////////////////////////////////////////////////////////////// //
264 begin
267 //mRecRefOwned := false;
275 begin
282 begin
289 begin
296 //if mRecRefOwned then mRecRef.Free();
298 //mRecRefOwned := false;
319 var
321 begin
333 {
334 result.mRecRefOwned := mRecRefOwned;
335 if mRecRefOwned then
336 begin
337 if (mRecRef <> nil) then result.mRecRef := mRecRef.clone();
338 end
339 else
340 begin
341 result.mRecRef := mRecRef;
342 end;
343 }
364 procedure TDynField.setSVal (const v: AnsiString); inline; begin mSVal := v; mDefined := true; end;
367 // won't work for lists
369 begin
393 var
396 begin
398 begin
400 begin
402 raise Exception.Create(Format('field ''%s'' in record ''%s'' of record type ''%s'' is not set', [mName, mOwner.mId, mOwner.mName]));
405 begin
406 if (CompareText(mDefSVal, 'null') <> 0) then raise Exception.Create(Format('field ''%s'' in record ''%s'' of record type ''%s'' has non-null default value ''%s''', [mName, mOwner.mId, mOwner.mName, mDefSVal]));
410 exit;
418 //mDefined := true;
419 //writeln('DEFAULT for <', mName, '>: <', s, '>');
421 try
423 finally
433 var
437 begin
439 //result := mDefaultValueSet;
444 TType.TPoint, TType.TSize: begin result := false; exit; end; // no default values for these types yet
448 try
452 finally
460 begin
481 begin
490 TEBS.TBitSet: begin result += ' bitset '; if mBitSetUnique then result += 'unique '; result += mEBSTypeName; end;
493 begin
494 if (mType = TType.TChar) or (mType = TType.TString) then result += ' default '+TTextParser.quote(mDefSVal)
496 {
497 else
498 begin
499 if (mType = TType.TBool) then
500 begin
501 result += ' default ';
502 if (mDefIVal <> 0) then result += 'true' else result += 'false';
503 end
504 else
505 begin
506 result += Format(' default %d', [mDefIVal]);
507 end;
508 end;
509 }
512 begin
513 if (mType = TType.TPoint) then begin if (mAsT) then result += ' as txy' else result += ' as xy'; end
514 else if (mType = TType.TSize) then begin if (mAsT) then result += ' as twh' else result += ' as wh'; end;
522 var
539 begin
560 // field name
563 // field type
567 // fixed-size array?
569 begin
571 if (lmaxdim < 1) then raise Exception.Create(Format('invali field ''%s'' array size', [fldname]));
576 begin
578 begin
579 if (fldofs >= 0) then raise Exception.Create(Format('duplicate field ''%s'' offset', [fldname]));
582 continue;
586 begin
592 continue;
596 begin
598 if (Length(fldrecname) <> 0) then raise Exception.Create(Format('field ''%s'' already typed as ''%s''', [fldname, fldrecname]));
600 continue;
604 begin
606 if (Length(fldrecname) <> 0) then raise Exception.Create(Format('field ''%s'' already typed as ''%s''', [fldname, fldrecname]));
609 continue;
613 begin
614 if hasdefStr or hasdefInt or hasdefId then raise Exception.Create(Format('field ''%s'' has duplicate default', [fldname]));
617 begin
622 begin
627 begin
631 else
634 continue;
638 begin
640 continue;
644 begin
646 continue;
649 if (pr.tokType <> pr.TTId) then raise Exception.Create(Format('field ''%s'' has something unexpected in definition', [fldname]));
651 if (Length(fldrecname) <> 0) then raise Exception.Create(Format('field ''%s'' already typed as ''%s''', [fldname, fldrecname]));
658 // create field
673 else raise Exception.Create(Format('field ''%s'' has invalid type ''%s''', [fldname, fldtype]));
675 {if hasdefId and (self.baseType = self.TType.TBool) then
676 begin
677 if (defstr = 'true') or (defstr = 'tan') or (defstr = 'yes') then self.mDefIVal := 1
678 else if (defstr = 'false') or (defstr = 'ona') or (defstr = 'no') then self.mDefIVal := 0
679 else raise Exception.Create(Format('field ''%s'' has invalid boolean default ''%s''', [fldname, defstr]));
680 end
681 else}
682 begin
704 var
710 begin
714 begin
715 // this must be byte/word/int
717 begin
718 // this must be triggerdata
720 begin
721 raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
723 // write triggerdata
726 else raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
728 //writeln('trigdata size: ', mMaxDim);
730 if (buf = nil) then raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
731 try
734 begin
739 finally
743 exit;
746 begin
747 // no ref, write -1
752 else raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
754 exit;
763 else raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
765 // find record number
767 if (f < 0) then raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' not found in record list', [mEBSTypeName, mName]));
768 if (f > maxv) then raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' has too big index', [mEBSTypeName, mName]));
773 else raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
775 exit;
784 begin
786 exit;
789 begin
790 if (mMaxDim = 0) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
792 begin
793 if (Length(mSVal) <> 1) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
795 end
796 else
797 begin
798 if (Length(mSVal) > mMaxDim) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
799 //FillChar(s[0], sizeof(s), 0);
801 //writeln('writing char[', mMaxDim, '] <', mName, '>: ', TTextParser.quote(s));
805 exit;
809 begin
810 // either array, and this should be triggerdata, or byte
812 begin
813 // byte
815 end
816 else
817 begin
818 // array
821 exit;
825 begin
826 if (mMaxDim > 0) then raise Exception.Create(Format('short array in field ''%s'' cannot be written', [mName]));
828 exit;
832 begin
833 if (mMaxDim > 0) then raise Exception.Create(Format('int array in field ''%s'' cannot be written', [mName]));
835 exit;
838 begin
843 begin
844 if (mMaxDim > 0) then raise Exception.Create(Format('pos/size array in field ''%s'' cannot be written', [mName]));
847 exit;
850 begin
852 exit;
855 begin
857 exit;
865 var
870 begin
873 // if this field should contain struct, convert type and parse struct
877 begin
879 begin
881 end
883 begin
885 end
886 else
887 begin
891 exit;
894 begin
897 if (es = nil) then raise Exception.Create(Format('record enum type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
899 begin
901 begin
904 exit;
907 raise Exception.Create(Format('value %d in record enum type ''%s'' for field ''%s'' not found', [mIVal, mEBSTypeName, mName]));
910 begin
913 if (es = nil) then raise Exception.Create(Format('record bitset type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
914 // none?
916 begin
918 begin
920 begin
923 exit;
926 raise Exception.Create(Format('value %d in record bitset type ''%s'' for field ''%s'' not found', [0, mEBSTypeName, mName]));
928 // not none
932 begin
934 begin
937 begin
939 begin
943 break;
946 if not found then raise Exception.Create(Format('value %d in record bitset type ''%s'' for field ''%s'' not found', [mask, mEBSTypeName, mName]));
951 exit;
958 begin
960 exit;
963 begin
964 if (mMaxDim = 0) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
967 exit;
975 begin
977 exit;
980 begin
983 exit;
987 begin
989 exit;
992 begin
994 exit;
997 begin
999 exit;
1010 begin
1012 if (mIVal < min) or (mIVal > max) then raise Exception.Create(Format('invalid %s value for field ''%s''', [getTypeName(mType), mName]));
1016 var
1022 begin
1023 // if this field should contain struct, convert type and parse struct
1027 begin
1029 // ugly hack. sorry.
1031 begin
1033 // find trigger definition
1035 if (tfld = nil) then raise Exception.Create(Format('triggerdata value for field ''%s'' in record ''%s'' without ''type'' field', [mName, rec.mName]));
1036 if (tfld.mEBS <> TEBS.TEnum) then raise Exception.Create(Format('triggerdata value for field ''%s'' in record ''%s'' with bad ''type'' field', [mName, rec.mName]));
1038 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]));
1041 //if mRecRefOwned then mRecRef.Free();
1042 //mRecRefOwned := true;
1045 exit;
1047 // other record types
1049 begin
1051 if (rec = nil) then raise Exception.Create(Format('record ''%s'' (%s) value for field ''%s'' not found', [pr.tokStr, mEBSTypeName, mName]));
1053 //if mRecRefOwned then mRecRef.Free();
1054 //mRecRefOwned := false;
1058 exit;
1059 end
1061 begin
1063 if (rec = nil) then raise Exception.Create(Format('record type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1066 //if mRecRefOwned then mRecRef.Free();
1067 //mRecRefOwned := true;
1071 exit;
1076 begin
1079 if (es = nil) then raise Exception.Create(Format('record enum type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1081 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]));
1084 //writeln('ENUM ', mEBSName, '; element <', mSVal, '> with value ', mIVal);
1087 exit;
1090 begin
1093 if (es = nil) then raise Exception.Create(Format('record bitset type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1096 begin
1098 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]));
1102 if mBitSetUnique then raise Exception.Create(Format('record bitset of type ''%s'' for field ''%s'' expects only one value', [tk, mEBSTypeName, mName]));
1103 //pr.expectDelim('|');
1108 exit;
1115 begin
1121 exit;
1124 begin
1125 if (mMaxDim = 0) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
1128 begin
1129 // single char
1130 if (Length(mSVal) <> 1) then raise Exception.Create(Format('invalid string size for field ''%s''', [mName]));
1133 end
1134 else
1135 begin
1136 // string
1137 if (Length(mSVal) > mMaxDim) then raise Exception.Create(Format('invalid string size for field ''%s''', [mName]));
1141 exit;
1144 begin
1147 exit;
1150 begin
1153 exit;
1156 begin
1159 exit;
1162 begin
1165 exit;
1168 begin
1171 exit;
1174 begin
1177 exit;
1180 begin
1184 exit;
1188 begin
1192 begin
1193 if (mIVal < -32768) or (mIVal > 32767) then raise Exception.Create(Format('invalid %s value for field ''%s''', [getTypeName(mType), mName]));
1194 end
1195 else
1196 begin
1197 if (mIVal < 0) or (mIVal > 32767) then raise Exception.Create(Format('invalid %s value for field ''%s''', [getTypeName(mType), mName]));
1201 begin
1202 if (mIVal2 < -32768) or (mIVal2 > 32767) then raise Exception.Create(Format('invalid %s value for field ''%s''', [getTypeName(mType), mName]));
1203 end
1204 else
1205 begin
1206 if (mIVal2 < 0) or (mIVal2 > 32767) then raise Exception.Create(Format('invalid %s value for field ''%s''', [getTypeName(mType), mName]));
1211 exit;
1214 begin
1216 exit;
1219 begin
1221 exit;
1230 begin
1234 // ////////////////////////////////////////////////////////////////////////// //
1236 begin
1237 if (pr = nil) then raise Exception.Create('cannot create record type without type definition');
1250 begin
1260 begin
1269 begin
1272 begin
1281 begin
1287 var
1289 begin
1296 begin
1302 var
1304 begin
1312 var
1314 begin
1325 begin
1335 var
1338 begin
1340 begin
1343 begin
1345 begin
1349 if isForTrig[tdn] then raise Exception.Create(Format('duplicate trigdata ''%s'' trigtype ''%s''', [mName, tdn]));
1353 end
1354 else
1355 begin
1360 end
1361 else
1362 begin
1367 begin
1370 begin
1371 if (mSize > 0) then raise Exception.Create(Format('duplicate `size` in record ''%s''', [mName]));
1373 if (mSize < 1) then raise Exception.Create(Format('invalid record ''%s'' size: %d', [mName, mSize]));
1375 continue;
1378 begin
1379 if (mBinBlock >= 0) then raise Exception.Create(Format('duplicate `binblock` in record ''%s''', [mName]));
1381 if (mBinBlock < 1) then raise Exception.Create(Format('invalid record ''%s'' binblock: %d', [mName, mBinBlock]));
1382 continue;
1388 // load fields
1390 begin
1392 if hasByName(fld.name) then begin fld.Free(); raise Exception.Create(Format('duplicate field ''%s''', [fld.name])); end;
1393 // append
1397 // done with field
1398 //writeln('DEF: ', fld.definition);
1405 var
1407 begin
1409 begin
1410 // trigger data
1413 begin
1416 begin
1421 end
1422 else
1423 begin
1426 end
1427 else
1428 begin
1429 // record
1436 begin
1446 var
1455 begin
1457 begin
1458 if (mBinBlock < 1) then raise Exception.Create('cannot write binary record without block number');
1461 end
1462 else
1463 begin
1468 begin
1469 if (mOwner.curheader <> nil) then raise Exception.Create('`writeBinTo()` cannot be called recursively');
1472 try
1477 // write normal fields
1479 begin
1481 // record list?
1485 if (fld.mBinOfs >= bufsz) then raise Exception.Create('binary value offset is outside of the buffer');
1491 // write block with normal fields
1493 begin
1495 // signature and version
1506 // write other blocks, if any
1508 begin
1509 // calculate blkmax
1512 begin
1514 // record list?
1516 begin
1524 // write blocks
1526 begin
1530 begin
1532 // record list?
1534 begin
1540 //rec.writeBinTo(ws);
1544 // flush block
1546 begin
1557 finally
1566 var
1569 begin
1571 begin
1578 try
1580 begin
1582 // record list?
1584 begin
1587 begin
1591 continue;
1598 finally
1607 var
1611 //success: Boolean;
1612 begin
1613 if (mOwner = nil) then raise Exception.Create(Format('can''t parse record ''%s'' value without owner', [mName]));
1616 begin
1617 // id?
1624 begin
1629 // records
1631 begin
1633 // add records with this type (if any)
1636 begin
1638 try
1642 begin
1645 begin
1647 begin
1648 if (Length(fld.mRVal[c].mId) > 0) and (CompareText(fld.mRVal[c].mId, rec.mId) = 0) then raise Exception.Create(Format('duplicate thing ''%s'' in record ''%s''', [fld.mName, mName]));
1654 finally
1657 continue;
1659 {
1660 success := false;
1661 for f := 0 to High(mOwner.records) do
1662 begin
1663 if (CompareText(mOwner.records[f].mName, pr.tokStr) = 0) then
1664 begin
1665 // find (or create) list of records with this type
1666 fld := field[pr.tokStr];
1667 if (fld = nil) then
1668 begin
1669 // first record
1670 fld := TDynField.Create(mOwner.records[f].mName, TDynField.TType.TList);
1671 fld.mOwner := self;
1672 SetLength(mFields, Length(mFields)+1);
1673 mFields[High(mFields)] := fld;
1674 end;
1675 if (fld.mType <> TDynField.TType.TList) then raise Exception.Create(Format('thing ''%s'' in record ''%s'' must be record', [fld.mName, mName]));
1676 rec := mOwner.records[f].clone();
1677 try
1678 pr.skipToken();
1679 rec.parseValue(pr);
1680 if (Length(rec.mId) > 0) then
1681 begin
1682 for c := 0 to High(fld.mRVal) do
1683 begin
1684 if (Length(fld.mRVal[c].mId) > 0) and (CompareText(fld.mRVal[c].mId, rec.mId) = 0) then raise Exception.Create(Format('duplicate thing ''%s'' in record ''%s''', [fld.mName, mName]));
1685 end;
1686 end;
1687 SetLength(fld.mRVal, Length(fld.mRVal)+1);
1688 fld.mRVal[High(fld.mRVal)] := rec;
1689 writeln('added ''', mOwner.records[f].mName, ''' with id ''', rec.mId, ''' (total:', Length(fld.mRVal), ')');
1690 //assert(mOwner.findRecordById(mOwner.records[f].mName, rec.mId) <> nil);
1691 rec := nil;
1692 finally
1693 rec.Free();
1694 end;
1695 success := true;
1696 break;
1697 end;
1698 end;
1699 if success then continue;
1700 }
1703 // fields
1706 begin
1707 if fld.defined then raise Exception.Create(Format('duplicate field ''%s'' in record ''%s''', [fld.mName, mName]));
1708 if fld.internal then raise Exception.Create(Format('internal field ''%s'' in record ''%s''', [fld.mName, mName]));
1711 continue;
1714 // something is wrong
1718 // fix field defaults
1725 begin
1729 // ////////////////////////////////////////////////////////////////////////// //
1731 begin
1738 begin
1745 begin
1756 begin
1759 begin
1768 begin
1774 var
1776 begin
1783 var
1785 begin
1789 // fields
1792 begin
1796 begin
1800 end
1801 else
1802 begin
1807 // max field
1814 var
1820 begin
1829 begin
1832 begin
1833 if (CompareText(mIds[f], idname) = 0) then raise Exception.Create(Format('duplicate field ''%s'' in enum/bitset ''%s''', [idname, mName]));
1835 if (CompareText(mMaxName, idname) = 0) then raise Exception.Create(Format('duplicate field ''%s'' in enum/bitset ''%s''', [idname, mName]));
1839 // has value?
1841 begin
1843 begin
1844 if (Length(mMaxName) > 0) then raise Exception.Create(Format('duplicate max field ''%s'' in enum/bitset ''%s''', [idname, mName]));
1847 end
1848 else
1849 begin
1855 // append it?
1857 begin
1858 // fix maxvalue
1860 begin
1867 // next cv
1869 begin
1878 // add max field
1880 begin
1889 // ////////////////////////////////////////////////////////////////////////// //
1891 begin
1901 var
1903 begin
1915 begin
1922 var
1924 begin
1926 begin
1934 var
1936 begin
1938 begin
1946 var
1948 begin
1950 begin
1958 var
1962 begin
1965 // find record type
1966 //writeln('searching for type <', atypename, '>');
1969 // find record data
1970 //writeln('searching for data of type <', atypename, '>');
1974 // find by id
1975 //writeln('searching for data of type <', atypename, '> with id <', aid, '> (', Length(fld.mRVal), ')');
1977 begin
1979 begin
1980 //writeln(' FOUND!');
1982 exit;
1985 // alas
1990 var
1993 begin
1995 // find record type
1998 // find record data
1999 //writeln('searching for data of type <', atypename, '>');
2002 begin
2003 // first record
2010 // add
2016 function TDynMapDef.findRecordNumByType (const atypename: AnsiString; rc: TDynRecord): Integer;
2017 var
2021 begin
2024 // find record type
2027 // find record data
2031 // find by ref
2033 begin
2035 begin
2037 exit;
2040 // alas
2045 var
2049 begin
2052 begin
2057 begin
2060 begin
2067 //writeln(eb.definition); writeln;
2068 continue;
2072 begin
2075 begin
2077 begin
2085 //writeln(dr.definition); writeln;
2086 continue;
2090 //writeln(dr.definition); writeln;
2091 if (findRec(dr.name) <> nil) then begin dr.Free(); raise Exception.Create(Format('duplicate record ''%s''', [dr.name])); end;
2092 if (hdr <> nil) and (CompareText(dr.name, hdr.name) = 0) then begin dr.Free(); raise Exception.Create(Format('duplicate record ''%s''', [dr.name])); end;
2095 begin
2096 if (hdr <> nil) then begin dr.Free(); raise Exception.Create(Format('duplicate header record ''%s'' (previous is ''%s'')', [dr.name, hdr.name])); end;
2098 end
2099 else
2100 begin
2113 // ////////////////////////////////////////////////////////////////////////// //
2115 var
2117 begin
2118 if (curheader <> nil) then raise Exception.Create('cannot call `parseMap()` recursively, sorry');
2120 try
2127 finally
2135 begin