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
70 // default values
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;
133 private
144 private
154 public
169 public
183 private
192 private
201 public
207 public
216 private
218 function findRecordByTypeId (const atypename, aid: AnsiString; curheader: TDynRecord): TDynRecord;
219 function findRecordNumByType (const atypename: AnsiString; rc: TDynRecord; curheader: TDynRecord): Integer;
221 public
226 private
231 public
239 // creates new header record
242 // creates new header record
245 public
250 implementation
252 uses
253 SysUtils,
254 utils;
257 // ////////////////////////////////////////////////////////////////////////// //
259 begin
269 begin
276 begin
283 begin
311 var
313 begin
344 // won't work for lists
346 begin
370 var
373 begin
375 begin
377 begin
379 raise Exception.Create(Format('field ''%s'' in record ''%s'' of record type ''%s'' is not set', [mName, mOwner.mId, mOwner.mName]));
382 begin
383 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]));
387 exit;
395 //mDefined := true;
396 //writeln('DEFAULT for <', mName, '>: <', s, '>');
398 try
400 finally
410 var
414 begin
416 //result := mDefaultValueSet;
421 TType.TPoint, TType.TSize: begin result := false; exit; end; // no default values for these types yet
425 try
429 finally
437 begin
458 begin
467 TEBS.TBitSet: begin result += ' bitset '; if mBitSetUnique then result += 'unique '; result += mEBSTypeName; end;
470 begin
471 if (mType = TType.TChar) or (mType = TType.TString) then result += ' default '+TTextParser.quote(mDefSVal)
473 {
474 else
475 begin
476 if (mType = TType.TBool) then
477 begin
478 result += ' default ';
479 if (mDefIVal <> 0) then result += 'true' else result += 'false';
480 end
481 else
482 begin
483 result += Format(' default %d', [mDefIVal]);
484 end;
485 end;
486 }
489 begin
490 if (mType = TType.TPoint) then begin if (mAsT) then result += ' as txy' else result += ' as xy'; end
491 else if (mType = TType.TSize) then begin if (mAsT) then result += ' as twh' else result += ' as wh'; end;
499 var
516 begin
537 // field name
540 // field type
544 // fixed-size array?
546 begin
548 if (lmaxdim < 1) then raise Exception.Create(Format('invali field ''%s'' array size', [fldname]));
553 begin
555 begin
556 if (fldofs >= 0) then raise Exception.Create(Format('duplicate field ''%s'' offset', [fldname]));
559 continue;
563 begin
569 continue;
573 begin
575 if (Length(fldrecname) <> 0) then raise Exception.Create(Format('field ''%s'' already typed as ''%s''', [fldname, fldrecname]));
577 continue;
581 begin
583 if (Length(fldrecname) <> 0) then raise Exception.Create(Format('field ''%s'' already typed as ''%s''', [fldname, fldrecname]));
586 continue;
590 begin
591 if hasdefStr or hasdefInt or hasdefId then raise Exception.Create(Format('field ''%s'' has duplicate default', [fldname]));
594 begin
599 begin
604 begin
608 else
611 continue;
615 begin
617 continue;
621 begin
623 continue;
626 if (pr.tokType <> pr.TTId) then raise Exception.Create(Format('field ''%s'' has something unexpected in definition', [fldname]));
628 if (Length(fldrecname) <> 0) then raise Exception.Create(Format('field ''%s'' already typed as ''%s''', [fldname, fldrecname]));
635 // create field
650 else raise Exception.Create(Format('field ''%s'' has invalid type ''%s''', [fldname, fldtype]));
652 {if hasdefId and (self.baseType = self.TType.TBool) then
653 begin
654 if (defstr = 'true') or (defstr = 'tan') or (defstr = 'yes') then self.mDefIVal := 1
655 else if (defstr = 'false') or (defstr = 'ona') or (defstr = 'no') then self.mDefIVal := 0
656 else raise Exception.Create(Format('field ''%s'' has invalid boolean default ''%s''', [fldname, defstr]));
657 end
658 else}
659 begin
681 var
687 begin
691 begin
692 // this must be byte/word/int
694 begin
695 // this must be triggerdata
697 begin
698 raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
700 // write triggerdata
703 else raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
705 //writeln('trigdata size: ', mMaxDim);
707 if (buf = nil) then raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
708 try
711 begin
716 finally
720 exit;
723 begin
724 // no ref, write -1
729 else raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
731 exit;
740 else raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
742 // find record number
744 if (f < 0) then raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' not found in record list', [mEBSTypeName, mName]));
745 if (f > maxv) then raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' has too big index', [mEBSTypeName, mName]));
750 else raise Exception.Create(Format('record reference type ''%s'' in field ''%s'' cannot be written', [mEBSTypeName, mName]));
752 exit;
761 begin
763 exit;
766 begin
767 if (mMaxDim = 0) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
769 begin
770 if (Length(mSVal) <> 1) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
772 end
773 else
774 begin
775 if (Length(mSVal) > mMaxDim) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
776 //FillChar(s[0], sizeof(s), 0);
778 //writeln('writing char[', mMaxDim, '] <', mName, '>: ', TTextParser.quote(s));
782 exit;
786 begin
787 // either array, and this should be triggerdata, or byte
789 begin
790 // byte
792 end
793 else
794 begin
795 // array
798 exit;
802 begin
803 if (mMaxDim > 0) then raise Exception.Create(Format('short array in field ''%s'' cannot be written', [mName]));
805 exit;
809 begin
810 if (mMaxDim > 0) then raise Exception.Create(Format('int array in field ''%s'' cannot be written', [mName]));
812 exit;
815 begin
820 begin
821 if (mMaxDim > 0) then raise Exception.Create(Format('pos/size array in field ''%s'' cannot be written', [mName]));
824 exit;
827 begin
829 exit;
832 begin
834 exit;
842 var
847 begin
850 // if this field should contain struct, convert type and parse struct
854 begin
856 begin
858 end
860 begin
862 end
863 else
864 begin
868 exit;
871 begin
874 if (es = nil) then raise Exception.Create(Format('record enum type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
876 begin
878 begin
881 exit;
884 raise Exception.Create(Format('value %d in record enum type ''%s'' for field ''%s'' not found', [mIVal, mEBSTypeName, mName]));
887 begin
890 if (es = nil) then raise Exception.Create(Format('record bitset type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
891 // none?
893 begin
895 begin
897 begin
900 exit;
903 raise Exception.Create(Format('value %d in record bitset type ''%s'' for field ''%s'' not found', [0, mEBSTypeName, mName]));
905 // not none
909 begin
911 begin
914 begin
916 begin
920 break;
923 if not found then raise Exception.Create(Format('value %d in record bitset type ''%s'' for field ''%s'' not found', [mask, mEBSTypeName, mName]));
928 exit;
935 begin
937 exit;
940 begin
941 if (mMaxDim = 0) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
944 exit;
952 begin
954 exit;
957 begin
960 exit;
964 begin
966 exit;
969 begin
971 exit;
974 begin
976 exit;
987 begin
989 if (mIVal < min) or (mIVal > max) then raise Exception.Create(Format('invalid %s value for field ''%s''', [getTypeName(mType), mName]));
993 var
999 begin
1000 // if this field should contain struct, convert type and parse struct
1004 begin
1006 // ugly hack. sorry.
1008 begin
1010 // find trigger definition
1012 if (tfld = nil) then raise Exception.Create(Format('triggerdata value for field ''%s'' in record ''%s'' without ''type'' field', [mName, rec.mName]));
1013 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]));
1015 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]));
1020 exit;
1022 // other record types
1024 begin
1026 if (rec = nil) then raise Exception.Create(Format('record ''%s'' (%s) value for field ''%s'' not found', [pr.tokStr, mEBSTypeName, mName]));
1031 exit;
1032 end
1034 begin
1036 if (rec = nil) then raise Exception.Create(Format('record type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1042 exit;
1047 begin
1050 if (es = nil) then raise Exception.Create(Format('record enum type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1052 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]));
1055 //writeln('ENUM ', mEBSName, '; element <', mSVal, '> with value ', mIVal);
1058 exit;
1061 begin
1064 if (es = nil) then raise Exception.Create(Format('record bitset type ''%s'' for field ''%s'' not found', [mEBSTypeName, mName]));
1067 begin
1069 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]));
1073 if mBitSetUnique then raise Exception.Create(Format('record bitset of type ''%s'' for field ''%s'' expects only one value', [tk, mEBSTypeName, mName]));
1074 //pr.expectDelim('|');
1079 exit;
1086 begin
1092 exit;
1095 begin
1096 if (mMaxDim = 0) then raise Exception.Create(Format('invalid string size definition for field ''%s''', [mName]));
1099 begin
1100 // single char
1101 if (Length(mSVal) <> 1) then raise Exception.Create(Format('invalid string size for field ''%s''', [mName]));
1104 end
1105 else
1106 begin
1107 // string
1108 if (Length(mSVal) > mMaxDim) then raise Exception.Create(Format('invalid string size for field ''%s''', [mName]));
1112 exit;
1115 begin
1118 exit;
1121 begin
1124 exit;
1127 begin
1130 exit;
1133 begin
1136 exit;
1139 begin
1142 exit;
1145 begin
1148 exit;
1151 begin
1155 exit;
1159 begin
1163 begin
1164 if (mIVal < -32768) or (mIVal > 32767) then raise Exception.Create(Format('invalid %s value for field ''%s''', [getTypeName(mType), mName]));
1165 end
1166 else
1167 begin
1168 if (mIVal < 0) or (mIVal > 32767) then raise Exception.Create(Format('invalid %s value for field ''%s''', [getTypeName(mType), mName]));
1172 begin
1173 if (mIVal2 < -32768) or (mIVal2 > 32767) then raise Exception.Create(Format('invalid %s value for field ''%s''', [getTypeName(mType), mName]));
1174 end
1175 else
1176 begin
1177 if (mIVal2 < 0) or (mIVal2 > 32767) then raise Exception.Create(Format('invalid %s value for field ''%s''', [getTypeName(mType), mName]));
1182 exit;
1185 begin
1187 exit;
1190 begin
1192 exit;
1201 begin
1205 // ////////////////////////////////////////////////////////////////////////// //
1207 begin
1208 if (pr = nil) then raise Exception.Create('cannot create record type without type definition');
1221 begin
1231 begin
1240 begin
1243 begin
1252 begin
1258 var
1260 begin
1267 begin
1273 var
1275 begin
1283 var
1285 begin
1296 begin
1306 var
1309 begin
1311 begin
1314 begin
1316 begin
1320 if isForTrig[tdn] then raise Exception.Create(Format('duplicate trigdata ''%s'' trigtype ''%s''', [mName, tdn]));
1324 end
1325 else
1326 begin
1331 end
1332 else
1333 begin
1338 begin
1341 begin
1342 if (mSize > 0) then raise Exception.Create(Format('duplicate `size` in record ''%s''', [mName]));
1344 if (mSize < 1) then raise Exception.Create(Format('invalid record ''%s'' size: %d', [mName, mSize]));
1346 continue;
1349 begin
1350 if (mBinBlock >= 0) then raise Exception.Create(Format('duplicate `binblock` in record ''%s''', [mName]));
1352 if (mBinBlock < 1) then raise Exception.Create(Format('invalid record ''%s'' binblock: %d', [mName, mBinBlock]));
1353 continue;
1359 // load fields
1361 begin
1363 if hasByName(fld.name) then begin fld.Free(); raise Exception.Create(Format('duplicate field ''%s''', [fld.name])); end;
1364 // append
1368 // done with field
1369 //writeln('DEF: ', fld.definition);
1376 var
1378 begin
1380 begin
1381 // trigger data
1384 begin
1387 begin
1392 end
1393 else
1394 begin
1397 end
1398 else
1399 begin
1400 // record
1407 begin
1417 var
1425 begin
1428 begin
1429 if (mBinBlock < 1) then raise Exception.Create('cannot write binary record without block number');
1432 end
1433 else
1434 begin
1437 try
1442 // write normal fields
1444 begin
1446 // record list?
1450 if (fld.mBinOfs >= bufsz) then raise Exception.Create('binary value offset is outside of the buffer');
1456 // write block with normal fields
1458 begin
1460 // signature and version
1471 // write other blocks, if any
1473 begin
1474 // calculate blkmax
1477 begin
1479 // record list?
1481 begin
1489 // write blocks
1491 begin
1495 begin
1497 // record list?
1499 begin
1505 //rec.writeBinTo(ws);
1509 // flush block
1511 begin
1522 finally
1530 var
1533 begin
1535 begin
1542 try
1544 begin
1546 // record list?
1548 begin
1551 begin
1555 continue;
1562 finally
1571 var
1575 //success: Boolean;
1576 begin
1577 if (mOwner = nil) then raise Exception.Create(Format('can''t parse record ''%s'' value without owner', [mName]));
1579 // not a header?
1581 begin
1582 // id?
1589 begin
1591 //writeln('<', pr.tokStr, ':', asheader, '>');
1593 // records
1595 begin
1596 // add records with this type (if any)
1599 begin
1601 try
1605 begin
1608 begin
1610 begin
1611 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]));
1617 finally
1620 continue;
1624 // fields
1627 begin
1628 if fld.defined then raise Exception.Create(Format('duplicate field ''%s'' in record ''%s''', [fld.mName, mName]));
1629 if fld.internal then raise Exception.Create(Format('internal field ''%s'' in record ''%s''', [fld.mName, mName]));
1632 continue;
1635 // something is wrong
1639 // fix field defaults
1646 begin
1650 // ////////////////////////////////////////////////////////////////////////// //
1652 begin
1659 begin
1666 begin
1677 begin
1680 begin
1689 begin
1695 var
1697 begin
1704 var
1706 begin
1710 // fields
1713 begin
1717 begin
1721 end
1722 else
1723 begin
1728 // max field
1735 var
1741 begin
1750 begin
1753 begin
1754 if (CompareText(mIds[f], idname) = 0) then raise Exception.Create(Format('duplicate field ''%s'' in enum/bitset ''%s''', [idname, mName]));
1756 if (CompareText(mMaxName, idname) = 0) then raise Exception.Create(Format('duplicate field ''%s'' in enum/bitset ''%s''', [idname, mName]));
1760 // has value?
1762 begin
1764 begin
1765 if (Length(mMaxName) > 0) then raise Exception.Create(Format('duplicate max field ''%s'' in enum/bitset ''%s''', [idname, mName]));
1768 end
1769 else
1770 begin
1776 // append it?
1778 begin
1779 // fix maxvalue
1781 begin
1788 // next cv
1790 begin
1799 // add max field
1801 begin
1810 // ////////////////////////////////////////////////////////////////////////// //
1812 begin
1821 var
1823 begin
1835 begin
1842 var
1844 begin
1846 begin
1854 var
1856 begin
1858 begin
1866 var
1868 begin
1870 begin
1877 function TDynMapDef.findRecordByTypeId (const atypename, aid: AnsiString; curheader: TDynRecord): TDynRecord;
1878 var
1882 begin
1884 // find record type
1886 //writeln('searching for type <', atypename, '>');
1889 // find record data
1890 //writeln('searching for data of type <', atypename, '>');
1894 // find by id
1895 //writeln('searching for data of type <', atypename, '> with id <', aid, '> (', Length(fld.mRVal), ')');
1897 begin
1899 begin
1900 //writeln(' FOUND!');
1902 exit;
1905 // alas
1909 procedure TDynMapDef.addRecordByType (const atypename: AnsiString; rc: TDynRecord; curheader: TDynRecord);
1910 var
1913 begin
1915 // find record type
1918 // find record data
1919 //writeln('searching for data of type <', atypename, '>');
1922 begin
1923 // first record
1930 // add
1936 function TDynMapDef.findRecordNumByType (const atypename: AnsiString; rc: TDynRecord; curheader: TDynRecord): Integer;
1937 var
1941 begin
1944 // find record type
1947 // find record data
1951 // find by ref
1953 begin
1955 begin
1957 exit;
1960 // alas
1965 var
1969 begin
1972 begin
1977 begin
1980 begin
1987 //writeln(eb.definition); writeln;
1988 continue;
1992 begin
1995 begin
1997 begin
2005 //writeln(dr.definition); writeln;
2006 continue;
2010 //writeln(dr.definition); writeln;
2011 if (findRecType(dr.name) <> nil) then begin dr.Free(); raise Exception.Create(Format('duplicate record ''%s''', [dr.name])); end;
2012 if (hdr <> nil) and (CompareText(dr.name, hdr.name) = 0) then begin dr.Free(); raise Exception.Create(Format('duplicate record ''%s''', [dr.name])); end;
2015 begin
2016 if (hdr <> nil) then begin dr.Free(); raise Exception.Create(Format('duplicate header record ''%s'' (previous is ''%s'')', [dr.name, hdr.name])); end;
2018 end
2019 else
2020 begin
2033 // ////////////////////////////////////////////////////////////////////////// //
2035 var
2037 begin
2039 try
2046 begin
2055 begin