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
72 // default value
77 // temp
80 private
88 public
105 // won't work for lists
108 public
114 //property ival: Integer read mIVal write setIVal;
115 //property sval: AnsiString read mSVal write setSVal;
132 // "value" header record contains TList fields, with name equal to record type
134 private
145 private
155 public
170 public
184 private
193 private
202 public
208 public
217 private
219 function findRecordByTypeId (const atypename, aid: AnsiString; curheader: TDynRecord): TDynRecord;
220 function findRecordNumByType (const atypename: AnsiString; rc: TDynRecord; curheader: TDynRecord): Integer;
222 public
227 private
232 public
240 // creates new header record
243 // creates new header record
246 public
251 implementation
253 uses
254 SysUtils,
255 utils;
258 // ////////////////////////////////////////////////////////////////////////// //
260 begin
270 begin
277 begin
284 begin
312 var
314 begin
345 // won't work for lists
347 begin
371 var
374 begin
376 begin
378 begin
380 raise Exception.Create(Format('field ''%s'' in record ''%s'' of record type ''%s'' is not set', [mName, mOwner.mId, mOwner.mName]));
383 begin
384 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]));
388 exit;
396 //mDefined := true;
397 //writeln('DEFAULT for <', mName, '>: <', s, '>');
399 try
401 finally
411 var
415 begin
417 //result := mDefaultValueSet;
422 TType.TPoint, TType.TSize: begin result := false; exit; end; // no default values for these types yet
426 try
430 finally
438 begin
459 begin
468 TEBS.TBitSet: begin result += ' bitset '; if mBitSetUnique then result += 'unique '; result += mEBSTypeName; end;
471 begin
472 if (mType = TType.TChar) or (mType = TType.TString) then result += ' default '+TTextParser.quote(mDefSVal)
474 {
475 else
476 begin
477 if (mType = TType.TBool) then
478 begin
479 result += ' default ';
480 if (mDefIVal <> 0) then result += 'true' else result += 'false';
481 end
482 else
483 begin
484 result += Format(' default %d', [mDefIVal]);
485 end;
486 end;
487 }
490 begin
491 if (mType = TType.TPoint) then begin if (mAsT) then result += ' as txy' else result += ' as xy'; end
492 else if (mType = TType.TSize) then begin if (mAsT) then result += ' as twh' else result += ' as wh'; end;
500 var
517 begin
538 // field name
541 // field type
545 // fixed-size array?
547 begin
549 if (lmaxdim < 1) then raise Exception.Create(Format('invali field ''%s'' array size', [fldname]));
554 begin
556 begin
557 if (fldofs >= 0) then raise Exception.Create(Format('duplicate field ''%s'' offset', [fldname]));
560 continue;
564 begin
570 continue;
574 begin
576 if (Length(fldrecname) <> 0) then raise Exception.Create(Format('field ''%s'' already typed as ''%s''', [fldname, fldrecname]));
578 continue;
582 begin
584 if (Length(fldrecname) <> 0) then raise Exception.Create(Format('field ''%s'' already typed as ''%s''', [fldname, fldrecname]));
587 continue;
591 begin
592 if hasdefStr or hasdefInt or hasdefId then raise Exception.Create(Format('field ''%s'' has duplicate default', [fldname]));
595 begin
600 begin
605 begin
609 else
612 continue;
616 begin
618 continue;
622 begin
624 continue;
627 if (pr.tokType <> pr.TTId) then raise Exception.Create(Format('field ''%s'' has something unexpected in definition', [fldname]));
629 if (Length(fldrecname) <> 0) then raise Exception.Create(Format('field ''%s'' already typed as ''%s''', [fldname, fldrecname]));
636 // create field
651 else raise Exception.Create(Format('field ''%s'' has invalid type ''%s''', [fldname, fldtype]));
653 {if hasdefId and (self.baseType = self.TType.TBool) then
654 begin
655 if (defstr = 'true') or (defstr = 'tan') or (defstr = 'yes') then self.mDefIVal := 1
656 else if (defstr = 'false') or (defstr = 'ona') or (defstr = 'no') then self.mDefIVal := 0
657 else raise Exception.Create(Format('field ''%s'' has invalid boolean default ''%s''', [fldname, defstr]));
658 end
659 else}
660 begin
682 var
688 begin
692 begin
693 // this must be byte/word/int
695 begin
696 // this must be triggerdata
698 begin
699 raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
701 // write triggerdata
704 else raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
706 //writeln('trigdata size: ', mMaxDim);
708 if (buf = nil) then raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
709 try
712 begin
717 finally
721 exit;
724 begin
725 // no ref, write -1
730 else raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
732 exit;
741 else raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
743 // find record number
745 if (f < 0) then raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' not found in record list', [mEBSTypeName, mName]));
746 if (f > maxv) then raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' has too big index', [mEBSTypeName, mName]));
751 else raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
753 exit;
762 begin
764 exit;
767 begin
768 if (mMaxDim = 0) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
770 begin
771 if (Length(mSVal) <> 1) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
773 end
774 else
775 begin
776 if (Length(mSVal) > mMaxDim) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
777 //FillChar(s[0], sizeof(s), 0);
779 //writeln('writing char[', mMaxDim, '] <', mName, '>: ', TTextParser.quote(s));
783 exit;
787 begin
788 // either array, and this should be triggerdata, or byte
790 begin
791 // byte
793 end
794 else
795 begin
796 // array
799 exit;
803 begin
804 if (mMaxDim > 0) then raise Exception.Create(Format('short array in field ''%s'' cannot be written', [mName]));
806 exit;
810 begin
811 if (mMaxDim > 0) then raise Exception.Create(Format('int array in field ''%s'' cannot be written', [mName]));
813 exit;
816 begin
821 begin
822 if (mMaxDim > 0) then raise Exception.Create(Format('pos/size array in field ''%s'' cannot be written', [mName]));
825 exit;
828 begin
830 exit;
833 begin
835 exit;
843 var
848 begin
851 // if this field should contain struct, convert type and parse struct
855 begin
857 begin
859 end
861 begin
863 end
864 else
865 begin
869 exit;
872 begin
875 if (es = nil) then raise Exception.Create(Format('record enum type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
877 begin
879 begin
882 exit;
885 raise Exception.Create(Format('value %d in record enum type ''%s'' for field ''%s'' not found', [mIVal, mEBSTypeName, mName]));
888 begin
891 if (es = nil) then raise Exception.Create(Format('record bitset type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
892 // none?
894 begin
896 begin
898 begin
901 exit;
904 raise Exception.Create(Format('value %d in record bitset type ''%s'' for field ''%s'' not found', [0, mEBSTypeName, mName]));
906 // not none
910 begin
912 begin
915 begin
917 begin
921 break;
924 if not found then raise Exception.Create(Format('value %d in record bitset type ''%s'' for field ''%s'' not found', [mask, mEBSTypeName, mName]));
929 exit;
936 begin
938 exit;
941 begin
942 if (mMaxDim = 0) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
945 exit;
953 begin
955 exit;
958 begin
961 exit;
965 begin
967 exit;
970 begin
972 exit;
975 begin
977 exit;
988 begin
990 if (mIVal < min) or (mIVal > max) then raise Exception.Create(Format('invalid %s value for field ''%s''', [getTypeName(mType), mName]));
994 var
1000 begin
1001 // if this field should contain struct, convert type and parse struct
1005 begin
1007 // ugly hack. sorry.
1009 begin
1011 // find trigger definition
1013 if (tfld = nil) then raise Exception.Create(Format('triggerdata value for field ''%s'' in record ''%s'' without ''type'' field', [mName, rec.mName]));
1014 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]));
1016 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]));
1021 exit;
1023 // other record types
1025 begin
1027 if (rec = nil) then raise Exception.Create(Format('record ''%s'' (%s) value for field ''%s'' not found', [pr.tokStr, mEBSTypeName, mName]));
1032 exit;
1033 end
1035 begin
1037 if (rec = nil) then raise Exception.Create(Format('record type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1044 exit;
1049 begin
1052 if (es = nil) then raise Exception.Create(Format('record enum type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1054 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]));
1057 //writeln('ENUM ', mEBSName, '; element <', mSVal, '> with value ', mIVal);
1060 exit;
1063 begin
1066 if (es = nil) then raise Exception.Create(Format('record bitset type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1069 begin
1071 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]));
1075 if mBitSetUnique then raise Exception.Create(Format('record bitset of type ''%s'' for field ''%s'' expects only one value', [tk, mEBSTypeName, mName]));
1076 //pr.expectDelim('|');
1081 exit;
1088 begin
1094 exit;
1097 begin
1098 if (mMaxDim = 0) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
1101 begin
1102 // single char
1103 if (Length(mSVal) <> 1) then raise Exception.Create(Format('invalid string size for field ''%s''', [mName]));
1106 end
1107 else
1108 begin
1109 // string
1110 if (Length(mSVal) > mMaxDim) then raise Exception.Create(Format('invalid string size for field ''%s''', [mName]));
1114 exit;
1117 begin
1120 exit;
1123 begin
1126 exit;
1129 begin
1132 exit;
1135 begin
1138 exit;
1141 begin
1144 exit;
1147 begin
1150 exit;
1153 begin
1157 exit;
1161 begin
1165 begin
1166 if (mIVal < -32768) or (mIVal > 32767) then raise Exception.Create(Format('invalid %s value for field ''%s''', [getTypeName(mType), mName]));
1167 end
1168 else
1169 begin
1170 if (mIVal < 0) or (mIVal > 32767) then raise Exception.Create(Format('invalid %s value for field ''%s''', [getTypeName(mType), mName]));
1174 begin
1175 if (mIVal2 < -32768) or (mIVal2 > 32767) then raise Exception.Create(Format('invalid %s value for field ''%s''', [getTypeName(mType), mName]));
1176 end
1177 else
1178 begin
1179 if (mIVal2 < 0) or (mIVal2 > 32767) then raise Exception.Create(Format('invalid %s value for field ''%s''', [getTypeName(mType), mName]));
1184 exit;
1187 begin
1189 exit;
1192 begin
1194 exit;
1203 begin
1207 // ////////////////////////////////////////////////////////////////////////// //
1209 begin
1210 if (pr = nil) then raise Exception.Create('cannot create record type without type definition');
1223 begin
1233 begin
1242 begin
1245 begin
1254 begin
1260 var
1262 begin
1269 begin
1275 var
1277 begin
1285 var
1287 begin
1298 begin
1308 var
1311 begin
1313 begin
1316 begin
1318 begin
1322 if isForTrig[tdn] then raise Exception.Create(Format('duplicate trigdata ''%s'' trigtype ''%s''', [mName, tdn]));
1326 end
1327 else
1328 begin
1333 end
1334 else
1335 begin
1340 begin
1343 begin
1344 if (mSize > 0) then raise Exception.Create(Format('duplicate `size` in record ''%s''', [mName]));
1346 if (mSize < 1) then raise Exception.Create(Format('invalid record ''%s'' size: %d', [mName, mSize]));
1348 continue;
1351 begin
1352 if (mBinBlock >= 0) then raise Exception.Create(Format('duplicate `binblock` in record ''%s''', [mName]));
1354 if (mBinBlock < 1) then raise Exception.Create(Format('invalid record ''%s'' binblock: %d', [mName, mBinBlock]));
1355 continue;
1361 // load fields
1363 begin
1365 if hasByName(fld.name) then begin fld.Free(); raise Exception.Create(Format('duplicate field ''%s''', [fld.name])); end;
1366 // append
1370 // done with field
1371 //writeln('DEF: ', fld.definition);
1378 var
1380 begin
1382 begin
1383 // trigger data
1386 begin
1389 begin
1394 end
1395 else
1396 begin
1399 end
1400 else
1401 begin
1402 // record
1409 begin
1419 var
1427 begin
1430 begin
1431 if (mBinBlock < 1) then raise Exception.Create('cannot write binary record without block number');
1434 end
1435 else
1436 begin
1439 try
1444 // write normal fields
1446 begin
1448 // record list?
1452 if (fld.mBinOfs >= bufsz) then raise Exception.Create('binary value offset is outside of the buffer');
1458 // write block with normal fields
1460 begin
1462 // signature and version
1473 // write other blocks, if any
1475 begin
1476 // calculate blkmax
1479 begin
1481 // record list?
1483 begin
1491 // write blocks
1493 begin
1497 begin
1499 // record list?
1501 begin
1507 //rec.writeBinTo(ws);
1511 // flush block
1513 begin
1524 finally
1532 var
1535 begin
1537 begin
1544 try
1546 begin
1548 // record list?
1550 begin
1553 begin
1557 continue;
1564 finally
1573 var
1577 //success: Boolean;
1578 begin
1579 if (mOwner = nil) then raise Exception.Create(Format('can''t parse record ''%s'' value without owner', [mName]));
1581 // not a header?
1583 begin
1584 // id?
1591 begin
1593 //writeln('<', pr.tokStr, ':', asheader, '>');
1595 // records
1597 begin
1598 // add records with this type (if any)
1601 begin
1603 try
1607 begin
1610 begin
1612 begin
1613 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]));
1619 finally
1622 continue;
1626 // fields
1629 begin
1630 if fld.defined then raise Exception.Create(Format('duplicate field ''%s'' in record ''%s''', [fld.mName, mName]));
1631 if fld.internal then raise Exception.Create(Format('internal field ''%s'' in record ''%s''', [fld.mName, mName]));
1634 continue;
1637 // something is wrong
1641 // fix field defaults
1648 begin
1652 // ////////////////////////////////////////////////////////////////////////// //
1654 begin
1661 begin
1668 begin
1679 begin
1682 begin
1691 begin
1697 var
1699 begin
1706 var
1708 begin
1712 // fields
1715 begin
1719 begin
1723 end
1724 else
1725 begin
1730 // max field
1737 var
1743 begin
1752 begin
1755 begin
1756 if (CompareText(mIds[f], idname) = 0) then raise Exception.Create(Format('duplicate field ''%s'' in enum/bitset ''%s''', [idname, mName]));
1758 if (CompareText(mMaxName, idname) = 0) then raise Exception.Create(Format('duplicate field ''%s'' in enum/bitset ''%s''', [idname, mName]));
1762 // has value?
1764 begin
1766 begin
1767 if (Length(mMaxName) > 0) then raise Exception.Create(Format('duplicate max field ''%s'' in enum/bitset ''%s''', [idname, mName]));
1770 end
1771 else
1772 begin
1778 // append it?
1780 begin
1781 // fix maxvalue
1783 begin
1790 // next cv
1792 begin
1801 // add max field
1803 begin
1812 // ////////////////////////////////////////////////////////////////////////// //
1814 begin
1823 var
1825 begin
1837 begin
1844 var
1846 begin
1848 begin
1856 var
1858 begin
1860 begin
1868 var
1870 begin
1872 begin
1879 function TDynMapDef.findRecordByTypeId (const atypename, aid: AnsiString; curheader: TDynRecord): TDynRecord;
1880 var
1884 begin
1886 // find record type
1888 //writeln('searching for type <', atypename, '>');
1891 // find record data
1892 //writeln('searching for data of type <', atypename, '>');
1896 // find by id
1897 //writeln('searching for data of type <', atypename, '> with id <', aid, '> (', Length(fld.mRVal), ')');
1899 begin
1901 begin
1902 //writeln(' FOUND!');
1904 exit;
1907 // alas
1911 procedure TDynMapDef.addRecordByType (const atypename: AnsiString; rc: TDynRecord; curheader: TDynRecord);
1912 var
1915 begin
1917 // find record type
1920 // find record data
1921 //writeln('searching for data of type <', atypename, '>');
1924 begin
1925 // first record
1932 // add
1938 function TDynMapDef.findRecordNumByType (const atypename: AnsiString; rc: TDynRecord; curheader: TDynRecord): Integer;
1939 var
1943 begin
1946 // find record type
1949 // find record data
1953 // find by ref
1955 begin
1957 begin
1959 exit;
1962 // alas
1967 var
1971 begin
1974 begin
1979 begin
1982 begin
1989 //writeln(eb.definition); writeln;
1990 continue;
1994 begin
1997 begin
1999 begin
2007 //writeln(dr.definition); writeln;
2008 continue;
2012 //writeln(dr.definition); writeln;
2013 if (findRecType(dr.name) <> nil) then begin dr.Free(); raise Exception.Create(Format('duplicate record ''%s''', [dr.name])); end;
2014 if (hdr <> nil) and (CompareText(dr.name, hdr.name) = 0) then begin dr.Free(); raise Exception.Create(Format('duplicate record ''%s''', [dr.name])); end;
2017 begin
2018 if (hdr <> nil) then begin dr.Free(); raise Exception.Create(Format('duplicate header record ''%s'' (previous is ''%s'')', [dr.name, hdr.name])); end;
2020 end
2021 else
2022 begin
2035 // ////////////////////////////////////////////////////////////////////////// //
2037 var
2039 begin
2041 try
2048 begin
2057 begin